comparison plugins/gevolution/gevolution.c @ 8089:35db601609e3

[gaim-migrate @ 8788] Gaim-Evolution Buddy List-Addressbook syncronocity by our very own Chip X. Eightysix. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Tue, 13 Jan 2004 01:45:32 +0000
parents
children 96ee7b21c1ae
comparison
equal deleted inserted replaced
8088:a86784e3b98c 8089:35db601609e3
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 "gtkinternal.h"
23 #include "gtkblist.h"
24
25 #include "connection.h"
26 #include "debug.h"
27 #include "prefs.h"
28 #include "signals.h"
29
30 #include "gtkconv.h"
31 #include "gtkplugin.h"
32 #include "gtkutils.h"
33
34 #include "gevolution.h"
35
36 #include <libedata-book/Evolution-DataServer-Addressbook.h>
37
38 #include <libebook/e-book-listener.h>
39 #include <libebook/e-book-async.h>
40 #include <libedata-book/e-data-book-factory.h>
41 #include <bonobo/bonobo-main.h>
42
43 #define GEVOLUTION_PLUGIN_ID "gtk-x11-gevolution"
44
45 #define E_DATA_BOOK_FACTORY_OAF_ID \
46 "OAFIID:GNOME_Evolution_DataServer_BookFactory"
47
48 enum
49 {
50 COLUMN_AUTOADD,
51 COLUMN_ICON,
52 COLUMN_SCREENNAME,
53 COLUMN_DATA,
54 NUM_COLUMNS
55 };
56
57 static GaimBlistUiOps *backup_blist_ui_ops = NULL;
58 static GaimBlistUiOps *blist_ui_ops = NULL;
59 static EBook *book = NULL;
60 static gulong timer = 0;
61 static gulong book_view_tag = 0;
62 static EBookView *book_view = NULL;
63
64 static void
65 update_ims_from_contact(EContact *contact, const char *name,
66 const char *prpl_id, EContactField field)
67 {
68 GList *ims = e_contact_get(contact, field);
69 GList *l, *l2;
70
71 if (ims == NULL)
72 return;
73
74 for (l = gaim_connections_get_all(); l != NULL; l = l->next)
75 {
76 GaimConnection *gc = (GaimConnection *)l->data;
77 GaimAccount *account = gaim_connection_get_account(gc);
78
79 if (strcmp(gaim_account_get_protocol_id(account), prpl_id))
80 continue;
81
82 if (!gaim_account_get_bool(account, "gevo-autoadd", FALSE))
83 continue;
84
85 for (l2 = ims; l2 != NULL; l2 = l2->next)
86 {
87 if (gaim_find_buddy(account, l2->data) != NULL)
88 continue;
89
90 gevo_add_buddy(account, _("Buddies"), l2->data, name);
91 }
92 }
93
94 g_list_foreach(ims, (GFunc)g_free, NULL);
95 g_list_free(ims);
96 }
97
98 static void
99 update_buddies_from_contact(EContact *contact)
100 {
101 const char *name;
102
103 name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
104
105 update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_AIM);
106 update_ims_from_contact(contact, name, "prpl-jabber", E_CONTACT_IM_JABBER);
107 update_ims_from_contact(contact, name, "prpl-yahoo", E_CONTACT_IM_YAHOO);
108 update_ims_from_contact(contact, name, "prpl-msn", E_CONTACT_IM_MSN);
109 update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_ICQ);
110 }
111
112 static void
113 contacts_changed_cb(EBookView *book_view, const GList *contacts)
114 {
115 const GList *l;
116
117 if (gaim_connections_get_all() == NULL)
118 return;
119
120 for (l = contacts; l != NULL; l = l->next)
121 {
122 EContact *contact = (EContact *)l->data;
123
124 update_buddies_from_contact(contact);
125 }
126 }
127
128 static void
129 request_add_buddy(GaimAccount *account, const char *username,
130 const char *group, const char *alias)
131 {
132 if (book == NULL)
133 {
134 backup_blist_ui_ops->request_add_buddy(account, username, group,
135 alias);
136 }
137 else
138 {
139 gevo_add_buddy_dialog_show(account, username, group, alias);
140 }
141 }
142
143 static void
144 got_book_view_cb(EBook *book, EBookStatus status, EBookView *view,
145 gpointer user_data)
146 {
147 book_view_tag = 0;
148
149 if (status != E_BOOK_ERROR_OK)
150 {
151 gaim_debug_error("evolution", "Unable to retrieve book view! :(\n");
152
153 return;
154 }
155
156 book_view = view;
157
158 g_object_ref(book_view);
159
160 g_signal_connect(G_OBJECT(book_view), "contacts_changed",
161 G_CALLBACK(contacts_changed_cb), book);
162
163 g_signal_connect(G_OBJECT(book_view), "contacts_added",
164 G_CALLBACK(contacts_changed_cb), book);
165
166 e_book_view_start(view);
167 }
168
169 static void
170 signed_on_cb(GaimConnection *gc)
171 {
172 EBookQuery *query;
173 gboolean status;
174 GList *contacts;
175 GList *l;
176
177 if (book == NULL)
178 return;
179
180 query = e_book_query_any_field_contains("");
181
182 status = e_book_get_contacts(book, query, &contacts, NULL);
183
184 e_book_query_unref(query);
185
186 if (!status)
187 return;
188
189 for (l = contacts; l != NULL; l = l->next)
190 {
191 EContact *contact = E_CONTACT(l->data);
192
193 update_buddies_from_contact(contact);
194
195 g_object_unref(contact);
196 }
197
198 g_list_free(contacts);
199 }
200
201 static void
202 menu_item_activate_cb(GtkWidget *item, GaimBuddy *buddy)
203 {
204 gevo_associate_buddy_dialog_new(buddy);
205 }
206
207 static void
208 drawing_menu_cb(GtkWidget *menu, GaimBuddy *buddy)
209 {
210 GtkWidget *item;
211
212 if (gevo_prpl_is_supported(buddy->account, buddy))
213 {
214 item = gtk_menu_item_new_with_label(_("Add to Address Book"));
215 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
216
217 g_signal_connect(G_OBJECT(item), "activate",
218 G_CALLBACK(menu_item_activate_cb), buddy);
219 }
220 }
221
222 static gboolean
223 load_timeout(gpointer data)
224 {
225 GaimPlugin *plugin = (GaimPlugin *)data;
226
227 timer = 0;
228
229 if (!gevo_load_addressbook(&book, NULL))
230 return FALSE;
231
232 book_view_tag = e_book_async_get_book_view(book,
233 "(contains \"x-evolution-any-field\" \"\")",
234 got_book_view_cb, NULL);
235
236 gaim_signal_connect(GAIM_GTK_BLIST(gaim_get_blist()), "drawing-menu",
237 plugin, GAIM_CALLBACK(drawing_menu_cb), NULL);
238
239 return FALSE;
240 }
241
242 static gboolean
243 plugin_load(GaimPlugin *plugin)
244 {
245 if (!bonobo_init_full(NULL, NULL, bonobo_activation_orb_get(),
246 CORBA_OBJECT_NIL, CORBA_OBJECT_NIL))
247 {
248 gaim_debug_error("evolution", "Unable to initialize bonobo.\n");
249 return FALSE;
250 }
251
252 bonobo_activate();
253
254 backup_blist_ui_ops = gaim_blist_get_ui_ops();
255
256 blist_ui_ops = g_memdup(backup_blist_ui_ops, sizeof(GaimBlistUiOps));
257 blist_ui_ops->request_add_buddy = request_add_buddy;
258
259 gaim_blist_set_ui_ops(blist_ui_ops);
260
261 gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
262 plugin, GAIM_CALLBACK(signed_on_cb), NULL);
263
264 timer = g_timeout_add(1, load_timeout, plugin);
265
266 return TRUE;
267 }
268
269 static gboolean
270 plugin_unload(GaimPlugin *plugin)
271 {
272 gaim_blist_set_ui_ops(backup_blist_ui_ops);
273
274 g_free(blist_ui_ops);
275
276 backup_blist_ui_ops = NULL;
277 blist_ui_ops = NULL;
278
279 if (book_view != NULL)
280 {
281 e_book_view_stop(book_view);
282 g_object_unref(book_view);
283 book_view = NULL;
284 }
285
286 if (book != NULL)
287 {
288 g_object_unref(book);
289 book = NULL;
290 }
291
292 bonobo_debug_shutdown();
293
294 return TRUE;
295 }
296
297 static void
298 plugin_destroy(GaimPlugin *plugin)
299 {
300 }
301
302 static void
303 autoadd_toggled_cb(GtkCellRendererToggle *renderer, gchar *path_str,
304 gpointer data)
305 {
306 GaimAccount *account;
307 GtkTreeModel *model = (GtkTreeModel *)data;
308 GtkTreeIter iter;
309 gboolean autoadd;
310
311 gtk_tree_model_get_iter_from_string(model, &iter, path_str);
312 gtk_tree_model_get(model, &iter,
313 COLUMN_DATA, &account,
314 COLUMN_AUTOADD, &autoadd,
315 -1);
316
317 gaim_account_set_bool(account, "gevo-autoadd", !autoadd);
318
319 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
320 COLUMN_AUTOADD, !autoadd,
321 -1);
322 }
323
324 static GtkWidget *
325 get_config_frame(GaimPlugin *plugin)
326 {
327 GtkWidget *ret;
328 GtkWidget *vbox;
329 GtkWidget *label;
330 GtkWidget *sw;
331 GtkWidget *treeview;
332 GtkTreeViewColumn *column;
333 GtkCellRenderer *renderer;
334 GdkPixbuf *pixbuf, *scale = NULL;
335 GtkListStore *model;
336 GList *l;
337
338 /* Outside container */
339 ret = gtk_vbox_new(FALSE, 18);
340 gtk_container_set_border_width(GTK_CONTAINER(ret), 12);
341
342 /* Configuration frame */
343 vbox = gaim_gtk_make_frame(ret, _("Evolution Integration Configuration"));
344
345 /* Label */
346 label = gtk_label_new(_("Select all accounts that buddies should be "
347 "auto-added to."));
348 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
349 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
350 gtk_widget_show(label);
351
352 /* Scrolled window */
353 sw = gtk_scrolled_window_new(0, 0);
354 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
355 GTK_POLICY_AUTOMATIC,
356 GTK_POLICY_ALWAYS);
357 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
358 GTK_SHADOW_IN);
359 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
360 gtk_widget_set_size_request(sw, 300, 300);
361 gtk_widget_show(sw);
362
363 /* Create the list model for the treeview. */
364 model = gtk_list_store_new(NUM_COLUMNS,
365 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
366 G_TYPE_STRING, G_TYPE_POINTER);
367
368 /* Setup the treeview */
369 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
370 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
371 gtk_container_add(GTK_CONTAINER(sw), treeview);
372 gtk_widget_show(treeview);
373
374 /* Setup the column */
375 column = gtk_tree_view_column_new();
376 gtk_tree_view_column_set_title(column, _("Account"));
377 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
378
379 /* Checkbox */
380 renderer = gtk_cell_renderer_toggle_new();
381
382 g_signal_connect(G_OBJECT(renderer), "toggled",
383 G_CALLBACK(autoadd_toggled_cb), model);
384
385 gtk_tree_view_column_pack_start(column, renderer, FALSE);
386 gtk_tree_view_column_add_attribute(column, renderer,
387 "active", COLUMN_AUTOADD);
388
389 /* Icon */
390 renderer = gtk_cell_renderer_pixbuf_new();
391 gtk_tree_view_column_pack_start(column, renderer, FALSE);
392 gtk_tree_view_column_add_attribute(column, renderer,
393 "pixbuf", COLUMN_ICON);
394
395 /* Screenname */
396 renderer = gtk_cell_renderer_text_new();
397 gtk_tree_view_column_pack_start(column, renderer, TRUE);
398 gtk_tree_view_column_add_attribute(column, renderer,
399 "text", COLUMN_SCREENNAME);
400
401
402 /* Populate */
403 for (l = gaim_accounts_get_all(); l != NULL; l = l->next)
404 {
405 GaimAccount *account = (GaimAccount *)l->data;
406 GtkTreeIter iter;
407
408 gaim_debug_info("evolution", "Adding account\n");
409
410 gtk_list_store_append(model, &iter);
411
412 pixbuf = create_prpl_icon(account);
413
414 if (pixbuf != NULL)
415 {
416 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16,
417 GDK_INTERP_BILINEAR);
418
419 if (!gaim_account_is_connected(account))
420 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE);
421 }
422
423 gtk_list_store_set(model, &iter,
424 COLUMN_AUTOADD,
425 gaim_account_get_bool(account, "gevo-autoadd",
426 FALSE),
427 COLUMN_ICON, scale,
428 COLUMN_SCREENNAME,
429 gaim_account_get_username(account),
430 COLUMN_DATA, account,
431 -1);
432
433 if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf));
434 if (scale != NULL) g_object_unref(G_OBJECT(scale));
435 }
436
437 gtk_widget_show_all(ret);
438
439 return ret;
440 }
441
442 static GaimGtkPluginUiInfo ui_info =
443 {
444 get_config_frame
445 };
446
447 static GaimPluginInfo info =
448 {
449 2, /**< api_version */
450 GAIM_PLUGIN_STANDARD, /**< type */
451 GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */
452 0, /**< flags */
453 NULL, /**< dependencies */
454 GAIM_PRIORITY_DEFAULT, /**< priority */
455
456 GEVOLUTION_PLUGIN_ID, /**< id */
457 N_("Evolution Integration"), /**< name */
458 VERSION, /**< version */
459 /** summary */
460 N_("Provides integration with Ximian Evolution."),
461 /** description */
462 N_("Provides integration with Ximian Evolution."),
463 "Christian Hammond <chipx86@gnupdate.org>", /**< author */
464 GAIM_WEBSITE, /**< homepage */
465
466 plugin_load, /**< load */
467 plugin_unload, /**< unload */
468 plugin_destroy, /**< destroy */
469
470 &ui_info, /**< ui_info */
471 NULL /**< extra_info */
472 };
473
474 static void
475 init_plugin(GaimPlugin *plugin)
476 {
477 /* TODO: Change to core-remote when possible. */
478 /* info.dependencies = g_list_append(info.dependencies, "gtk-remote"); */
479
480 /*
481 * I'm going to rant a little bit here...
482 *
483 * For some reason, when we init bonobo from inside a plugin, it will
484 * segfault when destroyed. The backtraces are within gmodule somewhere.
485 * There's not much I can do, and I'm not sure where the bug lies.
486 * However, plugins are only destroyed when Gaim is shutting down. After
487 * destroying the plugins, gaim ends, and anything else is of course
488 * freed. That includes this, if we make the module resident, which
489 * prevents us from being able to actually unload it.
490 *
491 * So, in conclusion, this is an evil hack, but it doesn't harm anything
492 * and it works.
493 */
494 g_module_make_resident(plugin->handle);
495 }
496
497 GAIM_INIT_PLUGIN(gevolution, init_plugin, info)