comparison pidgin/plugins/gevolution/gevolution.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children d75099d2567e
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /*
2 * Evolution integration plugin for Gaim
3 *
4 * Copyright (C) 2003 Christian Hammond.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21 #include "internal.h"
22 #include "gtkgaim.h"
23
24 #include "connection.h"
25 #include "debug.h"
26 #include "prefs.h"
27 #include "notify.h"
28 #include "signals.h"
29 #include "util.h"
30 #include "version.h"
31
32 #include "gtkblist.h"
33 #include "gtkconv.h"
34 #include "gtkplugin.h"
35 #include "gtkutils.h"
36
37 #include "gevolution.h"
38
39 #include <libedata-book/Evolution-DataServer-Addressbook.h>
40
41 #include <libebook/e-book-listener.h>
42 #include <libedata-book/e-data-book-factory.h>
43 #include <bonobo/bonobo-main.h>
44
45 #include <glib.h>
46
47 #define GEVOLUTION_PLUGIN_ID "gtk-x11-gevolution"
48
49 #define E_DATA_BOOK_FACTORY_OAF_ID \
50 "OAFIID:GNOME_Evolution_DataServer_BookFactory"
51
52 enum
53 {
54 COLUMN_AUTOADD,
55 COLUMN_ICON,
56 COLUMN_SCREENNAME,
57 COLUMN_DATA,
58 NUM_COLUMNS
59 };
60
61 static GaimBlistUiOps *backup_blist_ui_ops = NULL;
62 static GaimBlistUiOps *blist_ui_ops = NULL;
63 static EBook *book = NULL;
64 static gulong timer = 0;
65 static gulong book_view_tag = 0;
66 static EBookView *book_view = NULL;
67
68 static void
69 update_ims_from_contact(EContact *contact, const char *name,
70 const char *prpl_id, EContactField field)
71 {
72 GList *ims = e_contact_get(contact, field);
73 GList *l, *l2;
74
75 if (ims == NULL)
76 return;
77
78 for (l = gaim_connections_get_all(); l != NULL; l = l->next)
79 {
80 GaimConnection *gc = (GaimConnection *)l->data;
81 GaimAccount *account = gaim_connection_get_account(gc);
82 char *me;
83
84 if (strcmp(gaim_account_get_protocol_id(account), prpl_id))
85 continue;
86
87 if (!gaim_account_get_bool(account, "gevo-autoadd", FALSE))
88 continue;
89
90 me = g_strdup(gaim_normalize(account, gaim_account_get_username(account)));
91 for (l2 = ims; l2 != NULL; l2 = l2->next)
92 {
93 if (gaim_find_buddy(account, l2->data) != NULL ||
94 !strcmp(me, gaim_normalize(account, l2->data)))
95 continue;
96
97 gevo_add_buddy(account, _("Buddies"), l2->data, name);
98 }
99 g_free(me);
100 }
101
102 g_list_foreach(ims, (GFunc)g_free, NULL);
103 g_list_free(ims);
104 }
105
106 static void
107 update_buddies_from_contact(EContact *contact)
108 {
109 const char *name;
110
111 name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
112
113 update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_AIM);
114 update_ims_from_contact(contact, name, "prpl-jabber", E_CONTACT_IM_JABBER);
115 update_ims_from_contact(contact, name, "prpl-yahoo", E_CONTACT_IM_YAHOO);
116 update_ims_from_contact(contact, name, "prpl-msn", E_CONTACT_IM_MSN);
117 update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_ICQ);
118 update_ims_from_contact(contact, name, "prpl-novell", E_CONTACT_IM_GROUPWISE);
119 }
120
121 static void
122 contacts_changed_cb(EBookView *book_view, const GList *contacts)
123 {
124 const GList *l;
125
126 if (gaim_connections_get_all() == NULL)
127 return;
128
129 for (l = contacts; l != NULL; l = l->next)
130 {
131 EContact *contact = (EContact *)l->data;
132
133 update_buddies_from_contact(contact);
134 }
135 }
136
137 static void
138 request_add_buddy(GaimAccount *account, const char *username,
139 const char *group, const char *alias)
140 {
141 if (book == NULL)
142 {
143 backup_blist_ui_ops->request_add_buddy(account, username, group,
144 alias);
145 }
146 else
147 {
148 gevo_add_buddy_dialog_show(account, username, group, alias);
149 }
150 }
151
152 static void
153 got_book_view_cb(EBook *book, EBookStatus status, EBookView *view,
154 gpointer user_data)
155 {
156 book_view_tag = 0;
157
158 if (status != E_BOOK_ERROR_OK)
159 {
160 gaim_debug_error("evolution", "Unable to retrieve book view! :(\n");
161
162 return;
163 }
164
165 book_view = view;
166
167 g_object_ref(book_view);
168
169 g_signal_connect(G_OBJECT(book_view), "contacts_changed",
170 G_CALLBACK(contacts_changed_cb), book);
171
172 g_signal_connect(G_OBJECT(book_view), "contacts_added",
173 G_CALLBACK(contacts_changed_cb), book);
174
175 e_book_view_start(view);
176 }
177
178 static void
179 signed_on_cb(GaimConnection *gc)
180 {
181 EBookQuery *query;
182 gboolean status;
183 GList *contacts;
184 GList *l;
185
186 if (book == NULL)
187 return;
188
189 query = e_book_query_any_field_contains("");
190
191 status = e_book_get_contacts(book, query, &contacts, NULL);
192
193 e_book_query_unref(query);
194
195 if (!status)
196 return;
197
198 for (l = contacts; l != NULL; l = l->next)
199 {
200 EContact *contact = E_CONTACT(l->data);
201
202 update_buddies_from_contact(contact);
203
204 g_object_unref(contact);
205 }
206
207 g_list_free(contacts);
208 }
209
210 static void
211 menu_item_activate_cb(GaimBlistNode *node, gpointer user_data)
212 {
213 GaimBuddy *buddy = (GaimBuddy *)node;
214 gevo_associate_buddy_dialog_new(buddy);
215 }
216
217 static void
218 menu_item_send_mail_activate_cb(GaimBlistNode *node, gpointer user_data)
219 {
220 GaimBuddy *buddy = (GaimBuddy *)node;
221 char *mail = NULL;
222
223 mail = gevo_get_email_for_buddy(buddy);
224
225 if (mail != NULL)
226 {
227 char *app = g_find_program_in_path("evolution");
228 if (app != NULL)
229 {
230 char *command_line = g_strdup_printf("%s mailto:%s", app, mail);
231 g_free(app);
232 g_free(mail);
233
234 g_spawn_command_line_async(command_line, NULL);
235 g_free(command_line);
236 }
237 else
238 {
239 gaim_notify_error(NULL, NULL, _("Unable to send e-mail"),
240 _("The evolution executable was not found in the PATH."));
241 }
242 }
243 else
244 {
245 gaim_notify_error(NULL, NULL, _("Unable to send e-mail"),
246 _("An e-mail address was not found for this buddy."));
247 }
248 }
249
250 static void
251 blist_node_extended_menu_cb(GaimBlistNode *node, GList **menu)
252 {
253 GaimMenuAction *act;
254 GaimBuddy *buddy;
255 GaimAccount *account;
256 EContact *contact;
257 char *mail;
258
259 if (!GAIM_BLIST_NODE_IS_BUDDY(node))
260 return;
261
262 buddy = (GaimBuddy *)node;
263 account = gaim_buddy_get_account(buddy);
264
265 if (!gevo_prpl_is_supported(account, buddy))
266 return;
267
268 contact = gevo_search_buddy_in_contacts(buddy, NULL);
269
270 if (contact == NULL)
271 {
272 act = gaim_menu_action_new(_("Add to Address Book"),
273 GAIM_CALLBACK(menu_item_activate_cb),
274 NULL, NULL);
275 *menu = g_list_append(*menu, act);
276 }
277 else
278 g_object_unref(contact);
279
280 mail = gevo_get_email_for_buddy(buddy);
281
282 if (mail != NULL)
283 {
284 act = gaim_menu_action_new(_("Send E-Mail"),
285 GAIM_CALLBACK(menu_item_send_mail_activate_cb), NULL, NULL);
286 *menu = g_list_append(*menu, act);
287 g_free(mail);
288 }
289 }
290
291 /* TODO: Something in here leaks 1 reference to a bonobo object! */
292 static gboolean
293 load_timeout(gpointer data)
294 {
295 GaimPlugin *plugin = (GaimPlugin *)data;
296 EBookQuery *query;
297
298 timer = 0;
299
300 /* Maybe this is it? */
301 if (!gevo_load_addressbook(NULL, &book, NULL))
302 return FALSE;
303
304 query = e_book_query_any_field_contains("");
305
306 /* Is it this? */
307 book_view_tag = e_book_async_get_book_view(book, query, NULL, -1,
308 got_book_view_cb, NULL);
309
310 e_book_query_unref(query);
311
312 gaim_signal_connect(gaim_blist_get_handle(), "blist-node-extended-menu",
313 plugin, GAIM_CALLBACK(blist_node_extended_menu_cb), NULL);
314
315 return FALSE;
316 }
317
318 static gboolean
319 plugin_load(GaimPlugin *plugin)
320 {
321 bonobo_activate();
322
323 backup_blist_ui_ops = gaim_blist_get_ui_ops();
324
325 blist_ui_ops = g_memdup(backup_blist_ui_ops, sizeof(GaimBlistUiOps));
326 blist_ui_ops->request_add_buddy = request_add_buddy;
327
328 gaim_blist_set_ui_ops(blist_ui_ops);
329
330 gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
331 plugin, GAIM_CALLBACK(signed_on_cb), NULL);
332
333 timer = g_timeout_add(1, load_timeout, plugin);
334
335 return TRUE;
336 }
337
338 static gboolean
339 plugin_unload(GaimPlugin *plugin)
340 {
341 gaim_blist_set_ui_ops(backup_blist_ui_ops);
342
343 g_free(blist_ui_ops);
344
345 backup_blist_ui_ops = NULL;
346 blist_ui_ops = NULL;
347
348 if (book_view != NULL)
349 {
350 e_book_view_stop(book_view);
351 g_object_unref(book_view);
352 book_view = NULL;
353 }
354
355 if (book != NULL)
356 {
357 g_object_unref(book);
358 book = NULL;
359 }
360
361 return TRUE;
362 }
363
364 static void
365 plugin_destroy(GaimPlugin *plugin)
366 {
367 bonobo_debug_shutdown();
368 }
369
370 static void
371 autoadd_toggled_cb(GtkCellRendererToggle *renderer, gchar *path_str,
372 gpointer data)
373 {
374 GaimAccount *account;
375 GtkTreeModel *model = (GtkTreeModel *)data;
376 GtkTreeIter iter;
377 gboolean autoadd;
378
379 gtk_tree_model_get_iter_from_string(model, &iter, path_str);
380 gtk_tree_model_get(model, &iter,
381 COLUMN_DATA, &account,
382 COLUMN_AUTOADD, &autoadd,
383 -1);
384
385 gaim_account_set_bool(account, "gevo-autoadd", !autoadd);
386
387 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
388 COLUMN_AUTOADD, !autoadd,
389 -1);
390 }
391
392 static GtkWidget *
393 get_config_frame(GaimPlugin *plugin)
394 {
395 GtkWidget *ret;
396 GtkWidget *vbox;
397 GtkWidget *label;
398 GtkWidget *sw;
399 GtkWidget *treeview;
400 GtkTreeViewColumn *column;
401 GtkCellRenderer *renderer;
402 GdkPixbuf *pixbuf;
403 GtkListStore *model;
404 GList *l;
405
406 /* Outside container */
407 ret = gtk_vbox_new(FALSE, 18);
408 gtk_container_set_border_width(GTK_CONTAINER(ret), 12);
409
410 /* Configuration frame */
411 vbox = gaim_gtk_make_frame(ret, _("Evolution Integration Configuration"));
412
413 /* Label */
414 label = gtk_label_new(_("Select all accounts that buddies should be "
415 "auto-added to."));
416 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
417 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
418 gtk_widget_show(label);
419
420 /* Scrolled window */
421 sw = gtk_scrolled_window_new(0, 0);
422 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
423 GTK_POLICY_AUTOMATIC,
424 GTK_POLICY_ALWAYS);
425 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
426 GTK_SHADOW_IN);
427 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
428 gtk_widget_set_size_request(sw, 300, 300);
429 gtk_widget_show(sw);
430
431 /* Create the list model for the treeview. */
432 model = gtk_list_store_new(NUM_COLUMNS,
433 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
434 G_TYPE_STRING, G_TYPE_POINTER);
435
436 /* Setup the treeview */
437 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
438 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
439 gtk_container_add(GTK_CONTAINER(sw), treeview);
440 gtk_widget_show(treeview);
441
442 /* Setup the column */
443 column = gtk_tree_view_column_new();
444 gtk_tree_view_column_set_title(column, _("Account"));
445 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
446
447 /* Checkbox */
448 renderer = gtk_cell_renderer_toggle_new();
449
450 g_signal_connect(G_OBJECT(renderer), "toggled",
451 G_CALLBACK(autoadd_toggled_cb), model);
452
453 gtk_tree_view_column_pack_start(column, renderer, FALSE);
454 gtk_tree_view_column_add_attribute(column, renderer,
455 "active", COLUMN_AUTOADD);
456
457 /* Icon */
458 renderer = gtk_cell_renderer_pixbuf_new();
459 gtk_tree_view_column_pack_start(column, renderer, FALSE);
460 gtk_tree_view_column_add_attribute(column, renderer,
461 "pixbuf", COLUMN_ICON);
462
463 /* Screenname */
464 renderer = gtk_cell_renderer_text_new();
465 gtk_tree_view_column_pack_start(column, renderer, TRUE);
466 gtk_tree_view_column_add_attribute(column, renderer,
467 "text", COLUMN_SCREENNAME);
468
469
470 /* Populate */
471 for (l = gaim_accounts_get_all(); l != NULL; l = l->next)
472 {
473 GaimAccount *account = (GaimAccount *)l->data;
474 GtkTreeIter iter;
475
476 gaim_debug_info("evolution", "Adding account\n");
477
478 gtk_list_store_append(model, &iter);
479
480 pixbuf = gaim_gtk_create_prpl_icon(account, 0.5);
481 if ((pixbuf != NULL) && (!gaim_account_is_connected(account)))
482 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
483
484 gtk_list_store_set(model, &iter,
485 COLUMN_AUTOADD,
486 gaim_account_get_bool(account, "gevo-autoadd",
487 FALSE),
488 COLUMN_ICON, pixbuf,
489 COLUMN_SCREENNAME,
490 gaim_account_get_username(account),
491 COLUMN_DATA, account,
492 -1);
493
494 if (pixbuf != NULL)
495 g_object_unref(G_OBJECT(pixbuf));
496 }
497
498 gtk_widget_show_all(ret);
499
500 return ret;
501 }
502
503 static GaimGtkPluginUiInfo ui_info =
504 {
505 get_config_frame, /**< get_config_frame */
506 0 /**< page_num */
507 };
508
509 static GaimPluginInfo info =
510 {
511 GAIM_PLUGIN_MAGIC,
512 GAIM_MAJOR_VERSION,
513 GAIM_MINOR_VERSION,
514 GAIM_PLUGIN_STANDARD, /**< type */
515 GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */
516 0, /**< flags */
517 NULL, /**< dependencies */
518 GAIM_PRIORITY_DEFAULT, /**< priority */
519
520 GEVOLUTION_PLUGIN_ID, /**< id */
521 N_("Evolution Integration"), /**< name */
522 VERSION, /**< version */
523 /** summary */
524 N_("Provides integration with Evolution."),
525 /** description */
526 N_("Provides integration with Evolution."),
527 "Christian Hammond <chipx86@chipx86.com>", /**< author */
528 GAIM_WEBSITE, /**< homepage */
529
530 plugin_load, /**< load */
531 plugin_unload, /**< unload */
532 plugin_destroy, /**< destroy */
533
534 &ui_info, /**< ui_info */
535 NULL, /**< extra_info */
536 NULL,
537 NULL
538 };
539
540 static void
541 init_plugin(GaimPlugin *plugin)
542 {
543 /* TODO: Change to core-remote when possible. */
544 /* info.dependencies = g_list_append(info.dependencies, "gtk-remote"); */
545
546 /*
547 * I'm going to rant a little bit here...
548 *
549 * For some reason, when we init bonobo from inside a plugin, it will
550 * segfault when destroyed. The backtraces are within gmodule somewhere.
551 * There's not much I can do, and I'm not sure where the bug lies.
552 * However, plugins are only destroyed when Gaim is shutting down. After
553 * destroying the plugins, gaim ends, and anything else is of course
554 * freed. That includes this, if we make the module resident, which
555 * prevents us from being able to actually unload it.
556 *
557 * So, in conclusion, this is an evil hack, but it doesn't harm anything
558 * and it works.
559 */
560 g_module_make_resident(plugin->handle);
561
562 if (!bonobo_init_full(NULL, NULL, bonobo_activation_orb_get(),
563 CORBA_OBJECT_NIL, CORBA_OBJECT_NIL))
564 {
565 gaim_debug_error("evolution", "Unable to initialize bonobo.\n");
566 }
567 }
568
569 GAIM_INIT_PLUGIN(gevolution, init_plugin, info)