# HG changeset patch # User Sean Egan # Date 1073958332 0 # Node ID 35db601609e3d7d91f618356d57046379678bd26 # Parent a86784e3b98c1fba4cac9cb47a117336ed0f6142 [gaim-migrate @ 8788] Gaim-Evolution Buddy List-Addressbook syncronocity by our very own Chip X. Eightysix. committer: Tailor Script diff -r a86784e3b98c -r 35db601609e3 configure.ac --- a/configure.ac Tue Jan 13 01:00:24 2004 +0000 +++ b/configure.ac Tue Jan 13 01:45:32 2004 +0000 @@ -238,6 +238,18 @@ AC_SUBST(STARTUP_NOTIFICATION_CFLAGS) AC_SUBST(STARTUP_NOTIFICATION_LIBS) + +dnl Check for stuff needed by the evolution integration plugin. +build_gevo=no + +evo_deps="libxml-2.0 libebook-1.0 libedata-book-1.0" +PKG_CHECK_MODULES(EVOLUTION_ADDRESSBOOK, $evo_deps, build_gevo=yes, build_gevo=no) + +AC_SUBST(EVOLUTION_ADDRESSBOOK_CFLAGS) +AC_SUBST(EVOLUTION_ADDRESSBOOK_LIBS) + +AM_CONDITIONAL(BUILD_GEVOLUTION, test "x$build_gevo" = "xyes") + dnl Check for XScreenSaver if test "x$enable_xss" = "xyes" ; then old_LIBS="$LIBS" @@ -1011,6 +1023,7 @@ pixmaps/status/default/Makefile plugins/Makefile plugins/docklet/Makefile + plugins/gevolution/Makefile plugins/gaim-remote/Makefile plugins/gestures/Makefile plugins/perl/Makefile diff -r a86784e3b98c -r 35db601609e3 plugins/Makefile.am --- a/plugins/Makefile.am Tue Jan 13 01:00:24 2004 +0000 +++ b/plugins/Makefile.am Tue Jan 13 01:45:32 2004 +0000 @@ -1,4 +1,8 @@ -DIST_SUBDIRS = docklet gaim-remote gestures perl ssl tcl ticker +DIST_SUBDIRS = docklet gevolution gaim-remote gestures perl ssl tcl ticker + +if BUILD_GEVOLUTION +GEVOLUTION_DIR = gevolution +endif if USE_PERL PERL_DIR = perl @@ -8,7 +12,9 @@ TCL_DIR = tcl endif -SUBDIRS = docklet gaim-remote gestures $(PERL_DIR) $(TCL_DIR) ssl ticker +SUBDIRS = \ + docklet gaim-remote $(GEVOLUTION_DIR) gestures \ + $(PERL_DIR) $(TCL_DIR) ssl ticker plugindir = $(libdir)/gaim diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/Makefile.am Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,28 @@ +plugindir = $(libdir)/gaim + +gevolution_la_LDFLAGS = \ + -module -avoid-version \ + $(EVOLUTION_ADDRESSBOOK_LIBS) + +if PLUGINS + +plugin_LTLIBRARIES = gevolution.la + +gevolution_la_SOURCES = \ + add_buddy_dialog.c \ + assoc-buddy.c \ + gevolution.c \ + gevo-util.c \ + new_person_dialog.c + +endif + +gevolution_la_LIBADD = + +AM_CPPFLAGS = \ + -DDATADIR=\"$(datadir)\" \ + -DVERSION=\"$(VERSION)\" \ + -I$(top_srcdir)/src \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) \ + $(DEBUG_CFLAGS) \ + $(GTK_CFLAGS) diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/add_buddy_dialog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/add_buddy_dialog.c Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,650 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include "gtkinternal.h" +#include "gtkblist.h" +#include "gtkutils.h" + +#include "debug.h" + +#include "gevolution.h" + +#include +#include +#include +#include +#include + +enum +{ + COLUMN_NAME, + COLUMN_PRPL_ICON, + COLUMN_USERNAME, + COLUMN_DATA, + NUM_COLUMNS +}; + +static gint +delete_win_cb(GtkWidget *w, GdkEvent *event, GevoAddBuddyDialog *dialog) +{ + gtk_widget_destroy(dialog->win); + + g_list_foreach(dialog->contacts, (GFunc)g_object_unref, NULL); + + if (dialog->contacts != NULL) + g_list_free(dialog->contacts); + + if (dialog->book != NULL) + g_object_unref(dialog->book); + + if (dialog->username != NULL) + g_free(dialog->username); + + g_free(dialog); + + return 0; +} + +static void +new_person_cb(GtkWidget *w, GevoAddBuddyDialog *dialog) +{ + const char *group_name; + + group_name = + gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(dialog->group_combo)->entry)); + + gevo_new_person_dialog_show(NULL, dialog->account, NULL, + (*group_name ? group_name : NULL), + NULL, FALSE); + + delete_win_cb(NULL, NULL, dialog); +} + +static void +cancel_cb(GtkWidget *w, GevoAddBuddyDialog *dialog) +{ + delete_win_cb(NULL, NULL, dialog); +} + +static void +select_buddy_cb(GtkWidget *w, GevoAddBuddyDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + const char *group_name; + const char *fullname; + const char *username; + EContact *contact; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_get_selected(selection, NULL, &iter); + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, + COLUMN_NAME, &fullname, + COLUMN_USERNAME, &username, + COLUMN_DATA, &contact, + -1); + + group_name = + gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(dialog->group_combo)->entry)); + + if (username == NULL || *username == '\0') + { + gevo_new_person_dialog_show(NULL, dialog->account, NULL, + (*group_name ? group_name : NULL), + NULL, FALSE); + } + else + { + gevo_add_buddy(dialog->account, group_name, username, fullname); + } + + delete_win_cb(NULL, NULL, dialog); +} + +static void +populate_address_books(GevoAddBuddyDialog *dialog) +{ + GtkWidget *item; + GtkWidget *menu; +#if notyet + ESourceList *addressbooks; + GList *groups, *g; +#endif + + menu = + gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->addressbooks_menu)); + + item = gtk_menu_item_new_with_label(_("Local Addressbook")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + +#if notyet + if (!e_book_get_addressbooks(&addressbooks, NULL)) + { + gaim_debug_error("evolution", + "Unable to fetch list of address books.\n"); + + item = gtk_menu_item_new_with_label(_("None")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + return; + } + + groups = e_source_list_peek_groups(list); + + if (groups == NULL) + { + item = gtk_menu_item_new_with_label(_("None")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + return; + } + + for (g = groups; g != NULL; g = g->next) + { + GList *sources, *s; + + sources = e_source_group_peek_sources(g->data); + + for (p = sources; p != NULL; p = p->next) + { + ESource *source = E_SOURCE(p->data); + + item = gtk_menu_item_new_with_label(e_source_peek_name(source)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + } + } +#endif +} + +static void +add_columns(GevoAddBuddyDialog *dialog) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* Name column */ + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Name")); + gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, + "text", COLUMN_NAME); + + /* Account column */ + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Instant Messaging")); + gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_USERNAME); + + /* Protocol icon */ + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_add_attribute(column, renderer, + "pixbuf", COLUMN_PRPL_ICON); + + /* Account name */ + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, + "text", COLUMN_USERNAME); +} + +static void +add_ims(GevoAddBuddyDialog *dialog, EContact *contact, const char *name, + GList *list, const char *id) +{ + GaimAccount *account = NULL; + GList *l; + GtkTreeIter iter; + GdkPixbuf *pixbuf, *icon = NULL; + + if (list == NULL) + return; + + for (l = gaim_connections_get_all(); l != NULL; l = l->next) + { + GaimConnection *gc = (GaimConnection *)l->data; + + account = gaim_connection_get_account(gc); + + if (!strcmp(gaim_account_get_protocol_id(account), id)) + break; + + account = NULL; + } + + if (account == NULL) + return; + + pixbuf = create_prpl_icon(account); + + if (pixbuf != NULL) + icon = gdk_pixbuf_scale_simple(pixbuf, 16, 16, + GDK_INTERP_BILINEAR); + + for (l = list; l != NULL; l = l->next) + { + char *account_name = (char *)l->data; + + if (account_name == NULL) + continue; + + if (gaim_find_buddy(dialog->account, account_name) != NULL) + continue; + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_PRPL_ICON, icon, + COLUMN_USERNAME, account_name, + COLUMN_DATA, contact, + -1); + + if (!strcmp(gaim_account_get_protocol_id(account), + gaim_account_get_protocol_id(dialog->account)) && + dialog->username != NULL && + !strcmp(account_name, dialog->username)) + { + GtkTreeSelection *selection; + + /* This is it. Select it. */ + selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_select_iter(selection, &iter); + } + } + + if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); + if (icon != NULL) g_object_unref(G_OBJECT(icon)); + + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); +} + +static void +populate_treeview(GevoAddBuddyDialog *dialog) +{ + EBookQuery *query; + EBook *book; + gboolean status; + GList *cards, *c; + + if (!gevo_load_addressbook(&book, NULL)) + { + gaim_debug_error("evolution", + "Error retrieving default addressbook\n"); + + return; + } + + query = e_book_query_field_exists(E_CONTACT_FULL_NAME); + + if (query == NULL) + { + gaim_debug_error("evolution", "Error in creating query\n"); + + g_object_unref(book); + + return; + } + + status = e_book_get_contacts(book, query, &cards, NULL); + + e_book_query_unref(query); + + if (!status) + { + gaim_debug_error("evolution", "Error %d in getting card list\n", + status); + + g_object_unref(book); + + return; + } + + for (c = cards; c != NULL; c = c->next) + { + EContact *contact = E_CONTACT(c->data); + const char *name; + GList *aims, *jabbers, *yahoos, *msns, *icqs; + + name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); + + aims = e_contact_get(contact, E_CONTACT_IM_AIM); + jabbers = e_contact_get(contact, E_CONTACT_IM_JABBER); + yahoos = e_contact_get(contact, E_CONTACT_IM_YAHOO); + msns = e_contact_get(contact, E_CONTACT_IM_MSN); + icqs = e_contact_get(contact, E_CONTACT_IM_ICQ); + + if (aims == NULL && jabbers == NULL && yahoos == NULL && + msns == NULL && icqs == NULL) + { + GtkTreeIter iter; + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_DATA, contact, + -1); + } + else + { + add_ims(dialog, contact, name, aims, "prpl-oscar"); + add_ims(dialog, contact, name, jabbers, "prpl-jabber"); + add_ims(dialog, contact, name, yahoos, "prpl-yahoo"); + add_ims(dialog, contact, name, msns, "prpl-msn"); + add_ims(dialog, contact, name, icqs, "prpl-oscar"); + } + } + + dialog->contacts = cards; + dialog->book = book; +} + +static void +selected_cb(GtkTreeSelection *sel, GevoAddBuddyDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->select_button, TRUE); +} + +static void +search_changed_cb(GtkEntry *entry, GevoAddBuddyDialog *dialog) +{ + const char *text = gtk_entry_get_text(entry); + GList *l; + + gtk_list_store_clear(dialog->model); + + for (l = dialog->contacts; l != NULL; l = l->next) + { + EContact *contact = E_CONTACT(l->data); + const char *name; + GList *aims, *jabbers, *yahoos, *msns, *icqs; + + name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); + + if (text != NULL && *text != '\0' && name != NULL && + g_ascii_strncasecmp(name, text, strlen(text))) + { + continue; + } + + aims = e_contact_get(contact, E_CONTACT_IM_AIM); + jabbers = e_contact_get(contact, E_CONTACT_IM_JABBER); + yahoos = e_contact_get(contact, E_CONTACT_IM_YAHOO); + msns = e_contact_get(contact, E_CONTACT_IM_MSN); + icqs = e_contact_get(contact, E_CONTACT_IM_ICQ); + + if (aims == NULL && jabbers == NULL && yahoos == NULL && + msns == NULL && icqs == NULL) + { + GtkTreeIter iter; + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_DATA, contact, + -1); + } + else + { + add_ims(dialog, contact, name, aims, "prpl-oscar"); + add_ims(dialog, contact, name, jabbers, "prpl-jabber"); + add_ims(dialog, contact, name, yahoos, "prpl-yahoo"); + add_ims(dialog, contact, name, msns, "prpl-msn"); + add_ims(dialog, contact, name, icqs, "prpl-oscar"); + } + } +} + +static void +clear_cb(GtkWidget *w, GevoAddBuddyDialog *dialog) +{ + static gboolean lock = FALSE; + + if (lock) + return; + + lock = TRUE; + gtk_entry_set_text(GTK_ENTRY(dialog->search_field), ""); + lock = FALSE; +} + +void +gevo_add_buddy_dialog_show(GaimAccount *account, const char *username, + const char *group, const char *alias) +{ + GevoAddBuddyDialog *dialog; + GtkWidget *button; + GtkWidget *sw; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *menu; + GtkWidget *sep; + GtkTreeSelection *selection; + + dialog = g_new0(GevoAddBuddyDialog, 1); + + dialog->account = + (account != NULL + ? account + : gaim_connection_get_account(gaim_connections_get_all()->data)); + + if (username != NULL) + dialog->username = g_strdup(username); + + dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_role(GTK_WINDOW(dialog->win), "add_buddy"); + gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12); + gtk_widget_set_size_request(dialog->win, -1, 400); + + g_signal_connect(G_OBJECT(dialog->win), "delete_event", + G_CALLBACK(delete_win_cb), dialog); + + /* Setup the vbox */ + vbox = gtk_vbox_new(FALSE, 12); + gtk_container_add(GTK_CONTAINER(dialog->win), vbox); + gtk_widget_show(vbox); + + /* Add the label. */ + label = gtk_label_new(_("Select a person from your address book below, " + "or add a new person.")); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0); + gtk_widget_show(label); + + /* Add the search hbox */ + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show(hbox); + + /* "Search" */ + label = gtk_label_new(_("Search")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + /* Addressbooks */ + dialog->addressbooks_menu = gtk_option_menu_new(); + menu = gtk_menu_new(); + gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->addressbooks_menu), menu); + + populate_address_books(dialog); + + gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->addressbooks_menu), 0); + + gtk_box_pack_start(GTK_BOX(hbox), dialog->addressbooks_menu, + FALSE, FALSE, 0); + gtk_widget_show(dialog->addressbooks_menu); + + /* Search field */ + dialog->search_field = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), dialog->search_field, TRUE, TRUE, 0); + gtk_widget_show(dialog->search_field); + + g_signal_connect(G_OBJECT(dialog->search_field), "changed", + G_CALLBACK(search_changed_cb), dialog); + + /* Clear button */ + button = gtk_button_new_from_stock(GTK_STOCK_CLEAR); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(clear_cb), dialog); + + /* Scrolled Window */ + sw = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gtk_widget_show(sw); + + /* Create the list model for the treeview. */ + dialog->model = gtk_list_store_new(NUM_COLUMNS, + G_TYPE_STRING, GDK_TYPE_PIXBUF, + G_TYPE_STRING, G_TYPE_POINTER); + + /* Now for the treeview */ + dialog->treeview = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); + gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); + gtk_widget_show(dialog->treeview); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(selected_cb), dialog); + + add_columns(dialog); + + populate_treeview(dialog); + + /* Group box */ + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show(hbox); + + label = gtk_label_new(_("Group:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + dialog->group_combo = gtk_combo_new(); + gtk_combo_set_popdown_strings(GTK_COMBO(dialog->group_combo), + gevo_get_groups()); + gtk_box_pack_start(GTK_BOX(hbox), dialog->group_combo, TRUE, TRUE, 0); + gtk_widget_show(dialog->group_combo); + + /* Cool. Now we only have a little left... */ + + /* Separator. */ + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + gtk_widget_show(sep); + + /* Button box */ + bbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(GTK_BOX(bbox), 6); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); + gtk_widget_show(bbox); + + /* "New Person" button */ + button = gaim_pixbuf_button_from_stock(_("New Person"), GTK_STOCK_NEW, + GAIM_BUTTON_HORIZONTAL); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(new_person_cb), dialog); + + /* "Cancel" button */ + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(cancel_cb), dialog); + + /* "Select Buddy" button */ + button = gaim_pixbuf_button_from_stock(_("Select Buddy"), GTK_STOCK_APPLY, + GAIM_BUTTON_HORIZONTAL); + dialog->select_button = button; + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive(button, FALSE); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(select_buddy_cb), dialog); + + /* Show it. */ + gtk_widget_show(dialog->win); +} + +void +gevo_add_buddy_dialog_add_person(GevoAddBuddyDialog *dialog, + EContact *contact, const char *name, + GaimAccount *account, const char *screenname) +{ + GdkPixbuf *pixbuf, *icon = NULL; + GtkTreeIter iter; + + pixbuf = create_prpl_icon(account); + + if (pixbuf != NULL) + icon = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_PRPL_ICON, icon, + COLUMN_DATA, contact, + COLUMN_USERNAME, screenname, + -1); + + if (contact != NULL) + dialog->contacts = g_list_append(dialog->contacts, contact); + + if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); + if (icon != NULL) g_object_unref(G_OBJECT(icon)); +} diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/assoc-buddy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/assoc-buddy.c Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,520 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include "gtkinternal.h" +#include "gtkblist.h" +#include "gtkutils.h" +#include "gtkimhtml.h" +#include "gaim-disclosure.h" + +#include "debug.h" + +#include "gevolution.h" + +#include +#include +#include +#include +#include + +enum +{ + COLUMN_NAME, + COLUMN_DATA, + NUM_COLUMNS +}; + +static gint +delete_win_cb(GtkWidget *w, GdkEvent *event, GevoAssociateBuddyDialog *dialog) +{ + GList *l; + + gtk_widget_destroy(dialog->win); + + g_list_foreach(dialog->contacts, (GFunc)g_free, NULL); + + if (dialog->contacts != NULL) + g_list_free(dialog->contacts); + + g_object_unref(dialog->book); + + g_free(dialog); + + return 0; +} + +static void +populate_address_books(GevoAssociateBuddyDialog *dialog) +{ + GtkWidget *item; + GtkWidget *menu; +#if notyet + ESourceList *addressbooks; + GList *groups, *g; +#endif + + menu = + gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->addressbooks_menu)); + + item = gtk_menu_item_new_with_label(_("Local Addressbook")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + +#if notyet + if (!e_book_get_addressbooks(&addressbooks, NULL)) + { + gaim_debug_error("evolution", + "Unable to fetch list of address books.\n"); + + item = gtk_menu_item_new_with_label(_("None")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + return; + } + + groups = e_source_list_peek_groups(list); + + if (groups == NULL) + { + item = gtk_menu_item_new_with_label(_("None")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + + return; + } + + for (g = groups; g != NULL; g = g->next) + { + GList *sources, *s; + + sources = e_source_group_peek_sources(g->data); + + for (p = sources; p != NULL; p = p->next) + { + ESource *source = E_SOURCE(p->data); + + item = gtk_menu_item_new_with_label(e_source_peek_name(source)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_show(item); + } + } +#endif +} + +static void +search_changed_cb(GtkEntry *entry, GevoAssociateBuddyDialog *dialog) +{ + const char *text = gtk_entry_get_text(entry); + GList *l; + + gtk_list_store_clear(dialog->model); + + for (l = dialog->contacts; l != NULL; l = l->next) + { + EContact *contact = E_CONTACT(l->data); + const char *name; + GtkTreeIter iter; + + name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); + + if (text != NULL && *text != '\0' && name != NULL && + g_ascii_strncasecmp(name, text, strlen(text))) + { + continue; + } + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_DATA, contact, + -1); + } +} + +static void +clear_cb(GtkWidget *w, GevoAssociateBuddyDialog *dialog) +{ + static gboolean lock = FALSE; + + if (lock) + return; + + lock = TRUE; + gtk_entry_set_text(GTK_ENTRY(dialog->search_field), ""); + lock = FALSE; +} + +static void +selected_cb(GtkTreeSelection *sel, GevoAssociateBuddyDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->assoc_button, TRUE); +} + +static void +add_columns(GevoAssociateBuddyDialog *dialog) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* Name column */ + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Name")); + gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, + "text", COLUMN_NAME); +} + +static void +populate_treeview(GevoAssociateBuddyDialog *dialog) +{ + EBookQuery *query; + EBook *book; + const char *prpl_id; + gboolean status; + GList *cards, *c; + + if (!gevo_load_addressbook(&book, NULL)) + { + gaim_debug_error("evolution", + "Error retrieving default addressbook\n"); + + return; + } + + query = e_book_query_field_exists(E_CONTACT_FULL_NAME); + + if (query == NULL) + { + gaim_debug_error("evolution", "Error in creating query\n"); + + g_object_unref(book); + + return; + } + + status = e_book_get_contacts(book, query, &cards, NULL); + + e_book_query_unref(query); + + if (!status) + { + gaim_debug_error("evolution", "Error %d in getting card list\n", + status); + + g_object_unref(book); + + return; + } + + prpl_id = gaim_account_get_protocol_id(dialog->buddy->account); + + for (c = cards; c != NULL; c = c->next) + { + EContact *contact = E_CONTACT(c->data); + const char *name; + GtkTreeIter iter; + EContactField protocol_field = 0; + + name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_DATA, contact, + -1); + + /* See if this user has the buddy in its list. */ + protocol_field = gevo_prpl_get_field(dialog->buddy->account, + dialog->buddy); + + if (protocol_field > 0) + { + GList *ims, *l; + + ims = e_contact_get(contact, protocol_field); + + for (l = ims; l != NULL; l = l->next) + { + if (!strcmp(l->data, dialog->buddy->name)) + { + GtkTreeSelection *selection; + + /* This is it. Select it. */ + selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_select_iter(selection, &iter); + break; + } + } + } + } + + dialog->contacts = cards; + dialog->book = book; +} + +static void +new_person_cb(GtkWidget *w, GevoAssociateBuddyDialog *dialog) +{ + gevo_new_person_dialog_show(NULL, dialog->buddy->account, + dialog->buddy->name, NULL, dialog->buddy, + TRUE); + + delete_win_cb(NULL, NULL, dialog); +} + +static void +cancel_cb(GtkWidget *w, GevoAssociateBuddyDialog *dialog) +{ + delete_win_cb(NULL, NULL, dialog); +} + +static void +assoc_buddy_cb(GtkWidget *w, GevoAssociateBuddyDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + GList *list, *new_list = NULL, *l; + const char *fullname; + EContactField protocol_field; + EContact *contact; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_get_selected(selection, NULL, &iter); + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, + COLUMN_NAME, &fullname, + COLUMN_DATA, &contact, + -1); + + protocol_field = gevo_prpl_get_field(dialog->buddy->account, dialog->buddy); + + if (protocol_field == 0) + return; /* XXX */ + + list = e_contact_get(contact, protocol_field); + + /* Make a copy of the list */ + for (l = list; l != NULL; l = l->next) + new_list = g_list_append(new_list, g_strdup((char *)l->data)); + + new_list = g_list_append(new_list, dialog->buddy->name); + + e_contact_set(contact, protocol_field, new_list); + + /* Free the list. */ + g_list_foreach(new_list, (GFunc)g_free, NULL); + g_list_free(new_list); + + delete_win_cb(NULL, NULL, dialog); +} + +GevoAssociateBuddyDialog * +gevo_associate_buddy_dialog_new(GaimBuddy *buddy) +{ + GevoAssociateBuddyDialog *dialog; + GtkWidget *button; + GtkWidget *sw; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *menu; + GtkWidget *sep; + GtkWidget *disclosure; + GtkTreeSelection *selection; + + g_return_val_if_fail(buddy != NULL, NULL); + + dialog = g_new0(GevoAssociateBuddyDialog, 1); + + dialog->buddy = buddy; + + dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_role(GTK_WINDOW(dialog->win), "assoc_buddy"); + gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12); + + g_signal_connect(G_OBJECT(dialog->win), "delete_event", + G_CALLBACK(delete_win_cb), dialog); + + /* Setup the vbox */ + vbox = gtk_vbox_new(FALSE, 12); + gtk_container_add(GTK_CONTAINER(dialog->win), vbox); + gtk_widget_show(vbox); + + /* Add the label. */ + label = gtk_label_new(_("Select a person from your address book to " + "add this buddy to, or create a new person.")); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0); + gtk_widget_show(label); + + /* Add the search hbox */ + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show(hbox); + + /* "Search" */ + label = gtk_label_new(_("Search")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + /* Addressbooks */ + dialog->addressbooks_menu = gtk_option_menu_new(); + menu = gtk_menu_new(); + gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->addressbooks_menu), menu); + + populate_address_books(dialog); + + gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->addressbooks_menu), 0); + + gtk_box_pack_start(GTK_BOX(hbox), dialog->addressbooks_menu, + FALSE, FALSE, 0); + gtk_widget_show(dialog->addressbooks_menu); + + /* Search field */ + dialog->search_field = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), dialog->search_field, TRUE, TRUE, 0); + gtk_widget_show(dialog->search_field); + + g_signal_connect(G_OBJECT(dialog->search_field), "changed", + G_CALLBACK(search_changed_cb), dialog); + + /* Clear button */ + button = gtk_button_new_from_stock(GTK_STOCK_CLEAR); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(clear_cb), dialog); + + /* Scrolled Window */ + sw = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gtk_widget_show(sw); + + /* Create the list model for the treeview. */ + dialog->model = gtk_list_store_new(NUM_COLUMNS, + G_TYPE_STRING, G_TYPE_POINTER); + + /* Now for the treeview */ + dialog->treeview = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); + gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); + gtk_widget_show(dialog->treeview); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(selected_cb), dialog); + + add_columns(dialog); + + populate_treeview(dialog); + + /* Add the disclosure */ + disclosure = gaim_disclosure_new(_("Show user details"), + _("Hide user details")); + gtk_box_pack_start(GTK_BOX(vbox), disclosure, FALSE, FALSE, 0); + gtk_widget_show(disclosure); + + /* + * User details + */ + + /* Scrolled Window */ + sw = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, + GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gaim_disclosure_set_container(GAIM_DISCLOSURE(disclosure), sw); + + /* Textview */ + dialog->imhtml = gtk_imhtml_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(sw), dialog->imhtml); + gtk_widget_show(dialog->imhtml); + + /* Separator. */ + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + gtk_widget_show(sep); + + /* Button box */ + bbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(GTK_BOX(bbox), 6); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); + gtk_widget_show(bbox); + + /* "New Person" button */ + button = gaim_pixbuf_button_from_stock(_("New Person"), GTK_STOCK_NEW, + GAIM_BUTTON_HORIZONTAL); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(new_person_cb), dialog); + + /* "Cancel" button */ + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(cancel_cb), dialog); + + /* "Associate Buddy" button */ + button = gaim_pixbuf_button_from_stock(_("_Associate Buddy"), + GTK_STOCK_APPLY, + GAIM_BUTTON_HORIZONTAL); + dialog->assoc_button = button; + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive(button, FALSE); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(assoc_buddy_cb), dialog); + + /* Show it. */ + gtk_widget_show(dialog->win); + + return dialog; +} diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/gevo-util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/gevo-util.c Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,158 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include "gtkinternal.h" +#include "gtkblist.h" +#include "gtkutils.h" + +#include + +void +gevo_add_buddy(GaimAccount *account, const char *group_name, + const char *screenname, const char *alias) +{ + GaimConversation *conv = NULL; + GaimBuddy *buddy; + GaimGroup *group; + + conv = gaim_find_conversation_with_account(screenname, account); + + if ((group = gaim_find_group(group_name)) == NULL) + { + group = gaim_group_new(group_name); + gaim_blist_add_group(group, NULL); + } + + buddy = gaim_buddy_new(account, screenname, alias); + gaim_blist_add_buddy(buddy, NULL, group, NULL); + serv_add_buddy(gaim_account_get_connection(account), screenname, group); + + if (conv != NULL) + { + gaim_buddy_icon_update(gaim_conv_im_get_icon(GAIM_CONV_IM(conv))); + gaim_conversation_update(conv, GAIM_CONV_UPDATE_ADD); + + gaim_blist_save(); + } +} + +GList * +gevo_get_groups(void) +{ + GList *tmp = NULL; + char *tmp2; + GaimGroup *g; + GaimBlistNode *gnode; + + if (gaim_get_blist()->root == NULL) + { + tmp2 = g_strdup(_("Buddies")); + tmp = g_list_append(tmp, tmp2); + } + else + { + for (gnode = gaim_get_blist()->root; + gnode != NULL; + gnode = gnode->next) + { + if (GAIM_BLIST_NODE_IS_GROUP(gnode)) + { + g = (GaimGroup *)gnode; + tmp2 = g->name; + tmp = g_list_append(tmp, tmp2); + } + } + } + + return tmp; +} + +EContactField +gevo_prpl_get_field(GaimAccount *account, GaimBuddy *buddy) +{ + EContactField protocol_field = 0; + const char *protocol_id; + + g_return_val_if_fail(account != NULL, 0); + + protocol_id = gaim_account_get_protocol_id(account); + + if (!strcmp(protocol_id, "prpl-oscar")) + { + GaimConnection *gc; + GaimPluginProtocolInfo *prpl_info; + + gc = gaim_account_get_connection(account); + + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); + + if (!strcmp("aim", prpl_info->list_icon(account, buddy))) + { + protocol_field = E_CONTACT_IM_AIM; + } + else + protocol_field = E_CONTACT_IM_ICQ; + } + else if (!strcmp(protocol_id, "prpl-msn")) + protocol_field = E_CONTACT_IM_MSN; + else if (!strcmp(protocol_id, "prpl-yahoo")) + protocol_field = E_CONTACT_IM_YAHOO; + else if (!strcmp(protocol_id, "prpl-jabber")) + protocol_field = E_CONTACT_IM_JABBER; + + return protocol_field; +} + +gboolean +gevo_prpl_is_supported(GaimAccount *account, GaimBuddy *buddy) +{ + return (gevo_prpl_get_field(account, buddy) != 0); +} + +gboolean +gevo_load_addressbook(EBook **book, GError **error) +{ + char *filename; + char *uri; + gboolean result; + + g_return_val_if_fail(book != NULL, FALSE); + + *book = e_book_new(); + + filename = g_build_filename(g_get_home_dir(), + ".evolution/addressbook/local/OnThisComputer/Personal", NULL); + + uri = g_strdup_printf("file://%s", filename); + + g_free(filename); + + result = e_book_load_uri(*book, uri, FALSE, error); + + g_free(uri); + + if (!result) + { + g_object_unref(*book); + *book = NULL; + } + + return result; +} diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/gevolution.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/gevolution.c Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,497 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include "internal.h" +#include "gtkinternal.h" +#include "gtkblist.h" + +#include "connection.h" +#include "debug.h" +#include "prefs.h" +#include "signals.h" + +#include "gtkconv.h" +#include "gtkplugin.h" +#include "gtkutils.h" + +#include "gevolution.h" + +#include + +#include +#include +#include +#include + +#define GEVOLUTION_PLUGIN_ID "gtk-x11-gevolution" + +#define E_DATA_BOOK_FACTORY_OAF_ID \ + "OAFIID:GNOME_Evolution_DataServer_BookFactory" + +enum +{ + COLUMN_AUTOADD, + COLUMN_ICON, + COLUMN_SCREENNAME, + COLUMN_DATA, + NUM_COLUMNS +}; + +static GaimBlistUiOps *backup_blist_ui_ops = NULL; +static GaimBlistUiOps *blist_ui_ops = NULL; +static EBook *book = NULL; +static gulong timer = 0; +static gulong book_view_tag = 0; +static EBookView *book_view = NULL; + +static void +update_ims_from_contact(EContact *contact, const char *name, + const char *prpl_id, EContactField field) +{ + GList *ims = e_contact_get(contact, field); + GList *l, *l2; + + if (ims == NULL) + return; + + for (l = gaim_connections_get_all(); l != NULL; l = l->next) + { + GaimConnection *gc = (GaimConnection *)l->data; + GaimAccount *account = gaim_connection_get_account(gc); + + if (strcmp(gaim_account_get_protocol_id(account), prpl_id)) + continue; + + if (!gaim_account_get_bool(account, "gevo-autoadd", FALSE)) + continue; + + for (l2 = ims; l2 != NULL; l2 = l2->next) + { + if (gaim_find_buddy(account, l2->data) != NULL) + continue; + + gevo_add_buddy(account, _("Buddies"), l2->data, name); + } + } + + g_list_foreach(ims, (GFunc)g_free, NULL); + g_list_free(ims); +} + +static void +update_buddies_from_contact(EContact *contact) +{ + const char *name; + + name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); + + update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_AIM); + update_ims_from_contact(contact, name, "prpl-jabber", E_CONTACT_IM_JABBER); + update_ims_from_contact(contact, name, "prpl-yahoo", E_CONTACT_IM_YAHOO); + update_ims_from_contact(contact, name, "prpl-msn", E_CONTACT_IM_MSN); + update_ims_from_contact(contact, name, "prpl-oscar", E_CONTACT_IM_ICQ); +} + +static void +contacts_changed_cb(EBookView *book_view, const GList *contacts) +{ + const GList *l; + + if (gaim_connections_get_all() == NULL) + return; + + for (l = contacts; l != NULL; l = l->next) + { + EContact *contact = (EContact *)l->data; + + update_buddies_from_contact(contact); + } +} + +static void +request_add_buddy(GaimAccount *account, const char *username, + const char *group, const char *alias) +{ + if (book == NULL) + { + backup_blist_ui_ops->request_add_buddy(account, username, group, + alias); + } + else + { + gevo_add_buddy_dialog_show(account, username, group, alias); + } +} + +static void +got_book_view_cb(EBook *book, EBookStatus status, EBookView *view, + gpointer user_data) +{ + book_view_tag = 0; + + if (status != E_BOOK_ERROR_OK) + { + gaim_debug_error("evolution", "Unable to retrieve book view! :(\n"); + + return; + } + + book_view = view; + + g_object_ref(book_view); + + g_signal_connect(G_OBJECT(book_view), "contacts_changed", + G_CALLBACK(contacts_changed_cb), book); + + g_signal_connect(G_OBJECT(book_view), "contacts_added", + G_CALLBACK(contacts_changed_cb), book); + + e_book_view_start(view); +} + +static void +signed_on_cb(GaimConnection *gc) +{ + EBookQuery *query; + gboolean status; + GList *contacts; + GList *l; + + if (book == NULL) + return; + + query = e_book_query_any_field_contains(""); + + status = e_book_get_contacts(book, query, &contacts, NULL); + + e_book_query_unref(query); + + if (!status) + return; + + for (l = contacts; l != NULL; l = l->next) + { + EContact *contact = E_CONTACT(l->data); + + update_buddies_from_contact(contact); + + g_object_unref(contact); + } + + g_list_free(contacts); +} + +static void +menu_item_activate_cb(GtkWidget *item, GaimBuddy *buddy) +{ + gevo_associate_buddy_dialog_new(buddy); +} + +static void +drawing_menu_cb(GtkWidget *menu, GaimBuddy *buddy) +{ + GtkWidget *item; + + if (gevo_prpl_is_supported(buddy->account, buddy)) + { + item = gtk_menu_item_new_with_label(_("Add to Address Book")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + g_signal_connect(G_OBJECT(item), "activate", + G_CALLBACK(menu_item_activate_cb), buddy); + } +} + +static gboolean +load_timeout(gpointer data) +{ + GaimPlugin *plugin = (GaimPlugin *)data; + + timer = 0; + + if (!gevo_load_addressbook(&book, NULL)) + return FALSE; + + book_view_tag = e_book_async_get_book_view(book, + "(contains \"x-evolution-any-field\" \"\")", + got_book_view_cb, NULL); + + gaim_signal_connect(GAIM_GTK_BLIST(gaim_get_blist()), "drawing-menu", + plugin, GAIM_CALLBACK(drawing_menu_cb), NULL); + + return FALSE; +} + +static gboolean +plugin_load(GaimPlugin *plugin) +{ + if (!bonobo_init_full(NULL, NULL, bonobo_activation_orb_get(), + CORBA_OBJECT_NIL, CORBA_OBJECT_NIL)) + { + gaim_debug_error("evolution", "Unable to initialize bonobo.\n"); + return FALSE; + } + + bonobo_activate(); + + backup_blist_ui_ops = gaim_blist_get_ui_ops(); + + blist_ui_ops = g_memdup(backup_blist_ui_ops, sizeof(GaimBlistUiOps)); + blist_ui_ops->request_add_buddy = request_add_buddy; + + gaim_blist_set_ui_ops(blist_ui_ops); + + gaim_signal_connect(gaim_connections_get_handle(), "signed-on", + plugin, GAIM_CALLBACK(signed_on_cb), NULL); + + timer = g_timeout_add(1, load_timeout, plugin); + + return TRUE; +} + +static gboolean +plugin_unload(GaimPlugin *plugin) +{ + gaim_blist_set_ui_ops(backup_blist_ui_ops); + + g_free(blist_ui_ops); + + backup_blist_ui_ops = NULL; + blist_ui_ops = NULL; + + if (book_view != NULL) + { + e_book_view_stop(book_view); + g_object_unref(book_view); + book_view = NULL; + } + + if (book != NULL) + { + g_object_unref(book); + book = NULL; + } + + bonobo_debug_shutdown(); + + return TRUE; +} + +static void +plugin_destroy(GaimPlugin *plugin) +{ +} + +static void +autoadd_toggled_cb(GtkCellRendererToggle *renderer, gchar *path_str, + gpointer data) +{ + GaimAccount *account; + GtkTreeModel *model = (GtkTreeModel *)data; + GtkTreeIter iter; + gboolean autoadd; + + gtk_tree_model_get_iter_from_string(model, &iter, path_str); + gtk_tree_model_get(model, &iter, + COLUMN_DATA, &account, + COLUMN_AUTOADD, &autoadd, + -1); + + gaim_account_set_bool(account, "gevo-autoadd", !autoadd); + + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + COLUMN_AUTOADD, !autoadd, + -1); +} + +static GtkWidget * +get_config_frame(GaimPlugin *plugin) +{ + GtkWidget *ret; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *sw; + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GdkPixbuf *pixbuf, *scale = NULL; + GtkListStore *model; + GList *l; + + /* Outside container */ + ret = gtk_vbox_new(FALSE, 18); + gtk_container_set_border_width(GTK_CONTAINER(ret), 12); + + /* Configuration frame */ + vbox = gaim_gtk_make_frame(ret, _("Evolution Integration Configuration")); + + /* Label */ + label = gtk_label_new(_("Select all accounts that buddies should be " + "auto-added to.")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + /* Scrolled window */ + sw = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gtk_widget_set_size_request(sw, 300, 300); + gtk_widget_show(sw); + + /* Create the list model for the treeview. */ + model = gtk_list_store_new(NUM_COLUMNS, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_STRING, G_TYPE_POINTER); + + /* Setup the treeview */ + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); + gtk_container_add(GTK_CONTAINER(sw), treeview); + gtk_widget_show(treeview); + + /* Setup the column */ + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Account")); + gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1); + + /* Checkbox */ + renderer = gtk_cell_renderer_toggle_new(); + + g_signal_connect(G_OBJECT(renderer), "toggled", + G_CALLBACK(autoadd_toggled_cb), model); + + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_add_attribute(column, renderer, + "active", COLUMN_AUTOADD); + + /* Icon */ + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_add_attribute(column, renderer, + "pixbuf", COLUMN_ICON); + + /* Screenname */ + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, + "text", COLUMN_SCREENNAME); + + + /* Populate */ + for (l = gaim_accounts_get_all(); l != NULL; l = l->next) + { + GaimAccount *account = (GaimAccount *)l->data; + GtkTreeIter iter; + + gaim_debug_info("evolution", "Adding account\n"); + + gtk_list_store_append(model, &iter); + + pixbuf = create_prpl_icon(account); + + if (pixbuf != NULL) + { + scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, + GDK_INTERP_BILINEAR); + + if (!gaim_account_is_connected(account)) + gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); + } + + gtk_list_store_set(model, &iter, + COLUMN_AUTOADD, + gaim_account_get_bool(account, "gevo-autoadd", + FALSE), + COLUMN_ICON, scale, + COLUMN_SCREENNAME, + gaim_account_get_username(account), + COLUMN_DATA, account, + -1); + + if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); + if (scale != NULL) g_object_unref(G_OBJECT(scale)); + } + + gtk_widget_show_all(ret); + + return ret; +} + +static GaimGtkPluginUiInfo ui_info = +{ + get_config_frame +}; + +static GaimPluginInfo info = +{ + 2, /**< api_version */ + GAIM_PLUGIN_STANDARD, /**< type */ + GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + GAIM_PRIORITY_DEFAULT, /**< priority */ + + GEVOLUTION_PLUGIN_ID, /**< id */ + N_("Evolution Integration"), /**< name */ + VERSION, /**< version */ + /** summary */ + N_("Provides integration with Ximian Evolution."), + /** description */ + N_("Provides integration with Ximian Evolution."), + "Christian Hammond ", /**< author */ + GAIM_WEBSITE, /**< homepage */ + + plugin_load, /**< load */ + plugin_unload, /**< unload */ + plugin_destroy, /**< destroy */ + + &ui_info, /**< ui_info */ + NULL /**< extra_info */ +}; + +static void +init_plugin(GaimPlugin *plugin) +{ + /* TODO: Change to core-remote when possible. */ + /* info.dependencies = g_list_append(info.dependencies, "gtk-remote"); */ + + /* + * I'm going to rant a little bit here... + * + * For some reason, when we init bonobo from inside a plugin, it will + * segfault when destroyed. The backtraces are within gmodule somewhere. + * There's not much I can do, and I'm not sure where the bug lies. + * However, plugins are only destroyed when Gaim is shutting down. After + * destroying the plugins, gaim ends, and anything else is of course + * freed. That includes this, if we make the module resident, which + * prevents us from being able to actually unload it. + * + * So, in conclusion, this is an evil hack, but it doesn't harm anything + * and it works. + */ + g_module_make_resident(plugin->handle); +} + +GAIM_INIT_PLUGIN(gevolution, init_plugin, info) diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/gevolution.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/gevolution.h Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,107 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef _GEVOLUTION_H_ +#define _GEVOLUTION_H_ + +#include + +typedef struct +{ + GaimAccount *account; + char *username; + + EBook *book; + + GtkWidget *win; + GtkWidget *treeview; + GtkWidget *addressbooks_menu; + GtkWidget *search_field; + GtkWidget *group_combo; + GtkWidget *select_button; + GtkWidget *account_optmenu; + GtkListStore *model; + + GList *contacts; + +} GevoAddBuddyDialog; + +typedef struct +{ + gboolean person_only; + + GaimAccount *account; + GaimBuddy *buddy; + + EContact *contact; + + GtkWidget *win; + GtkWidget *accounts_menu; + GtkWidget *screenname; + GtkWidget *firstname; + GtkWidget *lastname; + GtkWidget *email; + GtkWidget *group_combo; + GtkWidget *add_button; + + char *buddy_icon; + +} GevoNewPersonDialog; + +typedef struct +{ + GaimBuddy *buddy; + + EBook *book; + + GtkWidget *win; + GtkWidget *treeview; + GtkWidget *addressbooks_menu; + GtkWidget *search_field; + GtkWidget *assoc_button; + GtkWidget *imhtml; + GtkListStore *model; + + GList *contacts; + +} GevoAssociateBuddyDialog; + +void gevo_add_buddy_dialog_show(GaimAccount *account, const char *username, + const char *group, const char *alias); +void gevo_add_buddy_dialog_add_person(GevoAddBuddyDialog *dialog, + EContact *contact, + const char *name, GaimAccount *account, + const char *screenname); + +void gevo_new_person_dialog_show(EContact *contact, GaimAccount *account, + const char *username, const char *group, + GaimBuddy *buddy, gboolean person_only); + +void gevo_add_buddy(GaimAccount *account, const char *group_name, + const char *screenname, const char *alias); +GList *gevo_get_groups(void); + +EContactField gevo_prpl_get_field(GaimAccount *account, GaimBuddy *buddy); +gboolean gevo_prpl_is_supported(GaimAccount *account, GaimBuddy *buddy); +gboolean gevo_load_addressbook(EBook **book, GError **error); + +GevoAssociateBuddyDialog *gevo_associate_buddy_dialog_new(GaimBuddy *buddy); + +#endif /* _GEVOLUTION_H_ */ diff -r a86784e3b98c -r 35db601609e3 plugins/gevolution/new_person_dialog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/gevolution/new_person_dialog.c Tue Jan 13 01:45:32 2004 +0000 @@ -0,0 +1,427 @@ +/* + * Evolution integration plugin for Gaim + * + * Copyright (C) 2003 Christian Hammond. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include "gtkinternal.h" +#include "gtkutils.h" + +#include "debug.h" + +#include "gevolution.h" + +#include +#include + +static GtkWidget * +add_pref_box(GtkSizeGroup *sg, GtkWidget *parent, const char *text, + GtkWidget *widget) +{ + GtkWidget *hbox; + GtkWidget *label; + + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); + gtk_widget_show(hbox); + + label = gtk_label_new_with_mnemonic(text); + gtk_size_group_add_widget(sg, label); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_widget_show(widget); + + return hbox; +} + +static gint +delete_win_cb(GtkWidget *w, GdkEvent *event, GevoNewPersonDialog *dialog) +{ + gtk_widget_destroy(dialog->win); + + g_free(dialog); + + return 0; +} + +static void +cancel_cb(GtkWidget *w, GevoNewPersonDialog *dialog) +{ + delete_win_cb(NULL, NULL, dialog); +} + +static void +screenname_changed_cb(GtkEntry *entry, GevoNewPersonDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->add_button, + *gtk_entry_get_text(entry) != '\0'); +} + +static void +person_info_changed_cb(GtkEntry *entry, GevoNewPersonDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->add_button, + (*gtk_entry_get_text(GTK_ENTRY(dialog->firstname)) != '\0' || + *gtk_entry_get_text(GTK_ENTRY(dialog->lastname)) != '\0')); +} + +static void +add_cb(GtkWidget *w, GevoNewPersonDialog *dialog) +{ + EContact *contact = NULL; + EBook *book; + const char *screenname; + const char *firstname; + const char *lastname; + const char *email; + const char *im_service; + gboolean new_contact = FALSE; + EContactField field = 0; + EContactName *name = NULL; + char *full_name = NULL; + + if (dialog->person_only) + screenname = dialog->buddy->name; + else + screenname = gtk_entry_get_text(GTK_ENTRY(dialog->screenname)); + + firstname = gtk_entry_get_text(GTK_ENTRY(dialog->firstname)); + lastname = gtk_entry_get_text(GTK_ENTRY(dialog->lastname)); + email = gtk_entry_get_text(GTK_ENTRY(dialog->email)); + + if (*firstname || *lastname) + { + if (!gevo_load_addressbook(&book, NULL)) + { + gaim_debug_error("evolution", + "Error retrieving default addressbook\n"); + + return; + } + + if (dialog->contact == NULL) + { + char *file_as; + + dialog->contact = e_contact_new(); + + if (lastname != NULL && firstname != NULL) + file_as = g_strdup_printf("%s, %s", lastname, firstname); + else if (lastname != NULL) + file_as = g_strdup(lastname); + else + file_as = g_strdup(firstname); + + e_contact_set(contact, E_CONTACT_FILE_AS, file_as); + + g_free(file_as); + + new_contact = TRUE; + } + + contact = dialog->contact; + + name = e_contact_name_new(); + + name->given = g_strdup(firstname); + name->family = g_strdup(lastname); + + full_name = e_contact_name_to_string(name); + e_contact_set(contact, E_CONTACT_FULL_NAME, full_name); + + im_service = gaim_account_get_protocol_id(dialog->account); + + if (*email) + e_contact_set(contact, E_CONTACT_EMAIL_1, (gpointer)email); + + if (!strcmp(im_service, "prpl-oscar")) + { + if (isdigit(*screenname)) + field = E_CONTACT_IM_ICQ; + else + field = E_CONTACT_IM_AIM; + } + else if (!strcmp(im_service, "prpl-yahoo")) + field = E_CONTACT_IM_YAHOO; + else if (!strcmp(im_service, "prpl-jabber")) + field = E_CONTACT_IM_JABBER; + else if (!strcmp(im_service, "prpl-msn")) + field = E_CONTACT_IM_MSN; + + if (field > 0) + { + GList *list = g_list_append(NULL, g_strdup(screenname)); + + e_contact_set(contact, field, list); + + g_free(list->data); + g_list_free(list); + } + + if (new_contact) + { + if (!e_book_add_contact(book, contact, NULL)) + { + gaim_debug_error("evolution", "Error adding contact to book\n"); + + g_object_unref(contact); + delete_win_cb(NULL, NULL, dialog); + return; + } + } + else + { + if (!e_book_commit_contact(book, contact, NULL)) + { + gaim_debug_error("evolution", "Error adding contact to book\n"); + + g_object_unref(contact); + delete_win_cb(NULL, NULL, dialog); + return; + } + } + + g_object_unref(contact); + } + + if (!dialog->person_only) + { + GtkWidget *entry = GTK_COMBO(dialog->group_combo)->entry; + const char *group_name; + + group_name = gtk_entry_get_text(GTK_ENTRY(entry)); + + gevo_add_buddy(dialog->account, group_name, screenname, full_name); + } + + if (name != NULL) + e_contact_name_free(name); + + if (full_name != NULL) + g_free(full_name); + + delete_win_cb(NULL, NULL, dialog); +} + +static void +select_account_cb(GObject *w, GaimAccount *account, + GevoNewPersonDialog *dialog) +{ + dialog->account = account; +} + +void +gevo_new_person_dialog_show(EContact *contact, GaimAccount *account, + const char *username, const char *group, + GaimBuddy *buddy, gboolean person_only) +{ + GevoNewPersonDialog *dialog; + GtkWidget *vbox, *vbox2; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *label; + GtkWidget *button; + GtkWidget *sep; + GtkSizeGroup *sg, *sg2; + const char *str; + + g_return_if_fail(!person_only || (person_only && buddy)); + + dialog = g_new0(GevoNewPersonDialog, 1); + + dialog->account = account; + dialog->person_only = person_only; + dialog->buddy = buddy; + + dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_role(GTK_WINDOW(dialog->win), "new_person"); + gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE); + gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12); + + g_signal_connect(G_OBJECT(dialog->win), "delete_event", + G_CALLBACK(delete_win_cb), dialog); + + /* Setup the vbox */ + vbox = gtk_vbox_new(FALSE, 12); + gtk_container_add(GTK_CONTAINER(dialog->win), vbox); + gtk_widget_show(vbox); + + /* Label */ + if (person_only) + { + label = gtk_label_new( + _("Please enter the person's information below.")); + } + else + { + label = gtk_label_new(_("Please enter the buddy's screen name and " + "account type below.")); + } + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0); + gtk_widget_show(label); + + /* Setup the size groups */ + sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + sg2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + + if (!person_only) + { + /* Add the account type stuff. */ + dialog->accounts_menu = + gaim_gtk_account_option_menu_new(account, FALSE, + G_CALLBACK(select_account_cb), + NULL, dialog); + add_pref_box(sg, vbox, _("Account type:"), dialog->accounts_menu); + + /* Screen Name */ + dialog->screenname = gtk_entry_new(); + add_pref_box(sg, vbox, _("Screenname:"), dialog->screenname); + + if (username != NULL) + gtk_entry_set_text(GTK_ENTRY(dialog->screenname), username); + + g_signal_connect(G_OBJECT(dialog->screenname), "changed", + G_CALLBACK(screenname_changed_cb), dialog); + + /* Group */ + dialog->group_combo = gtk_combo_new(); + gtk_combo_set_popdown_strings(GTK_COMBO(dialog->group_combo), + gevo_get_groups()); + add_pref_box(sg, vbox, _("Group:"), dialog->group_combo); + + /* Separator */ + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + gtk_widget_show(sep); + + /* Optional Information section */ + label = gtk_label_new(_("Optional information:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + } + + /* Create the parent hbox for this whole thing. */ + hbox = gtk_hbox_new(FALSE, 12); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + +#if 0 + /* Now the left side of the hbox */ + vbox2 = gtk_vbox_new(FALSE, 12); + gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0); + gtk_widget_show(vbox2); + + /* Buddy icon button */ + button = gtk_button_new_from_stock(GTK_STOCK_OPEN); + gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + /* Label */ + label = gtk_label_new(_("Buddy Icon")); + gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0); + gtk_widget_show(label); +#endif + + /* Now the right side. */ + vbox2 = gtk_vbox_new(FALSE, 12); + gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0); + gtk_widget_show(vbox2); + + /* First Name field */ + dialog->firstname = gtk_entry_new(); + add_pref_box(sg2, vbox2, _("First name:"), dialog->firstname); + + if (contact != NULL) + { + str = e_contact_get_const(contact, E_CONTACT_GIVEN_NAME); + + if (str != NULL) + gtk_entry_set_text(GTK_ENTRY(dialog->firstname), str); + } + + /* Last Name field */ + dialog->lastname = gtk_entry_new(); + add_pref_box(sg2, vbox2, _("Last name:"), dialog->lastname); + + if (contact != NULL) + { + str = e_contact_get_const(contact, E_CONTACT_FAMILY_NAME); + + if (str != NULL) + gtk_entry_set_text(GTK_ENTRY(dialog->lastname), str); + } + + if (person_only) + { + g_signal_connect(G_OBJECT(dialog->firstname), "changed", + G_CALLBACK(person_info_changed_cb), dialog); + g_signal_connect(G_OBJECT(dialog->lastname), "changed", + G_CALLBACK(person_info_changed_cb), dialog); + } + + /* E-Mail address field */ + dialog->email = gtk_entry_new(); + add_pref_box(sg2, vbox2, _("E-mail:"), dialog->email); + + if (contact != NULL) + { + str = e_contact_get_const(contact, E_CONTACT_EMAIL_1); + + if (str != NULL) + gtk_entry_set_text(GTK_ENTRY(dialog->email), str); + } + + /* Separator */ + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + gtk_widget_show(sep); + + /* Button box */ + bbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(GTK_BOX(bbox), 6); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); + gtk_widget_show(bbox); + + /* Cancel button */ + button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(cancel_cb), dialog); + + /* Add button */ + button = gtk_button_new_from_stock(GTK_STOCK_ADD); + dialog->add_button = button; + gtk_widget_set_sensitive(button, FALSE); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(add_cb), dialog); + + /* Show it. */ + gtk_widget_show(dialog->win); +} diff -r a86784e3b98c -r 35db601609e3 src/gtkblist.c --- a/src/gtkblist.c Tue Jan 13 01:00:24 2004 +0000 +++ b/src/gtkblist.c Tue Jan 13 01:45:32 2004 +0000 @@ -1072,6 +1072,138 @@ } } +static void +add_buddies_from_vcard(const char *prpl_id, GaimGroup *group, GList *list, + const char *alias) +{ + GList *l; + GaimAccount *account = NULL; + GaimConnection *gc; + + if (list == NULL) + return; + + for (l = gaim_connections_get_all(); l != NULL; l = l->next) + { + gc = (GaimConnection *)l->data; + account = gaim_connection_get_account(gc); + + if (!strcmp(gaim_account_get_protocol_id(account), prpl_id)) + break; + + account = NULL; + } + + if (account != NULL) + { + for (l = list; l != NULL; l = l->next) + { + gaim_blist_request_add_buddy(account, l->data, + (group ? group->name : NULL), + alias); + } + } + + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); +} + +static gboolean +parse_vcard(const char *vcard, GaimGroup *group) +{ + char *temp_vcard; + char *s, *c; + char *alias = NULL; + GList *aims = NULL; + GList *icqs = NULL; + GList *yahoos = NULL; + GList *msns = NULL; + GList *jabbers = NULL; + + s = temp_vcard = g_strdup(vcard); + + while (*s != '\0' && strncmp(s, "END:vCard", strlen("END:vCard"))) + { + char *field, *value; + + field = s; + + /* Grab the field */ + while (*s != '\r' && *s != '\n' && *s != '\0' && *s != ':') + s++; + + if (*s == '\r') s++; + if (*s == '\n') + { + s++; + continue; + } + + if (*s != '\0') *s++ = '\0'; + + if ((c = strchr(field, ';')) != NULL) + *c = '\0'; + + /* Proceed to the end of the line */ + value = s; + + while (*s != '\r' && *s != '\n' && *s != '\0') + s++; + + if (*s == '\r') *s++ = '\0'; + if (*s == '\n') *s++ = '\0'; + + /* We only want to worry about a few fields here. */ + if (!strcmp(field, "FN")) + alias = g_strdup(value); + else if (!strcmp(field, "X-AIM") || !strcmp(field, "X-ICQ") || + !strcmp(field, "X-YAHOO") || !strcmp(field, "X-MSN") || + !strcmp(field, "X-JABBER")) + { + char **values = g_strsplit(value, ":", 0); + char **im; + + for (im = values; *im != NULL; im++) + { + if (!strcmp(field, "X-AIM")) + aims = g_list_append(aims, g_strdup(*im)); + else if (!strcmp(field, "X-ICQ")) + icqs = g_list_append(icqs, g_strdup(*im)); + else if (!strcmp(field, "X-YAHOO")) + yahoos = g_list_append(yahoos, g_strdup(*im)); + else if (!strcmp(field, "X-MSN")) + msns = g_list_append(msns, g_strdup(*im)); + else if (!strcmp(field, "X-JABBER")) + jabbers = g_list_append(jabbers, g_strdup(*im)); + } + + g_strfreev(values); + } + } + + g_free(temp_vcard); + + if (aims == NULL && icqs == NULL && yahoos == NULL && + msns == NULL && jabbers == NULL) + { + if (alias != NULL) + g_free(alias); + + return FALSE; + } + + add_buddies_from_vcard("prpl-oscar", group, aims, alias); + add_buddies_from_vcard("prpl-oscar", group, icqs, alias); + add_buddies_from_vcard("prpl-yahoo", group, yahoos, alias); + add_buddies_from_vcard("prpl-msn", group, msns, alias); + add_buddies_from_vcard("prpl-jabber", group, jabbers, alias); + + if (alias != NULL) + g_free(alias); + + return TRUE; +} + static void gaim_gtk_blist_drag_data_get_cb (GtkWidget *widget, GdkDragContext *dc, GtkSelectionData *data, @@ -1079,7 +1211,8 @@ guint time, gpointer *null) { - if (data->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) { + if (data->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) + { GtkTreeRowReference *ref = g_object_get_data(G_OBJECT(dc), "gtk-tree-view-source-row"); GtkTreePath *sourcerow = gtk_tree_row_reference_get_path(ref); GtkTreeIter iter; @@ -1098,9 +1231,8 @@ gtk_tree_path_free(sourcerow); } - else if (data->target == gdk_atom_intern("application/x-im-contact", - FALSE)) { - + else if (data->target == gdk_atom_intern("application/x-im-contact", FALSE)) + { GtkTreeRowReference *ref; GtkTreePath *sourcerow; GtkTreeIter iter; @@ -1400,6 +1532,45 @@ gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); } + else if (sd->target == gdk_atom_intern("text/x-vcard", FALSE) && sd->data) + { + gboolean result; + GaimGroup *group = NULL; + GtkTreePath *path = NULL; + GtkTreeViewDropPosition position; + + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), + x, y, &path, &position)) + { + GtkTreeIter iter; + GaimBlistNode *node; + GValue val = {0}; + + gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), + &iter, path); + gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), + &iter, NODE_COLUMN, &val); + node = g_value_get_pointer(&val); + + if (GAIM_BLIST_NODE_IS_BUDDY(node)) + { + group = (GaimGroup *)node->parent->parent; + } + else if (GAIM_BLIST_NODE_IS_CHAT(node) || + GAIM_BLIST_NODE_IS_CONTACT(node)) + { + group = (GaimGroup *)node->parent; + } + else if (GAIM_BLIST_NODE_IS_GROUP(node)) + { + group = (GaimGroup *)node; + } + } + + result = parse_vcard(sd->data, group); + + gtk_drag_finish(dc, result, (dc->action == GDK_ACTION_MOVE), t); + } } static void gaim_gtk_blist_paint_tip(GtkWidget *widget, GdkEventExpose *event, GaimBlistNode *node) @@ -2335,7 +2506,7 @@ } } -enum {DRAG_BUDDY, DRAG_ROW}; +enum {DRAG_BUDDY, DRAG_ROW, DRAG_VCARD}; static char * item_factory_translate_func (const char *path, gpointer func_data) @@ -2374,7 +2545,8 @@ GtkAccelGroup *accel_group; GtkTreeSelection *selection; GtkTargetEntry gte[] = {{"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, - {"application/x-im-contact", 0, DRAG_BUDDY}}; + {"application/x-im-contact", 0, DRAG_BUDDY}, + {"text/x-vcard", 0, DRAG_VCARD }}; if (gtkblist && gtkblist->window) { gtk_widget_show(gtkblist->window); @@ -2440,10 +2612,10 @@ /* Set up dnd */ gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(gtkblist->treeview), - GDK_BUTTON1_MASK, gte, 2, + GDK_BUTTON1_MASK, gte, 3, GDK_ACTION_COPY); gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(gtkblist->treeview), - gte, 2, + gte, 3, GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect(G_OBJECT(gtkblist->treeview), "drag-data-received", G_CALLBACK(gaim_gtk_blist_drag_data_rcv_cb), NULL);