? attachment.cgi?id=61913
? attachment.cgi?id=62634
? attachment.cgi?id=64528
? b
? backends.diff
? entry-type.diff
? ipod.diff
? rediff.diff
? backends/.deps
? backends/.libs
? backends/librbbackends.la
? backends/rb-encoder.lo
? backends/gstreamer/.deps
? backends/gstreamer/.libs
? backends/gstreamer/librbbackendsgstreamer.la
? backends/gstreamer/rb-encoder-gst.lo
? bindings/python/.deps
? bindings/python/.libs
? bindings/python/rb.la
? bindings/python/rb_la-override_common.lo
? bindings/python/rb_la-rb.lo
? bindings/python/rb_la-rhythmdb.lo
? daapsharing/.deps
? daapsharing/.libs
? daapsharing/libdaapsharing.la
? daapsharing/rb-daap-connection.lo
? daapsharing/rb-daap-dialog.lo
? daapsharing/rb-daap-marshal.lo
? daapsharing/rb-daap-mdns-browser-avahi.lo
? daapsharing/rb-daap-mdns-publisher-avahi.lo
? daapsharing/rb-daap-share.lo
? daapsharing/rb-daap-sharing.lo
? daapsharing/rb-daap-src.lo
? daapsharing/rb-daap-structure.lo
? iradio/librbiradio.la
? iradio/rb-new-station-dialog.lo
? iradio/rb-station-properties-dialog.lo
? lib/librb.la
? lib/md5.lo
? lib/rb-cut-and-paste-code.lo
? lib/rb-debug.lo
? lib/rb-file-helpers.lo
? lib/rb-glade-helpers.lo
? lib/rb-marshal.lo
? lib/rb-proxy-config.lo
? lib/rb-stock-icons.lo
? lib/rb-tree-dnd.lo
? lib/rb-util.lo
? metadata/.deps
? metadata/.libs
? metadata/librbmetadata.la
? metadata/librbmetadatasvc.la
? metadata/rb-metadata-common.lo
? metadata/rb-metadata-dbus-client.lo
? metadata/rb-metadata-dbus.lo
? metadata/rb-metadata-gst.lo
? metadata/sj-error.lo
? metadata/sj-metadata-marshal.lo
? metadata/sj-metadata-musicbrainz.lo
? metadata/sj-metadata.lo
? metadata/sj-structures.lo
? player/.deps
? player/.libs
? player/librbplayer.la
? player/rb-player-gst.lo
? player/rb-recorder-gst.lo
? plugins/.deps
? plugins/.libs
? plugins/librbplugins.la
? plugins/rb-module.lo
? plugins/rb-plugin-manager.lo
? plugins/rb-plugin.lo
? plugins/rb-plugins-engine.lo
? plugins/rb-python-module.lo
? plugins/rb-python-plugin.lo
? plugins/audioscrobbler/.deps
? plugins/audioscrobbler/.libs
? plugins/audioscrobbler/libaudioscrobbler.la
? plugins/audioscrobbler/rb-audioscrobbler-plugin.lo
? plugins/audioscrobbler/rb-audioscrobbler.lo
? plugins/ipod/.deps
? plugins/ipod/.libs
? plugins/ipod/libipod.la
? plugins/ipod/rb-ipod-manager.c
? plugins/ipod/rb-ipod-manager.h
? plugins/ipod/rb-ipod-playlist-source.c
? plugins/ipod/rb-ipod-playlist-source.h
? plugins/ipod/rb-ipod-plugin.lo
? plugins/ipod/rb-ipod-source.lo
? plugins/ipod/rb-ipod.c
? plugins/ipod/rb-ipod.h
? plugins/lirc/.deps
? plugins/lirc/.libs
? plugins/lirc/librblirc.la
? plugins/lirc/rb-lirc-plugin.lo
? plugins/sample/.deps
? plugins/sample/.libs
? plugins/sample/libsample.la
? plugins/sample/rb-sample-plugin.lo
? po/.intltool-merge-cache
? podcast/.deps
? podcast/.libs
? podcast/librbpodcast.la
? podcast/rb-feed-podcast-properties-dialog.lo
? podcast/rb-new-podcast-dialog.lo
? podcast/rb-podcast-manager.lo
? podcast/rb-podcast-marshal.lo
? podcast/rb-podcast-parse.lo
? podcast/rb-podcast-properties-dialog.lo
? remote/.deps
? remote/.libs
? remote/librbremote.la
? remote/rb-remote-client-proxy.lo
? remote/rb-remote-common.lo
? remote/rb-remote-proxy.lo
? remote/bonobo/.deps
? remote/bonobo/.libs
? remote/bonobo/Rhythmbox-common.lo
? remote/bonobo/Rhythmbox-skels.lo
? remote/bonobo/Rhythmbox-stubs.lo
? remote/bonobo/libmain.lo
? remote/bonobo/librb-nautilus-context-menu.la
? remote/bonobo/librbbonobo.la
? remote/bonobo/librbcorba.la
? remote/bonobo/rb-nautilus-context-menu.lo
? remote/bonobo/rb-remote-bonobo.lo
? rhythmdb/.deps
? rhythmdb/.libs
? rhythmdb/gsequence.lo
? rhythmdb/librhythmdb.la
? rhythmdb/rb-refstring.lo
? rhythmdb/rhythmdb-property-model.lo
? rhythmdb/rhythmdb-query-model.lo
? rhythmdb/rhythmdb-query-results.lo
? rhythmdb/rhythmdb-tree.lo
? rhythmdb/rhythmdb.lo
? shell/.deps
? shell/.libs
? shell/librbshell.la
? shell/rb-history.lo
? shell/rb-play-order-linear-loop.lo
? shell/rb-play-order-linear.lo
? shell/rb-play-order-queue.lo
? shell/rb-play-order-random-by-age-and-rating.lo
? shell/rb-play-order-random-by-age.lo
? shell/rb-play-order-random-by-rating.lo
? shell/rb-play-order-random-equal-weights.lo
? shell/rb-play-order-random.lo
? shell/rb-play-order-shuffle.lo
? shell/rb-play-order.lo
? shell/rb-playlist-manager.lo
? shell/rb-removable-media-manager.lo
? shell/rb-shell-clipboard.lo
? shell/rb-shell-player.lo
? shell/rb-shell-preferences.lo
? shell/rb-shell.lo
? shell/rb-source-header.lo
? shell/rb-statusbar.lo
? shell/rb-tray-icon.lo
? sources/.deps
? sources/.libs
? sources/libsources.la
? sources/libsourcesimpl.la
? sources/rb-audiocd-source.lo
? sources/rb-auto-playlist-source.lo
? sources/rb-browser-source.lo
? sources/rb-daap-source.lo
? sources/rb-generic-player-source.lo
? sources/rb-import-errors-source.lo
? sources/rb-ipod-source.lo
? sources/rb-iradio-source.lo
? sources/rb-library-source.lo
? sources/rb-missing-files-source.lo
? sources/rb-nokia770-source.lo
? sources/rb-play-queue-source.lo
? sources/rb-playlist-source-recorder.lo
? sources/rb-playlist-source.lo
? sources/rb-podcast-source.lo
? sources/rb-psp-source.lo
? sources/rb-removable-media-source.lo
? sources/rb-source.lo
? sources/rb-sourcelist-model.lo
? sources/rb-sourcelist.lo
? sources/rb-static-playlist-source.lo
? tests/test-rb-ipod-manager.c
? widgets/.deps
? widgets/.libs
? widgets/bacon-volume.lo
? widgets/disclosure-widget.lo
? widgets/eel-gconf-extensions.lo
? widgets/eggnotificationbubble.lo
? widgets/eggtrayicon.lo
? widgets/librbwidgets.la
? widgets/rb-cell-renderer-pixbuf.lo
? widgets/rb-cell-renderer-rating.lo
? widgets/rb-dialog.lo
? widgets/rb-druid.lo
? widgets/rb-entry-view.lo
? widgets/rb-header.lo
? widgets/rb-library-browser.lo
? widgets/rb-property-view.lo
? widgets/rb-query-creator-properties.lo
? widgets/rb-query-creator.lo
? widgets/rb-rating-helper.lo
? widgets/rb-rating.lo
? widgets/rb-search-entry.lo
? widgets/rb-song-display-box.lo
? widgets/rb-song-info.lo
? widgets/libsexy/.deps
? widgets/libsexy/.libs
? widgets/libsexy/libsexy.la
? widgets/libsexy/sexy-icon-entry.lo
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.235
diff -u -b -B -r1.235 configure.ac
--- configure.ac	9 May 2006 12:32:17 -0000	1.235
+++ configure.ac	9 May 2006 16:21:16 -0000
@@ -886,7 +886,8 @@
 
 AM_CONDITIONAL([ENABLE_PYTHON],[test "x$enable_python" = "xyes"])
 
-
+AM_PATH_CHECK([], have_check=yes, have_check=no)
+AM_CONDITIONAL([HAVE_CHECK],[test "x$have_check" = "xyes"])
 
 dnl ================================================================
 dnl end-game
Index: data/ui/ipod-ui.xml
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/ui/ipod-ui.xml,v
retrieving revision 1.1
diff -u -b -B -r1.1 ipod-ui.xml
--- data/ui/ipod-ui.xml	16 Apr 2006 10:24:04 -0000	1.1
+++ data/ui/ipod-ui.xml	9 May 2006 16:21:16 -0000
@@ -2,5 +2,12 @@
   <popup name="iPodSourcePopup">
     <menuitem name="iPodSrcPopupRename" action="iPodSourceRename"/>
     <menuitem name="iPodSrcPopupEject" action="RemovableSourceEject"/>
