Index: configure.ac
===================================================================
--- configure.ac	(revision 4938)
+++ configure.ac	(working copy)
@@ -123,7 +123,27 @@
 fi
 AM_CONDITIONAL(USE_IPOD, test x"$use_ipod" = xyes)
 
+dnl mtp support
 
+AC_ARG_WITH(mtp,
+            AC_HELP_STRING([--with-mtp],
+			   [Enable MTP support]),,
+	      with_mtp=auto)
+if test "x$with_mtp" != "xno"; then
+
+	PKG_CHECK_MODULES(MTP, libmtp, have_libmtp=yes, have_libmtp=no)
+	if test "x$have_libmtp" = "xno" -a "x$with_mtp" = "xyes"; then
+	  AC_MSG_ERROR([MTP explicitly requested but libmtp couldn't be found])
+	fi
+	if test "x$have_libmtp" = "xyes"; then
+	  use_mtp=yes
+	  AC_SUBST(MTP_CFLAGS)
+	  AC_SUBST(MTP_LIBS)
+	fi
+fi			  
+AM_CONDITIONAL(USE_MTP, test x"$use_mtp" = xyes)
+
+
 dnl gnome-keyring support
 
 AC_ARG_WITH(gnome-keyring,
@@ -952,6 +972,7 @@
 plugins/cd-recorder/Makefile
 plugins/daap/Makefile
 plugins/ipod/Makefile
+plugins/mtpdevice/Makefile
 plugins/iradio/Makefile
 plugins/lirc/Makefile
 plugins/lyrics/Makefile
@@ -1033,6 +1054,11 @@
 else
 	AC_MSG_NOTICE([   iPod integration disabled])
 fi
+if test x"$use_mtp" = xyes; then
+	AC_MSG_NOTICE([** MTP integration enabled])
+else
+	AC_MSG_NOTICE([   MTP integration disabled])
+fi
 if test x"$enable_cd_burning" != xno; then
 	AC_MSG_NOTICE([** CD burning support enabled])
 else
Index: plugins/Makefile.am
===================================================================
--- plugins/Makefile.am	(revision 4938)
+++ plugins/Makefile.am	(working copy)
@@ -47,6 +47,10 @@
 SUBDIRS += daap
 endif
 
+if USE_MTP
+SUBDIRS += mtpdevice
+endif
+
 noinst_LTLIBRARIES = librbplugins.la
 
 librbplugins_la_SOURCES =				\
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/Makefile.am	2007-03-08 23:48:30.000000000 +0100
@@ -0,0 +1,50 @@
+NULL =
+
+plugindir = $(PLUGINDIR)/mtpdevice
+plugin_LTLIBRARIES = libmtpdevice.la
+
+libmtpdevice_la_SOURCES = \
+	rb-mtp-plugin.c	\
+	rb-mtp-source.c	\
+	rb-mtp-source.h
+	
+libmtpdevice_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libmtpdevice_la_LIBADD = 					\
+	$(top_builddir)/lib/librb.la			\
+	$(HAL_LIBS)					\
+	$(MTP_LIBS)
+
+INCLUDES = 						\
+        -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DG_LOG_DOMAIN=\"Rhythmbox\"		 	\
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/backends				\
+	-I$(top_srcdir)/lib                        	\
+	-I$(top_srcdir)/metadata                       	\
+	-I$(top_srcdir)/player                       	\
+	-I$(top_srcdir)/rhythmdb                       	\
+	-I$(top_srcdir)/widgets                    	\
+	-I$(top_srcdir)/sources                    	\
+	-I$(top_srcdir)/podcast                    	\
+	-I$(top_srcdir)/plugins				\
+	-I$(top_srcdir)/shell				\
+	-DPIXMAP_DIR=\""$(datadir)/pixmaps"\"		\
+	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
+	-DDATADIR=\""$(datadir)"\"			\
+	$(RHYTHMBOX_CFLAGS)				\
+	$(WARN_CFLAGS)					\
+	$(HAL_CFLAGS)					\
+	$(MTP_CFLAGS)					\
+	-D_XOPEN_SOURCE -D_BSD_SOURCE
+
+plugin_in_files = mtpdevice.rb-plugin.desktop.in
+
+%.rb-plugin: %.rb-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+uixmldir = $(plugindir)
+uixml_DATA = mtp-ui.xml
+
+plugin_DATA = $(plugin_in_files:.rb-plugin.desktop.in=.rb-plugin)
+
+EXTRA_DIST = $(uixml_DATA) $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/mtpdevice.rb-plugin.desktop.in	2007-03-07 23:42:12.000000000 +0100
@@ -0,0 +1,8 @@
+[RB Plugin]
+Module=mtpdevice
+IAge=1
+_Name=MTP Support
+_Description=Adds mtp support to Rhythmbox so that it can show an mtp-device content
+Authors=Peter Grundström
+Copyright=Copyright © 2006,2007 Peter Grundström
+Website=http://www.rhythmbox.org
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/mtp-ui.xml	2007-03-07 23:46:30.000000000 +0100
@@ -0,0 +1,6 @@
+<ui>
+  <popup name="MTPSourcePopup">
+  	<menuitem name="MTPSrcPopupRename" action="MTPSourceRename"/>
+    <menuitem name="MTPSrcPopupEject" action="RemovableSourceEject"/>
+  </popup>
+</ui>
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-plugin.c	2007-03-12 20:27:39.000000000 +0100
@@ -0,0 +1,408 @@
+/*
+ * rb-mtp-plugin.c
+ * 
+ * Copyright (C) 2006 Peter Grundström <pete@openfestis.org>
+ *
+ * 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, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libmtp.h>
+#ifdef HAVE_HAL_0_5
+#include <hal/libhal.h>
+#include <dbus/dbus.h>
+#endif
+
+#include "rb-source.h"
+#include "rb-sourcelist.h"
+#include "rb-mtp-source.h"
+#include "rb-plugin.h"
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+#include "rb-util.h"
+#include "rb-shell.h"
+#include "rb-stock-icons.h"
+
+
+#define RB_TYPE_MTP_PLUGIN		(rb_mtp_plugin_get_type ())
+#define RB_MTP_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_MTP_PLUGIN, RBMtpPlugin))
+#define RB_MTP_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_IPOD_PLUGIN, RBMtpPluginClass))
+#define RB_IS_MTP_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_MTP_PLUGIN))
+#define RB_IS_MTP_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_MTP_PLUGIN))
+#define RB_MTP_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_MTP_PLUGIN, RBMtpPluginClass))
+
+typedef struct
+{
+	RBPlugin parent;
+
+	RBShell *shell;
+	GtkActionGroup *action_group;
+	guint ui_merge_id;
+
+	GList *mtp_sources;
+	
+	#ifdef HAVE_HAL_0_5
+	LibHalContext *hal_context;
+	DBusConnection *dbus_connection;
+	#endif
+} RBMtpPlugin;
+
+typedef struct
+{
+	RBPluginClass parent_class;
+} RBMtpPluginClass;
+
+
+G_MODULE_EXPORT GType register_rb_plugin (GTypeModule *module);
+GType	rb_mtp_plugin_get_type		(void) G_GNUC_CONST;
+
+static void rb_mtp_plugin_init (RBMtpPlugin *plugin);
+static void rb_mtp_plugin_finalize (GObject *object);
+static void impl_activate (RBPlugin *plugin, RBShell *shell);
+static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
+
+#ifdef HAVE_HAL_0_5
+
+static void rb_mtp_plugin_device_added(LibHalContext *context, const char *udi);
+static void rb_mtp_plugin_device_removed(LibHalContext *context, const char *udi);
+static void rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin);
+
+#endif
+
+static RBSource * create_source_cb (RBMtpPlugin *plugin,LIBMTP_mtpdevice_t *device, char *udi);
+
+static void  rb_mtp_plugin_eject  (GtkAction *action, RBMtpPlugin *plugin);
+static void  rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin);
+
+RB_PLUGIN_REGISTER(RBMtpPlugin, rb_mtp_plugin)
+
+static GtkActionEntry rb_mtp_plugin_actions [] =
+{
+	{ "RemovableSourceEject", GNOME_MEDIA_EJECT, N_("_Eject"), NULL,
+	  N_("Eject MTP-device"),
+	  G_CALLBACK (rb_mtp_plugin_eject) },
+	{ "MTPSourceRename", NULL, N_("_Rename"), NULL,
+	  N_("Rename MTP-device"),
+	  G_CALLBACK (rb_mtp_plugin_rename) }
+};
+
+static void
+rb_mtp_plugin_class_init (RBMtpPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBPluginClass *plugin_class = RB_PLUGIN_CLASS (klass);
+
+	object_class->finalize = rb_mtp_plugin_finalize;
+	
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+
+	/* register types used by the plugin */
+	RB_PLUGIN_REGISTER_TYPE(rb_mtp_source);
+}
+
+static void
+rb_mtp_plugin_init (RBMtpPlugin *plugin)
+{
+	rb_debug ("RBMtpPlugin initialising");
+	LIBMTP_Init();
+}
+
+static void
+rb_mtp_plugin_finalize (GObject *object)
+{
+	rb_debug ("RBMtpPlugin finalising");
+
+	G_OBJECT_CLASS (rb_mtp_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (RBPlugin *bplugin, RBShell *shell)
+{
+	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
+	GtkUIManager *uimanager = NULL;
+	char *file;
+
+	plugin->shell = shell;
+
+	g_object_get (G_OBJECT (shell),
+		      "ui-manager", &uimanager, 
+		      NULL);
+	
+	/*ui*/
+	
+	plugin->action_group = gtk_action_group_new ("MTPActions");
+	gtk_action_group_set_translation_domain (plugin->action_group,
+						 GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (plugin->action_group,
+				      rb_mtp_plugin_actions, G_N_ELEMENTS (rb_mtp_plugin_actions),
+				      plugin);
+	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
+	file = rb_plugin_find_file (bplugin, "mtp-ui.xml");
+	plugin->ui_merge_id = gtk_ui_manager_add_ui_from_file (uimanager,
+							       file,
+							       NULL);
+							       
+	/*device detection*/
+	
+	rb_mtp_plugin_setup_dbus_hal_connection(plugin);
+
+	uint16_t vid;
+    uint16_t pid;
+
+    LIBMTP_Detect_Descriptor(&vid, &pid);
+    
+	
+	#ifdef HAVE_HAL_0_5
+	int num,i;
+	char **devices = libhal_get_all_devices (plugin->hal_context, &num, NULL);
+	for (i = 0; i < num; i++)
+	{
+		char *tmpudi = devices[i];
+		
+		int vendor_id = libhal_device_get_property_int	(plugin->hal_context, tmpudi, "usb.vendor_id",NULL);
+		int product_id = libhal_device_get_property_int	(plugin->hal_context, tmpudi, "usb.product_id",NULL);
+		
+		if (vid == vendor_id && pid == product_id) {
+			LIBMTP_mtpdevice_t *device = LIBMTP_Get_First_Device();
+			if (device != NULL) {
+				create_source_cb(plugin,device,tmpudi);
+			} else {
+				g_print("Error: could not get a hold on the device. Reset and Restart");
+			}
+		}
+	}
+	#else
+	LIBMTP_mtpdevice_t *device = LIBMTP_Get_First_Device();
+	create_source_cb(plugin,device,NULL);
+	#endif
+
+	g_object_unref (G_OBJECT (uimanager));
+}
+
+static void
+impl_deactivate (RBPlugin *bplugin, RBShell *shell)
+{
+	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
+	GtkUIManager *uimanager = NULL;
+	DBusError error;
+
+	g_object_get (G_OBJECT (shell),
+		      "ui-manager", &uimanager, 
+		      NULL);
+
+	gtk_ui_manager_remove_ui (uimanager, plugin->ui_merge_id);
+	gtk_ui_manager_remove_action_group (uimanager, plugin->action_group);
+	
+	g_list_foreach (plugin->mtp_sources, (GFunc)rb_source_delete_thyself, NULL);
+	g_list_free (plugin->mtp_sources);
+	plugin->mtp_sources = NULL;
+	
+	dbus_error_init(&error);
+	libhal_ctx_shutdown(plugin->hal_context, &error);
+	libhal_ctx_free(plugin->hal_context);
+	dbus_connection_unref(plugin->dbus_connection);
+	dbus_error_free(&error);
+
+	g_object_unref (G_OBJECT (uimanager));
+}
+
+static void
+rb_mtp_plugin_source_deleted (RBmtpSource *source, RBMtpPlugin *plugin)
+{
+	g_print("rb_mtp_plugin_source_deleted");
+	plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
+}
+
+static RBSource *
+create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, char *udi)
+{
+	RBSource *source;
+	GtkUIManager *uimanager;
+	
+	source = RB_SOURCE (rb_mtp_source_new (plugin->shell,device,udi));
+
+	rb_shell_append_source (plugin->shell, source, NULL);
+	plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
+	
+	g_signal_connect_object (G_OBJECT (source),
+				"deleted", G_CALLBACK (rb_mtp_plugin_source_deleted),
+				plugin, 0);
+				
+	g_object_get (G_OBJECT (source),
+                   "ui-manager", &uimanager, 
+                    NULL);
+                   
+	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
+	
+	g_object_unref(uimanager);
+		
+	return source;
+}
+
+static void 
+rb_mtp_plugin_eject (GtkAction *action,
+			   RBMtpPlugin *plugin)
+{
+	RBSourceList *sourcelist = NULL;
+	RBSource *source = NULL;
+
+	g_object_get (G_OBJECT (plugin->shell),
+		      "selected-source", &source,
+		      NULL);
+	if ((source == NULL) || !RB_IS_MTP_SOURCE (source)) {
+		g_critical ("got MTPSourceEject action for non-mtp source");
+		if (source != NULL)
+			g_object_unref (source);
+		return;
+	}
+
+	g_object_get (plugin->shell, "sourcelist", &sourcelist, NULL);
+
+	rb_source_delete_thyself(source);
+
+	g_object_unref (sourcelist);
+	g_object_unref (source);
+}
+
+static void 
+rb_mtp_plugin_rename (GtkAction *action,
+			   RBMtpPlugin *plugin)
+{
+	RBSourceList *sourcelist = NULL;
+	RBSource *source = NULL;
+
+	g_object_get (G_OBJECT (plugin->shell),
+		      "selected-source", &source,
+		      NULL);
+	if ((source == NULL) || !RB_IS_MTP_SOURCE (source)) {
+		g_critical ("got MTPSourceEject action for non-mtp source");
+		if (source != NULL)
+			g_object_unref (source);
+		return;
+	}
+
+	g_object_get (plugin->shell, "sourcelist", &sourcelist, NULL);
+
+	rb_sourcelist_edit_source_name (sourcelist, source);
+
+
+	g_object_unref (sourcelist);
+	g_object_unref (source);
+}
+
+#ifdef HAVE_HAL_0_5
+
+static void
+rb_mtp_plugin_device_added(LibHalContext *context, const char *udi)
+{
+	g_print("\nHAL DEVICE ADD WORKS\n");
+	RBMtpPlugin *plugin = (RBMtpPlugin *) libhal_ctx_get_user_data(context);
+
+	if (g_list_length(plugin->mtp_sources) > 0) { /*only support one device at the time right now.*/
+		return;
+	}
+
+	LIBMTP_device_entry_t *entries;
+	int numentries;
+	int vendor_id = libhal_device_get_property_int (context, udi, "usb.vendor_id",NULL);
+	int product_id = libhal_device_get_property_int (context, udi, "usb.product_id",NULL);
+
+	int ret = LIBMTP_Get_Supported_Devices_List(&entries, &numentries);
+	if (ret == 0) {
+		int i;
+		for (i = 0; i < numentries; i++) {
+			LIBMTP_device_entry_t * entry = &entries[i];
+	
+			if ((entry->vendor_id==vendor_id) && (entry->product_id == product_id)) { 
+				/*It usualy takes a while for the device o set itself up.
+				Solving that by trying 10 times with some sleep in between.
+				There is probably a better solution, but this works.*/
+				int p;
+				for (p = 0;p < 10;p++) {
+					LIBMTP_mtpdevice_t *device = LIBMTP_Get_First_Device();
+					if (device != NULL) {
+						create_source_cb(plugin, device, strdup(udi));
+						break;
+					}
+					usleep(200000);
+				}
+			}
+    	}
+    }
+}
+
+static void
+rb_mtp_plugin_device_removed (LibHalContext *context, const char *udi)
+{
+	RBMtpPlugin *plugin = (RBMtpPlugin *) libhal_ctx_get_user_data(context);
+	g_print ("längden %i", g_list_length(plugin->mtp_sources));
+
+	GList* list = plugin->mtp_sources;
+	GList *tmp;
+	
+	for (tmp = list; tmp != NULL; tmp = tmp->next) {
+		RBSource *source = (RBSource *)tmp->data;
+		g_print("udi %s\n", udi);
+		g_print("source %i", (int)source);
+		if (source != NULL && rb_mtp_source_is_udi(RB_MTP_SOURCE(source),udi) != 0) {
+			g_print("that is the one\n");
+			plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
+			rb_source_delete_thyself(source);
+			break;
+		}
+	}
+}
+
+static void
+rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin)
+{
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (!(plugin->dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+		fprintf(stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message);
+		return;
+	}
+
+	fprintf(stderr, "connected to: %s\n", dbus_bus_get_unique_name(plugin->dbus_connection));
+	if (!(plugin->hal_context = libhal_ctx_new())) return;
+	if (!libhal_ctx_set_dbus_connection(plugin->hal_context, plugin->dbus_connection)) return;
+	if (!libhal_ctx_init(plugin->hal_context, &error)) {
+		fprintf(stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
+		return;
+	}
+	
+	libhal_ctx_set_user_data(plugin->hal_context, (void *)plugin);
+	libhal_ctx_set_device_added(plugin->hal_context,rb_mtp_plugin_device_added);
+	libhal_ctx_set_device_removed(plugin->hal_context,rb_mtp_plugin_device_removed);
+	libhal_device_property_watch_all(plugin->hal_context, &error);
+	
+	dbus_error_free(&error);
+}
+
+#endif
+
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-source.h	2006-06-16 12:11:04.000000000 +0200
@@ -0,0 +1,57 @@
+/*
+ *  arch-tag: Header for mtp source object
+ *
+ *  Copyright (C) 2006 Peter Grundström  <pete@openfestis.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_MTP_SOURCE_H
+#define __RB_MTP_SOURCE_H
+
+#include "rb-shell.h"
+#include "rb-browser-source.h"
+#include "rhythmdb.h"
+#include <libmtp.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_MTP_SOURCE         (rb_mtp_source_get_type ())
+#define RB_MTP_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_MTP_SOURCE, RBmtpSource))
+#define RB_MTP_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_MTP_SOURCE, RBmtpSourceClass))
+#define RB_IS_MTP_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_MTP_SOURCE))
+#define RB_IS_MTP_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_MTP_SOURCE))
+#define RB_MTP_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_MTP_SOURCE, RBmtpSourceClass))
+
+typedef struct
+{
+	RBBrowserSource parent;
+} RBmtpSource;
+
+typedef struct
+{
+	RBBrowserSourceClass parent;
+} RBmtpSourceClass;
+
+RBBrowserSource * rb_mtp_source_new (RBShell *shell,LIBMTP_mtpdevice_t *device, char *udi);
+GType		rb_mtp_source_get_type		(void);
+GType		rb_mtp_source_register_type (GTypeModule *module);
+
+gboolean rb_mtp_source_is_udi(RBmtpSource *source, const char *udi);
+
+G_END_DECLS
+
+#endif /* __RB_MTP_SOURCE_H */
--- /dev/null	2006-10-19 01:07:53.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-source.c	2007-03-12 20:25:04.000000000 +0100
@@ -0,0 +1,797 @@
+/*
+ *  arch-tag: Implementation of mtp source object
+ *
+ *  Copyright (C) 2006 Peter Grundström  <pete@openfestis.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include <config.h>
+
+
+#include <gtk/gtktreeview.h>
+#include <string.h>
+#include "rhythmdb.h"
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-volume.h>
+#include <libgnomevfs/gnome-vfs-volume-monitor.h>
+#include "eel-gconf-extensions.h"
+#include "rb-mtp-source.h"
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+#include "rb-plugin.h"
+#include "rb-static-playlist-source.h"
+#include "rb-util.h"
+#include "rb-refstring.h"
+#include "rhythmdb.h"
+#include "rb-encoder.h"
+
+static GObject *rb_mtp_source_constructor (GType type, 
+					    guint n_construct_properties,
+					    GObjectConstructParam *construct_properties);
+static void rb_mtp_source_dispose (GObject *object);
+
+static GObject *rb_mtp_source_constructor (GType type, guint n_construct_properties,
+			       GObjectConstructParam *construct_properties);
+static void rb_mtp_source_dispose (GObject *object);
+
+
+static void 	rb_mtp_source_load_tracks 			(RBmtpSource*);
+static gboolean rb_mtp_source_transfer_track_to_disk(LIBMTP_mtpdevice_t *device, LIBMTP_track_t *track, const char *uri);
+static char* 	rb_mtp_source_get_playback_uri		(RhythmDBEntry *entry, gpointer data);
+
+static void		impl_delete_thyself			(RBSource *source);
+static void		impl_delete					(RBSource *asource);
+static void		impl_paste					(RBSource *source, GList *entries);
+static gboolean impl_receive_drag			(RBSource *source, GtkSelectionData *data);
+static gboolean impl_show_popup				(RBSource *source);
+static GList*	impl_get_ui_actions			(RBSource *source);
+static GList*	impl_copy					(RBSource *source);
+
+
+typedef struct
+{
+	LIBMTP_mtpdevice_t *device;
+	GHashTable *entry_map;
+	char *udi;
+} RBmtpSourcePrivate;
+
+RB_PLUGIN_DEFINE_TYPE(RBmtpSource, 
+		      rb_mtp_source, 
+		      RB_TYPE_BROWSER_SOURCE)
+
+#define MTP_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_MTP_SOURCE, RBmtpSourcePrivate))
+
+static void
+rb_mtp_source_class_init (RBmtpSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+
+	object_class->constructor = rb_mtp_source_constructor;
+	object_class->dispose = rb_mtp_source_dispose;
+	
+	source_class->impl_can_rename			= (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_delete			= (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_paste			= (RBSourceFeatureFunc) rb_true_function;
+   	source_class->impl_can_move_to_trash	= (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_copy				= (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_cut				= (RBSourceFeatureFunc) rb_false_function;
+	
+	source_class->impl_paste 			= impl_paste;
+  	source_class->impl_receive_drag 	= impl_receive_drag;
+	source_class->impl_show_popup 		= impl_show_popup;
+	source_class->impl_get_ui_actions	= impl_get_ui_actions;
+	source_class->impl_delete_thyself 	= impl_delete_thyself;
+	source_class->impl_delete 			= impl_delete;
+	source_class->impl_copy 			= impl_copy;
+
+	g_type_class_add_private (klass, sizeof (RBmtpSourcePrivate));
+}
+
+static void
+rb_mtp_source_name_changed_cb (RBmtpSource *source, GParamSpec *spec,
+				gpointer data)
+{
+	char *name;
+	RBmtpSourcePrivate *priv;
+
+	priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	g_object_get (source, "name", &name, NULL);
+	LIBMTP_Set_Friendlyname(priv->device,name);
+	g_free (name);
+}
+
+static void
+rb_mtp_source_init (RBmtpSource *source)
+{
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	priv = G_TYPE_INSTANCE_GET_PRIVATE (source, 
+						    RB_TYPE_MTP_SOURCE, 
+						    RBmtpSourcePrivate);	
+	
+	g_signal_connect (G_OBJECT (source), "notify::name",
+			  (GCallback)rb_mtp_source_name_changed_cb, NULL);		    
+}
+
+static GObject *
+rb_mtp_source_constructor (GType type, guint n_construct_properties,
+			    GObjectConstructParam *construct_properties)
+{
+	RBmtpSource *source;
+	RBEntryView *tracks;
+	
+	gint size;
+	GtkIconTheme *theme;
+	GdkPixbuf *pixbuf;
+
+	source = RB_MTP_SOURCE (G_OBJECT_CLASS (rb_mtp_source_parent_class)->
+			constructor (type, n_construct_properties, construct_properties));
+	
+	tracks = rb_source_get_entry_view (RB_SOURCE (source));
+	
+	/* icon */
+	theme = gtk_icon_theme_get_default ();
+	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
+	pixbuf = gtk_icon_theme_load_icon (theme, "multimedia-player", size, 0, NULL);
+
+	rb_source_set_pixbuf (RB_SOURCE (source), pixbuf);
+	g_object_unref (pixbuf);
+
+	return G_OBJECT (source);
+}
+
+static void 
+rb_mtp_source_dispose (GObject *object)
+{
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (object);
+
+	if (priv->entry_map) {
+		g_hash_table_destroy (priv->entry_map);
+		priv->entry_map = NULL;
+ 	}
+
+	G_OBJECT_CLASS (rb_mtp_source_parent_class)->dispose (object);
+}
+
+RBBrowserSource *
+rb_mtp_source_new (RBShell *shell, LIBMTP_mtpdevice_t *device, char *udi)
+{
+	RBmtpSource *source;
+	RhythmDBEntryType entry_type;
+	RhythmDB *db;
+	RBmtpSourcePrivate *priv;
+	char *name;
+	
+	g_object_get (shell, "db", &db, NULL);
+	name = g_strdup_printf ("MTP-%s", LIBMTP_Get_Serialnumber(device));
+	entry_type =  rhythmdb_entry_register_type (db, name);
+	entry_type->save_to_disk = FALSE;
+	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
+	entry_type->get_playback_uri = (RhythmDBEntryStringFunc) rb_mtp_source_get_playback_uri;
+	
+	g_free (name);
+	g_object_unref (db);
+	
+	source = RB_MTP_SOURCE (g_object_new (RB_TYPE_MTP_SOURCE,
+						"entry-type", entry_type,
+			  			"shell",shell,
+			  			"visibility", TRUE,
+			  			"source-group", RB_SOURCE_GROUP_DEVICES,
+						NULL));
+						
+	entry_type->get_playback_uri_data = source;
+
+	priv = MTP_SOURCE_GET_PRIVATE (source);
+	priv->device = device;
+	priv->udi = udi;
+
+	rb_mtp_source_load_tracks (source);
+
+	rb_shell_register_entry_type_for_source (shell, RB_SOURCE(source), entry_type);
+
+	return RB_BROWSER_SOURCE (source);
+}
+
+static void 
+entry_set_string_prop (RhythmDB *db, RhythmDBEntry *entry,
+		       RhythmDBPropType propid, const char *str)
+{
+	GValue value = {0,};
+
+	if (!str)
+		str = _("Unknown");
+
+	g_value_init (&value, G_TYPE_STRING);
+	g_value_set_static_string (&value, str);
+	rhythmdb_entry_set (RHYTHMDB (db), entry, propid, &value);
+	g_value_unset (&value);
+}
+
+static void
+add_mtp_track_to_db (RBmtpSource *source, LIBMTP_track_t *track)
+{	
+	RBShell *shell;
+	RhythmDBEntry *entry;
+	RhythmDBEntryType entry_type;
+	RhythmDB *db;
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	
+	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+
+	/* Set URI */
+	g_object_get (G_OBJECT (source), "entry-type", &entry_type, 
+		      NULL);
+
+	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, track->filename);
+
+	if (entry == NULL) {
+		rb_debug ("cannot create entry %s", track->filename);
+		g_object_unref (G_OBJECT (shell));
+		g_object_unref (G_OBJECT (db));
+		return;
+	}
+
+	/* Set track number */
+	if (track->tracknumber != 0) {
+		GValue value = {0, };
+		g_value_init (&value, G_TYPE_ULONG);
+		g_value_set_ulong (&value, track->tracknumber);
+		rhythmdb_entry_set (RHYTHMDB (db), entry, 
+					       RHYTHMDB_PROP_TRACK_NUMBER, 
+					       &value);
+		g_value_unset (&value);
+	}
+		
+	/* Set length */
+	if (track->duration != 0) {
+		GValue value = {0, };
+		g_value_init (&value, G_TYPE_ULONG);
+		g_value_set_ulong (&value, track->duration/1000);
+		rhythmdb_entry_set (RHYTHMDB (db), entry, 
+					       RHYTHMDB_PROP_DURATION, 
+					       &value);
+		g_value_unset (&value);
+	}
+		
+	/* Set file size */
+	if (track->filesize != 0) {
+		GValue value = {0, };
+		g_value_init (&value, G_TYPE_UINT64);
+		g_value_set_uint64 (&value, track->filesize);
+		rhythmdb_entry_set (RHYTHMDB (db), entry, 
+					       RHYTHMDB_PROP_FILE_SIZE, 
+					       &value);
+		g_value_unset (&value);
+	}
+		
+	/* Set title */		
+	entry_set_string_prop (RHYTHMDB (db), entry, 
+			       RHYTHMDB_PROP_TITLE, track->title);
+		
+	/* Set album, artist and genre from MTP */
+	entry_set_string_prop (RHYTHMDB (db), entry, 
+			       RHYTHMDB_PROP_ARTIST, track->artist);
+		
+	entry_set_string_prop (RHYTHMDB (db), entry, 
+			       RHYTHMDB_PROP_ALBUM, track->album);
+		
+	entry_set_string_prop (RHYTHMDB (db), entry, 
+			       RHYTHMDB_PROP_GENRE, track->genre);
+
+
+	g_hash_table_insert (priv->entry_map, entry, track);
+
+	rhythmdb_commit (RHYTHMDB (db));
+
+	g_object_unref (G_OBJECT (shell));
+	g_object_unref (G_OBJECT (db));
+}
+
+static gboolean
+load_mtp_db_idle_cb (RBmtpSource* source)
+{
+	RBShell *shell;
+	RhythmDB *db;
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	LIBMTP_track_t *tracks;
+  
+  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	g_object_unref (G_OBJECT (shell));
+  
+  	g_assert (db != NULL);
+
+	tracks = LIBMTP_Get_Tracklisting(priv->device);
+	if (tracks == NULL) {
+		rb_debug("No tracks.\n");
+	} else {
+		LIBMTP_track_t *track, *tmp = NULL;
+		for (track = tracks; track != NULL; track = track->next) {
+			add_mtp_track_to_db (source, track);
+			tmp = track;
+		}
+	}
+
+	g_object_unref (G_OBJECT (db));
+	return FALSE;
+}
+
+static void
+rb_mtp_source_load_tracks (RBmtpSource *source)
+{
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	priv->entry_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+	if ((priv->device != NULL) && (priv->entry_map != NULL)) {
+		char* name = LIBMTP_Get_Friendlyname(priv->device);
+		g_object_set (RB_SOURCE (source), 
+			      "name", name, 
+			      NULL);
+		g_free(name);
+		g_idle_add ((GSourceFunc)load_mtp_db_idle_cb, source);
+	}
+}
+
+static void
+impl_delete_thyself (RBSource *asource)
+{
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (asource);
+	RBEntryView *tracks;
+	GList *tem;
+	
+	tracks = rb_source_get_entry_view (asource);
+	rb_entry_view_select_all(tracks);
+	tem = rb_entry_view_get_selected_entries (tracks);
+	for (; tem != NULL; tem = tem->next) {
+		RhythmDBEntry *entry;
+		LIBMTP_track_t *track;
+
+		entry = (RhythmDBEntry *)tem->data;
+		track = g_hash_table_lookup (priv->entry_map, entry);
+		if (track == NULL)
+			continue;
+
+		LIBMTP_destroy_track_t(track);
+
+		g_hash_table_remove (priv->entry_map, entry);
+	}
+	g_list_free (tem);
+
+	LIBMTP_Release_Device(priv->device);
+	priv->device = NULL;
+	
+	if(priv->udi != NULL) {
+		g_free(priv->udi);
+		priv->udi = NULL;
+	}
+
+	RB_SOURCE_CLASS (rb_mtp_source_parent_class)->impl_delete_thyself (asource);
+}
+
+static char *
+gdate_to_char (GDate* date)
+{
+	char tmp[80];
+    snprintf(tmp, sizeof(tmp)-1, "%2i%2i%2iT0000.0", g_date_get_year(date),g_date_get_month(date),g_date_get_day(date));
+    tmp[sizeof(tmp)-1] = '\0';
+    return strdup(tmp);
+}
+
+static LIBMTP_filetype_t
+rb_mtp_filetype_from_mimetype (const char *mimetype)
+{
+	if (!strcasecmp(mimetype,"audio/mpeg") || !strcasecmp(mimetype,"application/x-id3") || !strcasecmp(mimetype,"application/octet-stream")) {
+		return LIBMTP_FILETYPE_MP3;
+	}  else if (!strcasecmp(mimetype,"audio/x-wav")) {
+		return LIBMTP_FILETYPE_WAV;
+	} else if (!strcasecmp(mimetype,"application/ogg")) {
+		return LIBMTP_FILETYPE_OGG;
+	} else if (!strcasecmp(mimetype,"audio/mp4")) {
+		return LIBMTP_FILETYPE_MP4;
+	} else if (	!strcasecmp(mimetype,"audio/x-ms-wma") || 
+				!strcasecmp(mimetype,"audio/x-ms-asf") || 
+				!strcasecmp(mimetype,"video/x-ms-asf")) {
+		return LIBMTP_FILETYPE_WMA;
+	}
+	return LIBMTP_FILETYPE_UNKNOWN;
+}
+
+
+static gboolean
+rb_mtp_mimetype_is_supported(LIBMTP_mtpdevice_t *device,const char *mimetype)
+{
+	LIBMTP_filetype_t mime = rb_mtp_filetype_from_mimetype (mimetype);
+
+	uint16_t *types;
+	uint16_t n;
+	LIBMTP_Get_Supported_Filetypes(device, &types, &n);
+	int i;
+	for (i = 0; i < n;i++)
+	{
+		if (mime == types[i])
+			return TRUE;
+	}
+	return FALSE;
+}
+
+
+static LIBMTP_track_t *
+transfer_track (LIBMTP_mtpdevice_t *device, RhythmDBEntry *entry, const char *filename, const char *mimetype)
+{
+	LIBMTP_track_t *trackmeta = LIBMTP_new_track_t();
+	
+	trackmeta->title	= rhythmdb_entry_dup_string(entry,RHYTHMDB_PROP_TITLE);
+    trackmeta->album	= rhythmdb_entry_dup_string(entry,RHYTHMDB_PROP_ALBUM);
+	trackmeta->artist	= rhythmdb_entry_dup_string(entry,RHYTHMDB_PROP_ARTIST);
+	trackmeta->genre	= rhythmdb_entry_dup_string(entry,RHYTHMDB_PROP_GENRE);
+	trackmeta->filename = g_path_get_basename (gnome_vfs_get_local_path_from_uri (rhythmdb_entry_get_string(entry,RHYTHMDB_PROP_LOCATION)));
+	GDate d;
+	g_date_set_julian(&d,rhythmdb_entry_get_ulong(entry,RHYTHMDB_PROP_DATE));
+	trackmeta->date	= gdate_to_char(&d);
+	trackmeta->tracknumber = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
+	trackmeta->duration = rhythmdb_entry_get_ulong(entry,RHYTHMDB_PROP_DURATION) * 1000;
+	trackmeta->filesize = rhythmdb_entry_get_uint64(entry,RHYTHMDB_PROP_FILE_SIZE);
+	trackmeta->filetype = rb_mtp_mimetype_is_supported(device,mimetype);
+
+	if (!LIBMTP_Send_Track_From_File(device, filename, trackmeta, NULL, NULL, 0))
+	{
+		free(trackmeta);
+		return 0;
+	}
+	
+	return trackmeta;
+}
+
+
+static void
+add_track_to_mtp (RBSource *asource, RhythmDBEntry *entry)
+{
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (asource);
+	RBShell *shell;
+	RhythmDB *db;
+	LIBMTP_track_t *trackmeta;
+	const char *mimetype = rhythmdb_entry_get_string(entry,RHYTHMDB_PROP_MIMETYPE);
+	
+	if (!rb_mtp_mimetype_is_supported(priv->device,mimetype))
+	{
+		
+		g_warning ("Mimetype not supported");
+		
+		return;
+	}
+	
+	g_object_get (G_OBJECT (asource), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	
+  	trackmeta = LIBMTP_new_track_t();
+	
+	if (transfer_track(priv->device,entry,gnome_vfs_get_local_path_from_uri(rhythmdb_entry_get_string(entry,RHYTHMDB_PROP_LOCATION)),mimetype))
+		add_mtp_track_to_db (RB_MTP_SOURCE(asource), trackmeta);
+		
+	g_object_unref (G_OBJECT (shell));
+	g_object_unref (G_OBJECT (db));
+}
+
+static void
+impl_paste (RBSource *asource, GList *entries)
+{
+	GList *l;
+	RBShell *shell;
+	RhythmDB *db;
+	RhythmDBEntryType our_entry_type;
+	
+	g_object_get (asource,
+		      "entry-type", &our_entry_type,
+		      NULL);
+  
+  	g_object_get (G_OBJECT (asource), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+
+	for (l = entries; l != NULL; l = l->next) {
+		RhythmDBEntry *entry;
+		RhythmDBEntryType entry_type;
+		entry = (RhythmDBEntry *)l->data;
+		entry_type = rhythmdb_entry_get_entry_type (entry);
+		
+		if (entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
+			if (rhythmdb_entry_get_ulong(entry,RHYTHMDB_PROP_STATUS) == RHYTHMDB_PODCAST_STATUS_COMPLETE) {
+				entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_LOCATION, rhythmdb_entry_dup_string(entry,RHYTHMDB_PROP_MOUNTPOINT));
+			} else {
+				/*FIXME: error dialog here*/
+				goto impl_paste_end;
+			}
+		} else {
+		
+			if (entry_type == our_entry_type ||
+			    entry_type->category != RHYTHMDB_ENTRY_NORMAL) {
+				goto impl_paste_end;
+			}
+
+			/* see if the responsible source lets us copy */
+			if (!rb_source_can_copy (rb_shell_get_source_by_entry_type (shell, entry_type))) {
+				goto impl_paste_end;
+			}	
+		}
+		
+		add_track_to_mtp(asource,entry);
+		
+impl_paste_end:
+		if (entry_type)
+			g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	}
+	
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, our_entry_type);
+	g_object_unref (G_OBJECT (shell));
+	g_object_unref (G_OBJECT (db));
+}
+
+static gboolean
+impl_receive_drag (RBSource *asource, GtkSelectionData *data)
+{
+	RBBrowserSource *source = RB_BROWSER_SOURCE (asource);
+	GList *list, *i;
+	GList *entries = NULL;
+	RBShell *shell;
+	RhythmDB *db;
+
+	rb_debug ("parsing uri list");
+	list = rb_uri_list_parse ((const char *) data->data);
+
+  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	g_object_unref (G_OBJECT (shell));
+
+	for (i = list; i != NULL; i = g_list_next (i)) {
+		if (i->data != NULL) {
+			gint id = atoi((const char *)i->data);
+			RhythmDBEntry *entry;
+
+			entry = rhythmdb_entry_lookup_by_id (db, id);
+
+			if (entry == NULL) {
+				/* add to the library */
+				g_print ("Where does that come from?\n");
+			} else {
+				/* add to list of entries to copy */
+				entries = g_list_prepend (entries, entry);
+			}
+		}
+	}
+	g_object_unref (db);
+	g_list_free (list);
+
+	if (entries) {
+		entries = g_list_reverse (entries);
+		if (rb_source_can_paste (asource)) {
+			rb_source_paste (asource, entries);
+		}
+		g_list_free (entries);
+	}
+
+	return TRUE;
+}
+
+static void
+impl_delete (RBSource *asource)
+{
+	GList *sel, *tem;
+	RBEntryView *tracks;
+	RBShell *shell;
+	RhythmDB *db;
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (asource);
+	RBmtpSource *source = RB_MTP_SOURCE (asource);
+	LIBMTP_mtpdevice_t *device = priv->device;
+
+  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	g_object_unref (G_OBJECT (shell));
+
+	tracks = rb_source_get_entry_view (RB_SOURCE (asource));
+	sel = rb_entry_view_get_selected_entries (tracks);
+	for (tem = sel; tem != NULL; tem = tem->next) {
+		RhythmDBEntry *entry;
+		const gchar *uri;
+		LIBMTP_track_t *track;
+
+		entry = (RhythmDBEntry *)tem->data;
+		uri = rhythmdb_entry_get_string (entry, 
+						 RHYTHMDB_PROP_LOCATION);
+		track = g_hash_table_lookup (priv->entry_map, entry);
+		if (track == NULL) {
+			g_warning ("Couldn't find track on mtp-device! (%s)", uri);
+			continue;
+		}
+		LIBMTP_Delete_Object(device, track->item_id);
+		LIBMTP_destroy_track_t(track);
+
+		g_hash_table_remove (priv->entry_map, entry);
+		
+		rhythmdb_entry_delete(db,entry);
+		rhythmdb_commit (db);
+	}
+
+	g_list_free (sel);
+	g_list_free (tem);
+}
+
+static gboolean
+impl_show_popup (RBSource *source)
+{
+	_rb_source_show_popup (RB_SOURCE (source), "/MTPSourcePopup");
+	return TRUE;
+}
+
+static GList *
+impl_get_ui_actions (RBSource *source)
+{
+	GList *actions = NULL;
+
+	actions = g_list_prepend (actions, g_strdup ("RemovableSourceEject"));
+
+	return actions;
+}
+
+gboolean
+rb_mtp_source_is_udi(RBmtpSource *source, const char *udi)
+{
+	if (source == NULL) {
+		return FALSE;
+	}
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	if (priv == NULL) {
+		return FALSE;
+	}
+	if (!strcmp(udi,priv->udi)) {
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/*Borowed from rb-playlist-source-recorder*/
+static gboolean
+check_dir_has_space (const char *path,
+                     guint64     bytes_needed)
+{
+    GnomeVFSResult   result     = GNOME_VFS_OK;
+    GnomeVFSURI     *dir_uri    = NULL;
+    GnomeVFSFileSize free_bytes = 0;
+
+    if (!g_file_test (path, G_FILE_TEST_IS_DIR))
+            return FALSE;
+
+    dir_uri = gnome_vfs_uri_new (path);
+	if (dir_uri == NULL) {
+		g_warning (_("Cannot get free space at %s"), path);
+		return FALSE;
+	}
+
+    result = gnome_vfs_get_volume_free_space (dir_uri, &free_bytes);
+
+    gnome_vfs_uri_unref (dir_uri);
+
+    if (result != GNOME_VFS_OK) {
+            g_warning (_("Cannot get free space at %s"), path);
+            return FALSE;
+    }
+
+    if (bytes_needed >= free_bytes)
+            return FALSE;
+
+    return TRUE;
+}
+
+/*FIXME: should return an enum so we can specifi what kind of error we are dealing with (out of memory etc..)*/
+static gboolean 
+rb_mtp_source_transfer_track_to_disk(LIBMTP_mtpdevice_t *device, LIBMTP_track_t *track, const char *uri)
+{
+	int ret;
+	GnomeVFSURI* guri;
+	if (device == NULL || track == NULL || uri == "") {
+		return FALSE;
+	}
+	guri = gnome_vfs_uri_new(uri);
+	if (!check_dir_has_space (gnome_vfs_uri_get_path(gnome_vfs_uri_get_parent (guri)), track->filesize)) {
+		g_object_unref (guri);
+		return FALSE;
+	}
+	gnome_vfs_uri_unref (guri);
+
+	ret = LIBMTP_Get_Track_To_File(device, track->item_id, uri, NULL, NULL);
+	
+    if(ret != 0) {
+		return FALSE;
+	}
+	else {
+		return TRUE;
+	}
+	
+}
+
+static char *
+rb_mtp_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
+{
+	const char *uri;
+	RBmtpSource *source;
+	RBmtpSourcePrivate *priv;
+	LIBMTP_track_t *track;
+	gboolean ret;
+
+	if (entry == NULL) {
+		rb_debug ("NULL entry");
+		return NULL;
+	}
+
+	source = RB_MTP_SOURCE (data);
+	if (source == NULL) {
+		rb_debug ("NULL source pointer");
+		return NULL;
+	}
+	priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	track = g_hash_table_lookup (priv->entry_map, entry);
+	
+	uri = g_strdup_printf ("%s/%s",g_get_tmp_dir (), track->filename);
+	ret = rb_mtp_source_transfer_track_to_disk(priv->device,track,uri);
+	
+    if(ret != TRUE) {
+		return g_strdup("");
+	} else {
+		return g_strdup_printf("file://%s",uri);
+	}
+}
+
+static GList *
+impl_copy (RBSource *source)
+{
+	RBShell *shell;
+	RhythmDB *db;
+	RBmtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (RB_MTP_SOURCE (source));
+	GList *selected_entries = rb_entry_view_get_selected_entries (rb_source_get_entry_view (source));
+	GList *copy_entries = NULL;
+	
+	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+	
+	for (; selected_entries != NULL; selected_entries = selected_entries->next) {
+		int ret;
+		const char *uri;
+		RhythmDBEntry *entry = NULL;
+		LIBMTP_track_t *track = NULL;
+
+		entry = (RhythmDBEntry *)selected_entries->data;
+		track = g_hash_table_lookup (priv->entry_map, entry);
+		if (track == NULL)
+			continue;
+			
+		uri = g_strdup_printf ("%s/%s",g_get_tmp_dir (), track->filename);
+		ret = rb_mtp_source_transfer_track_to_disk(priv->device,track,uri);
+	
+		if(ret == TRUE) {
+			entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_LOCATION, g_strdup_printf("file://%s",uri));
+			copy_entries = g_list_prepend (copy_entries, entry);
+		}
+	}
+	
+	g_object_unref (G_OBJECT (shell));
+	g_object_unref (G_OBJECT (db));
+	
+	return copy_entries;
+}
+
