Mercurial > pidgin
diff plugins/gevolution/gevolution.c @ 8089:35db601609e3
[gaim-migrate @ 8788]
Gaim-Evolution Buddy List-Addressbook syncronocity by our very own
Chip X. Eightysix.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Tue, 13 Jan 2004 01:45:32 +0000 |
parents | |
children | 96ee7b21c1ae |
line wrap: on
line diff
--- /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 <libedata-book/Evolution-DataServer-Addressbook.h> + +#include <libebook/e-book-listener.h> +#include <libebook/e-book-async.h> +#include <libedata-book/e-data-book-factory.h> +#include <bonobo/bonobo-main.h> + +#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 <chipx86@gnupdate.org>", /**< 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)