+    <separator/>
+    <menuitem name="iPodSrcPopupNewPlaylist" action="iPodSourceNewPlaylist"/>
+  </popup>
+
+  <popup name="iPodPlaylistSourcePopup">
+    <menuitem name="RenameiPodPlaylistPopup" action="MusicPlaylistRenamePlaylist"/>
+    <menuitem name="DeleteiPodPlaylistPopup" action="MusicPlaylistDeletePlaylist"/>
   </popup>
 </ui>
\ No newline at end of file
Index: lib/rb-marshal.list
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-marshal.list,v
retrieving revision 1.16
diff -u -b -B -r1.16 rb-marshal.list
--- lib/rb-marshal.list	17 Apr 2006 14:35:24 -0000	1.16
+++ lib/rb-marshal.list	9 May 2006 16:21:17 -0000
@@ -19,4 +19,5 @@
 VOID:STRING,POINTER
 VOID:STRING,STRING
 VOID:STRING,STRING,STRING
+VOID:POINTER,DOUBLE
 VOID:STRING,STRING,STRING,UINT,BOOLEAN
Index: plugins/ipod/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/plugins/ipod/Makefile.am,v
retrieving revision 1.1
diff -u -b -B -r1.1 Makefile.am
--- plugins/ipod/Makefile.am	17 Apr 2006 14:35:25 -0000	1.1
+++ plugins/ipod/Makefile.am	9 May 2006 16:21:17 -0000
@@ -1,14 +1,23 @@
 plugindir = $(PLUGINDIR)
+noinst_LTLIBRARIES = librbipodmanager.la
 plugin_LTLIBRARIES = libipod.la
 
+# build a separate lib so we can unittest it
+librbipodmanager_la_SOURCES =				\
+	rb-ipod.c					\
+	rb-ipod-manager.c
+
 libipod_la_SOURCES = \
 	rb-ipod-plugin.c			\
+	rb-ipod-playlist-source.c			\
 	$(top_srcdir)/sources/rb-ipod-source.c	\
 	$(top_srcdir)/sources/rb-ipod-source.h
 	
 libipod_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
 libipod_la_LIBADD = 					\
+	librbipodmanager.la				\
 	$(top_builddir)/lib/librb.la			\
+	$(top_builddir)/backends/librbbackends.la	\
 	$(HAL_LIBS)					\
 	$(IPOD_LIBS)
 
@@ -28,6 +37,7 @@
 	-I$(top_builddir)/remote			\
 	-I$(top_srcdir)/plugins				\
 	-I$(top_srcdir)/shell				\
+	-I$(top_srcdir)/backends			\
 	-DPIXMAP_DIR=\""$(datadir)/pixmaps"\"		\
 	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
 	-DDATADIR=\""$(datadir)"\"			\
Index: rhythmdb/rhythmdb-private.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-private.h,v
retrieving revision 1.7
diff -u -b -B -r1.7 rhythmdb-private.h
--- rhythmdb/rhythmdb-private.h	20 Apr 2006 20:43:28 -0000	1.7
+++ rhythmdb/rhythmdb-private.h	9 May 2006 16:21:17 -0000
@@ -98,6 +98,9 @@
 
 	/*Podcast*/
 	RhythmDBPodcastFields *podcast;
+
+  /* iPod */
+  guint ipod_status;
 };
 
 G_END_DECLS
Index: rhythmdb/rhythmdb-tree.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-tree.c,v
retrieving revision 1.103
diff -u -b -B -r1.103 rhythmdb-tree.c
--- rhythmdb/rhythmdb-tree.c	29 Apr 2006 23:10:34 -0000	1.103
+++ rhythmdb/rhythmdb-tree.c	9 May 2006 16:21:18 -0000
@@ -402,6 +402,8 @@
 		/* Handle indexed properties. */
 		switch (ctx->propid)
 		{
+		
+    case RHYTHMDB_PROP_IPOD_STATUS:
 		case RHYTHMDB_PROP_TYPE:
 			g_assert_not_reached ();
 			break;
@@ -769,6 +771,7 @@
 
 		switch (i)
 		{
+    case RHYTHMDB_PROP_IPOD_STATUS:
 		case RHYTHMDB_PROP_TYPE:
 			break;
 		case RHYTHMDB_PROP_TITLE:
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.214
diff -u -b -B -r1.214 rhythmdb.c
--- rhythmdb/rhythmdb.c	7 May 2006 21:32:24 -0000	1.214
+++ rhythmdb/rhythmdb.c	9 May 2006 16:21:28 -0000
@@ -735,6 +735,7 @@
 	g_hash_table_destroy (db->priv->propname_map);
 
 	g_hash_table_destroy (db->priv->monitored_directories);
+	if (db->priv->changed_files_id > 0)
 	g_source_remove (db->priv->changed_files_id);
 	g_hash_table_destroy (db->priv->changed_files);
 
@@ -2856,6 +2857,9 @@
 		case RHYTHMDB_PROP_POST_TIME:
 			entry->podcast->post_time = g_value_get_ulong (value);
 			break;	
+    case RHYTHMDB_PROP_IPOD_STATUS:
+      entry->ipod_status = g_value_get_ulong (value);
+      break;
 		case RHYTHMDB_NUM_PROPERTIES:
 			g_assert_not_reached ();
 			break;
@@ -3930,6 +3934,7 @@
 			ENUM_ENTRY (RHYTHMDB_PROP_COPYRIGHT, "Podcast copyright (gchararray) [copyright]"),
 			ENUM_ENTRY (RHYTHMDB_PROP_IMAGE, "Podcast image(gchararray) [image]"),
 			ENUM_ENTRY (RHYTHMDB_PROP_POST_TIME, "Podcast time of post (gulong) [post-time]"),
+			ENUM_ENTRY (RHYTHMDB_PROP_IPOD_STATUS, "iPod status (gulong) [ipod-status]"),
 			{ 0, 0, 0 }
 		};
 		g_assert ((sizeof (values) / sizeof (values[0]) - 1) == RHYTHMDB_NUM_PROPERTIES);
@@ -4789,6 +4794,8 @@
 			return entry->podcast->status;		
 		else
 			return 0;
+  case RHYTHMDB_PROP_IPOD_STATUS:
+    return entry->ipod_status;
 	default:
 		g_assert_not_reached ();
 		return 0;
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.82
diff -u -b -B -r1.82 rhythmdb.h
--- rhythmdb/rhythmdb.h	2 May 2006 11:50:45 -0000	1.82
+++ rhythmdb/rhythmdb.h	9 May 2006 16:21:28 -0000
@@ -174,6 +174,9 @@
 	RHYTHMDB_PROP_IMAGE,
 	RHYTHMDB_PROP_POST_TIME,
 	
+  /* iPod properties */
+  RHYTHMDB_PROP_IPOD_STATUS,
+  
 	RHYTHMDB_NUM_PROPERTIES
 } RhythmDBPropType;
 
@@ -182,6 +185,11 @@
 	RHYTHMDB_PODCAST_STATUS_ERROR = 101,
 	RHYTHMDB_PODCAST_STATUS_WAITING = 102,
 	RHYTHMDB_PODCAST_STATUS_PAUSED = 103,
+};
+
+enum {
+  RHYTHMDB_IPOD_STATUS_COMPLETE = 100,
+  RHYTHMDB_IPOD_STATUS_ERROR = 101
 };
 
 GType rhythmdb_query_type_get_type (void);
Index: sources/rb-ipod-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.c,v
retrieving revision 1.50
diff -u -b -B -r1.50 rb-ipod-source.c
--- sources/rb-ipod-source.c	6 May 2006 23:28:03 -0000	1.50
+++ sources/rb-ipod-source.c	9 May 2006 16:21:28 -0000
@@ -2,6 +2,7 @@
  *  arch-tag: Implementation of ipod source object
  *
  *  Copyright (C) 2004 Christophe Fergeau  <teuf@gnome.org>
+ *		  2006 Alessandro Decina   <alessandro@nnva.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
@@ -21,7 +22,7 @@
 
 #include <config.h>
 
-
+#include <gtk/gtk.h>
 #include <gtk/gtktreeview.h>
 #include <string.h>
 #include "rhythmdb.h"
@@ -36,13 +37,38 @@
 #include <gpod/itdb.h>
 #include "eel-gconf-extensions.h"
 #include "rb-ipod-source.h"
+#include "rb-library-source.h"
+#include "rb-stock-icons.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-ipod-playlist-source.h"
 #include "rb-util.h"
 #include "rhythmdb.h"
+#include "rb-sourcelist.h"
+#include "rb-sourcelist-model.h"
+#include "rb-ipod.h"
+#include "rb-ipod-manager.h"
+
+enum {
+	PROP_0,
+ 	PROP_MANAGER,
+};
+
+struct _RBiPodSourcePrivate
+{
+ 	RBiPodManager *manager;
+ 	RBShell *shell;
+ 	RhythmDB *db;
+ 	RBEntryView *entry_view;
+ 	RhythmDBEntryType entry_type;
+ 	GtkActionGroup *action_group;
+ 	GtkToggleAction *action_sync;
+ 	GHashTable *playlist_sources;
+};
+
+
 
 #ifdef IPOD_PHONE_SUPPORT
 #define PHONE_VENDOR_ID 0x22b8
