? attachment.cgi?id=61913
? attachment.cgi?id=62634
? backends.diff
? entry-type.diff
? ipod.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/Makefile
? plugins/ipod/Makefile.in
? plugins/ipod/ipod.rb-plugin
? plugins/ipod/libipod.la
? plugins/ipod/rb-ipod-plugin.lo
? plugins/ipod/rb-ipod-source.lo
? 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.loT
? 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
? 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: sources/rb-ipod-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.c,v
retrieving revision 1.43
diff -u -r1.43 rb-ipod-source.c
--- sources/rb-ipod-source.c	17 Apr 2006 14:35:26 -0000	1.43
+++ sources/rb-ipod-source.c	18 Apr 2006 07:53:05 -0000
@@ -44,7 +44,7 @@
 #include "rb-util.h"
 #include "rhythmdb.h"
 
-static GObject *rb_ipod_source_constructor (GType type, 
+static GObject *rb_ipod_source_constructor (GType type,
 					    guint n_construct_properties,
 					    GObjectConstructParam *construct_properties);
 static void rb_ipod_source_dispose (GObject *object);
@@ -63,6 +63,17 @@
 static gboolean hal_udi_is_ipod (const char *udi);
 #endif
 
+#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);
+#endif
+static void itdb_schedule_save (Itdb_iTunesDB *db);
+
+
 typedef struct
 {
 	Itdb_iTunesDB *ipod_db;
@@ -71,8 +82,8 @@
 } RBiPodSourcePrivate;
 
 
-RB_PLUGIN_DEFINE_TYPE(RBiPodSource, 
-		      rb_ipod_source, 
+RB_PLUGIN_DEFINE_TYPE(RBiPodSource,
+		      rb_ipod_source,
 		      RB_TYPE_REMOVABLE_MEDIA_SOURCE)
 
 #define IPOD_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_IPOD_SOURCE, RBiPodSourcePrivate))
@@ -93,6 +104,11 @@
    	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_receive_drag = impl_receive_drag;
+#endif
 
 	g_type_class_add_private (klass, sizeof (RBiPodSourcePrivate));
 }
@@ -111,11 +127,11 @@
 	}
 	g_free (mpl->name);
 	mpl->name = g_strdup (name);
-	itdb_write (priv->ipod_db, NULL);
+	itdb_schedule_save (priv->ipod_db);
 }
 
 static void
-rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec, 
+rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec,
 				gpointer data)
 {
 	char *name;
@@ -128,7 +144,7 @@
 static void
 rb_ipod_source_init (RBiPodSource *source)
 {
-	g_signal_connect (G_OBJECT (source), "notify::name", 
+	g_signal_connect (G_OBJECT (source), "notify::name",
 			  (GCallback)rb_ipod_source_name_changed_cb, NULL);
 }
 
@@ -153,7 +169,7 @@
 	return G_OBJECT (source);
 }
 
-static void 
+static void
 rb_ipod_source_dispose (GObject *object)
 {
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (object);
@@ -197,7 +213,7 @@
 	return RB_REMOVABLE_MEDIA_SOURCE (source);
 }
 
-static void 
+static void
 entry_set_string_prop (RhythmDB *db, RhythmDBEntry *entry,
 		       RhythmDBPropType propid, const char *str)
 {
@@ -219,8 +235,8 @@
  	char *rel_pc_path;
  	char *full_pc_path;
  	char *uri;
-	
- 	rel_pc_path = g_strdup (ipod_path);	
+
+ 	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);
@@ -238,13 +254,13 @@
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 	RhythmDBEntryType entry_type;
 
-  	g_object_get (G_OBJECT (source), 
-		      "shell", &shell, 
+  	g_object_get (G_OBJECT (source),
+		      "shell", &shell,
 		      "entry-type", &entry_type,
 		      NULL);
 
-	playlist_source = rb_static_playlist_source_new (shell, 
-							 playlist->name, 
+	playlist_source = rb_static_playlist_source_new (shell,
+							 playlist->name,
 							 FALSE,
 							 entry_type);
 
@@ -253,7 +269,7 @@
 		char *filename;
 
 		song = (Itdb_Track *)it->data;
- 		filename = ipod_path_to_uri (priv->ipod_mount_path, 
+ 		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);
@@ -287,20 +303,50 @@
 
 }
 
+#ifdef ENABLE_TRACK_TRANSFER
+static Itdb_Track *
+create_ipod_song_from_entry (RhythmDBEntry *entry)
+{
+	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;
+}
+#endif
 
 static void
 add_ipod_song_to_db (RBiPodSource *source, RhythmDB *db, Itdb_Track *song)
-{	
+{
 	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, 
+	g_object_get (G_OBJECT (source), "entry-type", &entry_type,
 		      NULL);
 
-	pc_path = ipod_path_to_uri (priv->ipod_mount_path, 
+	pc_path = ipod_path_to_uri (priv->ipod_mount_path,
 				    song->ipod_path);
 	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
 				    pc_path);
@@ -310,7 +356,7 @@
 		g_free (pc_path);
 		return;
 	}
-		
+
 	rb_debug ("Adding %s from iPod", pc_path);
 	g_free (pc_path);
 
@@ -319,8 +365,8 @@
 		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, 
+		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
+					       RHYTHMDB_PROP_TRACK_NUMBER,
 					       &value);
 		g_value_unset (&value);
 	}
@@ -330,41 +376,41 @@
 		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, 
+		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
+					       RHYTHMDB_PROP_DISC_NUMBER,
 					       &value);
 		g_value_unset (&value);
 	}
