No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Nat Friedman <nat@novell.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <string.h>
30
31 #include <libedataserverui/libedataserverui.h>
32
33 #include <e-util/e-config.h>
34 #include <addressbook/gui/widgets/eab-config.h>
35 #include <mail/em-event.h>
36 #include <composer/e-msg-composer.h>
37
38 #include "bbdb.h"
39
40 #define d(x)
41
42 /* Plugin hooks */
43 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
44 void bbdb_handle_send (EPlugin *ep, EMEventTargetComposer *target);
45 GtkWidget *bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
46
47 /* For internal use */
48 struct bbdb_stuff {
49 EABConfigTargetPrefs *target;
50
51 GtkWidget *combo_box;
52 GtkWidget *gaim_combo_box;
53 GtkWidget *check;
54 GtkWidget *check_gaim;
55 };
56
57 /* Static forward declarations */
58 static gboolean bbdb_timeout (gpointer data);
59 static void bbdb_do_it (EBookClient *client, const gchar *name, const gchar *email);
60 static void add_email_to_contact (EContact *contact, const gchar *email);
61 static void enable_toggled_cb (GtkWidget *widget, gpointer data);
62 static void source_changed_cb (ESourceComboBox *source_combo_box, struct bbdb_stuff *stuff);
63 static GtkWidget *create_addressbook_combo_box (struct bbdb_stuff *stuff, gint type);
64 static void cleanup_cb (GObject *o, gpointer data);
65
66 /* How often check, in minutes. Read only on plugin enable. Use <= 0 to disable polling. */
67 static gint
68 get_check_interval (void)
69 {
70 GSettings *settings;
71 gint res = BBDB_BLIST_DEFAULT_CHECK_INTERVAL;
72
73 settings = g_settings_new (CONF_SCHEMA);
74 res = g_settings_get_int (settings, CONF_KEY_GAIM_CHECK_INTERVAL);
75
76 g_object_unref (settings);
77
78 return res * 60;
79 }
80
81 gint
82 e_plugin_lib_enable (EPlugin *ep,
83 gint enable)
84 {
85 static guint update_source = 0;
86
87 if (update_source) {
88 g_source_remove (update_source);
89 update_source = 0;
90 }
91
92 /* Start up the plugin. */
93 if (enable) {
94 gint interval;
95
96 d (fprintf (stderr, "BBDB spinning up...\n"));
97
98 g_idle_add (bbdb_timeout, ep);
99
100 interval = get_check_interval ();
101 if (interval > 0)
102 update_source = g_timeout_add_seconds (interval, (GSourceFunc) bbdb_timeout, NULL);
103 }
104
105 return 0;
106 }
107
108 static gboolean
109 bbdb_timeout (gpointer data)
110 {
111 if (bbdb_check_gaim_enabled ())
112 bbdb_sync_buddy_list_check ();
113
114 /* not a NULL for a one-time idle check, thus stop it there */
115 return data == NULL;
116 }
117
118 typedef struct
119 {
120 gchar *name;
121 gchar *email;
122 } todo_struct;
123
124 static void
125 free_todo_struct (todo_struct *td)
126 {
127 if (td) {
128 g_free (td->name);
129 g_free (td->email);
130 g_free (td);
131 }
132 }
133
134 static GSList *todo = NULL;
135 G_LOCK_DEFINE_STATIC (todo);
136
137 static gpointer
138 bbdb_do_in_thread (gpointer data)
139 {
140 EBookClient *client = data;
141
142 /* Open the addressbook */
143 if (!client || !bbdb_open_book_client (client)) {
144 G_LOCK (todo);
145
146 g_slist_foreach (todo, (GFunc) free_todo_struct, NULL);
147 g_slist_free (todo);
148 todo = NULL;
149
150 G_UNLOCK (todo);
151 return NULL;
152 }
153
154 G_LOCK (todo);
155 while (todo) {
156 todo_struct *td = todo->data;
157
158 todo = g_slist_remove (todo, td);
159
160 G_UNLOCK (todo);
161
162 if (td) {
163 bbdb_do_it (client, td->name, td->email);
164 free_todo_struct (td);
165 }
166
167 G_LOCK (todo);
168 }
169 G_UNLOCK (todo);
170
171 g_object_unref (client);
172
173 return NULL;
174 }
175
176 static void
177 bbdb_do_thread (const gchar *name,
178 const gchar *email)
179 {
180 todo_struct *td;
181
182 if (!name && !email)
183 return;
184
185 td = g_new (todo_struct, 1);
186 td->name = g_strdup (name);
187 td->email = g_strdup (email);
188
189 G_LOCK (todo);
190 if (todo) {
191 /* the list isn't empty, which means there is a thread taking
192 * care of that, thus just add it to the queue */
193 todo = g_slist_append (todo, td);
194 } else {
195 GError *error = NULL;
196 EBookClient *client = bbdb_create_book_client (AUTOMATIC_CONTACTS_ADDRESSBOOK);
197
198 /* list was empty, add item and create a thread */
199 todo = g_slist_append (todo, td);
200 g_thread_create (bbdb_do_in_thread, client, FALSE, &error);
201
202 if (error) {
203 g_warning ("%s: Creation of the thread failed with error: %s", G_STRFUNC, error->message);
204 g_error_free (error);
205
206 G_UNLOCK (todo);
207 bbdb_do_in_thread (client);
208 G_LOCK (todo);
209 }
210 }
211 G_UNLOCK (todo);
212 }
213
214 static void
215 walk_destinations_and_free (EDestination **dests)
216 {
217 const gchar *name, *addr;
218 gint i;
219
220 if (!dests)
221 return;
222
223 for (i = 0; dests[i] != NULL; i++) {
224 if (e_destination_is_evolution_list (dests[i])) {
225 const GList *members;
226
227 for (members = e_destination_list_get_dests (dests[i]); members; members = members->next) {
228 const EDestination *member = members->data;
229
230 if (!member)
231 continue;
232
233 name = e_destination_get_name (member);
234 addr = e_destination_get_email (member);
235
236 if (name || addr)
237 bbdb_do_thread (name, addr);
238 }
239 } else {
240 name = e_destination_get_name (dests[i]);
241 addr = e_destination_get_email (dests[i]);
242
243 if (name || addr)
244 bbdb_do_thread (name, addr);
245 }
246 }
247
248 e_destination_freev (dests);
249 }
250
251 void
252 bbdb_handle_send (EPlugin *ep,
253 EMEventTargetComposer *target)
254 {
255 EComposerHeaderTable *table;
256 GSettings *settings;
257 gboolean enable;
258
259 settings = g_settings_new (CONF_SCHEMA);
260 enable = g_settings_get_boolean (settings, CONF_KEY_ENABLE);
261 g_object_unref (settings);
262
263 if (!enable)
264 return;
265
266 table = e_msg_composer_get_header_table (target->composer);
267 g_return_if_fail (table);
268
269 /* read information from the composer, not from a generated message */
270 walk_destinations_and_free (e_composer_header_table_get_destinations_to (table));
271 walk_destinations_and_free (e_composer_header_table_get_destinations_cc (table));
272 }
273
274 static void
275 bbdb_do_it (EBookClient *client,
276 const gchar *name,
277 const gchar *email)
278 {
279 gchar *query_string, *delim, *temp_name = NULL, *uid;
280 GSList *contacts = NULL;
281 gboolean status;
282 EContact *contact;
283 GError *error = NULL;
284
285 g_return_if_fail (client != NULL);
286
287 if (email == NULL || !strcmp (email, ""))
288 return;
289
290 if ((delim = strchr (email, '@')) == NULL)
291 return;
292
293 /* don't miss the entry if the mail has only e-mail id and no name */
294 if (name == NULL || !strcmp (name, "")) {
295 temp_name = g_strndup (email, delim - email);
296 name = temp_name;
297 }
298
299 /* If any contacts exists with this email address, don't do anything */
300 query_string = g_strdup_printf ("(contains \"email\" \"%s\")", email);
301 status = e_book_client_get_contacts_sync (client, query_string, &contacts, NULL, NULL);
302 g_free (query_string);
303 if (contacts != NULL || !status) {
304 e_client_util_free_object_slist (contacts);
305 g_free (temp_name);
306
307 return;
308 }
309
310 if (g_utf8_strchr (name, -1, '\"')) {
311 GString *tmp = g_string_new (name);
312 gchar *p;
313
314 while (p = g_utf8_strchr (tmp->str, tmp->len, '\"'), p)
315 tmp = g_string_erase (tmp, p - tmp->str, 1);
316
317 g_free (temp_name);
318 temp_name = g_string_free (tmp, FALSE);
319 name = temp_name;
320 }
321
322 contacts = NULL;
323 /* If a contact exists with this name, add the email address to it. */
324 query_string = g_strdup_printf ("(is \"full_name\" \"%s\")", name);
325 status = e_book_client_get_contacts_sync (client, query_string, &contacts, NULL, NULL);
326 g_free (query_string);
327 if (contacts != NULL || !status) {
328 /* FIXME: If there's more than one contact with this
329 * name, just give up; we're not smart enough for
330 * this. */
331 if (!status || contacts->next != NULL) {
332 e_client_util_free_object_slist (contacts);
333 g_free (temp_name);
334 return;
335 }
336
337 contact = (EContact *) contacts->data;
338 add_email_to_contact (contact, email);
339 if (!e_book_client_modify_contact_sync (client, contact, NULL, &error)) {
340 g_warning ("bbdb: Could not modify contact: %s\n", error->message);
341 g_error_free (error);
342 }
343
344 e_client_util_free_object_slist (contacts);
345 g_free (temp_name);
346 return;
347 }
348
349 /* Otherwise, create a new contact. */
350 contact = e_contact_new ();
351 e_contact_set (contact, E_CONTACT_FULL_NAME, (gpointer) name);
352 add_email_to_contact (contact, email);
353 g_free (temp_name);
354
355 uid = NULL;
356 if (!e_book_client_add_contact_sync (client, contact, &uid, NULL, &error)) {
357 g_warning ("bbdb: Failed to add new contact: %s", error->message);
358 g_error_free (error);
359 }
360
361 g_object_unref (contact);
362 g_free (uid);
363 }
364
365 EBookClient *
366 bbdb_create_book_client (gint type)
367 {
368 EShell *shell;
369 ESource *source = NULL;
370 ESourceRegistry *registry;
371 EBookClient *client = NULL;
372 GSettings *settings;
373 gboolean enable = TRUE;
374 gchar *uid;
375 GError *error = NULL;
376
377 settings = g_settings_new (CONF_SCHEMA);
378
379 /* Check to see if we're supposed to be running */
380 if (type == AUTOMATIC_CONTACTS_ADDRESSBOOK)
381 enable = g_settings_get_boolean (settings, CONF_KEY_ENABLE);
382 if (!enable) {
383 g_object_unref (settings);
384 return NULL;
385 }
386
387 /* Open the appropriate addresbook. */
388 if (type == GAIM_ADDRESSBOOK)
389 uid = g_settings_get_string (
390 settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM);
391 else
392 uid = g_settings_get_string (
393 settings, CONF_KEY_WHICH_ADDRESSBOOK);
394 g_object_unref (settings);
395
396 shell = e_shell_get_default ();
397 registry = e_shell_get_registry (shell);
398
399 if (uid != NULL) {
400 source = e_source_registry_ref_source (registry, uid);
401 g_free (uid);
402 }
403
404 if (source == NULL)
405 source = e_source_registry_ref_builtin_address_book (registry);
406
407 client = e_book_client_new (source, &error);
408 if (client == NULL) {
409 g_warning (
410 "bbdb: Failed to get addressbook: %s\n",
411 error->message);
412 g_error_free (error);
413 }
414
415 g_object_unref (source);
416
417 return client;
418 }
419
420 gboolean
421 bbdb_open_book_client (EBookClient *client)
422 {
423 GError *error = NULL;
424
425 if (!client)
426 return FALSE;
427
428 e_client_open_sync (E_CLIENT (client), FALSE, NULL, &error);
429
430 if (error != NULL) {
431 g_warning (
432 "bbdb: failed to open addressbook: %s",
433 error->message);
434 g_object_unref (client);
435 g_error_free (error);
436 return FALSE;
437 }
438
439 return TRUE;
440 }
441
442 gboolean
443 bbdb_check_gaim_enabled (void)
444 {
445 GSettings *settings;
446 gboolean gaim_enabled;
447
448 settings = g_settings_new (CONF_SCHEMA);
449 gaim_enabled = g_settings_get_boolean (settings, CONF_KEY_ENABLE_GAIM);
450
451 g_object_unref (settings);
452
453 return gaim_enabled;
454 }
455
456 static void
457 add_email_to_contact (EContact *contact,
458 const gchar *email)
459 {
460 GList *emails;
461
462 emails = e_contact_get (contact, E_CONTACT_EMAIL);
463 emails = g_list_append (emails, (gpointer) email);
464 e_contact_set (contact, E_CONTACT_EMAIL, (gpointer) emails);
465 }
466
467 /* Code to implement the configuration user interface follows */
468
469 static void
470 enable_toggled_cb (GtkWidget *widget,
471 gpointer data)
472 {
473 struct bbdb_stuff *stuff = (struct bbdb_stuff *) data;
474 gboolean active;
475 ESource *selected_source;
476 gchar *addressbook;
477 GSettings *settings = g_settings_new (CONF_SCHEMA);
478
479 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
480
481 /* Save the new setting to GSettings */
482 g_settings_set_boolean (settings, CONF_KEY_ENABLE, active);
483
484 gtk_widget_set_sensitive (stuff->combo_box, active);
485
486 addressbook = g_settings_get_string (settings, CONF_KEY_WHICH_ADDRESSBOOK);
487
488 if (active && !addressbook) {
489 selected_source = e_source_combo_box_ref_active (
490 E_SOURCE_COMBO_BOX (stuff->combo_box));
491 if (selected_source != NULL) {
492 g_settings_set_string (
493 settings, CONF_KEY_WHICH_ADDRESSBOOK,
494 e_source_get_uid (selected_source));
495 g_object_unref (selected_source);
496 } else {
497 g_settings_set_string (
498 settings, CONF_KEY_WHICH_ADDRESSBOOK, "");
499 }
500 }
501
502 g_free (addressbook);
503 g_object_unref (settings);
504 }
505
506 static void
507 enable_gaim_toggled_cb (GtkWidget *widget,
508 gpointer data)
509 {
510 struct bbdb_stuff *stuff = (struct bbdb_stuff *) data;
511 gboolean active;
512 ESource *selected_source;
513 gchar *addressbook_gaim;
514 GSettings *settings = g_settings_new (CONF_SCHEMA);
515
516 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
517
518 /* Save the new setting to GSettings */
519 g_settings_set_boolean (settings, CONF_KEY_ENABLE_GAIM, active);
520
521 addressbook_gaim = g_settings_get_string (
522 settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM);
523 gtk_widget_set_sensitive (stuff->gaim_combo_box, active);
524 if (active && !addressbook_gaim) {
525 selected_source = e_source_combo_box_ref_active (
526 E_SOURCE_COMBO_BOX (stuff->gaim_combo_box));
527 if (selected_source != NULL) {
528 g_settings_set_string (
529 settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM,
530 e_source_get_uid (selected_source));
531 g_object_unref (selected_source);
532 } else {
533 g_settings_set_string (
534 settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM, "");
535 }
536 }
537
538 g_free (addressbook_gaim);
539 g_object_unref (settings);
540 }
541
542 static void
543 synchronize_button_clicked_cb (GtkWidget *button)
544 {
545 bbdb_sync_buddy_list ();
546 }
547
548 static void
549 source_changed_cb (ESourceComboBox *source_combo_box,
550 struct bbdb_stuff *stuff)
551 {
552 GSettings *settings;
553 ESource *source;
554 const gchar *uid;
555
556 source = e_source_combo_box_ref_active (source_combo_box);
557 uid = (source != NULL) ? e_source_get_uid (source) : "";
558
559 settings = g_settings_new (CONF_SCHEMA);
560 g_settings_set_string (settings, CONF_KEY_WHICH_ADDRESSBOOK, uid);
561 g_object_unref (settings);
562
563 if (source != NULL)
564 g_object_unref (source);
565 }
566
567 static void
568 gaim_source_changed_cb (ESourceComboBox *source_combo_box,
569 struct bbdb_stuff *stuff)
570 {
571 GSettings *settings;
572 ESource *source;
573 const gchar *uid;
574
575 source = e_source_combo_box_ref_active (source_combo_box);
576 uid = (source != NULL) ? e_source_get_uid (source) : "";
577
578 settings = g_settings_new (CONF_SCHEMA);
579 g_settings_set_string (settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM, uid);
580 g_object_unref (settings);
581
582 if (source != NULL)
583 g_object_unref (source);
584 }
585
586 static GtkWidget *
587 create_addressbook_combo_box (struct bbdb_stuff *stuff,
588 gint type)
589 {
590 EShell *shell;
591 ESource *source;
592 ESourceRegistry *registry;
593 GtkWidget *combo_box;
594 const gchar *extension_name;
595 gchar *uid;
596 GSettings *settings = g_settings_new (CONF_SCHEMA);
597
598 shell = e_shell_get_default ();
599 registry = e_shell_get_registry (shell);
600 extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
601 combo_box = e_source_combo_box_new (registry, extension_name);
602
603 if (type == GAIM_ADDRESSBOOK)
604 uid = g_settings_get_string (settings, CONF_KEY_WHICH_ADDRESSBOOK_GAIM);
605 else
606 uid = g_settings_get_string (settings, CONF_KEY_WHICH_ADDRESSBOOK);
607 source = e_source_registry_ref_source (registry, uid);
608 g_free (uid);
609
610 if (source != NULL) {
611 e_source_combo_box_set_active (
612 E_SOURCE_COMBO_BOX (combo_box), source);
613 g_object_unref (source);
614 }
615
616 gtk_widget_show (combo_box);
617
618 g_object_unref (settings);
619
620 return combo_box;
621 }
622
623 GtkWidget *
624 bbdb_page_factory (EPlugin *ep,
625 EConfigHookItemFactoryData *hook_data)
626 {
627 struct bbdb_stuff *stuff;
628 EABConfigTargetPrefs *target = (EABConfigTargetPrefs *) hook_data->config->target;
629 GtkWidget *page;
630 GtkWidget *tab_label;
631 GtkWidget *frame;
632 GtkWidget *frame_label;
633 GtkWidget *padding_label;
634 GtkWidget *hbox;
635 GtkWidget *inner_vbox;
636 GtkWidget *check;
637 GtkWidget *combo_box;
638 GtkWidget *gaim_combo_box;
639 GtkWidget *check_gaim;
640 GtkWidget *label;
641 GtkWidget *gaim_label;
642 GtkWidget *button;
643 gchar *str;
644 GSettings *settings = g_settings_new (CONF_SCHEMA);
645
646 /* A structure to pass some stuff around */
647 stuff = g_new0 (struct bbdb_stuff, 1);
648 stuff->target = target;
649
650 /* Create a new notebook page */
651 page = gtk_vbox_new (FALSE, 0);
652 gtk_container_set_border_width (GTK_CONTAINER (page), 12);
653 tab_label = gtk_label_new (_("Automatic Contacts"));
654 gtk_notebook_append_page (GTK_NOTEBOOK (hook_data->parent), page, tab_label);
655
656 /* Frame */
657 frame = gtk_vbox_new (FALSE, 6);
658 gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
659
660 /* "Automatic Contacts" */
661 frame_label = gtk_label_new ("");
662 str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("Automatic Contacts"));
663 gtk_label_set_markup (GTK_LABEL (frame_label), str);
664 g_free (str);
665 gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5);
666 gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
667
668 /* Indent/padding */
669 hbox = gtk_hbox_new (FALSE, 12);
670 gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0);
671 padding_label = gtk_label_new ("");
672 gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
673 inner_vbox = gtk_vbox_new (FALSE, 6);
674 gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0);
675
676 /* Enable BBDB checkbox */
677 check = gtk_check_button_new_with_mnemonic (_("Create _address book entries when sending mails"));
678 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), g_settings_get_boolean (settings, CONF_KEY_ENABLE));
679 g_signal_connect (
680 check, "toggled",
681 G_CALLBACK (enable_toggled_cb), stuff);
682 gtk_box_pack_start (GTK_BOX (inner_vbox), check, FALSE, FALSE, 0);
683 stuff->check = check;
684
685 label = gtk_label_new (_("Select Address book for Automatic Contacts"));
686 gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0);
687
688 /* Source selection combo box */
689 combo_box = create_addressbook_combo_box (stuff, AUTOMATIC_CONTACTS_ADDRESSBOOK);
690 g_signal_connect (
691 combo_box, "changed",
692 G_CALLBACK (source_changed_cb), stuff);
693 gtk_widget_set_sensitive (combo_box, g_settings_get_boolean (settings, CONF_KEY_ENABLE));
694 gtk_box_pack_start (GTK_BOX (inner_vbox), combo_box, FALSE, FALSE, 0);
695 stuff->combo_box = combo_box;
696
697 /* "Instant Messaging Contacts" */
698 frame = gtk_vbox_new (FALSE, 6);
699 gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24);
700
701 frame_label = gtk_label_new ("");
702 str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("Instant Messaging Contacts"));
703 gtk_label_set_markup (GTK_LABEL (frame_label), str);
704 g_free (str);
705 gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5);
706 gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
707
708 /* Indent/padding */
709 hbox = gtk_hbox_new (FALSE, 12);
710 gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0);
711 padding_label = gtk_label_new ("");
712 gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
713 inner_vbox = gtk_vbox_new (FALSE, 6);
714 gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0);
715
716 /* Enable Gaim Checkbox */
717 check_gaim = gtk_check_button_new_with_mnemonic (_("_Synchronize contact info and images from Pidgin buddy list"));
718 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_gaim), g_settings_get_boolean (settings, CONF_KEY_ENABLE_GAIM));
719 g_signal_connect (
720 check_gaim, "toggled",
721 G_CALLBACK (enable_gaim_toggled_cb), stuff);
722 gtk_box_pack_start (GTK_BOX (inner_vbox), check_gaim, FALSE, FALSE, 0);
723 stuff->check_gaim = check_gaim;
724
725 gaim_label = gtk_label_new (_("Select Address book for Pidgin buddy list"));
726 gtk_box_pack_start (GTK_BOX (inner_vbox), gaim_label, FALSE, FALSE, 0);
727
728 /* Gaim Source Selection Combo Box */
729 gaim_combo_box = create_addressbook_combo_box (stuff, GAIM_ADDRESSBOOK);
730 g_signal_connect (
731 gaim_combo_box, "changed",
732 G_CALLBACK (gaim_source_changed_cb), stuff);
733 gtk_widget_set_sensitive (gaim_combo_box, g_settings_get_boolean (settings, CONF_KEY_ENABLE_GAIM));
734 gtk_box_pack_start (GTK_BOX (inner_vbox), gaim_combo_box, FALSE, FALSE, 0);
735 stuff->gaim_combo_box = gaim_combo_box;
736
737 /* Synchronize now button. */
738 button = gtk_button_new_with_mnemonic (_("Synchronize with _buddy list now"));
739 g_signal_connect (
740 button, "clicked",
741 G_CALLBACK (synchronize_button_clicked_cb), stuff);
742 gtk_box_pack_start (GTK_BOX (inner_vbox), button, FALSE, FALSE, 0);
743
744 /* Clean up */
745 g_signal_connect (
746 page, "destroy",
747 G_CALLBACK (cleanup_cb), stuff);
748
749 gtk_widget_show_all (page);
750
751 g_object_unref (settings);
752
753 return page;
754 }
755
756 static void
757 cleanup_cb (GObject *o,
758 gpointer data)
759 {
760 struct bbdb_stuff *stuff = data;
761
762 g_free (stuff);
763 }