Mercurial > pidgin.yaz
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) |