Index: configure.ac
===================================================================
--- configure.ac	(revision 5155)
+++ configure.ac	(working copy)
@@ -144,7 +144,32 @@
 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
+          if test "x$with_hal" = xyes && test "x$enable_hal" = xno; then
+	     AC_MSG_ERROR([iPod explicitly requested but HAL not found or too old])
+	  fi
+          if test "x$enable_hal" = xyes; then
+	     use_mtp=yes
+          fi
+	  AC_SUBST(MTP_CFLAGS)
+	  AC_SUBST(MTP_LIBS)
+	fi
+fi			  
+AM_CONDITIONAL(USE_MTP, test x"$use_mtp" = xyes)
+
+
 dnl ipod writing
 AC_ARG_ENABLE(ipod-writing,
 	      AC_HELP_STRING([--disable-ipod-writing],
@@ -945,6 +970,7 @@
 plugins/cd-recorder/Makefile
 plugins/daap/Makefile
 plugins/ipod/Makefile
+plugins/mtpdevice/Makefile
 plugins/iradio/Makefile
 plugins/lirc/Makefile
 plugins/lyrics/Makefile
@@ -1025,6 +1051,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 5155)
+++ plugins/Makefile.am	(working copy)
@@ -46,6 +46,10 @@
 SUBDIRS += daap
 endif
 
+if USE_MTP
+SUBDIRS += mtpdevice
+endif
+
 noinst_LTLIBRARIES = librbplugins.la
 
 librbplugins_la_SOURCES =				\
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/Makefile.am	2007-05-30 20:23:39.000000000 +0200
@@ -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)
+
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/mtpdevice.rb-plugin.desktop.in	2007-06-04 18:26:10.000000000 +0200
@@ -0,0 +1,8 @@
+[RB Plugin]
+Module=mtpdevice
+IAge=1
+_Name=Portable Players - MTP
+_Description=Support for MTP devices (show the content, transfer, play from device)
+Authors=Peter Grundström
+Copyright=Copyright © 2006,2007 Peter Grundström
+Website=http://www.rhythmbox.org
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/mtp-ui.xml	2007-05-30 20:23:39.000000000 +0200
@@ -0,0 +1,6 @@
+<ui>
+  <popup name="MTPSourcePopup">
+  	<menuitem name="MTPSrcPopupRename" action="MTPSourceRename"/>
+    <menuitem name="MTPSrcPopupEject" action="RemovableSourceEject"/>
+  </popup>
+</ui>
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-plugin.c	2007-06-04 18:12:07.000000000 +0200
@@ -0,0 +1,407 @@
+/*
+ * 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>
+#include <hal/libhal.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#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;
+	
+	LibHalContext *hal_context;
+	DBusConnection *dbus_connection;
+} 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);
+
+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);
+
+static RBSource* create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, const char *udi);
+/*static RBSource * create_source_cb (RBRemovableMediaManager *rmm,
+				    GnomeVFSVolume *volume,
+				    RBMtpPlugin *plugin);*/
+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 = NULL;
+	int num, i, ret;
+	char **devices;
+	LIBMTP_device_entry_t *entries;
+	int numentries;
+
+	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);
+
+	devices = libhal_get_all_devices (plugin->hal_context, &num, NULL);
+	ret = LIBMTP_Get_Supported_Devices_List (&entries, &numentries);
+	if (ret == 0) {
+		LIBMTP_device_entry_t *entry;
+		int  p;
+
+		for (p = 0; p < numentries; p++) {
+			entry = &entries[p];
+
+			for (i = 0; i < num; i++) {
+				int vendor_id;
+				int product_id;
+				const char *tmpudi;
+				
+				tmpudi = devices[i];
+				vendor_id = libhal_device_get_property_int (plugin->hal_context, tmpudi, "usb.vendor_id", NULL);
+				product_id = libhal_device_get_property_int (plugin->hal_context, tmpudi, "usb.product_id", NULL);
+				
+				if (entry->vendor_id == vendor_id && entry->product_id == product_id) {
+					LIBMTP_mtpdevice_t *device = LIBMTP_Get_First_Device ();
+					if (device != NULL) {
+						create_source_cb (plugin, device, tmpudi);
+					} else {
+						rb_debug ("error, could not get a hold on the device. Reset and Restart");
+					}
+				}
+			}
+		}
+	} else {
+		rb_debug ("Couldn't list mtp devices");
+	}
+	libhal_free_string_array (devices);
+
+	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)
+{
+	plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
+}
+
+static RBSource *
+create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *device, const char *udi)
+{
+	RBSource *source;
+	
+	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);
+		
+	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);
+}
+
+static void
+rb_mtp_plugin_device_added (LibHalContext *context, const char *udi)
+{
+	RBMtpPlugin *plugin = (RBMtpPlugin *) libhal_ctx_get_user_data (context);
+	LIBMTP_device_entry_t *entries;
+	int numentries;
+	int vendor_id;
+	int product_id;
+	int ret;
+
+	if (g_list_length (plugin->mtp_sources) > 0) {
+		rb_debug ("plugin only supports one device at the time right now.");
+		return;
+	}
+
+	vendor_id = libhal_device_get_property_int (context, udi, "usb.vendor_id",NULL);
+	product_id = libhal_device_get_property_int (context, udi, "usb.product_id",NULL);
+
+	ret = LIBMTP_Get_Supported_Devices_List (&entries, &numentries);
+	if (ret == 0) {
+		LIBMTP_device_entry_t *entry;
+		int i, p;
+
+		for (i = 0; i < numentries; i++) {
+			entry = &entries[i];
+	
+			if ((entry->vendor_id==vendor_id) && (entry->product_id == product_id)) { 
+				/*
+				 * FIXME:
+				 *
+				 * 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.
+				 */ 
+				rb_debug ("adding device source");
+				for (p = 0; p < 10; p++) {
+					LIBMTP_mtpdevice_t *device = LIBMTP_Get_First_Device ();
+					if (device != NULL) {
+						create_source_cb (plugin, device, 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);
+	GList *list = plugin->mtp_sources;
+	GList *tmp;
+
+	for (tmp = list; tmp != NULL; tmp = tmp->next) {
+		RBSource *source = (RBSource *)tmp->data;
+		if ((source != NULL) && (rb_mtp_source_is_udi (RB_MTP_SOURCE (source), udi) != 0)) {
+			rb_debug ("removing device %s, %p", udi, source);
+			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);
+	plugin->dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+	if (plugin->dbus_connection == NULL) {
+		rb_debug ("error: dbus_bus_get: %s: %s\n", error.name, error.message);
+		return;
+	}
+
+	dbus_connection_setup_with_g_main (plugin->dbus_connection, NULL);
+
+	rb_debug ("connected to: %s", dbus_bus_get_unique_name (plugin->dbus_connection));
+
+	plugin->hal_context = libhal_ctx_new ();
+	if (plugin->hal_context == NULL) {
+		return;
+	}
+	libhal_ctx_set_dbus_connection (plugin->hal_context, plugin->dbus_connection);
+
+	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);
+
+	if (!libhal_ctx_init(plugin->hal_context, &error)) {
+		rb_debug ("error: libhal_ctx_init: %s: %s\n", error.name, error.message);
+		dbus_error_free(&error);
+		return;
+	}
+	
+	dbus_error_free(&error);
+}
+
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-source.c	2007-06-06 01:49:42.000000000 +0200
@@ -0,0 +1,768 @@
+/*
+ *  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 <string.h>
+#include <gtk/gtktreeview.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 "rhythmdb.h"
+#include "eel-gconf-extensions.h"
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+#include "rb-plugin.h"
+#include "rb-removable-media-manager.h"
+#include "rb-static-playlist-source.h"
+#include "rb-util.h"
+#include "rb-refstring.h"
+#include "rhythmdb.h"
+#include "rb-encoder.h"
+
+#include "rb-mtp-source.h"
+
+static GObject *rb_mtp_source_constructor (GType type, 
+										   guint n_construct_properties,
+										   GObjectConstructParam *construct_properties);
+static void rb_mtp_source_finalize (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 gboolean impl_show_popup (RBSource *source);
+static GList* impl_get_ui_actions (RBSource *source);
+static GList* impl_copy (RBSource *source);
+
+static GList * impl_get_mime_types (RBRemovableMediaSource *source);
+static gboolean impl_track_added (RBRemovableMediaSource *source,
+								  RhythmDBEntry *entry,
+								  const char *dest,
+								  const char *mimetype);
+static char* impl_build_dest_uri (RBRemovableMediaSource *source,
+								  RhythmDBEntry *entry,
+								  const char *mimetype,
+								  const char *extension);
+
+static RhythmDB * get_db_for_source (RBMtpSource *source);
+
+typedef struct
+{
+	LIBMTP_mtpdevice_t *device;
+	GHashTable *entry_map;
+	char *udi;
+} RBMtpSourcePrivate;
+
+RB_PLUGIN_DEFINE_TYPE(RBMtpSource, 
+					  rb_mtp_source, 
+					  RB_TYPE_REMOVABLE_MEDIA_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);
+	RBRemovableMediaSourceClass *rms_class = RB_REMOVABLE_MEDIA_SOURCE_CLASS (klass);
+
+	object_class->constructor = rb_mtp_source_constructor;
+	object_class->finalize = rb_mtp_source_finalize;
+	
+	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_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;
+	
+	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
+	rms_class->impl_track_added = impl_track_added;
+	rms_class->impl_build_dest_uri = impl_build_dest_uri;
+	rms_class->impl_get_mime_types = impl_get_mime_types;
+
+	g_type_class_add_private (klass, sizeof (RBMtpSourcePrivate));
+}
+
+static void
+rb_mtp_source_name_changed_cb (RBMtpSource *source,
+							   GParamSpec *spec,
+							   gpointer data)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	char *name = NULL;
+	int ret = -1;
+
+	if (priv->device) {
+		g_object_get (source, "name", &name, NULL);
+		ret = LIBMTP_Set_Friendlyname (priv->device, name);
+		g_free (name);
+		if (ret != 0) {
+			rb_debug ("Set friendly name failed");
+		}
+	}
+}
+
+static void
+rb_mtp_source_init (RBMtpSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	priv->entry_map = g_hash_table_new (g_direct_hash,
+										g_direct_equal);
+
+	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 = NULL;
+	RBEntryView *tracks = NULL;
+	
+	gint size;
+	GtkIconTheme *theme = NULL;
+	GdkPixbuf *pixbuf = NULL;
+
+	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));
+	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_RATING, FALSE);
+	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
+
+	/* 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_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (rb_mtp_source_parent_class)->finalize (object);
+}
+
+RBBrowserSource *
+rb_mtp_source_new (RBShell *shell,
+				   LIBMTP_mtpdevice_t *device,
+				   const char *udi)
+{
+	RBMtpSource *source = NULL;
+	RhythmDBEntryType entry_type;
+	RhythmDB *db = NULL;
+	RBMtpSourcePrivate *priv = NULL;
+	char *name = NULL;
+	
+	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,
+						"volume", NULL,
+			  			"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 = g_strdup (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)
+{	
+	RhythmDBEntry *entry = NULL;
+	RhythmDBEntryType entry_type;
+	RhythmDB *db = NULL;
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	char *name = NULL;
+	
+	db = get_db_for_source(source);
+
+	/* Set URI */
+	g_object_get (G_OBJECT (source), "entry-type", &entry_type, 
+		      NULL);
+	name = g_strdup_printf ("rb-mtp-%i", track->item_id);
+
+	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, name);
+	
+	g_free(name);
+
+	if (entry == NULL) {
+		rb_debug ("cannot create entry %i", track->item_id);
+		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 (db));
+}
+
+static gboolean
+load_mtp_db_idle_cb (RBMtpSource* source)
+{
+	RhythmDB *db = NULL;
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	LIBMTP_track_t *tracks = NULL;
+  
+  	db = get_db_for_source(source);
+  
+  	g_assert (db != NULL);
+
+	tracks = LIBMTP_Get_Tracklisting (priv->device);
+	if (tracks == NULL) {
+		rb_debug ("No tracks");
+	} 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);
+	char* name = NULL;
+
+	if ((priv->device != NULL) && (priv->entry_map != NULL)) {
+		name = LIBMTP_Get_Friendlyname(priv->device);
+		g_object_set (RB_SOURCE (source), 
+					  "name", name, 
+					  NULL);
+		g_idle_add ((GSourceFunc)load_mtp_db_idle_cb, source);
+	}
+	g_free (name);
+}
+
+static gboolean
+destroy_entry_map_pair (gpointer key, gpointer value,gpointer data)
+{
+	RhythmDBEntry *entry = (RhythmDBEntry*)key;
+	LIBMTP_track_t *track = (LIBMTP_track_t*)value;
+	RhythmDB *db = (RhythmDB*)data;
+	
+	if (track != NULL) {
+		LIBMTP_destroy_track_t (track);
+	}
+									   
+	rhythmdb_entry_delete (db,entry);
+	
+	return TRUE;
+}
+
+static void
+impl_delete_thyself (RBSource *asource)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (asource);
+	RhythmDB *db = get_db_for_source(RB_MTP_SOURCE (asource));
+
+	if (priv->entry_map) {
+		g_hash_table_foreach_remove (priv->entry_map,destroy_entry_map_pair,db);
+		g_hash_table_destroy (priv->entry_map);
+		rhythmdb_commit (db);
+		priv->entry_map = NULL;
+ 	}
+	
+	g_object_unref(db);
+
+	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];
+
+	g_snprintf (tmp, sizeof(tmp), "%2i%2i%2iT0000.0",
+		    g_date_get_year(date),
+		    g_date_get_month(date),
+		    g_date_get_day(date));
+
+	return strdup(tmp);
+}
+
+/* This function is copied from pathutils.c in libmtp-0.1.5 */
+static LIBMTP_filetype_t
+mimetype_to_filetype (const char * mimetype)
+{
+	if (!strcasecmp (mimetype,"audio/mpeg") || !strcasecmp (mimetype,"application/x-id3")) {
+		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")) {
+		return LIBMTP_FILETYPE_WMA;
+	} else {
+		rb_debug ("\"%s\" is not a supported mimetype.", mimetype);
+		return LIBMTP_FILETYPE_UNKNOWN;
+	}
+}
+
+static const char*
+filetype_to_mimetype (LIBMTP_filetype_t filetype)
+{
+	if (filetype == LIBMTP_FILETYPE_WAV) {
+		return "audio/x-wav";
+	} else if (filetype == LIBMTP_FILETYPE_MP3) {
+		return "audio/mpeg";
+	} else if (filetype == LIBMTP_FILETYPE_WMA) {
+		return "audio/x-ms-wma";
+	} else if (filetype == LIBMTP_FILETYPE_OGG) {
+		return "application/ogg";
+	} else if (filetype == LIBMTP_FILETYPE_MP4) {
+		return "audio/mp4";
+	} else if (filetype == LIBMTP_FILETYPE_WMV) {
+		return "audio/x-ms-wmv";
+	}
+	return "";
+}
+
+static void
+impl_delete (RBSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	GList *sel = NULL;
+	GList *tem = NULL;
+	RBEntryView *tracks = NULL;
+	RhythmDB *db = NULL;
+	RhythmDBEntry *entry = NULL;
+	const gchar *uri = NULL;
+	LIBMTP_track_t *track = NULL;
+	int ret = -1;
+
+  	db = get_db_for_source (RB_MTP_SOURCE (source));
+
+	tracks = rb_source_get_entry_view (source);
+	sel = rb_entry_view_get_selected_entries (tracks);
+	for (tem = sel; tem != NULL; tem = tem->next) {
+
+		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) {
+			rb_debug ("Couldn't find track on mtp-device! (%s)\n", uri);
+			continue;
+		}
+		
+		ret = LIBMTP_Delete_Object (priv->device, track->item_id);
+		if (ret == 0) {
+			LIBMTP_destroy_track_t (track);
+			
+			g_hash_table_remove (priv->entry_map, entry);
+			
+			rhythmdb_entry_delete (db,entry);
+		} else {
+			rb_debug ("Delete track failed");
+		}
+	}
+	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)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	return (strcmp (udi, priv->udi) == 0);
+}
+
+/*Borowed from rb-playlist-source-recorder*/
+static gboolean
+check_dir_has_space (const char *path,
+					 guint64 bytes_needed)
+{
+	GnomeVFSResult result;
+	GnomeVFSURI *dir_uri = NULL;
+	GnomeVFSFileSize free_bytes;
+
+	if (!g_file_test (path, G_FILE_TEST_IS_DIR))
+		return FALSE;
+
+	dir_uri = gnome_vfs_uri_new (path);
+	if (dir_uri == NULL) {
+		rb_debug ("Cannot get free space at %s\n", 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) {
+		rb_debug ("Cannot get free space at %s\n", path);
+		return FALSE;
+	}
+
+	if (bytes_needed >= free_bytes) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean 
+rb_mtp_source_transfer_track_to_disk (LIBMTP_mtpdevice_t *device,
+									  LIBMTP_track_t *track,
+									  const char *uri)
+{
+	int ret = -1;
+	GnomeVFSURI* guri = NULL;
+
+	if (device == NULL || track == NULL || strlen(uri) == 0) {
+		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)) {
+		gnome_vfs_uri_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 TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+static char *
+rb_mtp_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
+{
+	RBMtpSourcePrivate *priv;
+	LIBMTP_track_t *track;
+	char *uri = NULL;
+	char *s = NULL;
+
+	priv = MTP_SOURCE_GET_PRIVATE (data);
+
+	track = g_hash_table_lookup (priv->entry_map, entry);
+	uri = g_strdup_printf ("%s/%s-%s", g_get_tmp_dir (),
+								  rhythmdb_entry_dup_string (entry,RHYTHMDB_PROP_ARTIST),
+								  rhythmdb_entry_dup_string (entry,RHYTHMDB_PROP_TITLE));
+
+	if (rb_mtp_source_transfer_track_to_disk (priv->device, track, uri) == TRUE) {
+		s = g_strdup_printf ("file://%s",uri);
+		g_free (uri);
+		return s;
+	} else {
+		g_free (uri);
+		return NULL;
+	}
+}
+
+static GList *
+impl_copy (RBSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (RB_MTP_SOURCE (source));
+	RhythmDB *db;
+	GList *selected_entries,*iter;
+	GList *copy_entries;
+	int ret = -1;
+	const char *uri = NULL;
+	RhythmDBEntry *entry = NULL;
+	LIBMTP_track_t *track = NULL;
+	
+	db = get_db_for_source (RB_MTP_SOURCE (source));
+
+	copy_entries = NULL;
+	selected_entries = rb_entry_view_get_selected_entries (rb_source_get_entry_view (source));
+	for (iter = selected_entries;
+	     iter != NULL;
+	     iter = g_list_next (iter)) {
+
+		entry = (RhythmDBEntry *)iter->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 == 0) {
+			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_list_free (selected_entries);
+	
+	g_object_unref (G_OBJECT (db));
+	
+	return copy_entries;
+}
+
+static RhythmDB *
+get_db_for_source (RBMtpSource *source)
+{
+	RBShell *shell = NULL;
+	RhythmDB *db = NULL;
+
+	g_object_get (source, "shell", &shell, NULL);
+	g_object_get (shell, "db", &db, NULL);
+	g_object_unref (shell);
+
+	return db;
+}
+
+static LIBMTP_track_t *
+transfer_track (RBMtpSource *source,
+				LIBMTP_mtpdevice_t *device,
+				RhythmDBEntry *entry,
+				const char *filename,
+				const char *mimetype)
+{
+	LIBMTP_track_t *trackmeta = LIBMTP_new_track_t();
+	GDate d;
+	
+	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_strdup(filename);
+
+	if (rhythmdb_entry_get_ulong (entry,RHYTHMDB_PROP_DATE) > 0) { /* Entries without a date returns 0, g_date_set_julian don't accept that */
+		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);
+	if (mimetype == NULL) {
+		trackmeta->filetype = mimetype_to_filetype (rhythmdb_entry_dup_string (entry,RHYTHMDB_PROP_MIMETYPE));
+	} else {
+		trackmeta->filetype = mimetype_to_filetype (mimetype);
+	}
+
+	if (LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL, 0) != 0) {
+		LIBMTP_destroy_track_t (trackmeta);
+		rb_debug ("Tracktransfer failed\n");
+		return NULL;
+	}
+	
+	return trackmeta;
+}
+
+static GList *
+impl_get_mime_types (RBRemovableMediaSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	guint16 *types = NULL;
+	guint16 n = 0;
+	int i = 0;
+	GList *list = NULL;
+	int ret = -1;
+
+	ret = LIBMTP_Get_Supported_Filetypes (priv->device, &types, &n);
+	if (ret == 0) {
+		for (i = 0; i < n; i++) {
+			list = g_list_prepend (list, g_strdup (filetype_to_mimetype (types[i])));
+		}
+	} else {
+		rb_debug ("Get supported filetypes failed");
+	}
+	return list;
+}
+
+static gboolean 
+impl_track_added (RBRemovableMediaSource *isource,
+								  RhythmDBEntry *entry,
+								  const char *dest,
+								  const char *mimetype)
+{
+	RBMtpSource *source = RB_MTP_SOURCE (isource);
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	char *filename = NULL;
+	LIBMTP_track_t *track = NULL;
+	
+	filename = g_filename_from_uri (dest, NULL, NULL);
+	track = transfer_track (source, priv->device, entry, filename, mimetype);
+	gnome_vfs_unlink (filename);
+	g_free (filename);
+	
+	if (track != NULL) {
+		/*request_artwork (isource, entry, song);*/
+		add_mtp_track_to_db (source, track);
+	}
+
+	return FALSE;
+}
+static char* 
+impl_build_dest_uri (RBRemovableMediaSource *source,
+								  RhythmDBEntry *entry,
+								  const char *mimetype,
+								  const char *extension)
+{
+	char* file = g_strdup_printf ("%s/%s-%s.%s", g_get_tmp_dir (),
+								  rhythmdb_entry_dup_string (entry,RHYTHMDB_PROP_ARTIST),
+								  rhythmdb_entry_dup_string (entry,RHYTHMDB_PROP_TITLE),
+								  extension);
+	char* uri = g_filename_to_uri (file,NULL,NULL);
+	g_free (file);
+	return uri;
+}
+
--- /dev/null	2007-04-11 19:44:01.000000000 +0200
+++ plugins/mtpdevice/rb-mtp-source.h	2007-06-01 16:35:35.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-removable-media-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
+{
+	RBRemovableMediaSource parent;
+} RBMtpSource;
+
+typedef struct
+{
+	RBRemovableMediaSourceClass parent;
+} RBMtpSourceClass;
+
+RBBrowserSource *	rb_mtp_source_new		(RBShell *shell, LIBMTP_mtpdevice_t *device, const 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 */