@@ -54,37 +80,75 @@
 					    GObjectConstructParam *construct_properties);
 static void rb_ipod_source_dispose (GObject *object);
 
-static GObject *rb_ipod_source_constructor (GType type, guint n_construct_properties,
-			       GObjectConstructParam *construct_properties);
-static void rb_ipod_source_dispose (GObject *object);
+
+static void rb_ipod_source_get_property (GObject *object, guint propid,
+                                         GValue *value, GParamSpec *pspec);
+static void rb_ipod_source_set_property (GObject *object, guint propid,
+                                         const GValue *value, GParamSpec *pspec);
 
 static gboolean impl_show_popup (RBSource *source);
-static void impl_move_to_trash (RBSource *asource);
-static void rb_ipod_load_songs (RBiPodSource *source);
-static gchar *rb_ipod_get_mount_path (GnomeVFSVolume *volume);
+static GList * impl_get_ui_actions (RBSource *source);
 static void impl_delete_thyself (RBSource *source);
-static GList* impl_get_ui_actions (RBSource *source);
-#ifdef HAVE_HAL
-static gboolean hal_udi_is_ipod (const char *udi);
-#endif
+static gboolean load_songs_idle_cb (RBiPodSource *source);
+static void add_status_column (RBiPodSource *source,
+                               RBEntryView *view);
+static gchar *rb_ipod_get_mount_path (GnomeVFSVolume *volume);
+
+static void manager_track_read_cb (RBiPodManager *manager,
+                                   Itdb_Playlist *playlist, Itdb_Track *track,
+                                   RBiPodSource *source);
+static void manager_playlist_read_cb (RBiPodManager *manager,
+                                      Itdb_Playlist *playlist,
+                                      RBiPodSource *source);
 
 #ifdef ENABLE_TRACK_TRANSFER
-static void impl_paste (RBSource *source, GList *entries);
-static gboolean impl_receive_drag (RBSource *asource, GtkSelectionData *data);
-static gchar *
-ipod_get_filename_for_uri (const gchar *mount_point, const gchar *uri_str);
-static gchar *
-ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path);
+static void action_new_playlist_cb (GtkAction *action, RBiPodSource *source);
+static void action_sync_toggled_cb (GtkToggleAction *action,
+                                    RBiPodSource *source);
+static gboolean impl_receive_drag (RBSource *source, GtkSelectionData *data);
+static void impl_delete (RBSource *source);
+static void manager_track_added_cb (RBiPodManager *manager,
+                                    Itdb_Playlist *playlist, Itdb_Track *track,
+                                    RBiPodSource *source);
+static void manager_track_removed_cb (RBiPodManager *manager,
+                                      Itdb_Playlist *playlist,
+                                      Itdb_Track *track,
+                                      RBiPodSource *source);
+static void manager_playlist_added_cb (RBiPodManager *manager,
+                                       Itdb_Playlist *playlist,
+                                       RBiPodSource *source);
+static void manager_playlist_removed_cb (RBiPodManager *manager,
+                                         Itdb_Playlist *playlist,
+                                         RBiPodSource *source);
+
+static void manager_dirty_cb (RBiPodManager *manager,
+                              gboolean dirty, RBiPodSource *source);
+
+static void manager_sync_started_cb (RBiPodManager *manager,
+                                     RBiPodSource *source);
+static void manager_track_transfer_progress_cb (RBiPodManager *manager,
+                                                RBiPodManagerTrackTransferInfo *info, gdouble progress,
+                                                RBiPodSource *source);
+static void manager_track_transfer_finished_cb (RBiPodManager *manager,
+                                                RBiPodManagerTrackTransferInfo *info,
+                                                RBiPodSource *source);
+static void manager_sync_finished_cb (RBiPodManager *manager,
+                                      gboolean canceled, RBiPodSource *source);
+
+static void manager_error_cb (RBiPodManager *manager,
+                              GError *error, RBiPodSource *source);
+static gboolean add_entry (RBiPodSource *source,
+                           RhythmDBEntry *entry, const gchar *uri);
+#endif
+
+#if 0
+static void impl_move_to_trash (RBSource *asource);
 #endif
-static void itdb_schedule_save (Itdb_iTunesDB *db);
 
 
-typedef struct
-{
-	Itdb_iTunesDB *ipod_db;
-	gchar *ipod_mount_path;
-	GHashTable *entry_map;
-} RBiPodSourcePrivate;
+#ifdef HAVE_HAL
+static gboolean hal_udi_is_ipod (const char *udi);
+#endif
 
 
 RB_PLUGIN_DEFINE_TYPE(RBiPodSource, 
@@ -94,63 +158,86 @@
 #define IPOD_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_IPOD_SOURCE, RBiPodSourcePrivate))
 
 
+#ifdef ENABLE_TRACK_TRANSFER
+static GtkActionEntry ui_actions[] = {
+	{"iPodSourceNewPlaylist", GNOME_MEDIA_PLAYLIST, N_("_New Playlist"),
+		NULL, N_("Create a new playlist"),
+		G_CALLBACK (action_new_playlist_cb)
+	}
+};
+
+static GtkToggleActionEntry toggle_ui_actions[] = {
+	{"iPodSourceSync", GTK_STOCK_REFRESH, N_("Synchronize"), NULL,
+		N_("Write changes to iPod"),
+		G_CALLBACK (action_sync_toggled_cb),
+		FALSE
+	}
+};
+#endif
+
 static void
 rb_ipod_source_class_init (RBiPodSourceClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+#ifdef ENABLE_TRACK_TRANSFER
+	RBBrowserSourceClass *browser_source_class =
+		RB_BROWSER_SOURCE_CLASS (klass);
+
+	browser_source_class->impl_has_drop_support =
+		(RBBrowserSourceFeatureFunc) rb_true_function;
+#endif
 
 	object_class->constructor = rb_ipod_source_constructor;
+	object_class->get_property = rb_ipod_source_get_property;
+	object_class->set_property = rb_ipod_source_set_property;
 	object_class->dispose = rb_ipod_source_dispose;
 
+	g_object_class_install_property (object_class, PROP_MANAGER,
+			g_param_spec_object ("ipod-manager",
+				"iPod Manager",
+				"Rhythmbox iPod Manager",
+				RB_TYPE_IPOD_MANAGER,
+				G_PARAM_READWRITE));
+
 	source_class->impl_show_popup = impl_show_popup;
 	source_class->impl_delete_thyself = impl_delete_thyself;
-   	source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_true_function;
-   	source_class->impl_move_to_trash = impl_move_to_trash;
-	source_class->impl_can_rename = (RBSourceFeatureFunc) rb_true_function;
+
 	source_class->impl_get_ui_actions = impl_get_ui_actions;
 #ifdef ENABLE_TRACK_TRANSFER
   	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
-  	source_class->impl_paste = impl_paste;
+	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
   	source_class->impl_receive_drag = impl_receive_drag;
+	source_class->impl_delete = impl_delete;
+	source_class->impl_can_rename = (RBSourceFeatureFunc) rb_true_function;
+#endif
+#if 0
+	source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_true_function;
+   	source_class->impl_move_to_trash = impl_move_to_trash;
 #endif
 
 	g_type_class_add_private (klass, sizeof (RBiPodSourcePrivate));
 }
 
+#ifdef ENABLE_TRACK_TRANSFER
 static void
-rb_ipod_source_set_ipod_name (RBiPodSource *source, const char *name)
-{
-	Itdb_Playlist *mpl;
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-
-	mpl = itdb_playlist_mpl (priv->ipod_db);
-	rb_debug ("Renaming iPod from %s to %s", mpl->name, name);
-	if (strcmp (mpl->name, name) == 0) {
-		rb_debug ("iPod is already named %s", name);
-		return;
-	}
-	g_free (mpl->name);
-	mpl->name = g_strdup (name);
-	itdb_schedule_save (priv->ipod_db);
-}
-
-static void
-rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec, 
-				gpointer data)
+name_changed_cb (RBiPodSource *source,
+		GParamSpec *spec, gpointer data)
 {
 	char *name;
 
 	g_object_get (RB_SOURCE (source), "name", &name, NULL);
-	rb_ipod_source_set_ipod_name (source, name);
+	rb_ipod_manager_rename (source->priv->manager, name);
 	g_free (name);
 }
+#endif
 
 static void
 rb_ipod_source_init (RBiPodSource *source)
 {
-	g_signal_connect (G_OBJECT (source), "notify::name", 
-			  (GCallback)rb_ipod_source_name_changed_cb, NULL);
+	source->priv = IPOD_SOURCE_GET_PRIVATE (source);
+	source->priv->playlist_sources =
+		g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static GObject *
@@ -158,40 +245,174 @@
 			    GObjectConstructParam *construct_properties)
 {
 	RBiPodSource *source;
-	RBEntryView *songs;
-	RBiPodSourcePrivate *priv;
+	GnomeVFSVolume *volume;
+	gchar *mount_path;
 
 	source = RB_IPOD_SOURCE (G_OBJECT_CLASS (rb_ipod_source_parent_class)->
-			constructor (type, n_construct_properties, construct_properties));
-	priv = IPOD_SOURCE_GET_PRIVATE (source);
+			constructor (type, n_construct_properties,
+				construct_properties));
 
