diff options
Diffstat (limited to 'sendto/plugins/gajim/gajim.c')
-rw-r--r-- | sendto/plugins/gajim/gajim.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/sendto/plugins/gajim/gajim.c b/sendto/plugins/gajim/gajim.c new file mode 100644 index 0000000..bb00d1d --- /dev/null +++ b/sendto/plugins/gajim/gajim.c @@ -0,0 +1,516 @@ +/* + * gajim.c + * gajim plugin for caja-sendto + * + * Copyright (C) 2006 Dimitur Kirov + * 2006 Roberto Majadas <[email protected]> + * + * 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 av. + * + * 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 02110-1301 USA. + * + */ + +#include "config.h" +#include <glib/gi18n-lib.h> +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> +#include "caja-sendto-plugin.h" + +#define OBJ_PATH "/org/gajim/dbus/RemoteObject" +#define INTERFACE "org.gajim.dbus.RemoteInterface" +#define SERVICE "org.gajim.dbus" + +const gchar *COMPLETION_PROPS[] = {"name", "jid"}; +/* list of contacts, which are not offline */ +static GHashTable *jid_table = NULL; +static gchar *iconset; + + +DBusGProxy *proxy = NULL; + +/* + * contact cb, gets property from contact dict + * and put online contacts to jid_table + */ +static void +_foreach_contact(gpointer contact, gpointer user_data) +{ + const gchar *show; + + GValue *value; + GHashTable *contact_table; + + /* holds contact props of already exisiting jid/nick */ + GHashTable *existing_contact; + + /* name of the contact in completion list + it may be jid, nick, jid (account), or nick(account) */ + GString *contact_str; + + gchar *jid; + gchar *account; + gint i; + + if (contact == NULL) { + g_warning("Null contact in the list"); + return; + } + contact_table = (GHashTable *) contact; + account = (gchar *) user_data; + + value = g_hash_table_lookup(contact_table, "show"); + if (value == NULL || !G_VALUE_HOLDS_STRING(value)) { + g_warning("String expected (contact - show)"); + g_hash_table_destroy(contact_table); + return; + } + show = g_value_get_string ((GValue *)value); + if(g_str_equal(show, "offline") || g_str_equal(show, "error")) { + g_hash_table_destroy(contact_table); + return; + } + /* remove unneeded item with key resource and add account + to contact properties */ + g_hash_table_insert(contact_table, "account", account); + g_hash_table_remove(contact_table, "resource"); + + /* add nick the same way as jid */ + for(i=0;i<2;i++) { + value = g_hash_table_lookup(contact_table, COMPLETION_PROPS[i]); + if(value == NULL || !G_VALUE_HOLDS_STRING(value)) { + g_warning("String expected (contact - name)"); + return; + } + jid = g_value_dup_string((GValue *)value); + existing_contact = g_hash_table_lookup(jid_table, jid); + if(existing_contact) { + /* add existing contact as nick (account) */ + contact_str = g_string_new(jid); + g_string_append(contact_str, " ("); + g_string_append(contact_str, + g_hash_table_lookup(existing_contact, "account")); + g_string_append(contact_str, ")"); + g_hash_table_insert(jid_table, contact_str->str, + existing_contact); + g_string_free(contact_str, FALSE); + + /* add current contact as nick (account) */ + contact_str = g_string_new(jid); + g_string_append(contact_str, " ("); + g_string_append(contact_str, + g_hash_table_lookup(contact_table, "account")); + g_string_append(contact_str, ")"); + g_hash_table_insert(jid_table, contact_str->str, + contact_table); + g_string_free(contact_str, FALSE); + } + else { + g_hash_table_insert(jid_table, jid, contact_table); + } + } + +} + +/* + * connect to session bus, onsuccess return TRUE + */ +static gboolean +init_dbus (void) +{ + DBusGConnection *connection; + GError *error; + gchar **accounts; + + error = NULL; + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if(error != NULL) { + g_warning("[Gajim] unable to get session bus, error was:\n %s", error->message); + g_error_free(error); + return FALSE; + } + proxy = dbus_g_proxy_new_for_name(connection, + SERVICE, + OBJ_PATH, + INTERFACE); + dbus_g_connection_unref(connection); + if (proxy == NULL){ + return FALSE; + } + + error = NULL; + if (!dbus_g_proxy_call (proxy, "list_accounts", &error, G_TYPE_INVALID, + G_TYPE_STRV, &accounts, G_TYPE_INVALID)) + { + g_object_unref(proxy); + g_error_free(error); + return FALSE; + } + g_strfreev(accounts); + return TRUE; +} + +/* + * Print appropriate warnings when dbus raised error + * on queries + */ +static void +_handle_dbus_exception (GError *error, gboolean empty_list_messages) +{ + if (error == NULL) { + g_warning("[Gajim] unable to parse result"); + return; + } + else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { + g_warning ("[Gajim] caught remote method exception %s: %s", + dbus_g_error_get_name (error), + error->message); + } + else if(empty_list_messages) { + /* empty list and error goes here */ + g_warning ("[Gajim] empty result set: %d %d %s\n", error->domain, + error->code, error->message); + } + g_error_free (error); +} + +/* + * query object, about the contact list for each account + * and fill all available contacts in the contacts table + */ +static gboolean +_get_contacts (void) +{ + GError *error; + GSList *contacts_list; + GHashTable *prefs_map; + gchar **accounts; + gchar **account_iter; + gchar *account; + + error = NULL; + + if (proxy == NULL) { + g_warning("[Gajim] unable to connect to session bus"); + return FALSE; + } + /* get gajim prefs and lookup for iconset */ + if (!dbus_g_proxy_call(proxy, "prefs_list", &error, G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), + &prefs_map, G_TYPE_INVALID)) + { + _handle_dbus_exception(error, TRUE); + return FALSE; + } + gpointer iconset_ptr = g_hash_table_lookup(prefs_map, "iconset"); + if (iconset_ptr != NULL) { + iconset = g_strdup((gchar *)iconset_ptr); + } else { + g_warning("[Gajim] unable to get prefs value for iconset"); + return FALSE; + } + g_hash_table_destroy(prefs_map); + /* END get gajim prefs */ + error= NULL; + if (!dbus_g_proxy_call (proxy, "list_accounts", &error, G_TYPE_INVALID, + G_TYPE_STRV, + &accounts, G_TYPE_INVALID)) + { + _handle_dbus_exception(error, TRUE); + return FALSE; + } + for(account_iter = accounts; *account_iter ; account_iter++) { + account = g_strdup(*account_iter); + error = NULL; + /* query gajim remote object and put results in 'contacts_list' */ + if (!dbus_g_proxy_call (proxy, "list_contacts", &error, + G_TYPE_STRING, account, /* call arguments */ + G_TYPE_INVALID, /* delimiter */ + /* return value is collection of maps */ + dbus_g_type_get_collection ("GSList", + dbus_g_type_get_map ("GHashTable", + G_TYPE_STRING, G_TYPE_VALUE)), + &contacts_list, G_TYPE_INVALID)) + { + _handle_dbus_exception(error, FALSE); + error = NULL; + continue; + } + g_slist_foreach (contacts_list, _foreach_contact, account); + g_slist_free(contacts_list); + } + g_strfreev (accounts); + return TRUE; +} + +static gboolean +init (NstPlugin *plugin) +{ + g_print ("Init gajim plugin\n"); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + /* connect to gajim dbus service */ + jid_table = g_hash_table_new (g_str_hash, g_str_equal); + if (!init_dbus()) { + return FALSE; + } + return TRUE; +} + + +static void +_set_pixbuf_from_status (const gchar *show, GdkPixbuf **pixbuf) +{ + GString *pixbuf_path; + GError *error; + + pixbuf_path = g_string_new(GAJIM_SHARE_DIR); + g_string_append_c(pixbuf_path, '/'); + g_string_append(pixbuf_path, "data"); + g_string_append_c(pixbuf_path, '/'); + g_string_append(pixbuf_path, "iconsets"); + g_string_append_c(pixbuf_path, '/'); + g_string_append(pixbuf_path, iconset); + g_string_append_c(pixbuf_path, '/'); + g_string_append(pixbuf_path, "16x16"); + g_string_append_c(pixbuf_path, '/'); + g_string_append(pixbuf_path, show); + g_string_append(pixbuf_path, ".png"); + if(g_file_test(pixbuf_path->str, G_FILE_TEST_EXISTS) && + g_file_test(pixbuf_path->str, G_FILE_TEST_IS_REGULAR)) { + error = NULL; + *pixbuf = gdk_pixbuf_new_from_file(pixbuf_path->str, &error); + if(error != NULL) { + g_error_free(error); + } + } + g_string_free(pixbuf_path, FALSE); +} + +static void +_add_contact_to_model(gpointer key, gpointer value, gpointer user_data) +{ + GtkTreeIter *iter; + GtkListStore *store; + GdkPixbuf *pixbuf; + GValue *val; + GHashTable *contact_props; + const gchar *show; + + contact_props = (GHashTable *) value; + pixbuf = NULL; + val = g_hash_table_lookup(contact_props, "show"); + if (value == NULL || !G_VALUE_HOLDS_STRING(val)) { + g_warning("String expected (contact - show)"); + pixbuf = NULL; + } else { + show = g_value_get_string ((GValue *)val); + _set_pixbuf_from_status(show, &pixbuf); + } + + store = (GtkListStore *) user_data; + iter = g_malloc (sizeof(GtkTreeIter)); + gtk_list_store_append (store, iter); + gtk_list_store_set (store, iter, 0, pixbuf, 1, key, -1); + g_free (iter); +} + +/* + * put gajim contacts to jid_list + * filtering only these which are connected + */ +static gboolean +add_gajim_contacts_to_model (GtkListStore *store) +{ + if(!_get_contacts()) { + return FALSE; + } + if(g_hash_table_size(jid_table) == 0) { + return FALSE; + } + g_hash_table_foreach(jid_table, _add_contact_to_model, store); + return TRUE; +} + +/* + * fill completion model for the entry, using list of + * available gajim contacts + */ +static GtkWidget * +get_contacts_widget (NstPlugin *plugin) +{ + GtkWidget *entry; + GtkEntryCompletion *completion; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeModel *completion_model; + + entry = gtk_entry_new (); + completion = gtk_entry_completion_new (); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), + renderer, + FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, + "pixbuf", 0, NULL); + + + store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING); + if(!add_gajim_contacts_to_model (store)) { + gtk_widget_set_sensitive(entry, FALSE); + } + completion_model = GTK_TREE_MODEL (store); + gtk_entry_completion_set_model (completion, completion_model); + gtk_entry_set_completion (GTK_ENTRY (entry), completion); + gtk_entry_completion_set_text_column (completion, 1); + g_object_unref (completion_model); + g_object_unref (completion); + return entry; +} + +static void +show_error (const gchar *title, const gchar *message) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new_with_markup(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, NULL); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), + g_markup_printf_escaped("<b>%s</b>\n\n%s", title, message)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + +} + +static gboolean +send_files (NstPlugin *plugin, + GtkWidget *contact_widget, + GList *file_list) +{ + GError *error; + GValue *value; + GList *file_iter; + GHashTable *contact_props; + + gchar *send_to; + gchar *jid; + gchar *account; + gchar *file_path; + + if(proxy == NULL) { + show_error(_("Unable to send file"), + _("There is no connection to gajim remote service.")); + return FALSE; + } + send_to = (gchar *) gtk_entry_get_text (GTK_ENTRY(contact_widget)); + g_debug("[Gajim] sending to: %s", send_to); + if (strlen (send_to) != 0){ + contact_props = g_hash_table_lookup (jid_table, send_to); + if(contact_props == NULL) { + jid = send_to; + account = NULL; + } + else { + value = g_hash_table_lookup(contact_props, "jid"); + if(value == NULL || !G_VALUE_HOLDS_STRING(value)) { + g_warning("[Gajim] string expected (contact - jid)"); + return FALSE; + } + + jid = g_value_dup_string((GValue *)value); + account = g_hash_table_lookup(contact_props, "account"); + } + } + else { + g_warning("[Gajim] missing recipient"); + show_error(_("Sending file failed"), + _("Recipient is missing.")); + return FALSE; + } + + error= NULL; + for(file_iter = file_list; file_iter != NULL; file_iter = file_iter->next) { + char *uri = file_iter->data; + + g_debug("[Gajim] file: %s", uri); + error= NULL; + file_path = g_filename_from_uri(uri, NULL, &error); + if(error != NULL) { + g_warning("%d Unable to convert URI `%s' to absolute file path", + error->code, uri); + g_error_free(error); + continue; + } + + g_debug("[Gajim] file: %s", file_path); + if(account) { + dbus_g_proxy_call (proxy, "send_file", &error, + G_TYPE_STRING, file_path, + G_TYPE_STRING, jid, + G_TYPE_STRING, account, + G_TYPE_INVALID, + G_TYPE_INVALID); + } else { + dbus_g_proxy_call (proxy, "send_file", &error, + G_TYPE_STRING, file_path, + G_TYPE_STRING, jid, + G_TYPE_INVALID, + G_TYPE_INVALID); + } + g_free(file_path); + if(error != NULL) + { + if(error->domain != DBUS_GERROR || error->code != DBUS_GERROR_INVALID_ARGS) { + g_warning("[Gajim] sending file %s to %s failed:", uri, send_to); + g_error_free(error); + show_error(_("Sending file failed"), _("Unknown recipient.")); + return FALSE; + } + g_error_free(error); + } + } + return TRUE; +} + +static gboolean +destroy (NstPlugin *plugin) +{ + if (proxy != NULL) { + g_object_unref(proxy); + } + g_hash_table_destroy(jid_table); + return TRUE; +} + +static +NstPluginInfo plugin_info = { + "im-jabber", + "gajim", + N_("Instant Message (Gajim)"), + NULL, + CAJA_CAPS_NONE, + init, + get_contacts_widget, + NULL, + send_files, + destroy +}; + +NST_INIT_PLUGIN (plugin_info) + |