summaryrefslogtreecommitdiff
path: root/sendto/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'sendto/plugins')
-rw-r--r--sendto/plugins/Makefile.am16
-rw-r--r--sendto/plugins/caja-burn/Makefile.am19
-rw-r--r--sendto/plugins/caja-burn/caja-burn.c189
-rw-r--r--sendto/plugins/emailclient/Makefile.am17
-rw-r--r--sendto/plugins/emailclient/emailclient.c274
-rw-r--r--sendto/plugins/gajim/Makefile.am18
-rw-r--r--sendto/plugins/gajim/gajim.c516
-rw-r--r--sendto/plugins/nst-common.c98
-rw-r--r--sendto/plugins/nst-common.h23
-rw-r--r--sendto/plugins/pidgin/Makefile.am18
-rw-r--r--sendto/plugins/pidgin/pidgin.c475
-rw-r--r--sendto/plugins/removable-devices/Makefile.am19
-rw-r--r--sendto/plugins/removable-devices/removable-devices.c259
-rw-r--r--sendto/plugins/upnp/Makefile.am18
-rw-r--r--sendto/plugins/upnp/upnp.c320
15 files changed, 2279 insertions, 0 deletions
diff --git a/sendto/plugins/Makefile.am b/sendto/plugins/Makefile.am
new file mode 100644
index 0000000..10097e8
--- /dev/null
+++ b/sendto/plugins/Makefile.am
@@ -0,0 +1,16 @@
+SUBDIRS = . \
+ caja-burn \
+ emailclient \
+ gajim \
+ pidgin \
+ removable-devices \
+ upnp
+
+NST_COMMON_SOURCES = nst-common.c nst-common.h
+
+noinst_LTLIBRARIES = libnstcommon.la
+libnstcommon_la_SOURCES = $(NST_COMMON_SOURCES)
+libnstcommon_la_CFLAGS = $(SENDTO_CFLAGS)
+libnstcommon_la_LIBADD = $(SENDTO_LIBS)
+
+EXTRA_DIST = $(NST_COMMON_SOURCES)
diff --git a/sendto/plugins/caja-burn/Makefile.am b/sendto/plugins/caja-burn/Makefile.am
new file mode 100644
index 0000000..50c309b
--- /dev/null
+++ b/sendto/plugins/caja-burn/Makefile.am
@@ -0,0 +1,19 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ -I$(srcdir)/../ \
+ $(SENDTO_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED)
+
+plugin_LTLIBRARIES = libnstburn.la
+
+libnstburn_la_SOURCES = caja-burn.c
+libnstburn_la_LDFLAGS = -module -avoid-version
+libnstburn_la_LIBADD = $(SENDTO_LIBS) $(builddir)/../libnstcommon.la
+
diff --git a/sendto/plugins/caja-burn/caja-burn.c b/sendto/plugins/caja-burn/caja-burn.c
new file mode 100644
index 0000000..07d2e41
--- /dev/null
+++ b/sendto/plugins/caja-burn/caja-burn.c
@@ -0,0 +1,189 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Copyright (C) 2008 Jader Henrique da Silva
+ *
+ * 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.
+ *
+ * Author: Jader Henrique da Silva <[email protected]>
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include "nst-common.h"
+#include "caja-sendto-plugin.h"
+
+enum {
+ COL_PIXBUF,
+ COL_LABEL,
+ NUM_COLS,
+};
+
+#define COMBOBOX_OPTION_NEW_DVD 0
+#define COMBOBOX_OPTION_EXISTING_DVD 1
+
+static GFile *burn = NULL;
+
+static
+gboolean init (NstPlugin *plugin)
+{
+ GtkIconTheme *it;
+ char *cmd;
+
+ g_print ("Init caja burn plugin\n");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ it = gtk_icon_theme_get_default ();
+ gtk_icon_theme_append_search_path (it, DATADIR "/brasero/icons");
+
+ cmd = g_find_program_in_path ("brasero");
+ if (cmd == NULL)
+ return FALSE;
+ g_free (cmd);
+
+ burn = g_file_new_for_uri ("burn:/");
+
+ return TRUE;
+}
+
+static
+GtkWidget* get_contacts_widget (NstPlugin *plugin)
+{
+ GtkWidget *widget;
+ GtkCellRenderer *renderer;
+ GtkListStore *store;
+ GtkTreeModel *model;
+ GFileEnumerator *fenum;
+ GFileInfo *file_info = NULL;
+ int selection = COMBOBOX_OPTION_NEW_DVD;
+
+ fenum = g_file_enumerate_children (burn,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (fenum != NULL) {
+ file_info = g_file_enumerator_next_file (fenum, NULL, NULL);
+ g_object_unref (fenum);
+ }
+
+ store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
+
+ gtk_list_store_insert_with_values (store, NULL,
+ INT_MAX,
+ COL_PIXBUF, "media-optical-blank",
+ COL_LABEL, _("New CD/DVD"),
+ -1);
+
+ if (file_info != NULL) {
+ gtk_list_store_insert_with_values (store, NULL,
+ INT_MAX,
+ COL_PIXBUF, "media-optical-data-new",
+ COL_LABEL, _("Existing CD/DVD"),
+ -1);
+ g_object_unref (file_info);
+ selection = COMBOBOX_OPTION_EXISTING_DVD;
+ }
+
+ model = GTK_TREE_MODEL (store);
+ widget = gtk_combo_box_new_with_model (model);
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget),
+ renderer,
+ FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget),
+ renderer,
+ "icon-name", COL_PIXBUF,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget),
+ renderer,
+ TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget),
+ renderer,
+ "text", COL_LABEL,
+ NULL);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), selection);
+
+ return widget;
+}
+
+static
+gboolean send_files (NstPlugin *plugin,
+ GtkWidget *burntype_widget,
+ GList *file_list)
+{
+ GFileEnumerator *fenum;
+ GFileInfo *file_info;
+ GFile *child;
+
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (burntype_widget)) == COMBOBOX_OPTION_NEW_DVD) {
+ fenum = g_file_enumerate_children (burn,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (fenum != NULL) {
+ while ((file_info = g_file_enumerator_next_file (fenum, NULL, NULL)) != NULL) {
+ child = g_file_get_child (burn,
+ g_file_info_get_name(file_info));
+
+ g_object_unref (file_info);
+ g_file_delete (child, NULL, NULL);
+ g_object_unref (child);
+ }
+ g_object_unref (fenum);
+ }
+ }
+
+ copy_files_to (file_list, burn);
+
+ gtk_show_uri (NULL, "burn:///", GDK_CURRENT_TIME, NULL);
+
+ return TRUE;
+}
+
+static
+gboolean destroy (NstPlugin *plugin){
+
+ g_object_unref (burn);
+ burn = NULL;
+ return TRUE;
+
+}
+
+static
+NstPluginInfo plugin_info = {
+ "brasero",
+ "caja-burn",
+ N_("CD/DVD Creator"),
+ NULL,
+ CAJA_CAPS_SEND_DIRECTORIES,
+ init,
+ get_contacts_widget,
+ NULL,
+ send_files,
+ destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+
diff --git a/sendto/plugins/emailclient/Makefile.am b/sendto/plugins/emailclient/Makefile.am
new file mode 100644
index 0000000..31ba40e
--- /dev/null
+++ b/sendto/plugins/emailclient/Makefile.am
@@ -0,0 +1,17 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ $(SENDTO_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstemailclient.la
+
+libnstemailclient_la_SOURCES = emailclient.c
+libnstemailclient_la_LDFLAGS = -module -avoid-version
+libnstemailclient_la_LIBADD = $(SENDTO_LIBS)
diff --git a/sendto/plugins/emailclient/emailclient.c b/sendto/plugins/emailclient/emailclient.c
new file mode 100644
index 0000000..14cb998
--- /dev/null
+++ b/sendto/plugins/emailclient/emailclient.c
@@ -0,0 +1,274 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Copyright (C) 2004 Roberto Majadas <[email protected]>
+ * Copyright (C) 2012 Stefano Karapetsas <[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.
+ *
+ * Authors: Roberto Majadas <[email protected]>
+ * Stefano Karapetsas <[email protected]>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "caja-sendto-plugin.h"
+#include <gio/gio.h>
+
+typedef enum {
+ MAILER_UNKNOWN,
+ MAILER_EVO,
+ MAILER_BALSA,
+ MAILER_SYLPHEED,
+ MAILER_THUNDERBIRD,
+} MailerType;
+
+static char *mail_cmd = NULL;
+static MailerType type = MAILER_UNKNOWN;
+
+static char *
+get_evo_cmd (void)
+{
+ char *tmp = NULL;
+ char *retval;
+ char *cmds[] = {"evolution",
+ "evolution-2.0",
+ "evolution-2.2",
+ "evolution-2.4",
+ "evolution-2.6",
+ "evolution-2.8", /* for the future */
+ "evolution-3.0", /* but how far to go ? */
+ NULL};
+ guint i;
+
+
+ for (i = 0; cmds[i] != NULL; i++) {
+ tmp = g_find_program_in_path (cmds[i]);
+ if (tmp != NULL)
+ break;
+ }
+
+ if (tmp == NULL)
+ return NULL;
+
+ retval = g_strdup_printf ("%s --component=mail %%s", tmp);
+ g_free (tmp);
+ return retval;
+}
+
+static gboolean
+init (NstPlugin *plugin)
+{
+ GAppInfo *app_info = NULL;
+
+ g_print ("Init email client plugin\n");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ app_info = g_app_info_get_default_for_uri_scheme ("mailto");
+ if (app_info) {
+ mail_cmd = g_strdup(g_app_info_get_executable (app_info));
+ g_object_unref (app_info);
+ }
+
+ if (mail_cmd == NULL || *mail_cmd == '\0') {
+ g_free (mail_cmd);
+ mail_cmd = get_evo_cmd ();
+ type = MAILER_EVO;
+ } else {
+ /* Find what the default mailer is */
+ if (strstr (mail_cmd, "balsa"))
+ type = MAILER_BALSA;
+ else if (strstr (mail_cmd, "thunder") || strstr (mail_cmd, "seamonkey")) {
+ char **strv;
+
+ type = MAILER_THUNDERBIRD;
+
+ /* Thunderbird sucks, see
+ * https://bugzilla.gnome.org/show_bug.cgi?id=614222 */
+ strv = g_strsplit (mail_cmd, " ", -1);
+ g_free (mail_cmd);
+ mail_cmd = g_strdup_printf ("%s %%s", strv[0]);
+ g_strfreev (strv);
+ } else if (strstr (mail_cmd, "sylpheed") || strstr (mail_cmd, "claws"))
+ type = MAILER_SYLPHEED;
+ else if (strstr (mail_cmd, "anjal"))
+ type = MAILER_EVO;
+ }
+
+ if (mail_cmd == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+static
+GtkWidget* get_contacts_widget (NstPlugin *plugin)
+{
+ GtkWidget *entry;
+
+ // TODO: add an email address format check
+ entry = gtk_entry_new();
+
+ return entry;
+}
+
+static void
+get_evo_mailto (GtkWidget *contact_widget, GString *mailto, GList *file_list)
+{
+ GList *l;
+
+ g_string_append (mailto, "mailto:");
+
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (contact_widget));
+ if (text != NULL && *text != '\0')
+ g_string_append_printf (mailto, "\"%s\"", text);
+ else
+ g_string_append (mailto, "\"\"");
+
+ g_string_append_printf (mailto,"?attach=\"%s\"", (char *)file_list->data);
+ for (l = file_list->next ; l; l=l->next){
+ g_string_append_printf (mailto,"&attach=\"%s\"", (char *)l->data);
+ }
+}
+
+static void
+get_balsa_mailto (GtkWidget *contact_widget, GString *mailto, GList *file_list)
+{
+ GList *l;
+
+ if (strstr (mail_cmd, " -m ") == NULL && strstr (mail_cmd, " --compose=") == NULL)
+ g_string_append (mailto, " --compose=");
+
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (contact_widget));
+ if (text != NULL && *text != '\0')
+ g_string_append_printf (mailto, "\"%s\"", text);
+ else
+ g_string_append (mailto, "\"\"");
+
+ g_string_append_printf (mailto," --attach=\"%s\"", (char *)file_list->data);
+ for (l = file_list->next ; l; l=l->next){
+ g_string_append_printf (mailto," --attach=\"%s\"", (char *)l->data);
+ }
+}
+
+static void
+get_thunderbird_mailto (GtkWidget *contact_widget, GString *mailto, GList *file_list)
+{
+ GList *l;
+
+ g_string_append (mailto, "-compose \"");
+
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (contact_widget));
+ if (text != NULL && *text != '\0')
+ g_string_append_printf (mailto, "to='%s',", text);
+
+ g_string_append_printf (mailto,"attachment='%s", (char *)file_list->data);
+ for (l = file_list->next ; l; l=l->next){
+ g_string_append_printf (mailto,",%s", (char *)l->data);
+ }
+ g_string_append (mailto, "'\"");
+}
+
+static void
+get_sylpheed_mailto (GtkWidget *contact_widget, GString *mailto, GList *file_list)
+{
+ GList *l;
+
+ g_string_append (mailto, "--compose ");
+
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (contact_widget));
+ if (text != NULL && *text != '\0')
+ g_string_append_printf (mailto, "\"%s\" ", text);
+ else
+ g_string_append (mailto, "\"\"");
+
+ g_string_append_printf (mailto,"--attach \"%s\"", (char *)file_list->data);
+ for (l = file_list->next ; l; l=l->next){
+ g_string_append_printf (mailto," \"%s\"", (char *)l->data);
+ }
+}
+
+static gboolean
+send_files (NstPlugin *plugin,
+ GtkWidget *contact_widget,
+ GList *file_list)
+{
+ gchar *cmd;
+ GString *mailto;
+
+ mailto = g_string_new ("");
+ switch (type) {
+ case MAILER_BALSA:
+ get_balsa_mailto (contact_widget, mailto, file_list);
+ break;
+ case MAILER_SYLPHEED:
+ get_sylpheed_mailto (contact_widget, mailto, file_list);
+ break;
+ case MAILER_THUNDERBIRD:
+ get_thunderbird_mailto (contact_widget, mailto, file_list);
+ break;
+ case MAILER_EVO:
+ default:
+ get_evo_mailto (contact_widget, mailto, file_list);
+ }
+
+ cmd = g_strdup_printf (mail_cmd, mailto->str);
+ g_string_free (mailto, TRUE);
+
+ g_message ("Mailer type: %d", type);
+ g_message ("Command: %s", cmd);
+
+ g_spawn_command_line_async (cmd, NULL);
+ g_free (cmd);
+
+ return TRUE;
+}
+
+static
+gboolean destroy (NstPlugin *plugin){
+ g_free (mail_cmd);
+ mail_cmd = NULL;
+ return TRUE;
+}
+
+static
+NstPluginInfo plugin_info = {
+ "emblem-mail",
+ "emailclient",
+ N_("Email"),
+ NULL,
+ CAJA_CAPS_NONE,
+ init,
+ get_contacts_widget,
+ NULL,
+ send_files,
+ destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+
diff --git a/sendto/plugins/gajim/Makefile.am b/sendto/plugins/gajim/Makefile.am
new file mode 100644
index 0000000..5acd5b0
--- /dev/null
+++ b/sendto/plugins/gajim/Makefile.am
@@ -0,0 +1,18 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ $(SENDTO_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstgajim.la
+
+libnstgajim_la_SOURCES = gajim.c
+libnstgajim_la_LDFLAGS = -module -avoid-version
+libnstgajim_la_LIBADD = $(SENDTO_LIBS)
+
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)
+
diff --git a/sendto/plugins/nst-common.c b/sendto/plugins/nst-common.c
new file mode 100644
index 0000000..2d2f102
--- /dev/null
+++ b/sendto/plugins/nst-common.c
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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.
+ *
+ * Author: Maxim Ermilov <[email protected]>
+ */
+
+#include <gio/gio.h>
+
+static gboolean
+copy_fobject (GFile* source, GFile* dst)
+{
+ GFileEnumerator* en;
+ GFileInfo* info;
+ GError *err = NULL;
+ char *file_name;
+ GFile *dest;
+
+ file_name = g_file_get_basename (source);
+ dest = g_file_get_child (dst, file_name);
+ g_free (file_name);
+
+ if (g_file_query_file_type (source, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY) {
+ gboolean ret;
+ ret = g_file_copy (source, dest, G_FILE_COPY_NONE, NULL, NULL, NULL, NULL);
+
+ g_object_unref (dest);
+
+ return ret;
+ }
+
+ en = g_file_enumerate_children (source, "*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ if (!g_file_make_directory (dest, NULL, NULL)) {
+ g_object_unref (en);
+ g_object_unref (dest);
+ return FALSE;
+ }
+
+ while ((info = g_file_enumerator_next_file (en, NULL, &err)) != NULL) {
+ const char *name;
+
+ name = g_file_info_get_name (G_FILE_INFO (info));
+
+ if (name != NULL) {
+ GFile *child;
+
+ child = g_file_get_child (source, name);
+
+ if (!copy_fobject (child, dest)) {
+ g_object_unref (en);
+ g_object_unref (dest);
+ g_object_unref (child);
+
+ return FALSE;
+ }
+ g_object_unref (child);
+ }
+
+ g_object_unref (info);
+ }
+ g_object_unref (en);
+ g_object_unref (dest);
+
+ if (err != NULL)
+ return FALSE;
+ return TRUE;
+}
+
+gboolean
+copy_files_to (GList *file_list, GFile *dest)
+{
+ GList *l;
+ gboolean retval = TRUE;
+
+ for (l = file_list; l != NULL; l = l->next) {
+ GFile *source;
+
+ source = g_file_new_for_commandline_arg (l->data);
+ if (copy_fobject (source, dest) == FALSE)
+ retval = FALSE;
+ g_object_unref (source);
+ }
+
+ return retval;
+}
diff --git a/sendto/plugins/nst-common.h b/sendto/plugins/nst-common.h
new file mode 100644
index 0000000..5a5e1dd
--- /dev/null
+++ b/sendto/plugins/nst-common.h
@@ -0,0 +1,23 @@
+/*
+ *
+ * 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.
+ *
+ * Author: Maxim Ermilov <[email protected]>
+ */
+
+#include <gio/gio.h>
+
+gboolean copy_files_to (GList *file_list, GFile *dest);
diff --git a/sendto/plugins/pidgin/Makefile.am b/sendto/plugins/pidgin/Makefile.am
new file mode 100644
index 0000000..b7f650a
--- /dev/null
+++ b/sendto/plugins/pidgin/Makefile.am
@@ -0,0 +1,18 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ $(SENDTO_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstpidgin.la
+
+libnstpidgin_la_SOURCES = pidgin.c
+libnstpidgin_la_LDFLAGS = -module -avoid-version
+libnstpidgin_la_LIBADD = $(SENDTO_LIBS)
+
diff --git a/sendto/plugins/pidgin/pidgin.c b/sendto/plugins/pidgin/pidgin.c
new file mode 100644
index 0000000..941d2b6
--- /dev/null
+++ b/sendto/plugins/pidgin/pidgin.c
@@ -0,0 +1,475 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * pidgin.c
+ * pidgin plugin for caja-sendto
+ *
+ * Copyright (C) 2004 Roberto Majadas
+ * Copyright (C) 2009 Pascal Terjan
+ *
+ * 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.
+ *
+ * Author: Roberto Majadas <[email protected]>
+ */
+
+#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 "/im/pidgin/purple/PurpleObject"
+#define INTERFACE "im.pidgin.purple.PurpleInterface"
+#define SERVICE "im.pidgin.purple.PurpleService"
+
+static DBusGProxy *proxy = NULL;
+static GHashTable *contact_hash = NULL;
+
+typedef struct _ContactData {
+ int account;
+ int id;
+ char *name;
+ char *alias;
+} ContactData;
+
+enum {
+ COL_ICON,
+ COL_ALIAS,
+ NUM_COLS
+};
+
+/*
+ * Print appropriate warnings when dbus raised error
+ * on queries
+ */
+static void
+handle_dbus_exception(GError *error)
+{
+ if (error == NULL) {
+ g_warning("[Pidgin] unable to parse result");
+ return;
+ }
+ else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) {
+ g_warning ("[Pidgin] caught remote method exception %s: %s",
+ dbus_g_error_get_name (error),
+ error->message);
+ }
+ g_error_free (error);
+}
+
+static gboolean
+init (NstPlugin *plugin)
+{
+ DBusGConnection *connection;
+ GError *error;
+ GArray *accounts;
+
+ g_print ("Init pidgin plugin\n");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ error = NULL;
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if(error != NULL) {
+ g_warning("[Pidgin] 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, "PurpleAccountsGetAllActive", &error, G_TYPE_INVALID,
+ DBUS_TYPE_G_INT_ARRAY, &accounts, G_TYPE_INVALID)) {
+ g_object_unref(proxy);
+ g_error_free(error);
+ return FALSE;
+ }
+ g_array_free(accounts, TRUE);
+
+ return TRUE;
+}
+
+static GdkPixbuf *
+get_buddy_icon(int id)
+{
+ GError *error;
+ GdkPixbuf *pixbuf = NULL;
+ gchar *path = NULL;
+ int icon;
+
+ error=NULL;
+ if (!dbus_g_proxy_call (proxy, "PurpleBuddyGetIcon", &error,
+ G_TYPE_INT, id,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &icon, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ }
+ if (icon) {
+ if (!dbus_g_proxy_call (proxy, "PurpleBuddyIconGetFullPath", &error,
+ G_TYPE_INT, icon,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &path, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ }
+ //FIXME Get the size from somewhere
+ pixbuf = gdk_pixbuf_new_from_file_at_scale(path, 24, 24, TRUE, NULL);
+ }
+
+ return pixbuf;
+}
+
+static void
+add_pidgin_contacts_to_model (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ GError *error;
+ GArray *contacts_list;
+ GArray *accounts;
+ int i, j;
+
+ GdkPixbuf *icon;
+ GHashTableIter hiter;
+ GPtrArray *contacts_group;
+ ContactData *dat;
+ GValue val = {0,};
+
+ if(proxy == NULL)
+ return;
+
+ error = NULL;
+ if (!dbus_g_proxy_call (proxy, "PurpleAccountsGetAllActive", &error, G_TYPE_INVALID,
+ DBUS_TYPE_G_INT_ARRAY,
+ &accounts, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ return;
+ }
+
+ contact_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for(i = 0; i < accounts->len; i++) {
+ int account = g_array_index(accounts, int, i);
+ error = NULL;
+ if (!dbus_g_proxy_call (proxy, "PurpleFindBuddies", &error,
+ G_TYPE_INT, account,
+ G_TYPE_STRING, NULL,
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_INT_ARRAY, &contacts_list, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ continue;
+ }
+ for(j = 0; j < contacts_list->len ; j++) {
+ int id = g_array_index(contacts_list, int, j);
+ int online;
+
+ error = NULL;
+ if (!dbus_g_proxy_call (proxy, "PurpleBuddyIsOnline", &error,
+ G_TYPE_INT, id,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &online, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ continue;
+ }
+ if (!online)
+ continue;
+
+ dat = g_new0 (ContactData, 1);
+
+ dat->account = account;
+ dat->id = id;
+
+ error = NULL;
+ if (!dbus_g_proxy_call (proxy, "PurpleBuddyGetName", &error,
+ G_TYPE_INT, id,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &dat->name, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ g_free(dat);
+ continue;
+ }
+ if (!dbus_g_proxy_call (proxy, "PurpleBuddyGetAlias", &error,
+ G_TYPE_INT, id,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &dat->alias, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ }
+
+ contacts_group = g_hash_table_lookup (contact_hash, dat->alias);
+ if (contacts_group == NULL){
+ GPtrArray *new_group = g_ptr_array_new ();
+ g_ptr_array_add (new_group, dat);
+ g_hash_table_insert (contact_hash, dat->alias, new_group);
+ } else {
+ g_ptr_array_add (contacts_group, dat);
+ }
+ }
+ g_array_free(contacts_list, TRUE);
+ }
+ g_array_free (accounts, TRUE);
+
+ g_hash_table_iter_init (&hiter, contact_hash);
+ while (g_hash_table_iter_next (&hiter, NULL, (gpointer)&contacts_group)) {
+ gint accounts;
+
+ dat = g_ptr_array_index (contacts_group, 0);
+
+ accounts = contacts_group->len;
+
+ gtk_tree_store_append (store, parent, NULL);
+ gtk_tree_store_set (store, parent, COL_ICON, NULL, COL_ALIAS, dat->alias, -1);
+
+ gint i;
+ for (i = 0; i < accounts; ++i) {
+ dat = g_ptr_array_index (contacts_group, i);
+
+ icon = get_buddy_icon(dat->id);
+
+ if (accounts == 1) {
+ g_value_init(&val, GDK_TYPE_PIXBUF);
+ g_value_set_object (&val, (gpointer)icon);
+ gtk_tree_store_set_value (store, parent, COL_ICON, &val);
+ g_value_unset (&val);
+ break;
+ }
+ gtk_tree_store_append (store, iter, parent);
+ gtk_tree_store_set (store, iter,
+ COL_ICON, icon,
+ COL_ALIAS, dat->alias,
+ -1);
+ }
+ }
+}
+
+static void
+customize (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer text)
+{
+ gboolean has_child;
+ has_child = gtk_tree_model_iter_has_child (tree_model, iter);
+ if (text) {
+ if (has_child)
+ g_object_set (G_OBJECT(cell), "xpad", 18, NULL);
+ else
+ g_object_set (G_OBJECT(cell), "xpad", 2, NULL);
+ }
+ g_object_set (G_OBJECT(cell), "sensitive", !has_child, NULL);
+}
+
+static GtkWidget *
+get_contacts_widget (NstPlugin *plugin)
+{
+ GtkWidget *cb;
+ GtkCellRenderer *renderer;
+ GtkTreeStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter *iter, *iter2;
+
+ iter = g_malloc (sizeof(GtkTreeIter));
+ iter2 = g_malloc (sizeof(GtkTreeIter));
+ store = gtk_tree_store_new (NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+ add_pidgin_contacts_to_model (store, iter, iter2);
+ model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), COL_ALIAS,
+ GTK_SORT_ASCENDING);
+ cb = gtk_combo_box_new_with_model (model);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cb),
+ renderer,
+ FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cb),
+ renderer,
+ "pixbuf", COL_ICON,
+ NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cb), renderer,
+ customize,
+ (gboolean *)FALSE, NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cb),
+ renderer,
+ TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cb),
+ renderer,
+ "text", COL_ALIAS,
+ NULL);
+ g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cb), renderer,
+ customize,
+ (gboolean *)TRUE, NULL);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 0);
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX(cb), iter);
+ if (gtk_tree_model_iter_has_child (model, iter)) {
+ GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
+ gtk_tree_model_get_iter (model, iter2, path);
+ gtk_tree_path_free (path);
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (cb), iter2);
+ }
+
+ g_free (iter);
+ g_free (iter2);
+ return cb;
+}
+
+static
+gboolean send_file(int account, const char *who, const char *filename)
+{
+ GError *error;
+ int connection;
+
+ error = NULL;
+ if (!dbus_g_proxy_call(proxy, "PurpleAccountGetConnection", &error,
+ G_TYPE_INT, account,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &connection, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ return FALSE;
+ }
+
+ if (!connection) {
+ g_warning("[Pidgin] account is not connected");
+ return FALSE;
+ }
+
+ error = NULL;
+ if (!dbus_g_proxy_call(proxy, "ServSendFile", &error,
+ G_TYPE_INT, connection,
+ G_TYPE_STRING, who,
+ G_TYPE_STRING, filename,
+ G_TYPE_INVALID, G_TYPE_INVALID)) {
+ handle_dbus_exception(error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static
+gboolean send_files (NstPlugin *plugin, GtkWidget *contact_widget,
+ GList *file_list)
+{
+ GError *error;
+ GList *file_iter;
+
+ GFile *file;
+ gchar *file_path;
+
+ gint depth;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gint *indices;
+ const gchar *alias;
+ GPtrArray *contacts_group;
+ ContactData *dat;
+ GValue val = {0,};
+
+
+ if(proxy == NULL)
+ return FALSE;
+
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (contact_widget), &iter);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (
+ gtk_combo_box_get_model (GTK_COMBO_BOX(
+ contact_widget))), &iter);
+ depth = gtk_tree_path_get_depth(path);
+ indices = gtk_tree_path_get_indices(path);
+ gtk_tree_path_free (path);
+ gtk_tree_model_get_value (GTK_TREE_MODEL (gtk_combo_box_get_model (
+ GTK_COMBO_BOX(contact_widget))),
+ &iter, COL_ALIAS, &val);
+ alias = g_value_get_string (&val);
+ contacts_group = g_hash_table_lookup (contact_hash, alias);
+ g_value_unset (&val);
+ dat = g_ptr_array_index (contacts_group, (depth == 2)?indices[1]:0);
+
+ for(file_iter = file_list; file_iter != NULL;
+ file_iter = g_list_next(file_iter)) {
+ error= NULL;
+
+ file = g_file_new_for_uri ((gchar *)file_iter->data);
+ file_path = g_file_get_path (file);
+ g_object_unref (file);
+
+ if(file_path == NULL) {
+ g_warning("[Pidgin] %d Unable to convert URI `%s' to absolute file path",
+ error->code, (gchar *)file_iter->data);
+ g_error_free(error);
+ continue;
+ }
+
+ if(!send_file(dat->account, dat->name, file_path))
+ g_warning("[Pidgin] Failed to send %s file to %s", file_path, dat->name);
+ }
+ return TRUE;
+}
+
+static void
+free_contact (ContactData *dat)
+{
+ g_free(dat->name);
+ g_free(dat->alias);
+ g_free(dat);
+}
+
+static gboolean
+destroy (NstPlugin *plugin)
+{
+ GHashTableIter iter;
+ GPtrArray *contacts_group;
+ ContactData *dat;
+
+ g_hash_table_iter_init (&iter, contact_hash);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer)&contacts_group)) {
+ gint accounts;
+ accounts = contacts_group->len;
+
+ gint i;
+ for (i = 0; i < accounts; ++i) {
+ dat = g_ptr_array_index (contacts_group, i);
+ free_contact (dat);
+ }
+ g_ptr_array_free (contacts_group, TRUE);
+ }
+ g_hash_table_destroy (contact_hash);
+ return TRUE;
+}
+
+static
+NstPluginInfo plugin_info = {
+ "im",
+ "pidgin",
+ N_("Instant Message (Pidgin)"),
+ NULL,
+ CAJA_CAPS_NONE,
+ init,
+ get_contacts_widget,
+ NULL,
+ send_files,
+ destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+
diff --git a/sendto/plugins/removable-devices/Makefile.am b/sendto/plugins/removable-devices/Makefile.am
new file mode 100644
index 0000000..294ca90
--- /dev/null
+++ b/sendto/plugins/removable-devices/Makefile.am
@@ -0,0 +1,19 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ -I$(srcdir)/../ \
+ $(SENDTO_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstremovable_devices.la
+
+libnstremovable_devices_la_SOURCES = removable-devices.c
+libnstremovable_devices_la_LDFLAGS = -module -avoid-version
+libnstremovable_devices_la_LIBADD = $(SENDTO_LIBS) $(builddir)/../libnstcommon.la
+
diff --git a/sendto/plugins/removable-devices/removable-devices.c b/sendto/plugins/removable-devices/removable-devices.c
new file mode 100644
index 0000000..0ecea14
--- /dev/null
+++ b/sendto/plugins/removable-devices/removable-devices.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * 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.
+ *
+ * Authors: Maxim Ermilov <[email protected]>
+ * Bastien Nocera <[email protected]>
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include "nst-common.h"
+#include "caja-sendto-plugin.h"
+
+enum {
+ NAME_COL,
+ ICON_COL,
+ MOUNT_COL,
+ NUM_COLS,
+};
+
+GVolumeMonitor* vol_monitor = NULL;
+GtkWidget *cb;
+
+static void
+cb_mount_removed (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NstPlugin *plugin)
+{
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gboolean b, found;
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (cb)));
+ b = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+ found = FALSE;
+
+ while (b) {
+ GMount *m;
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, MOUNT_COL, &m, -1);
+ if (m == mount) {
+ gtk_list_store_remove (store, &iter);
+ g_object_unref (m);
+ found = TRUE;
+ break;
+ }
+ g_object_unref (m);
+ b = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ }
+
+ /* If a mount was removed */
+ if (found != FALSE) {
+ /* And it was the selected one */
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (cb)) == -1) {
+ /* Select the first item in the list */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 0);
+ }
+ }
+}
+
+static void
+cb_mount_changed (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NstPlugin *plugin)
+{
+ GtkTreeIter iter;
+ gboolean b;
+ GtkListStore *store;
+
+ if (g_mount_is_shadowed (mount) != FALSE) {
+ cb_mount_removed (volume_monitor, mount, plugin);
+ return;
+ }
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (cb)));
+ b = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+
+ while (b) {
+ GMount *m;
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, MOUNT_COL, &m, -1);
+
+ if (m == mount) {
+ char *name;
+
+ name = g_mount_get_name (mount);
+ gtk_list_store_set (store, &iter,
+ NAME_COL, name,
+ ICON_COL, g_mount_get_icon (mount),
+ -1);
+ g_free (name);
+ g_object_unref (m);
+ break;
+ }
+ g_object_unref (m);
+ b = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ }
+}
+
+static void
+cb_mount_added (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ NstPlugin *plugin)
+{
+ char *name;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gboolean select_added;
+
+ if (g_mount_is_shadowed (mount) != FALSE)
+ return;
+
+ name = g_mount_get_name (mount);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (cb));
+
+ select_added = gtk_tree_model_iter_n_children (model, NULL) == 0;
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ NAME_COL, name,
+ ICON_COL, g_mount_get_icon (mount),
+ MOUNT_COL, mount,
+ -1);
+
+ g_free (name);
+
+ if (select_added != FALSE)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 0);
+
+}
+
+static gboolean
+init (NstPlugin *plugin)
+{
+ g_print ("Init removable-devices plugin\n");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ vol_monitor = g_volume_monitor_get ();
+ cb = gtk_combo_box_new ();
+
+ return TRUE;
+}
+
+static GtkWidget*
+get_contacts_widget (NstPlugin *plugin)
+{
+ GtkListStore *store;
+ GList *l, *mounts;
+ GtkTreeIter iter;
+ GtkCellRenderer *text_renderer, *icon_renderer;
+
+ mounts = g_volume_monitor_get_mounts (vol_monitor);
+
+ store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_OBJECT);
+
+ for (l = mounts; l != NULL; l = l->next) {
+ char *name;
+
+ if (g_mount_is_shadowed (l->data) != FALSE) {
+ g_object_unref (l->data);
+ continue;
+ }
+
+ name = g_mount_get_name (l->data);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ NAME_COL, name,
+ ICON_COL, g_mount_get_icon (l->data),
+ MOUNT_COL, l->data,
+ -1);
+ g_free (name);
+
+ g_object_unref (l->data);
+ }
+ g_list_free (mounts);
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (cb));
+ gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (store));
+
+ text_renderer = gtk_cell_renderer_text_new ();
+ icon_renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cb), icon_renderer, FALSE);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cb), text_renderer, TRUE);
+
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cb), text_renderer, "text", 0, NULL);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cb), icon_renderer, "gicon", 1, NULL);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 0);
+
+ g_signal_connect (G_OBJECT (vol_monitor), "mount-removed", G_CALLBACK (cb_mount_removed), plugin);
+ g_signal_connect (G_OBJECT (vol_monitor), "mount-added", G_CALLBACK (cb_mount_added), plugin);
+ g_signal_connect (G_OBJECT (vol_monitor), "mount-changed", G_CALLBACK (cb_mount_changed), plugin);
+
+ return cb;
+}
+
+static gboolean
+send_files (NstPlugin *plugin, GtkWidget *contact_widget,
+ GList *file_list)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GMount *dest_mount;
+ GFile *mount_root;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (contact_widget), &iter) == FALSE)
+ return TRUE;
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (cb)));
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, MOUNT_COL, &dest_mount, -1);
+ mount_root = g_mount_get_root (dest_mount);
+
+ copy_files_to (file_list, mount_root);
+
+ g_object_unref (mount_root);
+
+ return TRUE;
+}
+
+static gboolean
+destroy (NstPlugin *plugin)
+{
+ gtk_widget_destroy (cb);
+
+ g_object_unref (vol_monitor);
+ return TRUE;
+}
+
+static
+NstPluginInfo plugin_info = {
+ "folder-remote",
+ "folder-remote",
+ N_("Removable disks and shares"),
+ NULL,
+ CAJA_CAPS_SEND_DIRECTORIES,
+ init,
+ get_contacts_widget,
+ NULL,
+ send_files,
+ destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+
diff --git a/sendto/plugins/upnp/Makefile.am b/sendto/plugins/upnp/Makefile.am
new file mode 100644
index 0000000..4127abd
--- /dev/null
+++ b/sendto/plugins/upnp/Makefile.am
@@ -0,0 +1,18 @@
+plugindir = $(libdir)/caja-sendto/plugins
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DICONDIR=\"$(icondir)\" \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ -I$(top_srcdir)/sendto \
+ -I$(top_builddir) \
+ $(SENDTO_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstupnp.la
+
+libnstupnp_la_SOURCES = upnp.c
+libnstupnp_la_LDFLAGS = -module -avoid-version
+libnstupnp_la_LIBADD = $(SENDTO_LIBS)
+
diff --git a/sendto/plugins/upnp/upnp.c b/sendto/plugins/upnp/upnp.c
new file mode 100644
index 0000000..b381587
--- /dev/null
+++ b/sendto/plugins/upnp/upnp.c
@@ -0,0 +1,320 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Copyright (C) 2008 Zeeshan Ali (Khattak)
+ * Copyright (C) 2006 Peter Enseleit
+ *
+ * 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.
+ *
+ * Author: Zeeshan Ali (Khattak) <[email protected]>
+ * Peter Enseleit <[email protected]>
+ * Roberto Majadas <[email protected]>
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <libgupnp/gupnp.h>
+#include "caja-sendto-plugin.h"
+
+#define MEDIA_SERVER "urn:schemas-upnp-org:device:MediaServer:1"
+#define CDS "urn:schemas-upnp-org:service:ContentDirectory"
+
+enum {
+ UDN_COL,
+ NAME_COL,
+ INTERFACE_COL,
+ NUM_COLS
+};
+
+static GtkWidget *combobox;
+static GtkTreeModel *model;
+static GUPnPContextManager *context_manager;
+
+static gboolean
+find_device (const gchar *udn,
+ GtkTreeIter *iter)
+{
+ gboolean found = FALSE;
+
+ if (!gtk_tree_model_get_iter_first (model, iter))
+ return FALSE;
+
+ do {
+ gchar *tmp;
+
+ gtk_tree_model_get (model,
+ iter,
+ UDN_COL, &tmp,
+ -1);
+
+ if (tmp != NULL && strcmp (tmp, udn) == 0)
+ found = TRUE;
+
+ g_free (tmp);
+ } while (!found && gtk_tree_model_iter_next (model, iter));
+
+ return found;
+}
+
+static gboolean
+check_required_actions (GUPnPServiceIntrospection *introspection)
+{
+ if (gupnp_service_introspection_get_action (introspection,
+ "CreateObject") == NULL)
+ return FALSE;
+ if (gupnp_service_introspection_get_action (introspection,
+ "ImportResource") == NULL)
+ return FALSE;
+ return TRUE;
+}
+
+static void
+get_introspection_cb (GUPnPServiceInfo *service_info,
+ GUPnPServiceIntrospection *introspection, const GError *error,
+ gpointer user_data)
+{
+ GUPnPDeviceInfo *device_info;
+ gchar *name;
+ const gchar *udn, *interface;
+ GtkTreeIter iter;
+ GUPnPContext *context;
+
+ device_info = GUPNP_DEVICE_INFO (user_data);
+
+ if (introspection != NULL) {
+ /* If introspection is available, make sure required actions
+ * are implemented.
+ */
+ if (!check_required_actions (introspection))
+ goto error;
+ }
+
+ udn = gupnp_device_info_get_udn (device_info);
+ if (G_UNLIKELY (udn == NULL))
+ goto error;
+
+ /* First check if the device is already added */
+ if (find_device (udn, &iter))
+ goto error;
+
+ name = gupnp_device_info_get_friendly_name (device_info);
+ if (name == NULL)
+ name = g_strdup (udn);
+
+ context = gupnp_device_info_get_context (device_info);
+ interface = gssdp_client_get_interface (GSSDP_CLIENT (context));
+
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, -1,
+ UDN_COL, udn,
+ NAME_COL, name,
+ INTERFACE_COL, interface,
+ -1);
+
+ g_free (name);
+
+error:
+ /* We don't need the proxy objects anymore */
+ g_object_unref (service_info);
+ g_object_ref (device_info);
+}
+
+static void
+device_proxy_available_cb (GUPnPControlPoint *cp,
+ GUPnPDeviceProxy *proxy)
+{
+ GUPnPServiceInfo *info;
+
+ info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (proxy), CDS);
+ if (G_UNLIKELY (info == NULL)) {
+ /* No ContentDirectory implemented? Not interesting. */
+ return;
+ }
+
+ gupnp_service_info_get_introspection_async (info,
+ get_introspection_cb,
+ g_object_ref (proxy));
+}
+
+static void
+device_proxy_unavailable_cb (GUPnPControlPoint *cp,
+ GUPnPDeviceProxy *proxy)
+{
+ GtkTreeIter iter;
+ const gchar *udn;
+
+ udn = gupnp_device_info_get_udn (GUPNP_DEVICE_INFO (proxy));
+ if (udn == NULL)
+ return;
+
+ /* First check if the device is already added */
+ if (find_device (udn, &iter))
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+}
+
+static void
+on_context_available (GUPnPContextManager *context_manager,
+ GUPnPContext *context,
+ gpointer user_data)
+{
+ GUPnPControlPoint *cp;
+
+ cp = gupnp_control_point_new (context, MEDIA_SERVER);
+
+ g_signal_connect (cp,
+ "device-proxy-available",
+ G_CALLBACK (device_proxy_available_cb),
+ NULL);
+ g_signal_connect (cp,
+ "device-proxy-unavailable",
+ G_CALLBACK (device_proxy_unavailable_cb),
+ NULL);
+
+ gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
+
+ /* Let context manager take care of the control point life cycle */
+ gupnp_context_manager_manage_control_point (context_manager, cp);
+ g_object_unref (cp);
+}
+
+static gboolean
+init (NstPlugin *plugin)
+{
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ char *upload_cmd;
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ upload_cmd = g_find_program_in_path ("gupnp-upload");
+ if (upload_cmd == NULL)
+ return FALSE;
+ g_free (upload_cmd);
+
+ context_manager = gupnp_context_manager_new (NULL, 0);
+ g_assert (context_manager != NULL);
+ g_signal_connect (context_manager, "context-available",
+ G_CALLBACK (on_context_available), NULL);
+
+ combobox = gtk_combo_box_new ();
+
+ store = gtk_list_store_new (NUM_COLS,
+ G_TYPE_STRING, /* UDN */
+ G_TYPE_STRING, /* Name */
+ G_TYPE_STRING); /* Network Interface */
+ model = GTK_TREE_MODEL (store);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (combobox), model);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox),
+ renderer,
+ TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox),
+ renderer,
+ "text", NAME_COL);
+
+ return TRUE;
+}
+
+static GtkWidget*
+get_contacts_widget (NstPlugin *plugin)
+{
+ return combobox;
+}
+
+static gboolean
+send_files (NstPlugin *plugin,
+ GtkWidget *contact_widget,
+ GList *file_list)
+{
+ gchar *upload_cmd, *udn, *interface;
+ GPtrArray *argv;
+ gboolean ret;
+ GList *l;
+ GtkTreeIter iter;
+ GError *err = NULL;
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &iter))
+ return FALSE;
+
+ gtk_tree_model_get (model, &iter, UDN_COL, &udn, INTERFACE_COL,
+ &interface, -1);
+
+ upload_cmd = g_find_program_in_path ("gupnp-upload");
+ if (upload_cmd == NULL)
+ return FALSE;
+
+ argv = g_ptr_array_new ();
+ g_ptr_array_add (argv, upload_cmd);
+ g_ptr_array_add (argv, "-t");
+ g_ptr_array_add (argv, "15"); /* discovery timeout (seconds) */
+ g_ptr_array_add (argv, "-e");
+ g_ptr_array_add (argv, interface);
+ g_ptr_array_add (argv, udn);
+ for (l = file_list ; l; l=l->next) {
+ gchar *file_path;
+
+ file_path = g_filename_from_uri (l->data, NULL, NULL);
+ g_ptr_array_add (argv, file_path);
+ }
+ g_ptr_array_add (argv, NULL);
+
+ ret = g_spawn_async (NULL, (gchar **) argv->pdata,
+ NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err);
+
+ if (ret == FALSE) {
+ g_warning ("Could not send files to MediaServer: %s",
+ err->message);
+ g_error_free (err);
+ }
+
+ g_ptr_array_free (argv, TRUE);
+ g_free (upload_cmd);
+ g_free (udn);
+
+ return ret;
+}
+
+static gboolean
+destroy (NstPlugin *plugin)
+{
+ gtk_widget_destroy (combobox);
+ g_object_unref (model);
+
+ g_object_unref (context_manager);
+
+ return TRUE;
+}
+
+static
+NstPluginInfo plugin_info = {
+ "folder-remote",
+ "upnp",
+ N_("UPnP Media Server"),
+ NULL,
+ CAJA_CAPS_NONE,
+ init,
+ get_contacts_widget,
+ NULL,
+ send_files,
+ destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+