-	songs = rb_source_get_entry_view (RB_SOURCE (source));
-	rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_RATING, FALSE);
-	rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
+	g_object_get (G_OBJECT (source),
+			"shell", &source->priv->shell, "volume", &volume,
+			"entry-type", &source->priv->entry_type, NULL);
+	g_object_get (source->priv->shell, "db", &source->priv->db, NULL);
+
+	/* get the mount path and setup the iPodManager */
+	mount_path = rb_ipod_get_mount_path (volume);
+	source->priv->manager = rb_ipod_manager_new (mount_path,
+			source->priv->db);
+	g_free (mount_path);
+
+	/* append the status column to the entry view */
+	source->priv->entry_view =
+		rb_source_get_entry_view (RB_SOURCE (source));
+
+	rb_entry_view_append_column (source->priv->entry_view,
+			RB_ENTRY_VIEW_COL_RATING, FALSE);
+	rb_entry_view_append_column (source->priv->entry_view,
+			RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
+	add_status_column (source, source->priv->entry_view);
 
-	rb_ipod_load_songs (source);
+#ifdef ENABLE_TRACK_TRANSFER
+	/* setup UI actions */
+	source->priv->action_group =
+		_rb_source_register_action_group (RB_SOURCE (source),
+			"iPodSourceActions", ui_actions,
+			G_N_ELEMENTS (ui_actions), source);
+
+	gtk_action_group_add_toggle_actions (source->priv->action_group,
+			toggle_ui_actions, G_N_ELEMENTS (toggle_ui_actions),
+			source);
+
+	source->priv->action_sync = (GtkToggleAction *)
+		gtk_action_group_get_action (source->priv->action_group,
+			"iPodSourceSync");
+#endif
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"track-read",
+			G_CALLBACK (manager_track_read_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"playlist-read",
+			G_CALLBACK (manager_playlist_read_cb),
+			source, 0);
+#ifdef ENABLE_TRACK_TRANSFER
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"track-added",
+			G_CALLBACK (manager_track_added_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"track-transfer-progress",
+			G_CALLBACK (manager_track_transfer_progress_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"track-transfer-finished",
+			G_CALLBACK (manager_track_transfer_finished_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"track-removed",
+			G_CALLBACK (manager_track_removed_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"playlist-added",
+			G_CALLBACK (manager_playlist_added_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"playlist-removed",
+			G_CALLBACK (manager_playlist_removed_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"dirty",
+			G_CALLBACK (manager_dirty_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"sync-started",
+			G_CALLBACK (manager_sync_started_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"sync-finished",
+			G_CALLBACK (manager_sync_finished_cb),
+			source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->manager),
+			"error",
+			G_CALLBACK (manager_error_cb),
+			source, 0);
+#endif
+
+	/* load the itdb in an idle handler */
+	g_idle_add ((GSourceFunc) load_songs_idle_cb, source);
 
 	return G_OBJECT (source);
 }
 
 static void 
+rb_ipod_source_get_property (GObject *object, guint propid,
+		GValue *value, GParamSpec *pspec)
+{
+	RBiPodSource *source = RB_IPOD_SOURCE (object);
+
+	switch (propid) {
+		case PROP_MANAGER:
+			g_value_set_object (value, source->priv->manager);
+			break;
+		default:
+			g_assert_not_reached ();
+	}
+}
+
+static void
+rb_ipod_source_set_property (GObject *object, guint propid,
+		const GValue *value, GParamSpec *pspec)
+{
+	RBiPodSource *source = RB_IPOD_SOURCE (object);
+
+	switch (propid) {
+		case PROP_MANAGER:
+			if (source->priv->manager)
+				g_object_unref (source->priv->manager);
+			source->priv->manager =
+				RB_IPOD_MANAGER (g_value_dup_object (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+					propid, pspec);
+	}
+}
+
+static void
+unref_playlist_source (gpointer key, gpointer value, gpointer user_data)
+{
+	rb_ipod_playlist_source_delete_no_remove (RB_IPOD_PLAYLIST_SOURCE (value));
+}
+
+static void
 rb_ipod_source_dispose (GObject *object)
 {
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (object);
+	RBiPodSource *source = RB_IPOD_SOURCE (object);
 
- 	if (priv->ipod_db != NULL) {
- 		itdb_free (priv->ipod_db);
- 		priv->ipod_db = NULL;
+	if (source->priv->shell != NULL) {
+		g_object_unref (source->priv->shell);
+		source->priv->shell = NULL;
   	}
 
-	if (priv->ipod_mount_path) {
-		g_free (priv->ipod_mount_path);
-		priv->ipod_mount_path = NULL;
+	if (source->priv->db != NULL) {
+		g_object_unref (source->priv->db);
+		source->priv->db = NULL;
 	}
 
-	if (priv->entry_map) {
-		g_hash_table_destroy (priv->entry_map);
-		priv->entry_map = NULL;
+	if (source->priv->manager != NULL) {
+		g_object_unref (source->priv->manager);
+		source->priv->manager = NULL;
+	}
+
+	if (source->priv->action_group != NULL) {
+		GtkUIManager *uimanager;
+
+		g_object_get (source, "ui-manager", &uimanager, NULL);
+		gtk_ui_manager_remove_action_group (uimanager,
+				source->priv->action_group);
+		g_object_unref (uimanager);
+		source->priv->action_group = NULL;
  	}
 
 	G_OBJECT_CLASS (rb_ipod_source_parent_class)->dispose (object);
@@ -203,8 +424,6 @@
 	RBiPodSource *source;
 	RhythmDBEntryType entry_type;
 
-	g_assert (rb_ipod_is_volume_ipod (volume));
-
 	entry_type =  rhythmdb_entry_register_type ();
 
 	source = RB_IPOD_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
@@ -213,333 +432,134 @@
 					  "shell", shell,
 					  NULL));
 
-	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
+	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source),
+			entry_type);
 
 	return RB_REMOVABLE_MEDIA_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_uninserted (RHYTHMDB (db), entry, propid, &value);
-	g_value_unset (&value);
-}
-
-
-static char *
-ipod_path_to_uri (const char *mount_point, const char *ipod_path)
-{
- 	char *rel_pc_path;
- 	char *full_pc_path;
- 	char *uri;
-	
- 	rel_pc_path = g_strdup (ipod_path);	
- 	itdb_filename_ipod2fs (rel_pc_path);
- 	full_pc_path = g_build_filename (mount_point, rel_pc_path, NULL);
- 	g_free (rel_pc_path);
- 	uri = g_filename_to_uri (full_pc_path, NULL, NULL);
- 	g_free (full_pc_path);
- 	return uri;
-}
+rb_ipod_source_status_cell_data_func (GtkTreeViewColumn *column,
+		GtkCellRenderer *renderer,
+		GtkTreeModel *tree_model,
+		GtkTreeIter *iter,
+		RBiPodSource *source)
 
-static void
-add_rb_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
 {
-	RBShell *shell;
-	RBSource *playlist_source;
-	GList *it;
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	RhythmDBEntryType entry_type;
+	RhythmDBEntry *entry;
+	guint value;
+	gchar *status_string;
 
-  	g_object_get (G_OBJECT (source), 
-		      "shell", &shell, 
-		      "entry-type", &entry_type,
-		      NULL);
+	gtk_tree_model_get (tree_model, iter, 0, &entry, -1);
 
-	playlist_source = rb_static_playlist_source_new (shell, 
-							 playlist->name, 
-							 FALSE,
-							 entry_type);
-
-	for (it = playlist->members; it != NULL; it = it->next) {
-		Itdb_Track *song;
-		char *filename;
-
-		song = (Itdb_Track *)it->data;
- 		filename = ipod_path_to_uri (priv->ipod_mount_path, 
- 					    song->ipod_path);
-		rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (playlist_source),
-							filename, -1);
-		g_free (filename);
+	value = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_IPOD_STATUS);
+	switch (value) {
+	case RHYTHMDB_IPOD_STATUS_COMPLETE:
+		g_object_set (G_OBJECT (renderer), "text",
+				_("Completed"), NULL);
+		value = 100;
+		break;
+	case RHYTHMDB_IPOD_STATUS_ERROR:
+		g_object_set (G_OBJECT (renderer), "text", _("Failed"), NULL);
+		value = 0;
+		break;
+	default:
+		status_string = g_strdup_printf ("%u %%", value);
+		g_object_set (G_OBJECT (renderer), "text",
+				status_string, NULL);
+		g_free (status_string);
 	}
 
-	rb_shell_append_source (shell, playlist_source, RB_SOURCE (source));
-	g_object_unref (G_OBJECT (shell));
+	g_object_set (G_OBJECT (renderer), "visible", TRUE, NULL);
+	g_object_set (G_OBJECT (renderer), "value", value, NULL);
 }
 
-
-static void
-load_ipod_playlists (RBiPodSource *source)
+static gint
+rb_ipod_source_status_cell_sort_func (RhythmDBEntry *a,
+		RhythmDBEntry *b,
+		RhythmDBQueryModel *model)
 {
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	GList *it;
+	gulong a_val, b_val;
 
-	for (it = priv->ipod_db->playlists; it != NULL; it = it->next) {
-		Itdb_Playlist *playlist;
-
-		playlist = (Itdb_Playlist *)it->data;
-		if (itdb_playlist_is_mpl (playlist)) {
-			continue;
-		}
-		if (playlist->is_spl) {
-			continue;
-		}
-
-		add_rb_playlist (source, playlist);
-	}
+	a_val = rhythmdb_entry_get_ulong (a, RHYTHMDB_PROP_IPOD_STATUS);
+	b_val = rhythmdb_entry_get_ulong (b, RHYTHMDB_PROP_IPOD_STATUS);
 
+	if (a_val == b_val)
+		return 0;
+	return a_val > b_val ? 1 : -1;
 }
 
-#ifdef ENABLE_TRACK_TRANSFER
-static Itdb_Track *
-create_ipod_song_from_entry (RhythmDBEntry *entry)
+static void
+add_status_column (RBiPodSource *source, RBEntryView *view)
 {
-	Itdb_Track *track;
-
-	track = itdb_track_new ();
-
-	track->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE);
-	track->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);
-	track->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST);
-	track->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE);
-	/*	track->filetype = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP);*/
-	track->size = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);
-	track->tracklen = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION);
-	track->tracklen *= 1000;
-	track->cd_nr = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER);
-	track->track_nr = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
-	track->bitrate = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_BITRATE);
-	track->year = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE);
-	track->time_added = itdb_time_get_mac_time ();
-	track->time_played = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_LAST_PLAYED);
-	track->time_played = itdb_time_host_to_mac (track->time_played);
-	track->rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING);
-	track->app_rating = track->rating;
-	track->playcount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT);
-
-	return track;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	const gchar *status_strings[5];
+
+	status_strings[0] = _("Status");
+	status_strings[1] = _("Downloaded");
+	status_strings[2] = _("Failed");
+	status_strings[3] = "100 %";
+	status_strings[4] = NULL;
+
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_progress_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_set_clickable (column, TRUE);
+	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+	rb_entry_view_set_fixed_column_width (view,
+			column, renderer, status_strings);
+	gtk_tree_view_column_set_cell_data_func (column, renderer,
+			(GtkTreeCellDataFunc)
+				rb_ipod_source_status_cell_data_func,
+			source, NULL);
+	rb_entry_view_append_column_custom (view, column,
+			_("Status"), "Status",
+			(GCompareDataFunc) rb_ipod_source_status_cell_sort_func,
+			0);
 }
