From b40eb4903c03a3025cc513c04da70209c099d0c3 Mon Sep 17 00:00:00 2001 From: Nat Friedman Date: Tue, 26 Oct 2004 03:02:04 +0000 Subject: Sync the Gaim buddy list. Set a timer to check for Gaim buddy list chnages 2004-10-25 Nat Friedman * bbdb.c (e_plugin_lib_enable): Sync the Gaim buddy list. Set a timer to check for Gaim buddy list chnages to sync. (bbdb_do_it): Free some memory we were leaking before. (bbdb_open_addressbook): New function for Gaim buddy list support. (bbdb_check_gaim_enabled): Likewise. (enable_gaim_toggled_cb): Likewise. (synchronize_button_clicked_cb): Likewise. (bbdb_page_factory): Added UI for Gaim buddy list sync support. * gaimbuddies.c: New file, contains routines to synchronize IM information and buddy icons from a Gaim buddy list. * bbdb.h: New file, contains shared macros and prototypes. * test-evobuddy.c (main): New function, tests a gaim buddy list sync. svn path=/trunk/; revision=27723 --- plugins/bbdb/ChangeLog | 19 ++ plugins/bbdb/Makefile.am | 8 +- plugins/bbdb/bbdb.c | 200 +++++++++++++++---- plugins/bbdb/bbdb.h | 22 +++ plugins/bbdb/gaimbuddies.c | 459 +++++++++++++++++++++++++++++++++++++++++++ plugins/bbdb/test-evobuddy.c | 15 ++ 6 files changed, 685 insertions(+), 38 deletions(-) create mode 100644 plugins/bbdb/bbdb.h create mode 100644 plugins/bbdb/gaimbuddies.c create mode 100644 plugins/bbdb/test-evobuddy.c diff --git a/plugins/bbdb/ChangeLog b/plugins/bbdb/ChangeLog index d471940c29..423d30da74 100644 --- a/plugins/bbdb/ChangeLog +++ b/plugins/bbdb/ChangeLog @@ -1,3 +1,22 @@ +2004-10-25 Nat Friedman + + * bbdb.c (e_plugin_lib_enable): Sync the Gaim buddy list. Set a + timer to check for Gaim buddy list chnages to sync. + (bbdb_do_it): Free some memory we were leaking before. + (bbdb_open_addressbook): New function for Gaim buddy list support. + (bbdb_check_gaim_enabled): Likewise. + (enable_gaim_toggled_cb): Likewise. + (synchronize_button_clicked_cb): Likewise. + (bbdb_page_factory): Added UI for Gaim buddy list sync support. + + * gaimbuddies.c: New file, contains routines to synchronize IM + information and buddy icons from a Gaim buddy list. + + * bbdb.h: New file, contains shared macros and prototypes. + + * test-evobuddy.c (main): New function, tests a gaim buddy list + sync. + 2004-10-23 Nat Friedman * bbdb.c (bbdb_do_it): Change assertions to if statements, so as diff --git a/plugins/bbdb/Makefile.am b/plugins/bbdb/Makefile.am index 140cc9e2fc..aa84ee194d 100644 --- a/plugins/bbdb/Makefile.am +++ b/plugins/bbdb/Makefile.am @@ -8,5 +8,11 @@ INCLUDES = \ plugin_DATA = org-gnome-evolution-bbdb.eplug plugin_LTLIBRARIES = liborg-gnome-evolution-bbdb.la -liborg_gnome_evolution_bbdb_la_SOURCES = bbdb.c +liborg_gnome_evolution_bbdb_la_SOURCES = bbdb.c gaimbuddies.c liborg_gnome_evolution_bbdb_la_LDFLAGS = -module -avoid-version + +noinst_PROGRAMS = test-evobuddy + +test_evobuddy_LDADD = $(top_builddir)/camel/libcamel.la $(EVOLUTION_ADDRESSBOOK_LIBS) $(EVOLUTION_MAIL_LIBS) $(CAMEL_LIBS) +test_evobuddy_SOURCES = test-evobuddy.c gaimbuddies.c bbdb.c +test_evobuddy_INCLUDES = $(INCLUDES) diff --git a/plugins/bbdb/bbdb.c b/plugins/bbdb/bbdb.c index bc1b2cc4fe..66e56879f3 100644 --- a/plugins/bbdb/bbdb.c +++ b/plugins/bbdb/bbdb.c @@ -47,11 +47,10 @@ #include #include -/* Where to store the config values */ -#define GCONF_KEY_ENABLE "/apps/evolution/mail/autopopulate_addressbook" -#define GCONF_KEY_WHICH_ADDRESSBOOK "/apps/evolution/mail/autopopulate_source" +#include "bbdb.h" /* Plugin hooks */ +int e_plugin_lib_enable (EPluginLib *ep, int enable); void bbdb_handle_reply (EPlugin *ep, EMEventTargetMessage *target); GtkWidget *bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data); GtkWidget *bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data); @@ -63,9 +62,11 @@ struct bbdb_stuff { GtkWidget *option_menu; GtkWidget *check; + GtkWidget *check_gaim; }; /* Static forward declarations */ +static gboolean bbdb_timeout (gpointer data); static void bbdb_do_it (EBook *book, const char *name, const char *email); static void add_email_to_contact (EContact *contact, const char *email); static void enable_toggled_cb (GtkWidget *widget, gpointer data); @@ -73,7 +74,31 @@ static void source_changed_cb (GtkWidget *widget, ESource *source, gpointer data static GtkWidget *create_addressbook_option_menu (struct bbdb_stuff *stuff); static void cleanup_cb (GObject *o, gpointer data); +int +e_plugin_lib_enable (EPluginLib *ep, int enable) +{ + /* Start up the plugin. */ + if (enable) { + fprintf (stderr, "BBDB spinning up...\n"); + + if (bbdb_check_gaim_enabled ()) + bbdb_sync_buddy_list_check (); + + g_timeout_add (BBDB_BLIST_CHECK_INTERVAL, + (GSourceFunc) bbdb_timeout, + NULL); + } + return 0; +} + +static gboolean +bbdb_timeout (gpointer data) +{ + bbdb_sync_buddy_list_check (); + + return TRUE; +} /* Code to populate addressbook when you reply to a mail follows */ @@ -83,33 +108,11 @@ bbdb_handle_reply (EPlugin *ep, EMEventTargetMessage *target) const CamelInternetAddress *cia; const char *name; const char *email; - char *uri; EBook *book = NULL; int i; - GConfClient *gconf; - - gboolean status; - GError *error; - - gconf = gconf_client_get_default (); - uri = gconf_client_get_string (gconf, GCONF_KEY_WHICH_ADDRESSBOOK, NULL); - g_object_unref (G_OBJECT (gconf)); - if (uri == NULL) - book = e_book_new_system_addressbook (&error); - else - book = e_book_new_from_uri (uri, &error); - if (book == NULL) { - g_warning ("bbdb: failed to open addressbook: %s\n", error->message); - return; - } - - status = e_book_open (book, FALSE, NULL); - - if (status == FALSE) { - g_warning ("bbdb: failed to open local addressbook\n"); - return; - } + /* Open the addressbook */ + book = bbdb_open_addressbook (); cia = camel_mime_message_get_from (target->message); for (i = 0; i < camel_address_length CAMEL_ADDRESS (cia); i ++) { @@ -143,7 +146,7 @@ bbdb_do_it (EBook *book, const char *name, const char *email) { char *query_string; EBookQuery *query; - GList *contacts; + GList *contacts, *l; EContact *contact; gboolean status; @@ -166,8 +169,15 @@ bbdb_do_it (EBook *book, const char *name, const char *email) g_free (query_string); status = e_book_get_contacts (book, query, &contacts, NULL); - if (contacts != NULL) + e_book_query_unref (query); + if (contacts != NULL) { + GList *l; + for (l = contacts; l != NULL; l = l->next) + g_object_unref ((GObject *)l->data); + g_list_free (contacts); + return; + } /* If a contact exists with this name, add the email address to it. */ query_string = g_strdup_printf ("(is \"full_name\" \"%s\")", name); @@ -175,17 +185,26 @@ bbdb_do_it (EBook *book, const char *name, const char *email) g_free (query_string); status = e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); if (contacts != NULL) { - /* If there's more than one contact with this name, - just give up; we're not smart enough for this. */ + /* FIXME: If there's more than one contact with this + name, just give up; we're not smart enough for + this. */ if (contacts->next != NULL) return; contact = (EContact *) contacts->data; add_email_to_contact (contact, email); - if (! e_book_commit_contact (book, contact, &error)) + if (! e_book_commit_contact (book, contact, &error)) { g_warning ("bbdb: Could not modify contact: %s\n", error->message); + g_error_free (error); + } + + for (l = contacts; l != NULL; l = l->next) + g_object_unref ((GObject *)l->data); + g_list_free (contacts); + return; } @@ -196,8 +215,69 @@ bbdb_do_it (EBook *book, const char *name, const char *email) if (! e_book_add_contact (book, contact, &error)) { g_warning ("bbdb: Failed to add new contact: %s\n", error->message); + g_error_free (error); return; } + + g_object_unref (G_OBJECT (contact)); +} + +EBook * +bbdb_open_addressbook (void) +{ + GConfClient *gconf; + char *uri; + EBook *book = NULL; + + gboolean enable; + + gboolean status; + GError *error; + + gconf = gconf_client_get_default (); + + /* Check to see if we're supposed to be running */ + enable = gconf_client_get_bool (gconf, GCONF_KEY_ENABLE, NULL); + if (! enable) { + g_object_unref (G_OBJECT (gconf)); + return NULL; + } + + /* Open the appropriate addresbook. */ + uri = gconf_client_get_string (gconf, GCONF_KEY_WHICH_ADDRESSBOOK, NULL); + g_object_unref (G_OBJECT (gconf)); + if (uri == NULL) + book = e_book_new_system_addressbook (&error); + else + book = e_book_new_from_uri (uri, &error); + if (book == NULL) { + g_warning ("bbdb: failed to get addressbook: %s\n", error->message); + g_error_free (error); + return NULL; + } + + status = e_book_open (book, FALSE, &error); + if (! status) { + g_warning ("bbdb: failed to open addressbook: %s\n", error->message); + g_error_free (error); + return NULL; + } + + return book; +} + +gboolean +bbdb_check_gaim_enabled () +{ + GConfClient *gconf; + gboolean gaim_enabled; + + gconf = gconf_client_get_default (); + gaim_enabled = gconf_client_get_bool (gconf, GCONF_KEY_ENABLE_GAIM, NULL); + + g_object_unref (G_OBJECT (gconf)); + + return gaim_enabled; } static void @@ -228,6 +308,24 @@ enable_toggled_cb (GtkWidget *widget, gpointer data) gtk_widget_set_sensitive (stuff->option_menu, active); } +static void +enable_gaim_toggled_cb (GtkWidget *widget, gpointer data) +{ + struct bbdb_stuff *stuff = (struct bbdb_stuff *) data; + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + /* Save the new setting to gconf */ + gconf_client_set_bool (stuff->target->gconf, GCONF_KEY_ENABLE_GAIM, active, NULL); +} + +static void +synchronize_button_clicked_cb (GtkWidget *button) +{ + bbdb_sync_buddy_list (); +} + static void source_changed_cb (GtkWidget *widget, ESource *source, gpointer data) { @@ -276,6 +374,8 @@ bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data) GtkWidget *inner_vbox; GtkWidget *check; GtkWidget *option; + GtkWidget *check_gaim; + GtkWidget *button; /* A structure to pass some stuff around */ stuff = g_new0 (struct bbdb_stuff, 1); @@ -289,9 +389,9 @@ bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data) /* Frame */ frame = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0); - /* Label */ + /* "Automatic Contacts" */ frame_label = gtk_label_new (""); gtk_label_set_markup (GTK_LABEL (frame_label), _("Automatic Contacts")); GTK_MISC (frame_label)->xalign = 0.0; @@ -319,6 +419,35 @@ bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data) gtk_box_pack_start (GTK_BOX (inner_vbox), option, FALSE, FALSE, 0); stuff->option_menu = option; + /* "Instant Messaging Contacts" */ + frame = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24); + + frame_label = gtk_label_new (""); + gtk_label_set_markup (GTK_LABEL (frame_label), _("Instant Messaging Contacts")); + GTK_MISC (frame_label)->xalign = 0.0; + gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0); + + /* Indent/padding */ + hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0); + padding_label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0); + inner_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0); + + /* Enable Gaim Checkbox */ + check_gaim = gtk_check_button_new_with_mnemonic (_("Periodically synchronize contact information and images from my _instant messenger")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_gaim), gconf_client_get_bool (target->gconf, GCONF_KEY_ENABLE_GAIM, NULL)); + g_signal_connect (GTK_TOGGLE_BUTTON (check_gaim), "toggled", G_CALLBACK (enable_gaim_toggled_cb), stuff); + gtk_box_pack_start (GTK_BOX (inner_vbox), check_gaim, FALSE, FALSE, 0); + stuff->check_gaim = check_gaim; + + /* Synchronize now button. */ + button = gtk_button_new_with_label (_("Synchronize with _buddy list now")); + g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (synchronize_button_clicked_cb), stuff); + gtk_box_pack_start (GTK_BOX (inner_vbox), button, FALSE, FALSE, 0); + /* Clean up */ g_signal_connect (page, "destroy", G_CALLBACK (cleanup_cb), stuff); @@ -335,6 +464,3 @@ cleanup_cb (GObject *o, gpointer data) g_object_unref (stuff->source_list); g_free (stuff); } - - - diff --git a/plugins/bbdb/bbdb.h b/plugins/bbdb/bbdb.h new file mode 100644 index 0000000000..5fe9e39bdd --- /dev/null +++ b/plugins/bbdb/bbdb.h @@ -0,0 +1,22 @@ +#ifndef __BBDB_H__ +#define __BBDB_H__ + +/* Where to store the config values */ +#define GCONF_KEY_ENABLE "/apps/evolution/autocontacts/enable_autocontacts" +#define GCONF_KEY_ENABLE_GAIM "/apps/evolution/autocontacts/auto_sync_gaim" +#define GCONF_KEY_WHICH_ADDRESSBOOK "/apps/evolution/autocontacts/addressbook_source" +#define GCONF_KEY_GAIM_LAST_SYNC "/apps/evolution/autocontacts/gaim_last_sync_time" + +/* How often to poll the buddy list for changes (every two minutes) */ +#define BBDB_BLIST_CHECK_INTERVAL (2 * 60 * 1000) + +/* bbdb.c */ +EBook *bbdb_open_addressbook (void); +gboolean bbdb_check_gaim_enabled (void); + +/* gaimbuddies.c */ +void bbdb_sync_buddy_list (void); +void bbdb_sync_buddy_list_check (void); + + +#endif /* __BBDB_H__ */ diff --git a/plugins/bbdb/gaimbuddies.c b/plugins/bbdb/gaimbuddies.c new file mode 100644 index 0000000000..a9bd81bc9b --- /dev/null +++ b/plugins/bbdb/gaimbuddies.c @@ -0,0 +1,459 @@ +/* + * Routines to copy information from a Gaim buddy list into an + * Evolution addressbook. + * + * I currently copy IM account names and buddy icons, provided you + * don't already have a buddy icon defined for a person. + * + * This works today (25 October 2004), but is pretty sure to break + * later on as the Gaim buddylist file format shifts. + * + * Nat Friedman + * + * Copyright 2004 Novell, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "bbdb.h" + +typedef struct { + char *account_name; + char *proto; + char *alias; + char *icon; +} GaimBuddy; + +/* Defined in bbdb.c */ +EBook *bbdb_open_addressbook (void); + +/* Forward declarations for this file. */ +void bbdb_sync_buddy_list (void); +static EBookQuery *e_book_query_im_field_contains (const char *im); +static void bbdb_merge_buddy_to_contact (EBook *book, GaimBuddy *b, EContact *c); +static GList *bbdb_get_gaim_buddy_list (void); +static char *get_node_text (xmlNodePtr node); +static char *get_buddy_icon_from_setting (xmlNodePtr setting); +static char *get_node_text (xmlNodePtr node); +static void free_contact_list (GList *contacts); +static void free_buddy_list (GList *blist); +static void parse_buddy_group (xmlNodePtr group, GList **buddies); +static EContactField proto_to_contact_field (const char *proto); + +void +bbdb_sync_buddy_list_check (void) +{ + GConfClient *gconf; + struct stat statbuf; + time_t last_sync; + char *blist_path; + char *last_sync_str; + + gconf = gconf_client_get_default (); + + if (! gconf_client_get_bool (gconf, GCONF_KEY_ENABLE_GAIM, NULL)) { + g_object_unref (G_OBJECT (gconf)); + return; + } + + blist_path = g_build_path ("/", getenv ("HOME"), ".gaim/blist.xml", NULL); + if (stat (blist_path, &statbuf) < 0) { + g_object_unref (G_OBJECT (gconf)); + return; + } + + /* Reprocess the buddy list if it's been updated. */ + last_sync_str = gconf_client_get_string (gconf, GCONF_KEY_GAIM_LAST_SYNC, NULL); + if (last_sync_str == NULL || ! strcmp (last_sync_str, "")) + last_sync = (time_t) 0; + else + last_sync = (time_t) g_ascii_strtoull (last_sync_str, NULL, 10); + + g_free (last_sync_str); + g_object_unref (G_OBJECT (gconf)); + + printf ("bbdb: Last sync: %ld\n", last_sync); + printf ("bbdb: Modified: %ld\n", statbuf.st_mtime); + + if (statbuf.st_mtime > last_sync) { + fprintf (stderr, "bbdb: Buddy list dirty!\n"); + + bbdb_sync_buddy_list (); + } +} + +void +bbdb_sync_buddy_list (void) +{ + GList *blist, *l; + EBook *book = NULL; + + /* Get the Gaim buddy list */ + blist = bbdb_get_gaim_buddy_list (); + if (blist == NULL) + return; + + /* Open the addressbook */ + book = bbdb_open_addressbook (); + if (book == NULL) { + free_buddy_list (blist); + return; + } + + /* Walk the buddy list */ + for (l = blist; l != NULL; l = l->next) { + GaimBuddy *b = l->data; + EBookQuery *query; + GList *contacts; + GError *error; + EContact *c; + + if (b->alias == NULL || strlen (b->alias) == 0) + continue; + + /* Check to see if the buddy is already in the addressbook */ + query = e_book_query_im_field_contains (b->account_name); + e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); + if (contacts != NULL) { + free_contact_list (contacts); + continue; + } + free_contact_list (contacts); + + /* Look for an exact match full name == buddy alias */ + query = e_book_query_field_test (E_CONTACT_FULL_NAME, E_BOOK_QUERY_IS, b->alias); + e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); + if (contacts != NULL) { + + /* FIXME: If there's more than one contact with this + name, just give up; we're not smart enough for + this. */ + if (contacts->next != NULL) + continue; + + c = E_CONTACT (contacts->data); + + bbdb_merge_buddy_to_contact (book, b, c); + + /* Write it out to the addressbook */ + if (! e_book_commit_contact (book, c, &error)) { + g_warning ("bbdb: Could not modify contact: %s\n", error->message); + g_error_free (error); + } + + continue; + } + + /* Otherwise, create a new contact. */ + c = e_contact_new (); + e_contact_set (c, E_CONTACT_FULL_NAME, (gpointer) b->alias); + bbdb_merge_buddy_to_contact (book, b, c); + if (! e_book_add_contact (book, c, &error)) { + g_warning ("bbdb: Failed to add new contact: %s\n", error->message); + g_error_free (error); + return; + } + g_object_unref (G_OBJECT (c)); + } + + + /* Update the last-sync'd time */ + { + GConfClient *gconf; + time_t last_sync; + char *last_sync_str; + + gconf = gconf_client_get_default (); + + time (&last_sync); + last_sync_str = g_strdup_printf ("%ld", (glong) last_sync); + printf ("Str: %s\n", last_sync_str); + gconf_client_set_string (gconf, GCONF_KEY_GAIM_LAST_SYNC, last_sync_str, NULL); + g_free (last_sync_str); + + g_object_unref (G_OBJECT (gconf)); + } +} + +static EBookQuery * +e_book_query_im_field_contains (const char *im) +{ + char *query_string; + EBookQuery *query; + + query_string = g_strdup_printf ( + "(or " + "(is \"im_aim\" \"%s\") " + "(is \"im_yahoo\" \"%s\") " + "(is \"im_msn\" \"%s\") " + "(is \"im_icq\" \"%s\") " + "(is \"im_jabber\" \"%s\") " + "(is \"im_groupwise\" \"%s\")" + ")", + im, im, im, im, im, im); + + query = e_book_query_from_string (query_string); + + g_free (query_string); + + return query; +} + +static void +bbdb_merge_buddy_to_contact (EBook *book, GaimBuddy *b, EContact *c) +{ + EContactField field; + GList *ims, *l; + + EContactPhoto *photo = NULL; + + GError *error = NULL; + + /* Set the IM account */ + field = proto_to_contact_field (b->proto); + ims = e_contact_get (c, field); + ims = g_list_append (ims, (gpointer) b->account_name); + e_contact_set (c, field, (gpointer) ims); + + /* Set the photo if it's not set */ + if (b->icon != NULL) { + photo = e_contact_get (c, E_CONTACT_PHOTO); + if (photo == NULL) { + + photo = g_new0 (EContactPhoto, 1); + + if (! g_file_get_contents (b->icon, &photo->data, &photo->length, &error)) { + g_warning ("bbdb: Could not read buddy icon: %s\n", error->message); + g_error_free (error); + return; + } + + e_contact_set (c, E_CONTACT_PHOTO, (gpointer) photo); + } + } + + /* Clean up */ + if (photo != NULL) { + g_free (photo->data); + g_free (photo); + } + + for (l = ims; l != NULL; l = l->next) + g_free ((char *) l->data); + g_list_free (ims); +} + +static EContactField +proto_to_contact_field (const char *proto) +{ + if (! strcmp (proto, "prpl-oscar")) + return E_CONTACT_IM_AIM; + if (! strcmp (proto, "prpl-novell")) + return E_CONTACT_IM_GROUPWISE; + if (! strcmp (proto, "prpl-msn")) + return E_CONTACT_IM_MSN; + if (! strcmp (proto, "prpl-icq")) + return E_CONTACT_IM_ICQ; + if (! strcmp (proto, "prpl-yahoo")) + return E_CONTACT_IM_YAHOO; + if (! strcmp (proto, "prpl-jabber")) + return E_CONTACT_IM_JABBER; + + return E_CONTACT_IM_AIM; +} + +static void +free_contact_list (GList *contacts) +{ + GList *l; + + for (l = contacts; l != NULL; l = l->next) + g_object_unref (G_OBJECT (l->data)); + g_list_free (contacts); +} + +static GList * +bbdb_get_gaim_buddy_list (void) +{ + char *blist_path; + xmlDocPtr buddy_xml; + xmlNodePtr root, child, blist; + GList *buddies = NULL; + + blist_path = g_build_path ("/", getenv ("HOME"), ".gaim/blist.xml", NULL); + + buddy_xml = xmlParseFile (blist_path); + g_free (blist_path); + if (! buddy_xml) { + fprintf (stderr, "bbdb: Could not open Gaim buddy list.\n"); + return NULL; + } + + root = xmlDocGetRootElement (buddy_xml); + if (strcmp (root->name, "gaim")) { + fprintf (stderr, "bbdb: Could not parse Gaim buddy list.\n"); + xmlFreeDoc (buddy_xml); + return NULL; + } + + blist = NULL; + for (child = root->children; child != NULL; child = child->next) { + if (! strcmp (child->name, "blist")) { + blist = child; + break; + } + } + if (blist == NULL) { + fprintf (stderr, "bbdb: Could not find 'blist' element in Gaim buddy list.\n"); + xmlFreeDoc (buddy_xml); + return NULL; + } + + for (child = blist->children; child != NULL; child = child->next) { + if (! strcmp (child->name, "group")) + parse_buddy_group (child, &buddies); + } + + xmlFreeDoc (buddy_xml); + + return buddies; +} + +static void +free_buddy_list (GList *blist) +{ + GList *l; + + for (l = blist; l != NULL; l = l->next) { + GaimBuddy *gb = l->data; + + g_free (gb->icon); + g_free (gb->alias); + g_free (gb->account_name); + g_free (gb->proto); + g_free (gb); + } + + g_list_free (l); +} + +static char * +get_node_text (xmlNodePtr node) +{ + if (node->children == NULL || node->children->content == NULL || + strcmp (node->children->name, "text")) + return NULL; + + return g_strdup (node->children->content); +} + +static char * +get_buddy_icon_from_setting (xmlNodePtr setting) +{ + char *icon = NULL; + + icon = get_node_text (setting); + if (icon [0] != '/') { + char *path; + + path = g_build_path ("/", getenv ("HOME"), ".gaim/icons", icon, NULL); + g_free (icon); + icon = path; + } + + + return icon; +} + +static void +parse_contact (xmlNodePtr contact, GList **buddies) +{ + xmlNodePtr child; + xmlNodePtr buddy = NULL; + GaimBuddy *gb; + + for (child = contact->children; child != NULL; child = child->next) { + if (! strcmp (child->name, "buddy")) { + buddy = child; + break; + } + } + + if (buddy == NULL) { + fprintf (stderr, "bbdb: Could not find buddy in contact. Malformed Gaim buddy list file.\n"); + return; + } + + gb = g_new0 (GaimBuddy, 1); + + gb->proto = e_xml_get_string_prop_by_name (buddy, "proto"); + + for (child = buddy->children; child != NULL; child = child->next) { + if (! strcmp (child->name, "setting")) { + char *setting_type; + setting_type = e_xml_get_string_prop_by_name (child, "name"); + + if (! strcmp (setting_type, "buddy_icon")) + gb->icon = get_buddy_icon_from_setting (child); + + g_free (setting_type); + } else if (! strcmp (child->name, "name")) + gb->account_name = get_node_text (child); + else if (! strcmp (child->name, "alias")) + gb->alias = get_node_text (child); + + } + + *buddies = g_list_prepend (*buddies, gb); +} + +static void +parse_buddy_group (xmlNodePtr group, GList **buddies) +{ + xmlNodePtr child; + + for (child = group->children; child != NULL; child = child->next) { + if (strcmp (child->name, "contact")) + continue; + + parse_contact (child, buddies); + } +} diff --git a/plugins/bbdb/test-evobuddy.c b/plugins/bbdb/test-evobuddy.c new file mode 100644 index 0000000000..269999beb1 --- /dev/null +++ b/plugins/bbdb/test-evobuddy.c @@ -0,0 +1,15 @@ +#include + +void bbdb_sync_buddy_list (void); + +int +main (void) +{ + printf ("Syncing...\n"); + + bbdb_sync_buddy_list (); + + printf ("Done!\n"); + + return 0; +} -- cgit v1.2.3