nautilus-sendto r361 - in trunk: . src/plugins



Author: hadess
Date: Tue Oct 14 20:19:37 2008
New Revision: 361
URL: http://svn.gnome.org/viewvc/nautilus-sendto?rev=361&view=rev

Log:
2008-10-14  Zeeshan Ali (Khattak)  <zeeshanak gnome org>

	* configure.in:
	* src/plugins/Makefile.am:
	* src/plugins/upnp.c:
	Add a plugin based on GUPnP that upload files to UPnP Media Servers. It
	launches 'gupnp-upload' for the actual file transfer, which is a part of
	gupnp-tools package. (Closes: #553661)



Added:
   trunk/src/plugins/upnp.c
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/src/plugins/Makefile.am

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Tue Oct 14 20:19:37 2008
@@ -31,6 +31,7 @@
 NAUTILUS_EXTENSION=2.13.3
 DBUS_REQUIRED=1.0
 DBUS_GLIB_REQUIRED=0.60
+GUPNP_AV_REQUIRED=0.2.1
 
 AC_SUBST(GLIB_REQUIRED)
 AC_SUBST(GTK_REQUIRED)
@@ -42,6 +43,7 @@
 AC_SUBST(NAUTILUS_EXTENSION)
 AC_SUBST(BLUETOOTH_REQUIRED)
 AC_SUBST(DBUS_REQUIRED)
+AC_SUBST(GUPNP_AV_REQUIRED)
 
 PKG_CHECK_MODULES(NAUTILUS_SENDTO,\
 	 glib-2.0 >= $GLIB_REQUIRED                \
@@ -146,6 +148,23 @@
 
 AM_CONDITIONAL(HAVE_BLUETOOTH, test "x$enable_bluetooth" = "xyes")
 
+PKG_CHECK_MODULES(UPNP, gupnp-av-1.0 >= $GUPNP_AV_REQUIRED,
+	[
+	AC_SUBST(UPNP_CFLAGS)
+	AC_SUBST(UPNP_LIBS)
+	enable_upnp=yes
+	],
+	[
+	echo "Building without UPnP"
+	enable_upnp=no
+	]
+)
+
+dnl GUPnP AV if it's installed
+dnl -----------------------------------
+
+AM_CONDITIONAL(HAVE_UPNP, test "x$enable_upnp" = "xyes")
+
 GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
 
@@ -266,6 +285,12 @@
    echo "     Enable bluetooth plugin : NO"
 fi
 
+if test "x${enable_upnp}" = "xyes" ; then
+   echo " **  Enable UPnP plugin : YES"
+else
+   echo "     Enable UPnP plugin : NO"
+fi
+
 if test "x${enable_balsa}" = "xyes" ; then
    echo " **  Enable balsa plugin : YES"
 else

Modified: trunk/src/plugins/Makefile.am
==============================================================================
--- trunk/src/plugins/Makefile.am	(original)
+++ trunk/src/plugins/Makefile.am	Tue Oct 14 20:19:37 2008
@@ -12,6 +12,7 @@
 	$(GAIM_CFLAGS)				\
 	$(PIDGIN_CFLAGS)			\
 	$(BLUETOOTH_CFLAGS)			\
+	$(UPNP_CFLAGS)				\
 	$(DBUS_CFLAGS)				\
 	$(WARN_CFLAGS)
 
@@ -33,6 +34,12 @@
 BLUETOOTH_PLUGIN = 
 endif
 
+if HAVE_UPNP
+UPNP_PLUGIN = libnstupnp.la
+else
+UPNP_PLUGIN =
+endif
+
 if HAVE_EVOLUTION
 EVOLUTION_PLUGIN = libnstevolution.la
 else
@@ -76,7 +83,7 @@
 regenerate-built-sources:
 	EGGFILES="$(CLA_FILES) econtactentry-marshal.list" EGGDIR="$(CLADIR)" $(srcdir)/update-from-egg.sh || true
 
-plugin_LTLIBRARIES = $(EVOLUTION_PLUGIN) $(GAIM_PLUGIN) $(PIDGIN_PLUGIN) $(BLUETOOTH_PLUGIN) $(BALSA_PLUGIN) $(SYLPHEED_PLUGIN) $(THUNDERBIRD_PLUGIN) $(GAJIM_PLUGIN)
+plugin_LTLIBRARIES = $(EVOLUTION_PLUGIN) $(GAIM_PLUGIN) $(PIDGIN_PLUGIN) $(BLUETOOTH_PLUGIN) $(UPNP_PLUGIN) $(BALSA_PLUGIN) $(SYLPHEED_PLUGIN) $(THUNDERBIRD_PLUGIN) $(GAJIM_PLUGIN)
 
 libnstevolution_la_SOURCES = evolution.c $(CLA_FILES) $(MARSHALFILES)
 libnstevolution_la_LDFLAGS = -module -avoid-version
@@ -101,6 +108,10 @@
 libnstbluetooth_la_LDFLAGS = -module -avoid-version
 libnstbluetooth_la_LIBADD = $(BLUETOOTH_LIBS)
 
+libnstupnp_la_SOURCES = upnp.c
+libnstupnp_la_LDFLAGS = -module -avoid-version
+libnstupnp_la_LIBADD = $(UPNP_LIBS)
+
 libnstbalsa_la_SOURCES = balsa.c
 libnstbalsa_la_LDFLAGS = -module -avoid-version
 #libnstbalsa_la_LIBADD = $(BALSA_LIBS)

Added: trunk/src/plugins/upnp.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/upnp.c	Tue Oct 14 20:19:37 2008
@@ -0,0 +1,308 @@
+/* -*- 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) <zeeshanak gnome org>
+ *          Peter Enseleit <penseleit gmail com>
+ *          Roberto Majadas <telemaco openshine com>
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <libgupnp-av/gupnp-av.h>
+#include "../nautilus-sendto-plugin.h"
+
+#define MEDIA_SERVER "urn:schemas-upnp-org:device:MediaServer:*"
+#define CDS "urn:schemas-upnp-org:service:ContentDirectory"
+
+enum {
+	UDN_COL,
+	NAME_COL,
+	NUM_COLS
+};
+
+static GtkWidget *combobox;
+static GtkTreeModel *model;
+static GUPnPContext *context;
+static GUPnPControlPoint *cp;
+
+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;
+	GtkTreeIter iter;
+
+	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);
+
+	gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, -1,
+					   UDN_COL, udn,
+					   NAME_COL, name,
+					   -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;
+	const gchar *type;
+
+	type = gupnp_device_info_get_device_type (GUPNP_DEVICE_INFO (proxy));
+	if (!g_pattern_match_simple (MEDIA_SERVER, type)) {
+		/* We are only interested in MediaServer */
+		return;
+	}
+
+	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 gboolean
+init (NstPlugin *plugin)
+{
+	GtkListStore *store;
+	GtkCellRenderer *renderer;
+	GError *error;
+	char *upload_cmd;
+
+	upload_cmd = g_find_program_in_path ("gupnp-upload");
+	if (upload_cmd == NULL)
+		return FALSE;
+	g_free (upload_cmd);
+
+	error = NULL;
+	context = gupnp_context_new (NULL, NULL, 0, &error);
+	if (error != NULL) {
+		g_error (error->message);
+		g_error_free (error);
+
+		return FALSE;
+	}
+
+	cp = gupnp_control_point_new (context, "ssdp:all");
+
+	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);
+
+	combobox = gtk_combo_box_new ();
+
+	store = gtk_list_store_new (NUM_COLS,
+				    G_TYPE_STRING,   /* UDN  */
+				    G_TYPE_STRING);  /* Name */
+	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;
+	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, -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, 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 (cp);
+	g_object_unref (context);
+
+	return TRUE;
+}
+
+static
+NstPluginInfo plugin_info = {
+	"folder-remote",
+	"upnp",
+	N_("UPnP Media Server"),
+	FALSE,
+	init,
+	get_contacts_widget,
+	NULL,
+	send_files,
+	destroy
+};
+
+NST_INIT_PLUGIN (plugin_info)
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]