# HG changeset patch # User Luke Schierer # Date 1190289693 0 # Node ID e172db483c073f929ab52d2fbec7f280b5e37e78 # Parent 46f4ca8a4a273c980afba56c205ea4672dfe6fab disapproval of revision '87db1277801f9f4bb6cf456b1344a263f51f2864' diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/Makefile.am Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,29 @@ +plugindir = $(libdir)/pidgin + +gevolution_la_LDFLAGS = -module -avoid-version + +if PLUGINS + +plugin_LTLIBRARIES = gevolution.la + +gevolution_la_SOURCES = \ + add_buddy_dialog.c \ + assoc-buddy.c \ + gevolution.c \ + gevolution.h \ + gevo-util.c \ + new_person_dialog.c \ + eds-utils.c + +gevolution_la_LIBADD = $(EVOLUTION_ADDRESSBOOK_LIBS) $(GTK_LIBS) + +endif + +AM_CPPFLAGS = \ + -DDATADIR=\"$(datadir)\" \ + -I$(top_srcdir)/libpurple \ + -I$(top_builddir)/libpurple \ + -I$(top_srcdir)/pidgin \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) \ + $(DEBUG_CFLAGS) \ + $(GTK_CFLAGS) diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/add_buddy_dialog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/add_buddy_dialog.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,631 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#include "internal.h" +#include "gtkblist.h" +#include "pidgin.h" +#include "gtkutils.h" + +#include "debug.h" + +#include "gevolution.h" + +#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); + + if (dialog->contacts != NULL) + { + g_list_foreach(dialog->contacts, (GFunc)g_object_unref, NULL); + g_list_free(dialog->contacts); + } + + if (dialog->book != NULL) + g_object_unref(dialog->book); + + gevo_addrbooks_model_unref(dialog->addrbooks); + + 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 = + pidgin_text_combo_box_entry_get_text(dialog->group_combo); + + gevo_new_person_dialog_show(dialog->book, NULL, dialog->account, dialog->username, + (*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)); + + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, + COLUMN_NAME, &fullname, + COLUMN_USERNAME, &username, + COLUMN_DATA, &contact, + -1); + + group_name = + pidgin_text_combo_box_entry_get_text(dialog->group_combo); + + if (username == NULL || *username == '\0') + { + gevo_new_person_dialog_show(dialog->book, NULL, dialog->account, dialog->username, + (*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 +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) +{ + PurpleAccount *account = NULL; + GList *l; + GtkTreeIter iter; + GdkPixbuf *pixbuf; + + if (list == NULL) + return; + + for (l = purple_connections_get_all(); l != NULL; l = l->next) + { + PurpleConnection *gc = (PurpleConnection *)l->data; + + account = purple_connection_get_account(gc); + + if (!strcmp(purple_account_get_protocol_id(account), id)) + break; + + account = NULL; + } + + if (account == NULL) + return; + + pixbuf = pidgin_create_prpl_icon(account, 0.5); + + for (l = list; l != NULL; l = l->next) + { + char *account_name = (char *)l->data; + + if (account_name == NULL) + continue; + + if (purple_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, pixbuf, + COLUMN_USERNAME, account_name, + COLUMN_DATA, contact, + -1); + + if (!strcmp(purple_account_get_protocol_id(account), + purple_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)); + + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); +} + +static void +populate_treeview(GevoAddBuddyDialog *dialog, const gchar *uri) +{ + EBookQuery *query; + EBook *book; + gboolean status; + GList *cards, *c; + + if (dialog->book != NULL) + { + g_object_unref(dialog->book); + dialog->book = NULL; + } + + if (dialog->contacts != NULL) + { + g_list_foreach(dialog->contacts, (GFunc)g_object_unref, NULL); + g_list_free(dialog->contacts); + dialog->contacts = NULL; + } + + gtk_list_store_clear(dialog->model); + + if (!gevo_load_addressbook(uri, &book, NULL)) + { + purple_debug_error("evolution", + "Error retrieving default addressbook\n"); + + return; + } + + query = e_book_query_field_exists(E_CONTACT_FULL_NAME); + + if (query == NULL) + { + purple_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) + { + purple_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, *novells; + + 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); + novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE); + + if (aims == NULL && jabbers == NULL && yahoos == NULL && + msns == NULL && icqs == NULL && novells == 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"); + add_ims(dialog, contact, name, novells, "prpl-novell"); + } + } + + dialog->contacts = cards; + dialog->book = book; +} + +static void +addrbook_change_cb(GtkComboBox *combo, GevoAddBuddyDialog *dialog) +{ + GtkTreeIter iter; + const char *esource_uri; + + if (!gtk_combo_box_get_active_iter(combo, &iter)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->addrbooks), &iter, + ADDRBOOK_COLUMN_URI, &esource_uri, + -1); + + populate_treeview(dialog, esource_uri); +} + +static void +selected_cb(GtkTreeSelection *sel, GevoAddBuddyDialog *dialog) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + gtk_widget_set_sensitive(dialog->select_button, + gtk_tree_selection_get_selected(selection, NULL, NULL)); +} + +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, *novells; + + 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); + novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE); + + if (aims == NULL && jabbers == NULL && yahoos == NULL && + msns == NULL && icqs == NULL && novells == 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"); + add_ims(dialog, contact, name, novells, "prpl-novell"); + } + } +} + +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(PurpleAccount *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 *sep; + GtkTreeSelection *selection; + GtkCellRenderer *cell; + + dialog = g_new0(GevoAddBuddyDialog, 1); + + dialog->account = + (account != NULL + ? account + : purple_connection_get_account(purple_connections_get_all()->data)); + + if (username != NULL) + dialog->username = g_strdup(username); + + dialog->win = pidgin_create_window(_("Add Buddy"), PIDGIN_HIG_BORDER, "add_buddy", TRUE); + 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->addrbooks = gevo_addrbooks_model_new(); + + dialog->addrbooks_combo = gtk_combo_box_new_with_model( + dialog->addrbooks); + cell = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dialog->addrbooks_combo), + cell, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dialog->addrbooks_combo), + cell, + "text", ADDRBOOK_COLUMN_NAME, + NULL); + gtk_box_pack_start(GTK_BOX(hbox), dialog->addrbooks_combo, FALSE, + FALSE, 0); + gtk_widget_show(dialog->addrbooks_combo); + + /* 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); + + /* + * Catch addressbook selection and populate treeview with the first + * addressbook + */ + gevo_addrbooks_model_populate(dialog->addrbooks); + g_signal_connect(G_OBJECT(dialog->addrbooks_combo), "changed", + G_CALLBACK(addrbook_change_cb), dialog); + gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->addrbooks_combo), 0); + + /* 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 = + pidgin_text_combo_box_entry_new(NULL, 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 = pidgin_pixbuf_button_from_stock(_("New Person"), GTK_STOCK_NEW, + PIDGIN_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 = pidgin_pixbuf_button_from_stock(_("Select Buddy"), GTK_STOCK_APPLY, + PIDGIN_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, + PurpleAccount *account, const char *screenname) +{ + GdkPixbuf *pixbuf; + GtkTreeIter iter; + + pixbuf = pidgin_create_prpl_icon(account, 0.5); + + gtk_list_store_append(dialog->model, &iter); + + gtk_list_store_set(dialog->model, &iter, + COLUMN_NAME, name, + COLUMN_PRPL_ICON, pixbuf, + 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)); +} diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/assoc-buddy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/assoc-buddy.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,499 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#include "internal.h" +#include "gtkblist.h" +#include "gtkexpander.h" +#include "pidgin.h" +#include "gtkutils.h" +#include "gtkimhtml.h" + +#include "debug.h" + +#include "gevolution.h" + +#include +#include + +enum +{ + COLUMN_NAME, + COLUMN_DATA, + NUM_COLUMNS +}; + +static gint +delete_win_cb(GtkWidget *w, GdkEvent *event, GevoAssociateBuddyDialog *dialog) +{ + gtk_widget_destroy(dialog->win); + + if (dialog->contacts != NULL) + { + g_list_foreach(dialog->contacts, (GFunc)g_object_unref, NULL); + g_list_free(dialog->contacts); + } + + g_object_unref(dialog->book); + gevo_addrbooks_model_unref(dialog->addrbooks); + + g_free(dialog); + + return 0; +} + +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) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + gtk_widget_set_sensitive(dialog->assoc_button, + gtk_tree_selection_get_selected(selection, NULL, NULL)); +} + +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, const gchar *uri) +{ + EBook *book; + EBookQuery *query; + const char *prpl_id; + gboolean status; + GList *cards, *c; + + if (dialog->book != NULL) + { + g_object_unref(dialog->book); + dialog->book = NULL; + } + + if (dialog->contacts != NULL) + { + g_list_foreach(dialog->contacts, (GFunc) g_object_unref, NULL); + g_list_free(dialog->contacts); + dialog->contacts = NULL; + } + + gtk_list_store_clear(dialog->model); + + if (!gevo_load_addressbook(uri, &book, NULL)) + { + purple_debug_error("evolution", + "Error retrieving addressbook\n"); + + return; + } + + query = e_book_query_field_exists(E_CONTACT_FULL_NAME); + + if (query == NULL) + { + purple_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) + { + purple_debug_error("evolution", "Error %d in getting card list\n", + status); + + g_object_unref(book); + + return; + } + + prpl_id = purple_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 +addrbook_change_cb(GtkComboBox *combo, GevoAssociateBuddyDialog *dialog) +{ + GtkTreeIter iter; + const char *esource_uri; + + if (!gtk_combo_box_get_active_iter(combo, &iter)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->addrbooks), &iter, + ADDRBOOK_COLUMN_URI, &esource_uri, + -1); + + populate_treeview(dialog, esource_uri); +} + +static void +new_person_cb(GtkWidget *w, GevoAssociateBuddyDialog *dialog) +{ + gevo_new_person_dialog_show(dialog->book, 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; + const char *fullname; + EContactField protocol_field; + EContact *contact; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + 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); + list = g_list_append(list, g_strdup(dialog->buddy->name)); + + e_contact_set(contact, protocol_field, list); + + if (!e_book_commit_contact(dialog->book, contact, NULL)) + purple_debug_error("evolution", "Error adding contact to book\n"); + + /* Free the list. */ + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); + + delete_win_cb(NULL, NULL, dialog); +} + +GevoAssociateBuddyDialog * +gevo_associate_buddy_dialog_new(PurpleBuddy *buddy) +{ + GevoAssociateBuddyDialog *dialog; + GtkWidget *button; + GtkWidget *sw; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *sep; + GtkWidget *expander; + GtkTreeSelection *selection; + GtkCellRenderer *cell; + + g_return_val_if_fail(buddy != NULL, NULL); + + dialog = g_new0(GevoAssociateBuddyDialog, 1); + + dialog->buddy = buddy; + + dialog->win = pidgin_create_window(NULL, PIDGIN_HIG_BORDER, "assoc_buddy", TRUE); + + 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->addrbooks = gevo_addrbooks_model_new(); + + dialog->addrbooks_combo = gtk_combo_box_new_with_model(dialog->addrbooks); + cell = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dialog->addrbooks_combo), + cell, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dialog->addrbooks_combo), + cell, + "text", ADDRBOOK_COLUMN_NAME, + NULL); + gtk_box_pack_start(GTK_BOX(hbox), dialog->addrbooks_combo, FALSE, FALSE, 0); + gtk_widget_show(dialog->addrbooks_combo); + + + /* 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); + + /* + * Catch addressbook selection and populate treeview with the first + * addressbook + */ + gevo_addrbooks_model_populate( dialog->addrbooks ); + g_signal_connect(G_OBJECT(dialog->addrbooks_combo), "changed", + G_CALLBACK(addrbook_change_cb), dialog); + gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->addrbooks_combo), 0); + + /* Add the expander */ + expander = gtk_expander_new_with_mnemonic(_("User _details")); + gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0); + gtk_widget_show(expander); + + /* + * 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_container_add(GTK_CONTAINER(expander), sw); + gtk_widget_show(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 = pidgin_pixbuf_button_from_stock(_("New Person"), GTK_STOCK_NEW, + PIDGIN_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 = pidgin_pixbuf_button_from_stock(_("_Associate Buddy"), + GTK_STOCK_APPLY, + PIDGIN_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 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/eds-utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/eds-utils.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,244 @@ +/* + * Evolution integration plugin for Purple + * + * Copyright (C) 2004 Henry Jen. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ + +#include "internal.h" +#include "gtkblist.h" +#include "pidgin.h" +#include "gtkutils.h" +#include "gtkimhtml.h" + +#include "debug.h" +#include "gevolution.h" + +GtkTreeModel * +gevo_addrbooks_model_new() +{ + return GTK_TREE_MODEL(gtk_list_store_new(NUM_ADDRBOOK_COLUMNS, + G_TYPE_STRING, G_TYPE_STRING)); +} + +void +gevo_addrbooks_model_unref(GtkTreeModel *model) +{ + GtkTreeIter iter; + + g_return_if_fail(model != NULL); + g_return_if_fail(GTK_IS_LIST_STORE(model)); + + if (!gtk_tree_model_get_iter_first(model, &iter)) + return; + + g_object_unref(model); +} + +void +gevo_addrbooks_model_populate(GtkTreeModel *model) +{ + ESourceList *addressbooks; + GError *err; + GSList *groups, *g; + GtkTreeIter iter; + GtkListStore *list; + + g_return_if_fail(model != NULL); + g_return_if_fail(GTK_IS_LIST_STORE(model)); + + list = GTK_LIST_STORE(model); + + if (!e_book_get_addressbooks(&addressbooks, &err)) + { + purple_debug_error("evolution", + "Unable to fetch list of address books.\n"); + + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, + ADDRBOOK_COLUMN_NAME, _("None"), + ADDRBOOK_COLUMN_URI, NULL, + -1); + + return; + } + + groups = e_source_list_peek_groups(addressbooks); + + if (groups == NULL) + { + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, + ADDRBOOK_COLUMN_NAME, _("None"), + ADDRBOOK_COLUMN_URI, NULL, + -1); + + return; + } + + for (g = groups; g != NULL; g = g->next) + { + GSList *sources, *s; + + sources = e_source_group_peek_sources(g->data); + + for (s = sources; s != NULL; s = s->next) + { + ESource *source = E_SOURCE(s->data); + + g_object_ref(source); + + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, + ADDRBOOK_COLUMN_NAME, e_source_peek_name(source), + ADDRBOOK_COLUMN_URI, e_source_get_uri(source), + -1); + } + } + + g_object_unref(addressbooks); +} + +static EContact * +gevo_run_query_in_uri(const gchar *uri, EBookQuery *query) +{ + EBook *book; + gboolean status; + GList *cards; + + if (!gevo_load_addressbook(uri, &book, NULL)) + { + purple_debug_error("evolution", + "Error retrieving addressbook\n"); + return NULL; + } + + status = e_book_get_contacts(book, query, &cards, NULL); + if (!status) + { + purple_debug_error("evolution", "Error %d in getting card list\n", + status); + g_object_unref(book); + return NULL; + } + g_object_unref(book); + + if (cards != NULL) + { + EContact *contact = E_CONTACT(cards->data); + GList *cards2 = cards->next; + + if (cards2 != NULL) + { + /* Break off the first contact and free the rest. */ + cards->next = NULL; + cards2->prev = NULL; + g_list_foreach(cards2, (GFunc)g_object_unref, NULL); + } + + /* Free the whole list. */ + g_list_free(cards); + + return contact; + } + + return NULL; +} + +/* + * Search for a buddy in the Evolution contacts. + * + * @param buddy The buddy to search for. + * @param query An optional query. This function takes ownership of @a query, + * so callers must e_book_query_ref() it in advance (to obtain a + * second reference) if they want to reuse @a query. + */ +EContact * +gevo_search_buddy_in_contacts(PurpleBuddy *buddy, EBookQuery *query) +{ + ESourceList *addressbooks; + GError *err; + EBookQuery *full_query; + GSList *groups, *g; + EContact *result; + EContactField protocol_field = gevo_prpl_get_field(buddy->account, buddy); + + if (protocol_field == 0) + return NULL; + + if (query != NULL) + { + EBookQuery *queries[2]; + + queries[0] = query; + queries[1] = e_book_query_field_test(protocol_field, E_BOOK_QUERY_IS, buddy->name); + if (queries[1] == NULL) + { + purple_debug_error("evolution", "Error in creating protocol query\n"); + e_book_query_unref(query); + return NULL; + } + + full_query = e_book_query_and(2, queries, TRUE); + } + else + { + full_query = e_book_query_field_test(protocol_field, E_BOOK_QUERY_IS, buddy->name); + if (full_query == NULL) + { + purple_debug_error("evolution", "Error in creating protocol query\n"); + return NULL; + } + } + + if (!e_book_get_addressbooks(&addressbooks, &err)) + { + purple_debug_error("evolution", + "Unable to fetch list of address books.\n"); + e_book_query_unref(full_query); + if (err != NULL) + g_error_free(err); + return NULL; + } + + groups = e_source_list_peek_groups(addressbooks); + if (groups == NULL) + { + g_object_unref(addressbooks); + e_book_query_unref(full_query); + return NULL; + } + + for (g = groups; g != NULL; g = g->next) + { + GSList *sources, *s; + sources = e_source_group_peek_sources(g->data); + for (s = sources; s != NULL; s = s->next) + { + result = gevo_run_query_in_uri(e_source_get_uri(E_SOURCE(s->data)), full_query); + if (result != NULL) { + g_object_unref(addressbooks); + e_book_query_unref(full_query); + return result; + } + } + } + + g_object_unref(addressbooks); + e_book_query_unref(full_query); + return NULL; +} diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/gevo-util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/gevo-util.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,186 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#include "internal.h" +#include "gtkblist.h" +#include "pidgin.h" +#include "gtkutils.h" + +#include "gevolution.h" + +void +gevo_add_buddy(PurpleAccount *account, const char *group_name, + const char *screenname, const char *alias) +{ + PurpleConversation *conv = NULL; + PurpleBuddy *buddy; + PurpleGroup *group; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, screenname, account); + + if ((group = purple_find_group(group_name)) == NULL) + { + group = purple_group_new(group_name); + purple_blist_add_group(group, NULL); + } + + buddy = purple_buddy_new(account, screenname, alias); + purple_blist_add_buddy(buddy, NULL, group, NULL); + purple_account_add_buddy(account, buddy); + + if (conv != NULL) + { + purple_buddy_icon_update(purple_conv_im_get_icon(PURPLE_CONV_IM(conv))); + purple_conversation_update(conv, PURPLE_CONV_UPDATE_ADD); + } +} + +GList * +gevo_get_groups(void) +{ + static GList *list = NULL; + PurpleGroup *g; + PurpleBlistNode *gnode; + + g_list_free(list); + list = NULL; + + if (purple_get_blist()->root == NULL) + { + list = g_list_append(list, (gpointer)_("Buddies")); + } + else + { + for (gnode = purple_get_blist()->root; + gnode != NULL; + gnode = gnode->next) + { + if (PURPLE_BLIST_NODE_IS_GROUP(gnode)) + { + g = (PurpleGroup *)gnode; + list = g_list_append(list, g->name); + } + } + } + + return list; +} + +EContactField +gevo_prpl_get_field(PurpleAccount *account, PurpleBuddy *buddy) +{ + EContactField protocol_field = 0; + const char *protocol_id; + + g_return_val_if_fail(account != NULL, 0); + + protocol_id = purple_account_get_protocol_id(account); + + if (!strcmp(protocol_id, "prpl-oscar")) + { + PurpleConnection *gc; + PurplePluginProtocolInfo *prpl_info; + + gc = purple_account_get_connection(account); + + prpl_info = PURPLE_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; + else if (!strcmp(protocol_id, "prpl-novell")) + protocol_field = E_CONTACT_IM_GROUPWISE; + + return protocol_field; +} + +gboolean +gevo_prpl_is_supported(PurpleAccount *account, PurpleBuddy *buddy) +{ + return (gevo_prpl_get_field(account, buddy) != 0); +} + +gboolean +gevo_load_addressbook(const gchar* uri, EBook **book, GError **error) +{ + gboolean result = FALSE; + + g_return_val_if_fail(book != NULL, FALSE); + + if (uri == NULL) + *book = e_book_new_system_addressbook(NULL); + else + *book = e_book_new_from_uri(uri, error); + + result = e_book_open(*book, FALSE, NULL); + + if (!result && *book != NULL) + { + g_object_unref(*book); + *book = NULL; + } + + return result; +} + +char * +gevo_get_email_for_buddy(PurpleBuddy *buddy) +{ + EContact *contact; + char *mail = NULL; + + contact = gevo_search_buddy_in_contacts(buddy, NULL); + + if (contact != NULL) + { + mail = g_strdup(e_contact_get(contact, E_CONTACT_EMAIL_1)); + g_object_unref(contact); + } + + if (mail == NULL) + { + PurpleAccount *account = purple_buddy_get_account(buddy); + const char *prpl_id = purple_account_get_protocol_id(account); + + if (!strcmp(prpl_id, "prpl-msn")) + { + mail = g_strdup(purple_normalize(account, + purple_buddy_get_name(buddy))); + } + else if (!strcmp(prpl_id, "prpl-yahoo")) + { + mail = g_strdup_printf("%s@yahoo.com", + purple_normalize(account, + purple_buddy_get_name(buddy))); + } + } + + return mail; +} diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/gevolution.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/gevolution.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,581 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#include "internal.h" +#include "pidgin.h" + +#include "connection.h" +#include "debug.h" +#include "prefs.h" +#include "notify.h" +#include "signals.h" +#include "util.h" +#include "version.h" + +#include "gtkblist.h" +#include "gtkconv.h" +#include "gtkplugin.h" +#include "gtkutils.h" + +#include "gevolution.h" + +#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 PurpleBlistUiOps *backup_blist_ui_ops = NULL; +static PurpleBlistUiOps *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 = purple_connections_get_all(); l != NULL; l = l->next) + { + PurpleConnection *gc = (PurpleConnection *)l->data; + PurpleAccount *account = purple_connection_get_account(gc); + char *me; + + if (strcmp(purple_account_get_protocol_id(account), prpl_id)) + continue; + + if (!purple_account_get_bool(account, "gevo-autoadd", FALSE)) + continue; + + me = g_strdup(purple_normalize(account, purple_account_get_username(account))); + for (l2 = ims; l2 != NULL; l2 = l2->next) + { + if (purple_find_buddy(account, l2->data) != NULL || + !strcmp(me, purple_normalize(account, l2->data))) + continue; + + gevo_add_buddy(account, _("Buddies"), l2->data, name); + } + g_free(me); + } + + 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); + update_ims_from_contact(contact, name, "prpl-novell", E_CONTACT_IM_GROUPWISE); +} + +static void +contacts_changed_cb(EBookView *book_view, GList *contacts) +{ + GList *l; + + if (purple_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(PurpleAccount *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) + { + purple_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(PurpleConnection *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(PurpleBlistNode *node, gpointer user_data) +{ + PurpleBuddy *buddy = (PurpleBuddy *)node; + gevo_associate_buddy_dialog_new(buddy); +} + +static void +menu_item_send_mail_activate_cb(PurpleBlistNode *node, gpointer user_data) +{ + PurpleBuddy *buddy = (PurpleBuddy *)node; + char *mail = NULL; + + mail = gevo_get_email_for_buddy(buddy); + + if (mail != NULL) + { + char *app = g_find_program_in_path("evolution"); + if (app != NULL) + { + char *command_line = g_strdup_printf("%s mailto:%s", app, mail); + char *quoted = g_shell_quote(command_line); + g_free(app); + g_free(mail); + + g_spawn_command_line_async(quoted, NULL); + g_free(command_line); + g_free(quoted); + } + else + { + purple_notify_error(NULL, NULL, _("Unable to send e-mail"), + _("The evolution executable was not found in the PATH.")); + } + } + else + { + purple_notify_error(NULL, NULL, _("Unable to send e-mail"), + _("An e-mail address was not found for this buddy.")); + } +} + +static void +blist_node_extended_menu_cb(PurpleBlistNode *node, GList **menu) +{ + PurpleMenuAction *act; + PurpleBuddy *buddy; + PurpleAccount *account; + EContact *contact; + char *mail; + + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) + return; + + buddy = (PurpleBuddy *)node; + account = purple_buddy_get_account(buddy); + + if (!gevo_prpl_is_supported(account, buddy)) + return; + + contact = gevo_search_buddy_in_contacts(buddy, NULL); + + if (contact == NULL) + { + act = purple_menu_action_new(_("Add to Address Book"), + PURPLE_CALLBACK(menu_item_activate_cb), + NULL, NULL); + *menu = g_list_append(*menu, act); + } + else + g_object_unref(contact); + + mail = gevo_get_email_for_buddy(buddy); + + if (mail != NULL) + { + act = purple_menu_action_new(_("Send E-Mail"), + PURPLE_CALLBACK(menu_item_send_mail_activate_cb), NULL, NULL); + *menu = g_list_append(*menu, act); + g_free(mail); + } +} + +/* TODO: Something in here leaks 1 reference to a bonobo object! */ +static gboolean +load_timeout(gpointer data) +{ + PurplePlugin *plugin = (PurplePlugin *)data; + EBookQuery *query; + + timer = 0; + + /* Maybe this is it? */ + if (!gevo_load_addressbook(NULL, &book, NULL)) + return FALSE; + + query = e_book_query_any_field_contains(""); + + /* Is it this? */ + book_view_tag = e_book_async_get_book_view(book, query, NULL, -1, + got_book_view_cb, NULL); + + e_book_query_unref(query); + + purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", + plugin, PURPLE_CALLBACK(blist_node_extended_menu_cb), NULL); + + return FALSE; +} + +static gboolean +plugin_load(PurplePlugin *plugin) +{ + bonobo_activate(); + + backup_blist_ui_ops = purple_blist_get_ui_ops(); + + blist_ui_ops = g_memdup(backup_blist_ui_ops, sizeof(PurpleBlistUiOps)); + blist_ui_ops->request_add_buddy = request_add_buddy; + + purple_blist_set_ui_ops(blist_ui_ops); + + purple_signal_connect(purple_connections_get_handle(), "signed-on", + plugin, PURPLE_CALLBACK(signed_on_cb), NULL); + + timer = g_timeout_add(1, load_timeout, plugin); + + return TRUE; +} + +static gboolean +plugin_unload(PurplePlugin *plugin) +{ + purple_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; + } + + return TRUE; +} + +static void +plugin_destroy(PurplePlugin *plugin) +{ + bonobo_debug_shutdown(); +} + +static void +autoadd_toggled_cb(GtkCellRendererToggle *renderer, gchar *path_str, + gpointer data) +{ + PurpleAccount *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); + + purple_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(PurplePlugin *plugin) +{ + GtkWidget *ret; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *sw; + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GdkPixbuf *pixbuf; + GtkListStore *model; + GList *l; + + /* Outside container */ + ret = gtk_vbox_new(FALSE, 18); + gtk_container_set_border_width(GTK_CONTAINER(ret), 12); + + /* Configuration frame */ + vbox = pidgin_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 = purple_accounts_get_all(); l != NULL; l = l->next) + { + PurpleAccount *account = (PurpleAccount *)l->data; + GtkTreeIter iter; + + purple_debug_info("evolution", "Adding account\n"); + + gtk_list_store_append(model, &iter); + + pixbuf = pidgin_create_prpl_icon(account, 0.5); + if ((pixbuf != NULL) && (!purple_account_is_connected(account))) + gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); + + gtk_list_store_set(model, &iter, + COLUMN_AUTOADD, + purple_account_get_bool(account, "gevo-autoadd", + FALSE), + COLUMN_ICON, pixbuf, + COLUMN_SCREENNAME, + purple_account_get_username(account), + COLUMN_DATA, account, + -1); + + if (pixbuf != NULL) + g_object_unref(G_OBJECT(pixbuf)); + } + + gtk_widget_show_all(ret); + + return ret; +} + +static PidginPluginUiInfo ui_info = +{ + get_config_frame, /**< get_config_frame */ + 0, /**< page_num */ + /* Padding */ + NULL, + NULL, + NULL, + NULL +}; + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, + PURPLE_MINOR_VERSION, + PURPLE_PLUGIN_STANDARD, /**< type */ + PIDGIN_PLUGIN_TYPE, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + PURPLE_PRIORITY_DEFAULT, /**< priority */ + + GEVOLUTION_PLUGIN_ID, /**< id */ + N_("Evolution Integration"), /**< name */ + VERSION, /**< version */ + /** summary */ + N_("Provides integration with Evolution."), + /** description */ + N_("Provides integration with Evolution."), + "Christian Hammond ", /**< author */ + PURPLE_WEBSITE, /**< homepage */ + + plugin_load, /**< load */ + plugin_unload, /**< unload */ + plugin_destroy, /**< destroy */ + + &ui_info, /**< ui_info */ + NULL, /**< extra_info */ + NULL, + NULL, + + /* Padding */ + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(PurplePlugin *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 Purple is shutting down. After + * destroying the plugins, purple 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); + + if (!bonobo_init_full(NULL, NULL, bonobo_activation_orb_get(), + CORBA_OBJECT_NIL, CORBA_OBJECT_NIL)) + { + purple_debug_error("evolution", "Unable to initialize bonobo.\n"); + } +} + +PURPLE_INIT_PLUGIN(gevolution, init_plugin, info) diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/gevolution.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/gevolution.h Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,136 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#ifndef _GEVOLUTION_H_ +#define _GEVOLUTION_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +enum +{ + ADDRBOOK_COLUMN_NAME, + ADDRBOOK_COLUMN_URI, + NUM_ADDRBOOK_COLUMNS +}; + +typedef struct +{ + GtkListStore *sources; + EBook *active_book; + GList *contacts; + +} GevoAddrbooksSelector; + +typedef struct +{ + PurpleAccount *account; + char *username; + + EBook *book; + + GtkWidget *win; + GtkWidget *treeview; + GtkWidget *addrbooks_combo; + GtkWidget *search_field; + GtkWidget *group_combo; + GtkWidget *select_button; + GtkWidget *account_optmenu; + GtkListStore *model; + + GtkTreeModel *addrbooks; + GList *contacts; + +} GevoAddBuddyDialog; + +typedef struct +{ + gboolean person_only; + + PurpleAccount *account; + PurpleBuddy *buddy; + + EBook *book; + 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 +{ + PurpleBuddy *buddy; + + EBook *book; + + GtkWidget *win; + GtkWidget *treeview; + GtkWidget *addrbooks_combo; + GtkWidget *search_field; + GtkWidget *assoc_button; + GtkWidget *imhtml; + GtkListStore *model; + + GtkTreeModel *addrbooks; + GList *contacts; + +} GevoAssociateBuddyDialog; + +void gevo_add_buddy_dialog_show(PurpleAccount *account, const char *username, + const char *group, const char *alias); +void gevo_add_buddy_dialog_add_person(GevoAddBuddyDialog *dialog, + EContact *contact, + const char *name, PurpleAccount *account, + const char *screenname); + +void gevo_new_person_dialog_show(EBook *book, EContact *contact, + PurpleAccount *account, const char *username, + const char *group, PurpleBuddy *buddy, + gboolean person_only); + +void gevo_add_buddy(PurpleAccount *account, const char *group_name, + const char *screenname, const char *alias); +GList *gevo_get_groups(void); + +EContactField gevo_prpl_get_field(PurpleAccount *account, PurpleBuddy *buddy); +gboolean gevo_prpl_is_supported(PurpleAccount *account, PurpleBuddy *buddy); +gboolean gevo_load_addressbook(const gchar *uri, EBook **book, GError **error); +char *gevo_get_email_for_buddy(PurpleBuddy *buddy); + +GevoAssociateBuddyDialog *gevo_associate_buddy_dialog_new(PurpleBuddy *buddy); + +GtkTreeModel *gevo_addrbooks_model_new(void); +void gevo_addrbooks_model_unref(GtkTreeModel *model); +void gevo_addrbooks_model_populate(GtkTreeModel *model); +EContact *gevo_search_buddy_in_contacts(PurpleBuddy *buddy, EBookQuery *query); + +#endif /* _GEVOLUTION_H_ */ diff -r 46f4ca8a4a27 -r e172db483c07 pidgin/plugins/gevolution/new_person_dialog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gevolution/new_person_dialog.c Thu Sep 20 12:01:33 2007 +0000 @@ -0,0 +1,419 @@ +/* + * Evolution integration plugin for Purple + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02111-1301, USA. + */ +#include "internal.h" +#include "pidgin.h" +#include "gtkutils.h" + +#include "debug.h" + +#include "gevolution.h" + +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_object_unref(dialog->book); + 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; + 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 (dialog->contact == NULL) + { + char *file_as; + + dialog->contact = e_contact_new(); + + if (*lastname && *firstname) + file_as = g_strdup_printf("%s, %s", lastname, firstname); + else if (*lastname) + file_as = g_strdup(lastname); + else + file_as = g_strdup(firstname); + + e_contact_set(dialog->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 = purple_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; + else if (!strcmp(im_service, "prpl-novell")) + field = E_CONTACT_IM_GROUPWISE; + + 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(dialog->book, contact, NULL)) + { + purple_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(dialog->book, contact, NULL)) + { + purple_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) + { + const char *group_name; + + group_name = pidgin_text_combo_box_entry_get_text(dialog->group_combo); + + 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, PurpleAccount *account, + GevoNewPersonDialog *dialog) +{ + dialog->account = account; +} + +void +gevo_new_person_dialog_show(EBook *book, EContact *contact, + PurpleAccount *account, const char *username, + const char *group, PurpleBuddy *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(book); + 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->book = book; + g_object_ref(book); + + dialog->win = pidgin_create_window(_("New Person"), PIDGIN_HIG_BORDER, "new_person", FALSE); + + 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 = + pidgin_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, _("Screen name:"), 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 = pidgin_text_combo_box_entry_new(NULL, + 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; + if (username == NULL || *username == '\0') + 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); +}