-		
+
 	/* Set bitrate */
 	if (song->bitrate != 0) {
 		GValue value = {0, };
 		g_value_init (&value, G_TYPE_ULONG);
 		g_value_set_ulong (&value, song->bitrate);
-		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
-					       RHYTHMDB_PROP_BITRATE, 
+		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
+					       RHYTHMDB_PROP_BITRATE,
 					       &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, 
+		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, 
+		rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
+					       RHYTHMDB_PROP_FILE_SIZE,
 					       &value);
 		g_value_unset (&value);
 	}
@@ -385,15 +431,15 @@
 		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);
@@ -412,7 +458,7 @@
 					       &value);
 		g_value_unset (&value);
 	}
-		
+
 	/* Set last played */
 	if (song->time_played != 0) {
 		GValue value = {0, };
@@ -423,19 +469,19 @@
 					       &value);
 		g_value_unset (&value);
 	}
-		
-	/* Set title */		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
+
+	/* 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, 
+	entry_set_string_prop (RHYTHMDB (db), entry,
 			       RHYTHMDB_PROP_ARTIST, song->artist);
-		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
+
+	entry_set_string_prop (RHYTHMDB (db), entry,
 			       RHYTHMDB_PROP_ALBUM, song->album);
-		
-	entry_set_string_prop (RHYTHMDB (db), entry, 
+
+	entry_set_string_prop (RHYTHMDB (db), entry,
 			       RHYTHMDB_PROP_GENRE, song->genre);
 
 
@@ -451,11 +497,11 @@
 	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);
@@ -482,8 +528,8 @@
 		/* 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, 
+		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);
 	}
@@ -519,7 +565,7 @@
 	if (mount_point == NULL) {
 		return NULL;
 	}
-	result = g_build_filename (mount_point, 
+	result = g_build_filename (mount_point,
 				   "iPod_Control/iTunes/iTunesDB",
 				   NULL);
 	g_free (mount_point);
@@ -565,7 +611,7 @@
 		}
 	}
 #endif
-	
+
 	return rb_ipod_volume_has_ipod_db (volume);
 }
 
@@ -582,11 +628,11 @@
 
 	result = FALSE;
 	dbus_error_init (&error);
-	
+
 	conn = NULL;
 	ctx = libhal_ctx_new ();
 	if (ctx == NULL) {
-		/* FIXME: should we return an error somehow so that we can 
+		/* FIXME: should we return an error somehow so that we can
 		 * fall back to a check for iTunesDB presence instead ?
 		 */
 		rb_debug ("cannot connect to HAL");
@@ -604,7 +650,7 @@
 			"info.parent", &error);
 	if (parent_udi == NULL || dbus_error_is_set (&error))
 		goto end;
-		
+
 	parent_name = libhal_device_get_property_string (ctx, parent_udi,
 			"storage.model", &error);
 	g_free (parent_udi);