-#endif
 
 static void
-add_ipod_song_to_db (RBiPodSource *source, RhythmDB *db, Itdb_Track *song)
+rb_ipod_source_playlist_add_track (RBiPodSource *source,
+		Itdb_Playlist *playlist,
+		Itdb_Track *track,
+		gboolean completed)
 {	
+	GValue value = {0};
 	RhythmDBEntry *entry;
-	RhythmDBEntryType entry_type;
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	char *pc_path;
-
-	/* Set URI */
-	g_object_get (G_OBJECT (source), "entry-type", &entry_type, 
-		      NULL);
-
-	pc_path = ipod_path_to_uri (priv->ipod_mount_path, 
-				    song->ipod_path);
-	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
-				    pc_path);
+	const gchar *uri = rb_ipod_track_get_ipod_uri (track);
 
-	if (entry == NULL) {
-		rb_debug ("cannot create entry %s", pc_path);
-		g_free (pc_path);
+	if (itdb_playlist_is_mpl (playlist) == FALSE)
 		return;
-	}
-		
-	rb_debug ("Adding %s from iPod", pc_path);
-	g_free (pc_path);
-
-	/* Set track number */
-	if (song->track_nr != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, song->track_nr);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_TRACK_NUMBER, 
-					       &value);
-		g_value_unset (&value);
-	}
 
-	/* Set disc number */
-	if (song->cd_nr != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, song->cd_nr);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_DISC_NUMBER, 
-					       &value);
-		g_value_unset (&value);
-	}
+	rb_debug ("adding %s to playlist %s", uri, playlist->name);
 		
-	/* Set bitrate */
-	if (song->bitrate != 0) {
-		GValue value = {0, };
+	entry = rhythmdb_entry_new (source->priv->db,
+			source->priv->entry_type, uri);
+	rb_ipod_entry_set_from_track (source->priv->db, entry, track);
+	if (completed) {
 		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, song->bitrate);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_BITRATE, 
-					       &value);
+		g_value_set_ulong (&value, RHYTHMDB_IPOD_STATUS_COMPLETE);
+		rhythmdb_entry_set_uninserted (source->priv->db, entry,
+				RHYTHMDB_PROP_IPOD_STATUS, &value);
 		g_value_unset (&value);
 	}
-		
-	/* Set length */
-	if (song->tracklen != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, song->tracklen/1000);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_DURATION, 
-					       &value);
-		g_value_unset (&value);
-	}
-		
-	/* Set file size */
-	if (song->size != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_UINT64);
-		g_value_set_uint64 (&value, song->size);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_FILE_SIZE, 
-					       &value);
-		g_value_unset (&value);
-	}
-
-	/* Set playcount */
-	if (song->playcount != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, song->playcount);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
-					       RHYTHMDB_PROP_PLAY_COUNT,
-					       &value);
-		g_value_unset (&value);
-	}
-
-	/* Set year */
-	if (song->year != 0) {
-		GDate *date = NULL;
-		GType type;
-		GValue value = {0, };
-			
-		date = g_date_new_dmy (1, G_DATE_JANUARY, song->year);
-
-		type = rhythmdb_get_property_type (RHYTHMDB(db),
-						   RHYTHMDB_PROP_DATE);
-			
-		g_value_init (&value, type);
-		g_value_set_ulong (&value, (date ? g_date_get_julian (date) : 0));
-			
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
-					       RHYTHMDB_PROP_DATE,
-					       &value);
-		g_value_unset (&value);
-		if (date)
-			g_date_free (date);
-	}
-
-	/* Set rating */
-	if (song->rating != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_DOUBLE);
-		g_value_set_double (&value, song->rating/20.0);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
-					       RHYTHMDB_PROP_RATING,
-					       &value);
-		g_value_unset (&value);
-	}
-		
-	/* Set last played */
-	if (song->time_played != 0) {
-		GValue value = {0, };
-		g_value_init (&value, G_TYPE_ULONG);
-		g_value_set_ulong (&value, itdb_time_mac_to_host (song->time_played));
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
-					       RHYTHMDB_PROP_LAST_PLAYED,
-					       &value);
-		g_value_unset (&value);
-	}
-		
-	/* Set title */		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
-			       RHYTHMDB_PROP_TITLE, song->title);
-		
-	/* Set album, artist and genre from iTunesDB */
-	entry_set_string_prop (RHYTHMDB (db), entry, 
-			       RHYTHMDB_PROP_ARTIST, song->artist);
-		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
-			       RHYTHMDB_PROP_ALBUM, song->album);
-		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
-			       RHYTHMDB_PROP_GENRE, song->genre);
-
-
-	g_hash_table_insert (priv->entry_map, entry, song);
-
-	rhythmdb_commit (RHYTHMDB (db));
+	rhythmdb_commit (source->priv->db);
 }
 
 static gboolean
-load_ipod_db_idle_cb (RBiPodSource *source)
+load_songs_idle_cb (RBiPodSource *source)
 {
-	RBShell *shell;
-	RhythmDB *db;
- 	GList *it;
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-  
-  	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);
- 	for (it = priv->ipod_db->tracks; it != NULL; it = it->next) {
-		add_ipod_song_to_db (source, db, (Itdb_Track *)it->data);
-	}
-
-	load_ipod_playlists (source);
+#ifdef ENABLE_TRACK_TRANSFER
+	g_signal_connect (G_OBJECT (source), "notify::name",
+			  G_CALLBACK (name_changed_cb), NULL);
+#endif
+	if (rb_ipod_manager_load_db (source->priv->manager, NULL) == FALSE)
+		rb_ipod_manager_create_db (source->priv->manager, NULL);
 
-	g_object_unref (G_OBJECT (db));
 	return FALSE;
 }
 
-static void
-rb_ipod_load_songs (RBiPodSource *source)
-{
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	GnomeVFSVolume *volume;
-
-	g_object_get (G_OBJECT (source), "volume", &volume, NULL);
-	priv->ipod_mount_path = rb_ipod_get_mount_path (volume);
-
- 	priv->ipod_db = itdb_parse (priv->ipod_mount_path, NULL);
-	priv->entry_map = g_hash_table_new (g_direct_hash, g_direct_equal);
-	if ((priv->ipod_db != NULL) && (priv->entry_map != NULL)) {
-		/* FIXME: we could set a different icon depending on the iPod
-		 * model
-		 */
-		g_object_set (RB_SOURCE (source), 
-			      "name", itdb_playlist_mpl (priv->ipod_db)->name, 
-			      NULL);
-		g_idle_add ((GSourceFunc)load_ipod_db_idle_cb, source);
-	}
-}
-
 static gchar *
 rb_ipod_get_mount_path (GnomeVFSVolume *volume)
 {
@@ -618,12 +638,10 @@
 
 		result = hal_udi_is_ipod (udi);
 		g_free (udi);
-		if (result == FALSE) {
-			return FALSE;
-		}
+		if (result == TRUE)
+			return TRUE;
 	}
 #endif
-	
 	return rb_ipod_volume_has_ipod_db (volume);
 }
 
@@ -764,16 +782,16 @@
 
 	return result;
 }
-
 #endif
 
-static GList*
+static GList *
 impl_get_ui_actions (RBSource *source)
 {
 	GList *actions = NULL;
- 
-	actions = g_list_prepend (actions, g_strdup ("RemovableSourceEject"));
- 
+#ifdef ENABLE_TRACK_TRANSFER
+	actions = g_list_append (actions, g_strdup ("iPodSourceSync"));
+#endif
+	actions = g_list_append (actions, g_strdup ("RemovableSourceEject"));
 	return actions;
 }
 
@@ -785,490 +802,357 @@
 	return TRUE;
 }
 
-
 static void