@@ -644,7 +690,7 @@
 	result = FALSE;
 	ctx = hal_initialize (NULL, FALSE);
 	if (ctx == NULL) {
-		/* FIXME: should we return an error somehow so that we can 
+		/* FIXME: should we return an error somehow so that we can
 		 * fall back to a check for iTunesDB presence instead ?
 		 */
 		return FALSE;
@@ -671,9 +717,9 @@
 impl_get_ui_actions (RBSource *source)
 {
 	GList *actions = NULL;
- 
+
 	actions = g_list_prepend (actions, g_strdup ("RemovableSourceEject"));
- 
+
 	return actions;
 }
 
@@ -719,7 +765,7 @@
 		Itdb_Track *track;
 
 		entry = (RhythmDBEntry *)tem->data;
-		uri = rhythmdb_entry_get_string (entry, 
+		uri = rhythmdb_entry_get_string (entry,
 						 RHYTHMDB_PROP_LOCATION);
 		track = g_hash_table_lookup (priv->entry_map, entry);
 		if (track == NULL) {
@@ -738,6 +784,356 @@
 
 	g_list_free (sel);
 }
+
+static void
+itdb_schedule_save (Itdb_iTunesDB *db)
+{
+       /* 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);
+}
+
+
+#ifdef ENABLE_TRACK_TRANSFER
+static char *
+build_filename (RBSource *asource, RhythmDBEntry *entry)
+{
+	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);
+	dest_uri = g_filename_to_uri (dest, NULL, NULL);
+	g_free (dest);
+
+	return dest_uri;
+}
+
+static void
+completed_cb (RhythmDBEntry *entry, const char *dest, 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);
+	}
+
+	g_object_unref (db);
+}
+
+static void
+impl_paste (RBSource *asource, GList *entries)
+{
+	RBRemovableMediaManager *rm_mgr;
+	GList *l;
+	RBShell *shell;
+
+	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));
+
+	for (l = entries; l != NULL; l = l->next) {
+		RhythmDBEntry *entry;
+		RhythmDBEntryType entry_type;
+		RhythmDBEntryType ipod_entry_type;
+		char *dest;
+
+		entry = (RhythmDBEntry *)l->data;
+		entry_type = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TYPE);
+		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;
+
+		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);
+	}
+	g_object_unref (G_OBJECT (rm_mgr));
+}
+
+
+static gboolean
+impl_receive_drag (RBSource *asource, GtkSelectionData *data)
+{
+	RBBrowserSource *source = RB_BROWSER_SOURCE (asource);
+	GList *list, *i;
+	GList *entries = NULL;
+	RBShell *shell;
+	RhythmDB *db;
+
+	rb_debug ("parsing uri list");
+	list = rb_uri_list_parse ((const char *) data->data);
+
+  	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+  	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+  	g_object_unref (G_OBJECT (shell));
+
+	for (i = list; i != NULL; i = g_list_next (i)) {
+		if (i->data != NULL) {
+			char *uri = i->data;
+			RhythmDBEntry *entry;
+
+			entry = rhythmdb_entry_lookup_by_location (db, uri);
+
+			if (entry == NULL) {
+				/* add to the library */
+				g_print ("Where does that come from?\n");
+			} else {
+				/* add to list of entries to copy */
+				entries = g_list_prepend (entries, entry);
+			}
+
+			g_free (uri);
+		}
+	}
+	g_object_unref (db);
+	g_list_free (list);
+
+	if (entries) {
+		entries = g_list_reverse (entries);
+		if (rb_source_can_paste (asource))
+			rb_source_paste (asource, entries);
+		g_list_free (entries);
+	}
+
+
+	return TRUE;
+}
+
+
+/* Generation of the filename for the ipod */
+
+#define IPOD_MAX_PATH_LEN 56
+
+static gchar *
+get_ipod_filename (const char *mount_point, const char *filename)
+{
+	char *dirname;
+	char *result;
+	char *tmp;
+
+	dirname = g_strdup_printf ("f%02d", g_random_int_range (0, 100));
+	result =  g_build_filename (G_DIR_SEPARATOR_S, "iPod_Control",
+				    "Music", dirname, filename, NULL);
+	g_free (dirname);
+
+	if (strlen (result) >= IPOD_MAX_PATH_LEN) {
+		char *ext;
+
+		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);
+		}
+	}
+
+	tmp = g_build_filename (mount_point, result, NULL);
+	g_free (result);
+	return tmp;
+}
+
+#define MAX_TRIES 5
+
+/* Strips non UTF8 characters from a string replacing them with _ */
+static gchar *
+utf8_to_ascii (const gchar *utf8)
+{
+	GString *string;
+	const guchar *it = (const guchar *)utf8;
+
+	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);
+		} else {
+			g_string_append_c (string, '_');
+		}
+		it = (const guchar *)g_utf8_next_char (it);
+	}
+
+	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)
+{
+	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, '_');
+
+		remaining_bytes -= valid_bytes + 1;
+		remainder = invalid + 1;
+	}
+
+	if (string == NULL) {
+		return g_strdup (name);
+	}
+
+	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++;
+	} while ((g_file_test (ipod_filename, G_FILE_TEST_EXISTS))
+		 && tries <= MAX_TRIES) ;
+
+	g_free (pc_filename);
+
+	if (tries > MAX_TRIES) {
+		/* FIXME: should create a unique filename */
+		return NULL;
+	} else {
+		return ipod_filename;
+	}
+}
+
+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;
+	}
+	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);
+
+	return result;
+}
+
+/* End of generation of the filename on the iPod */
+
+static gchar *
+ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path)
+{
+        gchar *ipod_path;
+
+        g_assert (g_utf8_validate (unix_path, -1, NULL));
+
+        if (!g_str_has_prefix (unix_path, mount_point)) {
+                return NULL;
+        }
+
+        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;
+        }
+
+        /* 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;
+}
+#endif
 
 static void
 impl_delete_thyself (RBSource *source)