-remove_track_from_db (Itdb_Track *track)
+impl_delete_thyself (RBSource *asource)
 {
-	GList *it;
+	RBiPodSource *source = RB_IPOD_SOURCE (asource);
 
-	for (it = track->itdb->playlists; it != NULL; it = it->next) {
-		itdb_playlist_remove_track ((Itdb_Playlist *)it->data, track);
-	}
-	itdb_track_remove (track);
+	rb_ipod_manager_sync_cancel (source->priv->manager);
+	rb_ipod_manager_write_itdb (source->priv->manager, NULL);
+
+	g_hash_table_foreach (source->priv->playlist_sources,
+			unref_playlist_source, NULL);
+	g_hash_table_destroy (source->priv->playlist_sources);
+	source->priv->playlist_sources = NULL;
+
+	RB_SOURCE_CLASS (rb_ipod_source_parent_class)->impl_delete_thyself (asource);
 }
 
 static void
-impl_move_to_trash (RBSource *asource)
+rb_ipod_source_add_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
 {
-	GList *sel, *tem;
-	RBEntryView *songs;
-	RBShell *shell;
-	RhythmDB *db;
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
-	RBiPodSource *source = RB_IPOD_SOURCE (asource);
+	RBSource *playlist_source;
+	RBEntryView *view;
 
-  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
-  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
-  	g_object_unref (G_OBJECT (shell));
+	rb_debug ("adding playlist %s", playlist->name);
 
-	songs = rb_source_get_entry_view (RB_SOURCE (asource));
-	sel = rb_entry_view_get_selected_entries (songs);
-	for (tem = sel; tem != NULL; tem = tem->next) {
-		RhythmDBEntry *entry;
-		const gchar *uri;
-		Itdb_Track *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 ipod! (%s)", uri);
-			continue;
-		}
+	playlist_source =
+		rb_ipod_playlist_source_new (source, playlist);
+	view = rb_source_get_entry_view (playlist_source);
+	add_status_column (source, view);
+
+	g_hash_table_insert (source->priv->playlist_sources,
+			playlist, playlist_source);
+	rb_shell_append_source (source->priv->shell,
+			playlist_source, RB_SOURCE (source));
+}
 
- 		remove_track_from_db (track);
-		g_hash_table_remove (priv->entry_map, entry);
-		rhythmdb_entry_move_to_trash (db, entry);
-		rhythmdb_commit (db);
-	}
-	if (sel != NULL) {
-		itdb_write (priv->ipod_db, NULL);
-	}
+static void
+manager_playlist_read_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist, RBiPodSource *source)
+{
+	if (itdb_playlist_is_mpl (playlist))
+		return;
 
-	g_list_free (sel);
+	rb_ipod_source_add_playlist (source, playlist);
 }
 
 static void
-itdb_schedule_save (Itdb_iTunesDB *db)
+manager_track_read_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist,
+		Itdb_Track *track,
+		RBiPodSource *source)
 {
-       /* FIXME: should probably be delayed a bit to avoid doing
-        * it after each file when we are copying several files
-        * consecutively
-        * FIXME: or this function could be called itdb_set_dirty, and we'd
-        * have a timeout firing every 5 seconds and saving the db if it's
-        * dirty
-        */
-       itdb_write (db, NULL);
+	rb_ipod_source_playlist_add_track (source,
+			playlist, track, track->transferred);
 }
 
-
 #ifdef ENABLE_TRACK_TRANSFER
-static char *
-build_filename (RBSource *asource, RhythmDBEntry *entry)
+static void
+manager_track_added_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist,
+		Itdb_Track *track,
+		RBiPodSource *source)
 {
-	const char *uri;
-	char *dest;
-	char *dest_uri;
-
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
-
-	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
-	dest = ipod_get_filename_for_uri (priv->ipod_mount_path,  uri);
-	if (dest != NULL) {
-		dest_uri = g_filename_to_uri (dest, NULL, NULL);
-		g_free (dest);
-		return dest_uri;
-	}
-
-	return NULL;
+	rb_ipod_source_playlist_add_track (source,
+			playlist, track, track->transferred);
 }
 
 static void
-completed_cb (RhythmDBEntry *entry, const char *dest, RBiPodSource *source)
+manager_track_removed_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist, Itdb_Track *track,
+		RBiPodSource *source)
 {
-	RBShell *shell;
-	RhythmDB *db;
-	Itdb_Track *song;
-
-  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
-  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
-  	g_object_unref (G_OBJECT (shell));
-
-	song = create_ipod_song_from_entry (entry);
-	if (song != NULL) {
-		RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-		char *filename;
-
-		filename = g_filename_from_uri (dest, NULL, NULL);
-		song->ipod_path = ipod_path_from_unix_path (priv->ipod_mount_path, filename);
-		g_free (filename);
-		itdb_track_add (priv->ipod_db, song, -1);
-		itdb_playlist_add_track (itdb_playlist_mpl (priv->ipod_db),
-					 song, -1);
-
-		add_ipod_song_to_db (source, db, song);
-		itdb_schedule_save (priv->ipod_db);
-	}
+	const gchar *uri;
 
-	g_object_unref (db);
+	uri = rb_ipod_track_get_source_uri (track);
+	if (uri == NULL)
+		uri = rb_ipod_track_get_ipod_uri (track);
+	rb_debug ("removed track %s from playlist %s", uri, playlist->name);
 }
 
 static void
-impl_paste (RBSource *asource, GList *entries)
+manager_playlist_added_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist, RBiPodSource *source)
 {
-	RBRemovableMediaManager *rm_mgr;
-	GList *l;
-	RBShell *shell;
+	rb_ipod_source_add_playlist (source, playlist);
+}
 
-	g_object_get (G_OBJECT (asource), "shell", &shell, NULL);
-	g_object_get (G_OBJECT (shell),
-		      "removable-media-manager", &rm_mgr,
-		      NULL);
-	g_object_unref (G_OBJECT (shell));
+static void
+manager_playlist_removed_cb (RBiPodManager *manager,
+		Itdb_Playlist *playlist, RBiPodSource *source)
+{
+	rb_debug ("removed playlist %s", playlist->name);
+	g_hash_table_remove (source->priv->playlist_sources, playlist);
+}
 
-	for (l = entries; l != NULL; l = l->next) {
+static void
+manager_track_transfer_progress_cb (RBiPodManager *manager,
+		RBiPodManagerTrackTransferInfo *info,
+		gdouble progress,
+		RBiPodSource *source)
+{
+	Itdb_Track *track;
+	const gchar *uri;
 		RhythmDBEntry *entry;
-		RhythmDBEntryType entry_type;
-		RhythmDBEntryType ipod_entry_type;
-		char *dest;
-
-		entry = (RhythmDBEntry *)l->data;
-		entry_type = rhythmdb_entry_get_entry_type (entry);
-		g_object_get (G_OBJECT (asource),
-			      "entry-type", &ipod_entry_type,
-			      NULL);
-		if (entry_type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION ||
-		    entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED ||
-//		    entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_EPISODE ||
-		    entry_type == ipod_entry_type)
-			continue;
+	GValue value = { 0 };
 
-		dest = build_filename (asource, entry);
-		if (dest == NULL) {
-			rb_debug ("could not create destination path for entry");
-			continue;
-		}
-		rb_removable_media_manager_queue_transfer (rm_mgr, entry,
-							   dest, NULL,
-							   (RBTranferCompleteCallback)completed_cb, asource);
-		g_free (dest);
+	track = info->track;
+	uri = rb_ipod_track_get_ipod_uri (track);
+	entry = rhythmdb_entry_lookup_by_location (source->priv->db, uri);
+	if (entry == NULL) {
+		/* the entry has been removed while synching...
+		 * the ipod manager should've canceled the transfer */
+		g_return_if_reached ();
+		return;
 	}
-	g_object_unref (G_OBJECT (rm_mgr));
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value, (gulong) (progress * 100));
+	rhythmdb_entry_set (source->priv->db, entry,
+			RHYTHMDB_PROP_IPOD_STATUS, &value);
+	g_value_unset (&value);
+	rhythmdb_commit (source->priv->db);
+	gtk_widget_queue_draw (GTK_WIDGET (source->priv->entry_view));
 }
 
-
-static gboolean
-impl_receive_drag (RBSource *asource, GtkSelectionData *data)
+static void
+manager_track_transfer_finished_cb (RBiPodManager *manager,
+		RBiPodManagerTrackTransferInfo *info,
+		RBiPodSource *source)
 {
-	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) {
-			char *uri = i->data;
 			RhythmDBEntry *entry;
+	Itdb_Track *track;
+	GValue value = {0};
+	guint status;
 
-			entry = rhythmdb_entry_lookup_by_location (db, uri);
+	track = info->track;
 
-			if (entry == NULL) {
-				/* add to the library */
-				g_print ("Where does that come from?\n");
+	if (info->error) {
+		rb_debug ("track sync finished: %s",
+				info->error->message);
+		status = RHYTHMDB_IPOD_STATUS_ERROR;
 			} else {
-				/* add to list of entries to copy */
-				entries = g_list_prepend (entries, entry);
-			}
-
-			g_free (uri);
+		status = RHYTHMDB_IPOD_STATUS_COMPLETE;
 		}
-	}
-	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);
+	entry = rhythmdb_entry_lookup_by_location (source->priv->db,
+			rb_ipod_track_get_ipod_uri (track));
+	if (entry != NULL) {
+		g_value_init (&value, G_TYPE_ULONG);
+		g_value_set_ulong (&value, status);
+		rhythmdb_entry_set (source->priv->db, entry,
+			RHYTHMDB_PROP_IPOD_STATUS, &value);
+		g_value_unset (&value);
+	} else {
+		/* the entry has been removed while it was being synched */
 	}
 
-
-	return TRUE;
+	gtk_widget_queue_draw (GTK_WIDGET (source->priv->entry_view));
 }
 
-
-/* Generation of the filename for the ipod */
-
-#define IPOD_MAX_PATH_LEN 56
-
-static gboolean
-test_dir_on_ipod (const char *mountpoint, const char *dirname)
+static void
+manager_dirty_cb (RBiPodManager *manager,
+		gboolean dirty, RBiPodSource *source)
 {
-	char *fullpath;
-	gboolean result;
-
-	fullpath  = g_build_filename (mountpoint, dirname, NULL);
-	result = g_file_test (fullpath, G_FILE_TEST_IS_DIR);
-	g_free (fullpath);
-	
-	return result;
+	rb_debug ("dirty %d", dirty);
 }
 
-static int
-ipod_mkdir_with_parents (const char *mountpoint, const char *dirname)
+static void
+manager_sync_started_cb (RBiPodManager *manager, RBiPodSource *source)
 {
-	char *fullpath;
-	int result;
-
-	fullpath  = g_build_filename (mountpoint, dirname, NULL);
-	result = g_mkdir_with_parents (fullpath, 0770);
-	g_free (fullpath);
-	
-	return result;
+	rb_debug ("sync started");
 }
 
-static gchar *
-build_ipod_dir_name (const char *mountpoint)
+static void
+manager_sync_finished_cb (RBiPodManager *manager, gboolean canceled,
+		RBiPodSource *source)
 {
-	/* FAT sucks, filename can be lowercase or uppercase, and if we try to
-	 * open the wrong one, we lose :-/
-	 */
-	char *dirname;
-	char *relpath;
-	gint32 suffix;
-	
-	suffix = g_random_int_range (0, 100);
-	dirname = g_strdup_printf ("F%02d", suffix);
-	relpath = g_build_filename (G_DIR_SEPARATOR_S, "iPod_Control",
-				    "Music", dirname, NULL);
-	g_free (dirname);
-
-	if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
-		return relpath;
-	}
-
-	g_free (relpath);
-	dirname = g_strdup_printf ("f%02d", g_random_int_range (0, 100));
-	relpath = g_build_filename (G_DIR_SEPARATOR_S, "iPod_Control",
-				    "Music", dirname, NULL);
-	g_free (dirname);
-
-	if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
-		return relpath;
+	if (canceled) {
+		rb_debug ("sync canceled");
+	} else {
+		rb_debug ("sync finished");
 	}
 
-	if (ipod_mkdir_with_parents (mountpoint, relpath) == 0) {
-		return relpath;
-	}
+	gtk_toggle_action_set_active (source->priv->action_sync, FALSE);
+}
 
-	g_free (relpath);
-	return NULL;
+static void
+manager_error_cb (RBiPodManager *manager,
+		GError *error, RBiPodSource *source)
+{
+	rb_debug ("manager error: %s", error->message);
 }
 
-static gchar *
-get_ipod_filename (const char *mount_point, const char *filename)
+static gboolean
+add_entry (RBiPodSource *source, RhythmDBEntry *entry, const gchar *uri)
 {
-	char *dirname;
-	char *result;
-	char *tmp;
+	RhythmDBEntryType entry_type;
+	Itdb_Track *track;
+	gboolean res;
+	gboolean is_podcast;
 
-	dirname = build_ipod_dir_name (mount_point);
-	if (dirname == NULL) {
-		return NULL;
+	entry_type = rhythmdb_entry_get_pointer (entry, RHYTHMDB_PROP_TYPE);
+	if (entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
+		is_podcast = TRUE;
+	} else if (entry_type == RHYTHMDB_ENTRY_TYPE_SONG) {
+		is_podcast = FALSE;
+	} else {
+		rb_debug ("%s is not a song nor a podcast", uri);
+		return FALSE;
 	}
-	result = g_build_filename (dirname, filename, NULL);
-	g_free (dirname);
 
-	if (strlen (result) >= IPOD_MAX_PATH_LEN) {
-		char *ext;
+	track = itdb_track_new ();
+	rb_ipod_track_set_from_entry (source->priv->db, track, entry);
+	rb_ipod_track_set_source_uri (track, uri);
 
-		ext = strrchr (result, '.');
-		if (ext == NULL) {
-			result [IPOD_MAX_PATH_LEN - 1] = '\0';
-		} else {
-			memmove (&result[IPOD_MAX_PATH_LEN - strlen (ext) - 1] ,
-				 ext, strlen (ext) + 1);
-		}
-	}
+	if (is_podcast)
+		res = rb_ipod_manager_podcasts_add_track (source->priv->manager,
+				track);
+	else
+		res = rb_ipod_manager_add_track (source->priv->manager, track);
 
-	tmp = g_build_filename (mount_point, result, NULL);
-	g_free (result);
-	return tmp;
-}
+	if (res == FALSE)
+		itdb_track_free (track);
 
-#define MAX_TRIES 5
+	return res;
+}
 
-/* Strips non UTF8 characters from a string replacing them with _ */
-static gchar *
-utf8_to_ascii (const gchar *utf8)
+static void
+action_new_playlist_cb (GtkAction *action, RBiPodSource *source)
 {
-	GString *string;
-	const guchar *it = (const guchar *)utf8;
+	/* create a nameless playlist */
+	Itdb_Playlist *playlist = itdb_playlist_new ("", FALSE);
+	rb_ipod_playlist_add_data (playlist);
+	rb_ipod_manager_add_playlist (source->priv->manager, playlist);
+}
 
-	string = g_string_new ("");
-	while ((it != NULL) && (*it != '\0')) {
-		/* Do we have a 7 bit char ? */
-		if (*it < 0x80) {
-			g_string_append_c (string, *it);
+static void
+action_sync_toggled_cb (GtkToggleAction *action, RBiPodSource *source)
+{
+	if (gtk_toggle_action_get_active (action)) {
+		rb_debug ("sync action start");
+		if (rb_ipod_manager_sync (source->priv->manager, TRUE) == FALSE)
+			gtk_toggle_action_set_active (source->priv->action_sync,
+					FALSE);
 		} else {
-			g_string_append_c (string, '_');
-		}
-		it = (const guchar *)g_utf8_next_char (it);
+		rb_debug ("sync action cancel");
+		rb_ipod_manager_sync_cancel (source->priv->manager);
 	}
-
-	return g_string_free (string, FALSE);
 }
 
-/* Copied from eel-vfs-extensions.c from eel CVS HEAD on 2004-05-09
- * This function is (C) 1999, 2000 Eazel, Inc.
- */
-static char *
-eel_make_valid_utf8 (const char *name)
+static gboolean
+impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 {
-	GString *string;
-	const char *remainder, *invalid;
-	int remaining_bytes, valid_bytes;
-
-	string = NULL;
-	remainder = name;
-	remaining_bytes = strlen (name);
-
-	while (remaining_bytes != 0) {
-		if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
-			break;
-		}
-		valid_bytes = invalid - remainder;
-
-		if (string == NULL) {
-			string = g_string_sized_new (remaining_bytes);
-		}
-		g_string_append_len (string, remainder, valid_bytes);
-		g_string_append_c (string, '_');
+	GList *uri_list = NULL;
+	RBiPodSource *source = RB_IPOD_SOURCE (asource);
+	gboolean res = FALSE;
 
-		remaining_bytes -= valid_bytes + 1;
-		remainder = invalid + 1;
-	}
+	rb_debug ("receive drag");
 
-	if (string == NULL) {
-		return g_strdup (name);
+	if (data->type == gdk_atom_intern ("text/uri-list", TRUE)) {
+		uri_list = rb_uri_list_parse ((gchar *) data->data);
 	}
 
-	g_string_append (string, remainder);
-	g_assert (g_utf8_validate (string->str, -1, NULL));
-
-	return g_string_free (string, FALSE);
-}
-
-
-static gchar *
-generate_ipod_filename (const gchar *mount_point, const gchar *filename)
-{
-	gchar *ipod_filename = NULL;
-	gchar *pc_filename;
-	gchar *tmp;
-	gint tries = 0;
-
-	/* First, we need a valid UTF-8 filename, strip all non-UTF-8 chars */
-	tmp = eel_make_valid_utf8 (filename);
-	/* The iPod doesn't seem to recognize non-ascii chars in filenames,
-	 * so we strip them
-	 */
-	pc_filename = utf8_to_ascii (tmp);
-	g_free (tmp);
-
-	g_assert (g_utf8_validate (pc_filename, -1, NULL));
-	/* Now we have a valid UTF-8 filename, try to find out where to put
-	 * it on the iPod
-	 */
-	do {
-		g_free (ipod_filename);
-		ipod_filename = get_ipod_filename (mount_point, pc_filename);
-		tries++;
-		if (tries > MAX_TRIES) {
-			break;
-		}
-	} while ((ipod_filename == NULL) 
-		 || (g_file_test (ipod_filename, G_FILE_TEST_EXISTS)));
+	if (uri_list) {
+		GList *walk;
+		RhythmDBEntry *entry;
 
-	g_free (pc_filename);
+		for (walk = uri_list; walk; walk = g_list_next (walk)) {
+			gchar *uri = (gchar *) walk->data;
 
-	if (tries > MAX_TRIES) {
-		/* FIXME: should create a unique filename */
-		return NULL;
-	} else {
-		return ipod_filename;
+			entry = rhythmdb_entry_lookup_by_location (source->priv->db,
+					uri);
+			if (entry == NULL) {
+				rb_debug ("skipping %s as it isn't in "
+						"library", uri);
+				continue;
 	}
-}
 
-static gchar *
-ipod_get_filename_for_uri (const gchar *mount_point, const gchar *uri_str)
-{
-	GnomeVFSURI *uri;
-	gchar *escaped;
-	gchar *filename;
-	gchar *result;
 
-	uri = gnome_vfs_uri_new (uri_str);
-	if (uri == NULL) {
-		return NULL;
-	}
-	escaped = gnome_vfs_uri_extract_short_path_name (uri);
-	gnome_vfs_uri_unref (uri);
-	if (escaped == NULL) {
-		return NULL;
+			if (add_entry (source, entry, uri) == TRUE) {
+				res = TRUE;
 	}
-	filename = gnome_vfs_unescape_string (escaped, G_DIR_SEPARATOR_S);
-	g_free (escaped);
-	if (filename == NULL) {
-		return NULL;
 	}
 
-	result = generate_ipod_filename (mount_point, filename);
-	g_free (filename);
+		rhythmdb_commit (source->priv->db);
+	}
 
-	return result;
+	return res;
 }
 
-/* End of generation of the filename on the iPod */
-
-static gchar *
-ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path)
+static void
+impl_delete (RBSource *asource)
 {
-        gchar *ipod_path;
-
-        g_assert (g_utf8_validate (unix_path, -1, NULL));
+	RBiPodSource *source = RB_IPOD_SOURCE (asource);
+	GList *selected, *walk;
+	const gchar *uri;
+	RhythmDBEntry *entry;
 
-        if (!g_str_has_prefix (unix_path, mount_point)) {
-                return NULL;
-        }
+	selected =
+		rb_entry_view_get_selected_entries (source->priv->entry_view);
+	for (walk = selected; walk; walk = g_list_next (walk)) {
+		entry = (RhythmDBEntry *) walk->data;
+		uri = rhythmdb_entry_get_string (entry,
+				RHYTHMDB_PROP_LOCATION);
 
-        ipod_path = g_strdup (unix_path + strlen (mount_point));
-        if (*ipod_path != G_DIR_SEPARATOR) {
-                gchar *tmp;
-                tmp = g_strdup_printf ("/%s", ipod_path);
-                g_free (ipod_path);
-                ipod_path = tmp;
+		rb_debug ("delete %s", uri);
+		rb_ipod_manager_remove_uri (source->priv->manager, uri);
+		rhythmdb_entry_delete (source->priv->db, entry);
         }
 
-        /* Make sure the filename doesn't contain any ':' */
-        g_strdelimit (ipod_path, ":", ';');
-
-
-        /* Convert path to a Mac path where the dir separator is ':' */
-	itdb_filename_fs2ipod (ipod_path);
-
-        return ipod_path;
+	rhythmdb_commit (source->priv->db);
 }
 #endif
 
+#if 0
 static void
-impl_delete_thyself (RBSource *source)
+impl_move_to_trash (RBSource *asource)
 {
-	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	GList *sel, *tem;
+	RBEntryView *songs;
+	RBShell *shell;
+	RhythmDB *db;
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
+	RBiPodSource *source = RB_IPOD_SOURCE (asource);
 
-	itdb_free (priv->ipod_db);
-	priv->ipod_db = NULL;
+  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	g_object_unref (G_OBJECT (shell));
 
-	RB_SOURCE_CLASS (rb_ipod_source_parent_class)->impl_delete_thyself (source);
-}
+	songs = rb_source_get_entry_view (RB_SOURCE (asource));
+	sel = rb_entry_view_get_selected_entries (songs);
+	for (tem = sel; tem != NULL; tem = tem->next) {
+		RhythmDBEntry *entry;
+		const gchar *uri;
+		Itdb_Track *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 ipod! (%s)", uri);
+			continue;
+		}
+
+ 		remove_track_from_db (track);
+		g_hash_table_remove (priv->entry_map, entry);
+		rhythmdb_entry_move_to_trash (db, entry);
+		rhythmdb_commit (db);
+	}
+	if (sel != NULL) {
+		itdb_write (priv->ipod_db, NULL);
+	}
+
+	g_list_free (sel);
+}
+#endif
Index: sources/rb-ipod-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.h,v
retrieving revision 1.6
diff -u -b -B -r1.6 rb-ipod-source.h
--- sources/rb-ipod-source.h	20 Apr 2006 20:43:30 -0000	1.6
+++ sources/rb-ipod-source.h	9 May 2006 16:21:28 -0000
@@ -22,6 +22,7 @@
 #ifndef __RB_IPOD_SOURCE_H
 #define __RB_IPOD_SOURCE_H
 
+#include <libgnomevfs/gnome-vfs.h>
 #include "rb-shell.h"
 #include "rb-removable-media-source.h"
 #include "rhythmdb.h"
@@ -35,9 +36,12 @@
 #define RB_IS_IPOD_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_IPOD_SOURCE))
 #define RB_IPOD_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_IPOD_SOURCE, RBiPodSourceClass))
 
+typedef struct _RBiPodSourcePrivate RBiPodSourcePrivate;
+
 typedef struct
 {
 	RBRemovableMediaSource parent;
+	RBiPodSourcePrivate *priv;
 } RBiPodSource;
 
 typedef struct
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.169
diff -u -b -B -r1.169 rb-library-source.c
--- sources/rb-library-source.c	9 May 2006 10:11:01 -0000	1.169
+++ sources/rb-library-source.c	9 May 2006 16:21:28 -0000
@@ -1152,6 +1152,7 @@
 	for (l = entries; l != NULL; l = g_list_next (l)) {
 		RhythmDBEntry *entry = (RhythmDBEntry *)l->data;
 		RhythmDBEntryType entry_type;
+		RBSource *copy_source;
 		char *dest;
 
 		rb_debug ("pasting entry %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
@@ -1162,7 +1163,9 @@
 			continue;
 		
 		/* see if the responsible source lets us copy */
-		if (!rb_source_can_copy (rb_shell_get_source_by_entry_type (shell, entry_type)))
+		copy_source = rb_shell_get_source_by_entry_type (shell,
+				entry_type);
+		if (copy_source && !rb_source_can_copy (copy_source))
 			continue;
 
 		dest = build_filename (source, entry);
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/tests/Makefile.am,v
retrieving revision 1.10
diff -u -b -B -r1.10 Makefile.am
--- tests/Makefile.am	3 Nov 2005 02:53:28 -0000	1.10
+++ tests/Makefile.am	9 May 2006 16:21:28 -0000
@@ -1,8 +1,6 @@
 ## arch-tag: Automake rules for test programs
 ## Process this file with automake to produce Makefile.in
 
-if FALSE
-
 #TESTS = test-rhythmdb-simple test-rhythmdb-indexing \
 #		  test-rhythmdb-query test-rhythmdb-tree-serialization \
 #		  test-rhythmdb-tree-deserialization \
@@ -10,8 +8,17 @@
 
 TESTS = 
 
-noinst_PROGRAMS = test-cmdline $(TESTS)
+if HAVE_CHECK
+if USE_IPOD
+if ENABLE_TRACK_TRANSFER
+TESTS += test-rb-ipod-manager
+endif
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)
 
+if FALSE
 test_rhythmdb_simple_SOURCES = test-rhythmdb-simple.c
 test_rhythmdb_simple_LDADD =					\
 	$(top_builddir)/rhythmdb/librhythmdb.la			\
@@ -56,17 +63,33 @@
 	$(RHYTHMBOX_LIBS)
 
 test_cmdline_LDFLAGS = -export-dynamic
+endif
 
 INCLUDES = 							\
         -DGNOMELOCALEDIR=\""$(datadir)/locale"\"	        \
 	-DG_LOG_DOMAIN=\"Rhythmbox-tests\"			\
 	-I$(top_srcdir) 					\
 	$(RHYTHMBOX_CFLAGS)					\
+	$(CHECK_CFLAGS)						\
+	$(IPOD_CFLAGS)						\
 	-I$(top_srcdir)/lib					\
 	-I$(top_srcdir)/monkey-media				\
 	-I$(top_srcdir)/rhythmdb				\
-	-I$(top_srcdir)/widgets
-
-endif
+	-I$(top_srcdir)/widgets					\
+	-I$(top_srcdir)/player					\
+	-I$(top_srcdir)/plugins/ipod
+
+test_rb_ipod_manager_SOURCES = test-rb-ipod-manager.c
+test_rb_ipod_manager_LDADD = 					\
+	$(CHECK_LIBS) 						\
+	$(RHYTHMBOX_LIBS)					\
+	$(GNOME_MEDIA_PROFILES_LIBS)				\
+	$(IPOD_LIBS)						\
+	$(top_builddir)/plugins/ipod/librbipodmanager.la	\
+	$(top_builddir)/rhythmdb/librhythmdb.la			\
+	$(top_builddir)/widgets/librbwidgets.la			\
+	$(top_builddir)/metadata/librbmetadata.la 		\
+	$(top_builddir)/lib/librb.la 				\
+	$(top_builddir)/backends/librbbackends.la
 
 EXTRA_DIST = deserialization-test1.xml deserialization-test2.xml deserialization-test3.xml
