? help/sv/.xml2po.mo
? help/sv/rhythmbox.xml
? lib/media-eject-inline.h
? lib/rhythmbox-no-star-inline.h
? lib/rhythmbox-podcast-inline.h
? lib/rhythmbox-set-star-inline.h
? lib/rhythmbox-tray-icon-inline.h
? lib/rhythmbox-unset-star-inline.h
? plugins/iradio
? plugins/artdisplay/artdisplay/Makefile
? plugins/artdisplay/artdisplay/Makefile.in
? plugins/generic-player/Makefile
? plugins/generic-player/Makefile.in
? plugins/generic-player/generic-player.rb-plugin
? plugins/lyrics/Makefile
? plugins/lyrics/Makefile.in
? plugins/lyrics/lyrics.rb-plugin
? plugins/rb/Makefile
? plugins/rb/Makefile.in
? remote/Makefile
? remote/Makefile.in
? remote/dbus/rhythmbox-client
? shell/main.c.new
? shell/rb-shell-binding.h
? shell/rb-shell-player-binding.h
? shell/rb-shell-player.loT
? tests/bench-rhythmdb-load
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/Makefile.am,v
retrieving revision 1.53
diff -p -u -r1.53 Makefile.am
--- Makefile.am	10 Jul 2006 02:00:32 -0000	1.53
+++ Makefile.am	10 Jul 2006 22:47:16 -0000
@@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS = 1.7
 DISTCHECK_CONFIGURE_FLAGS = --disable-schemas-install --enable-gtk-doc --disable-scrollkeeper
 distuninstallcheck_listfiles = find . -type f -print | grep -v '^\./var/scrollkeeper'
 
-SUBDIRS = macros lib metadata rhythmdb widgets sources iradio podcast \
+SUBDIRS = macros lib metadata rhythmdb widgets sources podcast \
 	daapsharing backends plugins bindings shell remote data po help tests doc
 
 EXTRA_DIST = 			\
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.251
diff -p -u -r1.251 configure.ac
--- configure.ac	10 Jul 2006 02:00:32 -0000	1.251
+++ configure.ac	10 Jul 2006 22:47:16 -0000
@@ -915,7 +915,6 @@ metadata/Makefile
 rhythmdb/Makefile
 widgets/Makefile
 widgets/libsexy/Makefile
-iradio/Makefile
 podcast/Makefile
 shell/Makefile
 data/Makefile
@@ -929,6 +928,7 @@ plugins/sample/Makefile
 plugins/audioscrobbler/Makefile
 plugins/cd-recorder/Makefile
 plugins/ipod/Makefile
+plugins/iradio/Makefile
 plugins/lirc/Makefile
 plugins/lyrics/Makefile
 plugins/sample-python/Makefile
Index: bindings/python/rb.defs
===================================================================
RCS file: /cvs/gnome/rhythmbox/bindings/python/rb.defs,v
retrieving revision 1.30
diff -p -u -r1.30 rb.defs
--- bindings/python/rb.defs	9 Jul 2006 13:39:21 -0000	1.30
+++ bindings/python/rb.defs	10 Jul 2006 22:47:16 -0000
@@ -252,7 +252,6 @@
   (c-name "rb_shell_add_uri")
   (return-type "gboolean")
   (parameters
-    '("RhythmDBEntryType_*" "entry_type")
     '("const-char*" "uri")
     '("const-char*" "title")
     '("const-char*" "genre")
Index: plugins/audioscrobbler/rb-audioscrobbler.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/plugins/audioscrobbler/rb-audioscrobbler.c,v
retrieving revision 1.28
diff -p -u -r1.28 rb-audioscrobbler.c
--- plugins/audioscrobbler/rb-audioscrobbler.c	1 Jul 2006 01:58:38 -0000	1.28
+++ plugins/audioscrobbler/rb-audioscrobbler.c	10 Jul 2006 22:47:16 -0000
@@ -1007,9 +1007,7 @@ rb_audioscrobbler_song_changed_cb (RBShe
 	}
 
 	type = rhythmdb_entry_get_entry_type (entry);
-	if (type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION ||
-	    type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST ||
-	    type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED ||
+	if (type != RHYTHMDB_ENTRY_TYPE_SONG ||
 	    rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_PLAYBACK_ERROR) != NULL) {
 		audioscrobbler->priv->should_queue = FALSE;
 		return;
Index: plugins/cd-recorder/rb-cd-recorder-plugin.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/plugins/cd-recorder/rb-cd-recorder-plugin.c,v
retrieving revision 1.1
diff -p -u -r1.1 rb-cd-recorder-plugin.c
--- plugins/cd-recorder/rb-cd-recorder-plugin.c	10 Jul 2006 02:00:34 -0000	1.1
+++ plugins/cd-recorder/rb-cd-recorder-plugin.c	10 Jul 2006 22:47:16 -0000
@@ -19,9 +19,7 @@
 
 #define __EXTENSIONS__
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
 
 #include <string.h> /* For strlen */
 #include <glib/gi18n-lib.h>
Index: rhythmdb/rhythmdb-tree.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-tree.c,v
retrieving revision 1.111
diff -p -u -r1.111 rhythmdb-tree.c
--- rhythmdb/rhythmdb-tree.c	1 Jul 2006 01:58:39 -0000	1.111
+++ rhythmdb/rhythmdb-tree.c	10 Jul 2006 22:47:16 -0000
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- * 
+ *
  *  arch-tag: Implementation of RhythmDB tree-structured database
  *
  *  Copyright (C) 2003, 2004 Colin Walters <walters@verbum.org>
@@ -51,7 +51,7 @@ typedef struct RhythmDBTreeProperty
 {
 #ifndef G_DISABLE_ASSERT
 	guint magic;
-#endif	
+#endif
 	struct RhythmDBTreeProperty *parent;
 	GHashTable *children;
 } RhythmDBTreeProperty;
@@ -79,22 +79,21 @@ static void rhythmdb_tree_do_full_query 
 static gboolean rhythmdb_tree_evaluate_query (RhythmDB *adb, GPtrArray *query,
 				       RhythmDBEntry *aentry);
 
-typedef void (*RBTreeEntryItFunc)(RhythmDBTree *db, 
-				  RhythmDBEntry *entry, 
+typedef void (*RBTreeEntryItFunc)(RhythmDBTree *db,
+				  RhythmDBEntry *entry,
 				  gpointer data);
 
-typedef void (*RBTreePropertyItFunc)(RhythmDBTree *db, 
-				     RhythmDBTreeProperty *property, 
+typedef void (*RBTreePropertyItFunc)(RhythmDBTree *db,
+				     RhythmDBTreeProperty *property,
 				     gpointer data);
-static void rhythmdb_hash_tree_foreach (RhythmDB *adb, 
+static void rhythmdb_hash_tree_foreach (RhythmDB *adb,
 					RhythmDBEntryType type,
-					RBTreeEntryItFunc entry_func, 
+					RBTreeEntryItFunc entry_func,
 					RBTreePropertyItFunc album_func,
 					RBTreePropertyItFunc artist_func,
 					RBTreePropertyItFunc genres_func,
 					gpointer data);
 
-
 #define RHYTHMDB_TREE_XML_VERSION "1.3"
 
 static void destroy_tree_property (RhythmDBTreeProperty *prop);
@@ -130,7 +129,6 @@ enum
 
 const int RHYTHMDB_TREE_PARSER_INITIAL_BUFFER_SIZE = 512;
 
-
 static void
 rhythmdb_tree_class_init (RhythmDBTreeClass *klass)
 {
@@ -294,7 +292,7 @@ rhythmdb_tree_parser_start_element (stru
 			ctx->in_unknown_elt = TRUE;
 			break;
 		}
-		
+
 		ctx->state = RHYTHMDB_TREE_PARSER_STATE_ENTRY_PROPERTY;
 		ctx->propid = val;
 		g_string_truncate (ctx->buf, 0);
@@ -315,10 +313,10 @@ rhythmdb_tree_parser_end_element (struct
 	}
 
 	if (ctx->in_unknown_elt) {
-		ctx->in_unknown_elt = FALSE;		
+		ctx->in_unknown_elt = FALSE;
 		return;
 	}
-	
+
 	switch (ctx->state)
 	{
 	case RHYTHMDB_TREE_PARSER_STATE_RHYTHMDB:
@@ -344,7 +342,7 @@ rhythmdb_tree_parser_end_element (struct
 				podcast->post_time = ctx->entry->last_seen;
 			}
 		}
-		
+
 		if (ctx->entry->location != NULL) {
 			RhythmDBEntry *entry;
 
@@ -373,7 +371,7 @@ rhythmdb_tree_parser_end_element (struct
 
 				if (ctx->entry->last_seen > entry->last_seen)
 					entry->last_seen = ctx->entry->last_seen;
-				
+
 				rhythmdb_entry_unref (ctx->entry);
 			}
 		} else {
@@ -484,7 +482,7 @@ rhythmdb_tree_load (RhythmDB *rdb, gbool
 
 		if (ctx->batch_count)
 			rhythmdb_commit (RHYTHMDB (ctx->db));
-			
+
 	}
 	g_string_free (ctx->buf, TRUE);
 	g_free (name);
@@ -638,8 +636,6 @@ save_entry (RhythmDBTree *db, RhythmDBEn
 
 	if (entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
 		RHYTHMDB_FWRITE_STATICSTR ("song", ctx->handle, ctx->error);
-	} else if (entry->type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION) {
-		RHYTHMDB_FWRITE_STATICSTR ("iradio", ctx->handle, ctx->error);
 	} else if (entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
 		RHYTHMDB_FWRITE_STATICSTR ("podcast-post", ctx->handle, ctx->error);
 	} else if (entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
@@ -647,18 +643,19 @@ save_entry (RhythmDBTree *db, RhythmDBEn
 	} else if (entry->type == RHYTHMDB_ENTRY_TYPE_IGNORE) {
 		RHYTHMDB_FWRITE_STATICSTR ("ignore", ctx->handle, ctx->error);
 	} else {
-		g_assert_not_reached ();
+		/* type installed by a plugin */
+		RHYTHMDB_FWRITE_STATICSTR (entry->type->name, ctx->handle, ctx->error);
 	}
 
 	RHYTHMDB_FWRITE_STATICSTR ("\">\n", ctx->handle, ctx->error);
-		
+
 	/* Skip over the first property - the type */
 	for (i = 1; i < RHYTHMDB_NUM_PROPERTIES; i++) {
 		const xmlChar *elt_name;
 
 		if (ctx->error)
 			return;
-		
+
 		elt_name = rhythmdb_nice_elt_name_from_propid ((RhythmDB *) ctx->db, i);
 
 		switch (i)
@@ -781,7 +778,7 @@ save_entry (RhythmDBTree *db, RhythmDBEn
 		case RHYTHMDB_PROP_POST_TIME:
 			if (podcast)
 				save_entry_ulong (ctx, elt_name, podcast->post_time, FALSE);
-			break;			
+			break;
 		case RHYTHMDB_PROP_TITLE_SORT_KEY:
 		case RHYTHMDB_PROP_GENRE_SORT_KEY:
 		case RHYTHMDB_PROP_ARTIST_SORT_KEY:
@@ -829,13 +826,14 @@ rhythmdb_tree_save (RhythmDB *rdb)
 	ctx.handle = f;
 	ctx.error = NULL;
 	RHYTHMDB_FWRITE_STATICSTR ("<?xml version=\"1.0\" standalone=\"yes\"?>\n"
-				   "<rhythmdb version=\"" RHYTHMDB_TREE_XML_VERSION "\">\n", 
+				   "<rhythmdb version=\"" RHYTHMDB_TREE_XML_VERSION "\">\n",
 				   ctx.handle, ctx.error);
 
 	rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_SONG,
 				    (RBTreeEntryItFunc)save_entry,
 				    NULL, NULL, NULL, &ctx);
-	rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_IRADIO_STATION,
+	/* FIXME: do this dynamically but exclude aliases */
+	rhythmdb_hash_tree_foreach (rdb, rhythmdb_entry_type_get_by_name ("iradio"),
 				    (RBTreeEntryItFunc)save_entry,
 				    NULL, NULL, NULL, &ctx);
 	rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
@@ -941,7 +939,7 @@ rhythmdb_tree_entry_new (RhythmDB *rdb, 
 
 	/* this accounts for the initial reference on the entry */
 	g_hash_table_insert (db->priv->entries, entry->location, entry);
-	
+
 	entry->flags &= ~RHYTHMDB_ENTRY_TREE_LOADING;
 }
 
@@ -951,7 +949,7 @@ rhythmdb_tree_property_new (RhythmDBTree
 	RhythmDBTreeProperty *ret = g_new0 (RhythmDBTreeProperty, 1);
 #ifndef G_DISABLE_ASSERT
 	ret->magic = 0xf00dbeef;
-#endif	
+#endif
 	return ret;
 }
 
@@ -970,22 +968,22 @@ get_genres_hash_for_type (RhythmDBTree *
 			g_warning ("Out of memory\n");
 			return NULL;
 		}
-		g_hash_table_insert (db->priv->genres, 
+		g_hash_table_insert (db->priv->genres,
 				     type,
 				     table);
-	} 
+	}
 	return table;
 }
 
 typedef void (*RBHFunc)(RhythmDBTree *db, GHashTable *genres, gpointer data);
 
-typedef struct {	
+typedef struct {
 	RhythmDBTree *db;
 	RBHFunc func;
 	gpointer data;
 } GenresIterCtxt;
 
-static void 
+static void
 genres_process_one (gpointer key,
 		    gpointer value,
 		    gpointer user_data)
@@ -1013,7 +1011,7 @@ get_or_create_genre (RhythmDBTree *db, R
 	GHashTable *table;
 
 	table = get_genres_hash_for_type (db, type);
-	genre = g_hash_table_lookup (table, name);		
+	genre = g_hash_table_lookup (table, name);
 
 	if (G_UNLIKELY (genre == NULL)) {
 		genre = rhythmdb_tree_property_new (db);
@@ -1082,7 +1080,7 @@ static void
 remove_entry_from_album (RhythmDBTree *db, RhythmDBEntry *entry)
 {
 	GHashTable *table;
-			
+
 	rb_refstring_ref (entry->genre);
 	rb_refstring_ref (entry->artist);
 	rb_refstring_ref (entry->album);
@@ -1149,16 +1147,16 @@ rhythmdb_tree_entry_set (RhythmDB *adb, 
 
 		if (strcmp (rb_refstring_get (entry->album), albumname)) {
 			RhythmDBTreeProperty *artist;
-			RhythmDBTreeProperty *genre;			
+			RhythmDBTreeProperty *genre;
 
 			rb_refstring_ref (entry->genre);
 			rb_refstring_ref (entry->artist);
 			rb_refstring_ref (entry->album);
 
-			remove_entry_from_album (db, entry); 
+			remove_entry_from_album (db, entry);
 
-			genre = get_or_create_genre (db, type, entry->genre); 
-			artist = get_or_create_artist (db, genre, entry->artist); 
+			genre = get_or_create_genre (db, type, entry->genre);
+			artist = get_or_create_artist (db, genre, entry->artist);
 			set_entry_album (db, entry, artist, rb_refstring_new (albumname));
 
 			rb_refstring_unref (entry->genre);
@@ -1173,17 +1171,17 @@ rhythmdb_tree_entry_set (RhythmDB *adb, 
 
 		if (strcmp (rb_refstring_get (entry->artist), artistname)) {
 			RhythmDBTreeProperty *new_artist;
-			RhythmDBTreeProperty *genre;			
+			RhythmDBTreeProperty *genre;
 
 			rb_refstring_ref (entry->genre);
 			rb_refstring_ref (entry->artist);
 			rb_refstring_ref (entry->album);
 
-			remove_entry_from_album (db, entry); 
+			remove_entry_from_album (db, entry);
 
-			genre = get_or_create_genre (db, type, entry->genre); 
+			genre = get_or_create_genre (db, type, entry->genre);
 			new_artist = get_or_create_artist (db, genre,
-							   rb_refstring_new (artistname)); 
+							   rb_refstring_new (artistname));
 			set_entry_album (db, entry, new_artist, entry->album);
 
 			rb_refstring_unref (entry->genre);
@@ -1197,14 +1195,14 @@ rhythmdb_tree_entry_set (RhythmDB *adb, 
 		const char *genrename = g_value_get_string (value);
 
 		if (strcmp (rb_refstring_get (entry->genre), genrename)) {
-			RhythmDBTreeProperty *new_genre;			
+			RhythmDBTreeProperty *new_genre;
 			RhythmDBTreeProperty *new_artist;
 
 			rb_refstring_ref (entry->genre);
 			rb_refstring_ref (entry->artist);
 			rb_refstring_ref (entry->album);
 
-			remove_entry_from_album (db, entry); 
+			remove_entry_from_album (db, entry);
 
 			new_genre = get_or_create_genre (db, type,
 							 rb_refstring_new (genrename));
@@ -1229,7 +1227,7 @@ rhythmdb_tree_entry_delete (RhythmDB *ad
 {
 	RhythmDBTree *db = RHYTHMDB_TREE (adb);
 
-	remove_entry_from_album (db, entry); 
+	remove_entry_from_album (db, entry);
 
 	g_assert (g_hash_table_lookup (db->priv->entries, entry->location) != NULL);
 
@@ -1243,21 +1241,20 @@ typedef struct {
 } RbEntryRemovalCtxt;
 
 static gboolean
-remove_one_song (gchar *uri, RhythmDBEntry *entry, 
+remove_one_song (gchar *uri, RhythmDBEntry *entry,
 		 RbEntryRemovalCtxt *ctxt)
 {
 	g_return_val_if_fail (entry != NULL, FALSE);
 
 	if (entry->type == ctxt->type) {
 		rhythmdb_emit_entry_deleted (ctxt->db, entry);
-		remove_entry_from_album (RHYTHMDB_TREE (ctxt->db), entry); 
+		remove_entry_from_album (RHYTHMDB_TREE (ctxt->db), entry);
 		rhythmdb_entry_unref (entry);
 		return TRUE;
 	}
 	return FALSE;
 }
 
-
 static void
 rhythmdb_tree_entry_delete_by_type (RhythmDB *adb, RhythmDBEntryType type)
 {
@@ -1266,11 +1263,10 @@ rhythmdb_tree_entry_delete_by_type (Rhyt
 
 	ctxt.db = adb;
 	ctxt.type = type;
-	g_hash_table_foreach_remove (db->priv->entries, 
+	g_hash_table_foreach_remove (db->priv->entries,
 				     (GHRFunc) remove_one_song, &ctxt);
 }
 
-
 static void
 destroy_tree_property (RhythmDBTreeProperty *prop)
 {
@@ -1365,14 +1361,14 @@ search_match_properties (RhythmDB *db, R
 	gboolean islike = TRUE;
 	gchar **current;
 	int i;
-	
+
 	for (current = words; *current != NULL; current++) {
 		gboolean word_found = FALSE;
 
 		for (i = 0; i < G_N_ELEMENTS (props); i++) {
 			const char *entry_string = rhythmdb_entry_get_string (entry, props[i]);
 			if (entry_string && (strstr (entry_string, *current) != NULL)) {
-				/* the word was found, go to the next one */	
+				/* the word was found, go to the next one */
 				word_found = TRUE;
 				break;
 			}
@@ -1450,7 +1446,7 @@ evaluate_conjunctive_subquery (RhythmDBT
 		{
 			const char *value_s;
 			const char *entry_s;
-			
+
 			g_assert (rhythmdb_get_property_type (db, data->propid) == G_TYPE_STRING);
 
 			value_s = g_value_get_string (data->val);
@@ -1460,7 +1456,7 @@ evaluate_conjunctive_subquery (RhythmDBT
 				return FALSE;
 			if (data->type == RHYTHMDB_QUERY_PROP_SUFFIX && !g_str_has_suffix (entry_s, value_s))
 				return FALSE;
-			
+
 			break;
 		}
 		case RHYTHMDB_QUERY_PROP_LIKE:
@@ -1472,7 +1468,7 @@ evaluate_conjunctive_subquery (RhythmDBT
 				if (data->propid == RHYTHMDB_PROP_SEARCH_MATCH) {
 					/* this is a special property, that should match several things */
 					islike = search_match_properties (db, entry, g_value_get_boxed (data->val));
-					
+
 				} else {
 					const gchar *value_string = g_value_get_string (data->val);
 					const char *entry_string = rhythmdb_entry_get_string (entry, data->propid);
@@ -1489,7 +1485,7 @@ evaluate_conjunctive_subquery (RhythmDBT
 				else
 					continue;
 				break;
-			} 
+			}
 			/* Fall through */
 		}
 		case RHYTHMDB_QUERY_PROP_EQUALS:
@@ -1543,7 +1539,7 @@ clone_remove_ptr_array_index (GPtrArray 
 	for (i = 0; i < arr->len; i++)
 		if (i != index)
 			g_ptr_array_add (ret, g_ptr_array_index (arr, i));
-	
+
 	return ret;
 }
 
@@ -1564,7 +1560,7 @@ conjunctive_query_albums (const char *na
 			if (album_query_idx > 0)
 				return;
 			album_query_idx = i;
-			
+
 		}
 	}
 
@@ -1575,7 +1571,7 @@ conjunctive_query_albums (const char *na
 		GPtrArray *oldquery = data->query;
 
 		data->query = clone_remove_ptr_array_index (data->query, album_query_idx);
-		
+
 		album = g_hash_table_lookup (artist->children, albumname);
 
 		if (album != NULL) {
@@ -1584,7 +1580,7 @@ conjunctive_query_albums (const char *na
 		g_ptr_array_free (data->query, TRUE);
 		data->query = oldquery;
 		return;
-	} 
+	}
 
 	g_hash_table_foreach (artist->children, (GHFunc) conjunctive_query_songs, data);
 }
@@ -1606,7 +1602,7 @@ conjunctive_query_artists (const char *n
 			if (artist_query_idx > 0)
 				return;
 			artist_query_idx = i;
-			
+
 		}
 	}
 
@@ -1617,7 +1613,7 @@ conjunctive_query_artists (const char *n
 		GPtrArray *oldquery = data->query;
 
 		data->query = clone_remove_ptr_array_index (data->query, artist_query_idx);
-		
+
 		artist = g_hash_table_lookup (genre->children, artistname);
 		if (artist != NULL) {
 			conjunctive_query_albums (rb_refstring_get (artistname), artist, data);
@@ -1625,7 +1621,7 @@ conjunctive_query_artists (const char *n
 		g_ptr_array_free (data->query, TRUE);
 		data->query = oldquery;
 		return;
-	} 
+	}
 
 	g_hash_table_foreach (genre->children, (GHFunc) conjunctive_query_albums, data);
 }
@@ -1639,7 +1635,7 @@ conjunctive_query_genre (RhythmDBTree *d
 
 	if (G_UNLIKELY (*data->cancel))
 		return;
-	
+
 	for (i = 0; i < data->query->len; i++) {
 		RhythmDBQueryData *qdata = g_ptr_array_index (data->query, i);
 		if (qdata->type == RHYTHMDB_QUERY_PROP_EQUALS
@@ -1650,7 +1646,7 @@ conjunctive_query_genre (RhythmDBTree *d
 			if (genre_query_idx > 0)
 				return;
 			genre_query_idx = i;
-			
+
 		}
 	}
 
@@ -1661,15 +1657,15 @@ conjunctive_query_genre (RhythmDBTree *d
 		GPtrArray *oldquery = data->query;
 
 		data->query = clone_remove_ptr_array_index (data->query, genre_query_idx);
-		
+
 		genre = g_hash_table_lookup (genres, genrename);
 		if (genre != NULL) {
 			conjunctive_query_artists (rb_refstring_get (genrename), genre, data);
-		} 
+		}
 		g_ptr_array_free (data->query, TRUE);
 		data->query = oldquery;
 		return;
-	} 
+	}
 
 	g_hash_table_foreach (genres, (GHFunc) conjunctive_query_artists, data);
 }
@@ -1682,7 +1678,7 @@ conjunctive_query (RhythmDBTree *db, GPt
 	int type_query_idx = -1;
 	guint i;
 	struct RhythmDBTreeTraversalData *traversal_data;
-	
+
 	for (i = 0; i < query->len; i++) {
 		RhythmDBQueryData *qdata = g_ptr_array_index (query, i);
 		if (qdata->type == RHYTHMDB_QUERY_PROP_EQUALS
@@ -1705,9 +1701,9 @@ conjunctive_query (RhythmDBTree *db, GPt
 		GHashTable *genres;
 		RhythmDBEntryType etype;
 		RhythmDBQueryData *qdata = g_ptr_array_index (query, type_query_idx);
-		
+
 		g_ptr_array_remove_index_fast (query, type_query_idx);
-		
+
 		etype = g_value_get_pointer (qdata->val);
 		genres = get_genres_hash_for_type (db, etype);
 		if (genres != NULL) {
@@ -1718,14 +1714,13 @@ conjunctive_query (RhythmDBTree *db, GPt
 	} else {
 		/* FIXME */
 		/* No type was given; punt and query everything */
-		genres_hash_foreach (db, (RBHFunc)conjunctive_query_genre, 
+		genres_hash_foreach (db, (RBHFunc)conjunctive_query_genre,
 				     traversal_data);
 	}
 
 	g_free (traversal_data);
 }
 
-
 static GList *
 split_query_by_disjunctions (RhythmDBTree *db, GPtrArray *query)
 {
@@ -1754,10 +1749,10 @@ split_query_by_disjunctions (RhythmDBTre
 	for (i = last_disjunction; i < query->len; i++) {
 		g_ptr_array_add (subquery, g_ptr_array_index (query, i));
 	}
-	
+
 	if (subquery->len > 0)
 		conjunctions = g_list_prepend (conjunctions, subquery);
-	
+
 	return conjunctions;
 }
 
@@ -1777,7 +1772,7 @@ do_query_recurse (RhythmDBTree *db, GPtr
 
 	if (query == NULL)
 		return;
-	
+
 	conjunctions = split_query_by_disjunctions (db, query);
 	rb_debug ("doing recursive query, %d conjunctions", g_list_length (conjunctions));
 
@@ -1867,7 +1862,7 @@ rhythmdb_tree_entry_foreach (RhythmDB *a
 	ctx->db = db;
 	ctx->func = func;
 	ctx->user_data = user_data;
-	g_hash_table_foreach (db->priv->entries, 
+	g_hash_table_foreach (db->priv->entries,
 			      (GHFunc) rhythmdb_tree_entry_foreach_func, ctx);
 	g_free (ctx);
 }
@@ -1888,11 +1883,10 @@ hash_tree_entries_foreach (gpointer key,
 	struct HashTreeIteratorCtxt *ctxt = (struct HashTreeIteratorCtxt*)data;
 
 	g_assert (ctxt->entry_func);
-	
+
 	ctxt->entry_func (ctxt->db, entry, ctxt->data);
 }
 
-
 static void
 hash_tree_albums_foreach (gpointer key, gpointer value, gpointer data)
 {
@@ -1903,56 +1897,52 @@ hash_tree_albums_foreach (gpointer key, 
 		ctxt->album_func (ctxt->db, album, ctxt->data);
 	}
 	if (ctxt->entry_func != NULL) {
-		g_hash_table_foreach (album->children, 
-				      hash_tree_entries_foreach, 
+		g_hash_table_foreach (album->children,
+				      hash_tree_entries_foreach,
 				      ctxt);
 	}
 }
 
-
 static void
 hash_tree_artists_foreach (gpointer key, gpointer value, gpointer data)
 {
 	RhythmDBTreeProperty *artist = (RhythmDBTreeProperty *)value;
 	struct HashTreeIteratorCtxt *ctxt = (struct HashTreeIteratorCtxt*)data;
 
-
 	if (ctxt->artist_func) {
 		ctxt->artist_func (ctxt->db, artist, ctxt->data);
 	}
 	if ((ctxt->album_func != NULL) || (ctxt->entry_func != NULL)) {
-		g_hash_table_foreach (artist->children, 
-				      hash_tree_albums_foreach, 
+		g_hash_table_foreach (artist->children,
+				      hash_tree_albums_foreach,
 				      ctxt);
 	}
 }
 
-
 static void
 hash_tree_genres_foreach (gpointer key, gpointer value, gpointer data)
 {
 	RhythmDBTreeProperty *genre = (RhythmDBTreeProperty *)value;
 	struct HashTreeIteratorCtxt *ctxt = (struct HashTreeIteratorCtxt*)data;
 
-
 	if (ctxt->genres_func) {
 		ctxt->genres_func (ctxt->db, genre, ctxt->data);
 	}
 
-	if ((ctxt->album_func != NULL) 
-	    || (ctxt->artist_func != NULL) 
+	if ((ctxt->album_func != NULL)
+	    || (ctxt->artist_func != NULL)
 	    || (ctxt->entry_func != NULL)) {
-		g_hash_table_foreach (genre->children, 
-				      hash_tree_artists_foreach, 
+		g_hash_table_foreach (genre->children,
+				      hash_tree_artists_foreach,
 				      ctxt);
 	}
 }
 
 static void
-rhythmdb_hash_tree_foreach (RhythmDB *adb, 
+rhythmdb_hash_tree_foreach (RhythmDB *adb,
 			    RhythmDBEntryType type,
-			    RBTreeEntryItFunc entry_func, 
-			    RBTreePropertyItFunc album_func, 
+			    RBTreeEntryItFunc entry_func,
+			    RBTreePropertyItFunc album_func,
 			    RBTreePropertyItFunc artist_func,
 			    RBTreePropertyItFunc genres_func,
 			    gpointer data)
@@ -1971,8 +1961,8 @@ rhythmdb_hash_tree_foreach (RhythmDB *ad
 	if (table == NULL) {
 		return;
 	}
-	if ((ctxt.album_func != NULL) 
-	    || (ctxt.artist_func != NULL) 
+	if ((ctxt.album_func != NULL)
+	    || (ctxt.artist_func != NULL)
 	    || (ctxt.genres_func != NULL)
 	    || (ctxt.entry_func != NULL)) {
 		g_hash_table_foreach (table, hash_tree_genres_foreach, &ctxt);
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.234
diff -p -u -r1.234 rhythmdb.c
--- rhythmdb/rhythmdb.c	10 Jul 2006 04:19:58 -0000	1.234
+++ rhythmdb/rhythmdb.c	10 Jul 2006 22:47:17 -0000
@@ -45,14 +45,11 @@
 #include "rb-preferences.h"
 #include "eel-gconf-extensions.h"
 
-
 #define RB_PARSE_NICK_START (xmlChar *) "["
 #define RB_PARSE_NICK_END (xmlChar *) "]"
 
-
 GType rhythmdb_property_type_map[RHYTHMDB_NUM_PROPERTIES];
 
-
 #define RHYTHMDB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RHYTHMDB_TYPE, RhythmDBPrivate))
 G_DEFINE_ABSTRACT_TYPE(RhythmDB, rhythmdb, G_TYPE_OBJECT)
 
@@ -83,7 +80,6 @@ typedef struct
  	RhythmDBEntryType entry_type;
 } RhythmDBAction;
 
-
 static void rhythmdb_finalize (GObject *object);
 static void rhythmdb_set_property (GObject *object,
 					guint prop_id,
@@ -100,11 +96,11 @@ static gboolean rhythmdb_idle_poll_event
 static gpointer add_thread_main (RhythmDBAddThreadData *data);
 static gpointer action_thread_main (RhythmDB *db);
 static gpointer query_thread_main (RhythmDBQueryThreadData *data);
-static void rhythmdb_entry_set_mount_point (RhythmDB *db, 
- 					    RhythmDBEntry *entry, 
+static void rhythmdb_entry_set_mount_point (RhythmDB *db,
+ 					    RhythmDBEntry *entry,
  					    const gchar *realuri);
- 
-static gboolean free_entry_changes (RhythmDBEntry *entry, 
+
+static gboolean free_entry_changes (RhythmDBEntry *entry,
 				    GSList *changes,
 				    RhythmDB *db);
 static gboolean rhythmdb_idle_save (RhythmDB *db);
@@ -197,7 +193,7 @@ rhythmdb_class_init (RhythmDBClass *klas
 			      G_STRUCT_OFFSET (RhythmDBClass, entry_changed),
 			      NULL, NULL,
 			      rb_marshal_VOID__BOXED_POINTER,
-			      G_TYPE_NONE, 2, 
+			      G_TYPE_NONE, 2,
 			      RHYTHMDB_TYPE_ENTRY, G_TYPE_POINTER);
 
 	rhythmdb_signals[LOAD_COMPLETE] =
@@ -232,7 +228,6 @@ rhythmdb_class_init (RhythmDBClass *klas
 			      G_TYPE_STRING,
 			      G_TYPE_POINTER);
 
-
 	rhythmdb_signals[READ_ONLY] =
 		g_signal_new ("read-only",
 			      G_OBJECT_CLASS_TYPE (object_class),
@@ -255,19 +250,19 @@ metadata_field_from_prop (RhythmDBPropTy
 		*field = RB_METADATA_FIELD_TITLE;
 		return TRUE;
 	case RHYTHMDB_PROP_ARTIST:
-		*field = RB_METADATA_FIELD_ARTIST; 
+		*field = RB_METADATA_FIELD_ARTIST;
 		return TRUE;
 	case RHYTHMDB_PROP_ALBUM:
-		*field = RB_METADATA_FIELD_ALBUM; 
+		*field = RB_METADATA_FIELD_ALBUM;
 		return TRUE;
 	case RHYTHMDB_PROP_GENRE:
-		*field = RB_METADATA_FIELD_GENRE; 
+		*field = RB_METADATA_FIELD_GENRE;
 		return TRUE;
 	case RHYTHMDB_PROP_TRACK_NUMBER:
-		*field = RB_METADATA_FIELD_TRACK_NUMBER; 
+		*field = RB_METADATA_FIELD_TRACK_NUMBER;
 		return TRUE;
 	case RHYTHMDB_PROP_DISC_NUMBER:
-		*field = RB_METADATA_FIELD_DISC_NUMBER; 
+		*field = RB_METADATA_FIELD_DISC_NUMBER;
 		return TRUE;
 	case RHYTHMDB_PROP_DATE:
 		*field = RB_METADATA_FIELD_DATE;
@@ -300,7 +295,7 @@ extract_gtype_from_enum_entry (RhythmDB 
 	RBMetaDataField field;
 	char *typename;
 	char *typename_end;
-	
+
 	value = g_enum_get_value (klass, i);
 
 	typename = strstr (value->value_nick, "(");
@@ -313,11 +308,11 @@ extract_gtype_from_enum_entry (RhythmDB 
 	typename = g_strndup (typename, typename_end-typename);
 	ret = g_type_from_name (typename);
 	g_free (typename);
-	
+
 	/* Check to see whether this is a property that maps to
 	   a RBMetaData property. */
 	if (metadata_field_from_prop (value->value, &field))
-		g_assert (ret == rb_metadata_get_field_type (field)); 
+		g_assert (ret == rb_metadata_get_field_type (field));
 	return ret;
 }
 
@@ -328,7 +323,7 @@ extract_nice_name_from_enum_entry (Rhyth
 	xmlChar *nick;
 	const xmlChar *name;
 	const xmlChar *name_end;
-	
+
 	value = g_enum_get_value (klass, i);
 	nick = BAD_CAST value->value_nick;
 
@@ -357,12 +352,12 @@ rhythmdb_init (RhythmDB *db)
 							 -1, FALSE, NULL);
 
 	db->priv->metadata = rb_metadata_new ();
-	
+
 	prop_class = g_type_class_ref (RHYTHMDB_TYPE_PROP_TYPE);
 
 	g_assert (prop_class->n_values == RHYTHMDB_NUM_PROPERTIES);
 	db->priv->column_xml_names = g_new (xmlChar *, RHYTHMDB_NUM_PROPERTIES);
-	
+
 	/* Now, extract the GType and XML tag of each column from the
 	 * enum descriptions, and cache that for later use. */
 	for (i = 0; i < prop_class->n_values; i++) {
@@ -371,7 +366,7 @@ rhythmdb_init (RhythmDB *db)
 		db->priv->column_xml_names[i] = extract_nice_name_from_enum_entry (db, prop_class, i);
 		g_assert (db->priv->column_xml_names[i]);
 	}
-			
+
 	g_type_class_unref (prop_class);
 
 	db->priv->propname_map = g_hash_table_new (g_str_hash, g_str_equal);
@@ -385,9 +380,8 @@ rhythmdb_init (RhythmDB *db)
 	rhythmdb_entry_song_get_type ();
 	rhythmdb_entry_ignore_get_type ();
 	rhythmdb_entry_import_error_get_type ();
-	
+
 	/* and other types we haven't kicked out of the rhythmdb core yet */
-	rhythmdb_entry_iradio_get_type ();
 	rhythmdb_entry_podcast_post_get_type ();
 	rhythmdb_entry_podcast_feed_get_type ();
 
@@ -400,7 +394,7 @@ rhythmdb_init (RhythmDB *db)
 	db->priv->changed_entries = g_hash_table_new (NULL, NULL);
 	db->priv->added_entries = g_hash_table_new (NULL, NULL);
 	db->priv->deleted_entries = g_hash_table_new (NULL, NULL);
-	
+
 	db->priv->event_poll_id = g_idle_add ((GSourceFunc) rhythmdb_idle_poll_events, db);
 
 	db->priv->saving_condition = g_cond_new ();
@@ -411,7 +405,7 @@ rhythmdb_init (RhythmDB *db)
 	db->priv->dirty = FALSE;
 
 	db->priv->empty_string = rb_refstring_new ("");
-	db->priv->octet_stream_str = rb_refstring_new ("application/octet-stream");      
+	db->priv->octet_stream_str = rb_refstring_new ("application/octet-stream");
 
 	rhythmdb_init_monitoring (db);
 }
@@ -437,7 +431,7 @@ rhythmdb_execute_multi_stat_info_cb (Gno
 			continue;
 		}
 		g_hash_table_remove (db->priv->stat_events, info_result->uri);
-		
+
 		if (info_result->result == GNOME_VFS_OK) {
 			event->vfsinfo = gnome_vfs_file_info_dup (info_result->file_info);
 		} else {
@@ -525,7 +519,7 @@ rhythmdb_event_free (RhythmDB *db, Rhyth
 		break;
 	case RHYTHMDB_EVENT_FILE_CREATED_OR_MODIFIED:
 		break;
-	case RHYTHMDB_EVENT_FILE_DELETED:	       
+	case RHYTHMDB_EVENT_FILE_DELETED:
 		break;
 	case RHYTHMDB_EVENT_ENTRY_SET:
 		g_value_unset (&result->change.new);
@@ -534,7 +528,6 @@ rhythmdb_event_free (RhythmDB *db, Rhyth
 	g_free (result);
 }
 
-
 /**
  * rhythmdb_shutdown:
  *
@@ -560,7 +553,6 @@ rhythmdb_shutdown (RhythmDB *db)
 		rhythmdb_action_free (db, action);
 	}
 
-	
 	rb_debug ("%d outstanding threads", g_atomic_int_get (&db->priv->outstanding_threads));
 	while (g_atomic_int_get (&db->priv->outstanding_threads) > 0) {
 		result = g_async_queue_pop (db->priv->event_queue);
@@ -611,7 +603,7 @@ rhythmdb_finalize (GObject *object)
 	rb_refstring_unref (db->priv->octet_stream_str);
 
 	g_free (db->priv->name);
-	
+
 	G_OBJECT_CLASS (rhythmdb_parent_class)->finalize (object);
 }
 
@@ -639,7 +631,7 @@ rhythmdb_set_property (GObject *object,
 	}
 }
 
-static void 
+static void
 rhythmdb_get_property (GObject *object,
 		      guint prop_id,
 		      GValue *value,
@@ -753,8 +745,6 @@ sync_entry_changed (RhythmDBEntry *entry
 	}
 }
 
-
-
 static gboolean
 rhythmdb_emit_entry_signals_idle (RhythmDB *db)
 {
@@ -772,9 +762,8 @@ rhythmdb_emit_entry_signals_idle (Rhythm
 	db->priv->deleted_entries_to_emit = NULL;
 
 	db->priv->emit_entry_signals_id = 0;
-	
-	g_mutex_unlock (db->priv->change_mutex);
 
+	g_mutex_unlock (db->priv->change_mutex);
 
 	/* emit added entries */
 	for (l = added_entries; l; l = g_list_next (l)) {
@@ -800,11 +789,11 @@ process_added_entries_cb (RhythmDBEntry 
 {
 	if (thread != g_thread_self ())
 		return FALSE;
-	
+
 	if (entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
 		const gchar *uri;
 
-		uri = rhythmdb_entry_get_string (entry, 
+		uri = rhythmdb_entry_get_string (entry,
 						 RHYTHMDB_PROP_LOCATION);
 
 		/* always start remote files hidden*/
@@ -817,7 +806,7 @@ process_added_entries_cb (RhythmDBEntry 
 
 	g_assert ((entry->flags & RHYTHMDB_ENTRY_INSERTED) == 0);
 	entry->flags |= RHYTHMDB_ENTRY_INSERTED;
-	
+
 	rhythmdb_entry_ref (entry);
 	db->priv->added_entries_to_emit = g_list_prepend (db->priv->added_entries_to_emit, entry);
 	return TRUE;
@@ -885,7 +874,6 @@ rhythmdb_add_timeout_commit (RhythmDB *d
 	g_timeout_add (100, (GSourceFunc)timeout_rhythmdb_commit, data);
 }
 
-
 /**
  * rhythmdb_commit:
  * @db: a #RhythmDB.
@@ -980,7 +968,6 @@ rhythmdb_entry_get_type_data (RhythmDBEn
 	return (gpointer) (((guint8 *)entry) + offset);
 }
 
-
 /**
  * rhythmdb_entry_insert:
  * @db: a #RhythmDB.
@@ -996,13 +983,12 @@ rhythmdb_entry_insert (RhythmDB *db, Rhy
 {
 	g_assert ((entry->flags & RHYTHMDB_ENTRY_INSERTED) == 0);
 	g_return_if_fail (entry->location != NULL);
-	
+
 	g_mutex_lock (db->priv->change_mutex);
 	g_hash_table_insert (db->priv->added_entries, entry, g_thread_self ());
 	g_mutex_unlock (db->priv->change_mutex);
 }
 
-
 /**
  * rhythmdb_entry_new:
  * @db: a #RhythmDB.
@@ -1015,7 +1001,7 @@ rhythmdb_entry_insert (RhythmDB *db, Rhy
  *
  * This may return NULL if entry creation fails. This can occur if there is
  * already an entry with the given uri.
- * 
+ *
  * Returns: the newly created #RhythmDBEntry
  **/
 RhythmDBEntry *
@@ -1023,7 +1009,7 @@ rhythmdb_entry_new (RhythmDB *db, Rhythm
 {
 	RhythmDBEntry *ret;
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
-	
+
 	ret = rhythmdb_entry_lookup_by_location (db, uri);
 	if (ret) {
 		g_warning ("attempting to create entry that already exists: %s", uri);
@@ -1049,14 +1035,14 @@ rhythmdb_entry_new (RhythmDB *db, Rhythm
  * it into the database.  This is indended for use as a example entry.
  *
  * This may return NULL if entry creation fails.
- * 
+ *
  * Returns: the newly created #RhythmDBEntry
  **/
 RhythmDBEntry *
 rhythmdb_entry_example_new (RhythmDB *db, RhythmDBEntryType type, const char *uri)
 {
 	RhythmDBEntry *ret;
-	
+
 	ret = rhythmdb_entry_allocate (db, type);
 	ret->location = g_strdup (uri);
 
@@ -1146,7 +1132,6 @@ rhythmdb_entry_is_editable (RhythmDB *db
 	return entry_type->can_sync_metadata (db, entry, entry_type->can_sync_metadata_data);
 }
 
-
 static void
 set_metadata_string_default_unknown (RhythmDB *db,
 				     RBMetaData *metadata,
@@ -1156,7 +1141,7 @@ set_metadata_string_default_unknown (Rhy
 {
 	const char *unknown = _("Unknown");
 	GValue val = {0, };
-	
+
 	if (!(rb_metadata_get (metadata,
 			       field,
 			       &val))) {
@@ -1321,7 +1306,6 @@ set_props_from_metadata (RhythmDB *db, R
 	}
 }
 
-
 static gboolean
 is_ghost_entry (RhythmDBEntry *entry)
 {
@@ -1336,16 +1320,16 @@ is_ghost_entry (RhythmDBEntry *entry)
 		return FALSE;
 	}
 	error = NULL;
-	grace_period = gconf_client_get_int (client, CONF_GRACE_PERIOD, 
+	grace_period = gconf_client_get_int (client, CONF_GRACE_PERIOD,
 					     &error);
 	g_object_unref (G_OBJECT (client));
 	if (error != NULL) {
 		g_error_free (error);
 		return FALSE;
 	}
-	
+
 	/* This is a bit silly, but I prefer to make sure we won't
-	 * overflow in the following calculations 
+	 * overflow in the following calculations
 	 */
 	if ((grace_period < 0) || (grace_period > 20000)) {
 		return FALSE;
@@ -1359,7 +1343,6 @@ is_ghost_entry (RhythmDBEntry *entry)
 	return (last_seen + grace_period < time.tv_sec);
 }
 
-
 static void
 rhythmdb_process_stat_event (RhythmDB *db, RhythmDBEvent *event)
 {
@@ -1390,8 +1373,8 @@ rhythmdb_process_stat_event (RhythmDB *d
 			const char *mount_point;
 
 			rhythmdb_entry_set_visibility (db, entry, TRUE);
-				
-			/* Update mount point if necessary (main reason is 
+
+			/* Update mount point if necessary (main reason is
 			 * that we want to set the mount point in legacy
 			 * rhythmdb that doesn't have it already
 			 */
@@ -1402,7 +1385,7 @@ rhythmdb_process_stat_event (RhythmDB *d
 			}
 
 			/* Update last seen time. It will also be updated
-			 * upon saving and when a volume is unmounted 
+			 * upon saving and when a volume is unmounted
 			 */
 			g_get_current_time (&time);
 			g_value_init (&val, G_TYPE_ULONG);
@@ -1419,7 +1402,7 @@ rhythmdb_process_stat_event (RhythmDB *d
 							     &val);
 			}
 			g_value_unset (&val);
-					    
+
 			if (mtime == event->vfsinfo->mtime) {
 				rb_debug ("not modified: %s", event->real_uri);
 				/* monitor the file for changes */
@@ -1433,7 +1416,7 @@ rhythmdb_process_stat_event (RhythmDB *d
 				new_event->db = db;
 				new_event->uri = g_strdup (event->real_uri);
 				new_event->type = RHYTHMDB_EVENT_FILE_CREATED_OR_MODIFIED;
-				g_async_queue_push (db->priv->event_queue, 
+				g_async_queue_push (db->priv->event_queue,
 						    new_event);
 			}
 		}
@@ -1471,7 +1454,7 @@ rhythmdb_add_import_error_entry (RhythmD
 
 		error_entry_type = RHYTHMDB_ENTRY_TYPE_IGNORE;
 	}
-	
+
 	entry = rhythmdb_entry_lookup_by_location (db, event->real_uri);
 	if (entry) {
 		RhythmDBEntryType entry_type = rhythmdb_entry_get_entry_type (entry);
@@ -1505,21 +1488,21 @@ rhythmdb_add_import_error_entry (RhythmD
 		}
 
 		rhythmdb_add_timeout_commit (db, FALSE);
-	} 
+	}
 
 	if (entry == NULL) {
 		/* create a new import error or ignore entry */
 		entry = rhythmdb_entry_new (db, error_entry_type, event->real_uri);
 		if (entry == NULL)
 			return;
-		
+
 		if (error_entry_type == RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR) {
 			g_value_init (&value, G_TYPE_STRING);
 			g_value_set_string (&value, event->error->message);
 			rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_PLAYBACK_ERROR, &value);
 			g_value_unset (&value);
 		}
-	
+
 		/* mtime */
 		if (event->vfsinfo) {
 			g_value_init (&value, G_TYPE_ULONG);
@@ -1576,7 +1559,7 @@ rhythmdb_process_metadata_load (RhythmDB
 			entry = NULL;
 		}
 	}
-	
+
 	if (!entry) {
 		if (event->entry_type == RHYTHMDB_ENTRY_TYPE_INVALID)
 			event->entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
@@ -1624,7 +1607,7 @@ rhythmdb_process_metadata_load (RhythmDB
 
 	/* we've seen this entry */
 	rhythmdb_entry_set_visibility (db, entry, TRUE);
-	
+
 	g_value_init (&value, G_TYPE_ULONG);
 	g_value_set_ulong (&value, time.tv_sec);
 	rhythmdb_entry_set_internal (db, entry, TRUE, RHYTHMDB_PROP_LAST_SEEN, &value);
@@ -1639,20 +1622,20 @@ rhythmdb_process_metadata_load (RhythmDB
 		rhythmdb_monitor_uri_path (db, entry->location, NULL);
 
 	rhythmdb_add_timeout_commit (db, FALSE);
-	
+
 	return TRUE;
 }
 
 static void
-rhythmdb_process_queued_entry_set_event (RhythmDB *db, 
+rhythmdb_process_queued_entry_set_event (RhythmDB *db,
 					 RhythmDBEvent *event)
 {
-	rhythmdb_entry_set_internal (db, event->entry, 
+	rhythmdb_entry_set_internal (db, event->entry,
 				     event->signal_change,
-				     event->change.prop, 
+				     event->change.prop,
 				     &event->change.new);
-	/* Don't run rhythmdb_commit right now in case there 
-	 * we can run a single commit for several queued 
+	/* Don't run rhythmdb_commit right now in case there
+	 * we can run a single commit for several queued
 	 * entry_set
 	 */
 	rhythmdb_add_timeout_commit (db, TRUE);
@@ -1689,7 +1672,7 @@ rhythmdb_process_events (RhythmDB *db, G
 {
 	RhythmDBEvent *event;
 	guint count = 0;
-	
+
 	while ((event = g_async_queue_try_pop (db->priv->event_queue)) != NULL) {
 		gboolean free = TRUE;
 
@@ -1700,8 +1683,8 @@ rhythmdb_process_events (RhythmDB *db, G
 		 * runs in).
 		 */
 		if (rhythmdb_get_readonly (db) &&
-		    ((event->type == RHYTHMDB_EVENT_STAT) 
-		     || (event->type == RHYTHMDB_EVENT_METADATA_LOAD) 
+		    ((event->type == RHYTHMDB_EVENT_STAT)
+		     || (event->type == RHYTHMDB_EVENT_METADATA_LOAD)
 		     || (event->type == RHYTHMDB_EVENT_ENTRY_SET))) {
 			if (count >= g_async_queue_length (db->priv->event_queue)) {
 				rb_debug ("Database is read-only, and we can't process any more events");
@@ -1729,7 +1712,7 @@ rhythmdb_process_events (RhythmDB *db, G
 		case RHYTHMDB_EVENT_DB_LOAD:
 			rb_debug ("processing RHYTHMDB_EVENT_DB_LOAD");
 			g_signal_emit (G_OBJECT (db), rhythmdb_signals[LOAD_COMPLETE], 0);
-			
+
 			/* save the db every five minutes */
 			if (db->priv->save_timeout_id > 0) {
 				g_source_remove (db->priv->save_timeout_id);
@@ -1762,7 +1745,7 @@ rhythmdb_process_events (RhythmDB *db, G
 		}
 		if (free)
 			rhythmdb_event_free (db, event);
-		
+
 		count++;
 	next_event:
 		if (timeout && (count % 8 == 0)) {
@@ -1835,7 +1818,7 @@ rhythmdb_execute_stat_info_cb (GnomeVFSA
 {
 	/* this is in the main thread, so we can't do any long operation here */
 	GnomeVFSGetFileInfoResult *info_result = results->data;
-	
+
 	if (info_result->result == GNOME_VFS_OK) {
 		event->vfsinfo = gnome_vfs_file_info_dup (info_result->file_info);
 	} else {
@@ -1869,7 +1852,6 @@ rhythmdb_execute_stat (RhythmDB *db, con
 	g_list_free (uri_list);
 }
 
-
 void
 queue_stat_uri (const char *uri, RhythmDB *db, RhythmDBEntryType type)
 {
@@ -1900,7 +1882,7 @@ queue_stat_uri (const char *uri, RhythmD
 		GnomeVFSURI *vfs_uri;
 
 		vfs_uri = gnome_vfs_uri_new (uri);
-		
+
 		/* construct a list of URIs and a hash table containing
 		 * stat events to fill in and post on the event queue.
 		 */
@@ -1911,9 +1893,9 @@ queue_stat_uri (const char *uri, RhythmD
 			result->real_uri = g_strdup (uri);
 			g_hash_table_insert (db->priv->stat_events, vfs_uri, result);
 			db->priv->stat_list = g_list_prepend (db->priv->stat_list, vfs_uri);
-		}	
+		}
 	}
-	
+
 	g_mutex_unlock (db->priv->stat_mutex);
 }
 
@@ -1923,7 +1905,6 @@ queue_stat_uri_tad (const char *uri, Rhy
 	queue_stat_uri (uri, data->db, data->type);
 }
 
-
 static gpointer
 add_thread_main (RhythmDBAddThreadData *data)
 {
@@ -1978,7 +1959,6 @@ rhythmdb_execute_load (RhythmDB *db, con
 	g_async_queue_push (db->priv->event_queue, event);
 }
 
-
 /**
  * rhythmdb_entry_get:
  * @entry: a #RhythmDBEntry.
@@ -1988,7 +1968,7 @@ rhythmdb_execute_load (RhythmDB *db, con
  * Gets a property of an entry, storing it in the given #GValue.
  **/
 void
-rhythmdb_entry_get (RhythmDB *db, RhythmDBEntry *entry, 
+rhythmdb_entry_get (RhythmDB *db, RhythmDBEntry *entry,
 		    RhythmDBPropType propid, GValue *val)
 {
 	rhythmdb_entry_sync_mirrored (entry, propid);
@@ -2027,14 +2007,14 @@ entry_to_rb_metadata (RhythmDB *db, Rhyt
 
 	for (i = RHYTHMDB_PROP_TYPE; i != RHYTHMDB_NUM_PROPERTIES; i++) {
 		RBMetaDataField field;
-		
+
 		if (metadata_field_from_prop (i, &field) == FALSE) {
 			continue;
 		}
 
 		g_value_init (&val, rhythmdb_property_type_map[i]);
 		rhythmdb_entry_get (db, entry, i, &val);
-		rb_metadata_set (metadata, 
+		rb_metadata_set (metadata,
 				 field,
 				 &val);
 		g_value_unset (&val);
@@ -2166,7 +2146,7 @@ rhythmdb_add_uri_with_type (RhythmDB *db
 {
 	char *realuri;
 	char *canon_uri;
-	       
+
 	canon_uri = rb_canonicalise_uri (uri);
 	realuri = rb_uri_resolve_symlink (canon_uri);
 	g_free (canon_uri);
@@ -2191,29 +2171,29 @@ rhythmdb_sync_library_idle (RhythmDB *db
 	return FALSE;
 }
 
-static gpointer 	 
-rhythmdb_load_thread_main (RhythmDB *db) 	 
-{ 	 
-	RhythmDBEvent *result; 	 
-	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db); 	 
+static gpointer
+rhythmdb_load_thread_main (RhythmDB *db)
+{
+	RhythmDBEvent *result;
+	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
 
 	g_mutex_lock (db->priv->saving_mutex);
-	klass->impl_load (db, &db->priv->exiting); 	 
+	klass->impl_load (db, &db->priv->exiting);
 	g_mutex_unlock (db->priv->saving_mutex);
 
 	g_timeout_add (10000, (GSourceFunc) rhythmdb_sync_library_idle, db);
 
-	rb_debug ("queuing db load complete signal"); 	 
-	result = g_new0 (RhythmDBEvent, 1); 	 
-	result->type = RHYTHMDB_EVENT_DB_LOAD; 	 
-	g_async_queue_push (db->priv->event_queue, result); 	 
-  	 
-	rb_debug ("exiting"); 	 
-	result = g_new0 (RhythmDBEvent, 1); 	 
-	result->type = RHYTHMDB_EVENT_THREAD_EXITED; 	 
-	g_async_queue_push (db->priv->event_queue, result); 	 
+	rb_debug ("queuing db load complete signal");
+	result = g_new0 (RhythmDBEvent, 1);
+	result->type = RHYTHMDB_EVENT_DB_LOAD;
+	g_async_queue_push (db->priv->event_queue, result);
+
+	rb_debug ("exiting");
+	result = g_new0 (RhythmDBEvent, 1);
+	result->type = RHYTHMDB_EVENT_THREAD_EXITED;
+	g_async_queue_push (db->priv->event_queue, result);
 
-	return NULL; 	 
+	return NULL;
 }
 
 /**
@@ -2231,7 +2211,7 @@ rhythmdb_load (RhythmDB *db)
 #if 0
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
 	RhythmDBEvent *result;
-	
+
 	/* grab the saving mutex, so that saves will block until the load is complete */
 	g_mutex_lock (db->priv->saving_mutex);
 	klass->impl_load (db, &db->priv->exiting);
@@ -2257,7 +2237,7 @@ rhythmdb_save_thread_main (RhythmDB *db)
 	RhythmDBEvent *result;
 
 	rb_debug ("entering save thread");
-	
+
 	g_mutex_lock (db->priv->saving_mutex);
 
 	if (!db->priv->dirty) {
@@ -2272,7 +2252,7 @@ rhythmdb_save_thread_main (RhythmDB *db)
 	db->priv->saving = TRUE;
 
 	rb_debug ("saving rhythmdb");
-			
+
 	klass = RHYTHMDB_GET_CLASS (db);
 	klass->impl_save (db);
 
@@ -2322,9 +2302,9 @@ void
 rhythmdb_save (RhythmDB *db)
 {
 	rb_debug("saving the rhythmdb and blocking");
-	
+
 	rhythmdb_save_async (db);
-	
+
 	g_mutex_lock (db->priv->saving_mutex);
 
 	while (db->priv->saving)
@@ -2354,8 +2334,8 @@ rhythmdb_save (RhythmDB *db)
  * this function, and that even after the commit, your change may not
  * have taken effect.
  **/
-void 
-rhythmdb_entry_set (RhythmDB *db, RhythmDBEntry *entry, 
+void
+rhythmdb_entry_set (RhythmDB *db, RhythmDBEntry *entry,
 		    guint propid, const GValue *value)
 {
 	if ((entry->flags & RHYTHMDB_ENTRY_INSERTED) != 0) {
@@ -2412,7 +2392,6 @@ record_entry_change (RhythmDB *db, Rhyth
 	g_mutex_unlock (db->priv->change_mutex);
 }
 
-
 void
 rhythmdb_entry_set_internal (RhythmDB *db, RhythmDBEntry *entry,
 			     gboolean notify_if_inserted,
@@ -2422,7 +2401,7 @@ rhythmdb_entry_set_internal (RhythmDB *d
 	gboolean handled;
 	RhythmDBPodcastFields *podcast = NULL;
 
-#ifndef G_DISABLE_ASSERT	
+#ifndef G_DISABLE_ASSERT
 	switch (G_VALUE_TYPE (value)) {
 	case G_TYPE_STRING:
 		/* the playback error is allowed to be NULL */
@@ -2569,27 +2548,27 @@ rhythmdb_entry_set_internal (RhythmDB *d
 			g_assert (podcast);
 			rb_refstring_unref (podcast->description);
 			podcast->description = rb_refstring_new (g_value_get_string (value));
-			break;	
+			break;
 		case RHYTHMDB_PROP_SUBTITLE:
 			g_assert (podcast);
 			rb_refstring_unref (podcast->subtitle);
 			podcast->subtitle = rb_refstring_new (g_value_get_string (value));
-			break;	
+			break;
 		case RHYTHMDB_PROP_SUMMARY:
 			g_assert (podcast);
 			rb_refstring_unref (podcast->summary);
 			podcast->summary = rb_refstring_new (g_value_get_string (value));
-			break;	
+			break;
 		case RHYTHMDB_PROP_LANG:
 			g_assert (podcast);
 			rb_refstring_unref (podcast->lang);
 			podcast->lang = rb_refstring_new (g_value_get_string (value));
-			break;	
+			break;
 		case RHYTHMDB_PROP_COPYRIGHT:
 			g_assert (podcast);
 			rb_refstring_unref (podcast->copyright);
 			podcast->copyright = rb_refstring_new (g_value_get_string (value));
-			break;	
+			break;
 		case RHYTHMDB_PROP_IMAGE:
 			g_assert (podcast);
 			rb_refstring_unref (podcast->image);
@@ -2598,13 +2577,13 @@ rhythmdb_entry_set_internal (RhythmDB *d
 		case RHYTHMDB_PROP_POST_TIME:
 			g_assert (podcast);
 			podcast->post_time = g_value_get_ulong (value);
-			break;	
+			break;
 		case RHYTHMDB_NUM_PROPERTIES:
 			g_assert_not_reached ();
 			break;
 		}
 	}
-	
+
 	/* set the dirty state */
 	db->priv->dirty = TRUE;
 }
@@ -2622,7 +2601,6 @@ rhythmdb_entry_set_internal (RhythmDB *d
  * This should only be used by RhythmDB itself, or a backend (such as rhythmdb-tree).
  **/
 
-
 static void
 rhythmdb_entry_sync_mirrored (RhythmDBEntry *entry, guint propid)
 {
@@ -2635,7 +2613,7 @@ rhythmdb_entry_sync_mirrored (RhythmDBEn
 		format = _("%Y-%m-%d %H:%M");
 	if (never == NULL)
 		never = _("Never");
-	
+
 	switch (propid) {
 	case RHYTHMDB_PROP_LAST_PLAYED_STR:
 	{
@@ -2719,7 +2697,7 @@ void
 rhythmdb_entry_delete (RhythmDB *db, RhythmDBEntry *entry)
 {
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
-	
+
 	klass->impl_entry_delete (db, entry);
 
 	rhythmdb_entry_ref (entry);
@@ -2858,7 +2836,7 @@ void
 rhythmdb_entry_delete_by_type (RhythmDB *db, RhythmDBEntryType type)
 {
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
-	
+
 	if (klass->impl_entry_delete_by_type) {
 		klass->impl_entry_delete_by_type (db, type);
 	} else {
@@ -2875,7 +2853,7 @@ rhythmdb_nice_elt_name_from_propid (Rhyt
 int
 rhythmdb_propid_from_nice_elt_name (RhythmDB *db, const xmlChar *name)
 {
-	gpointer ret, orig;	
+	gpointer ret, orig;
 	if (g_hash_table_lookup_extended (db->priv->propname_map, name,
 					  &orig, &ret)) {
 		return GPOINTER_TO_INT (ret);
@@ -2889,7 +2867,7 @@ rhythmdb_propid_from_nice_elt_name (Rhyt
  * @uri: the URI of the entry to lookup.
  *
  * Looks up the entry with location @uri.
- * 
+ *
  * Returns: the entry with location @uri, or NULL if no such entry exists.
  **/
 RhythmDBEntry *
@@ -2905,7 +2883,7 @@ rhythmdb_entry_lookup_by_location (Rhyth
  * @db: a #RhythmDB.
  * @func: the function to call with each entry.
  * @data: user data to pass to the function.
- * 
+ *
  * Calls the given function for each of the entries in the database.
  **/
 void
@@ -2978,7 +2956,7 @@ query_thread_main (RhythmDBQueryThreadDa
 }
 
 void
-rhythmdb_do_full_query_async_parsed (RhythmDB *db, 
+rhythmdb_do_full_query_async_parsed (RhythmDB *db,
 				     RhythmDBQueryResults *results,
 				     GPtrArray *query)
 {
@@ -3052,7 +3030,7 @@ rhythmdb_do_full_query_parsed (RhythmDB 
 }
 
 void
-rhythmdb_do_full_query (RhythmDB *db, 
+rhythmdb_do_full_query (RhythmDB *db,
 			RhythmDBQueryResults *results,
 			...)
 {
@@ -3066,7 +3044,7 @@ rhythmdb_do_full_query (RhythmDB *db, 
 	rhythmdb_do_full_query_internal (db, results, query);
 
 	rhythmdb_query_free (query);
-	
+
 	va_end (args);
 }
 
@@ -3218,7 +3196,7 @@ rhythmdb_is_busy (RhythmDB *db)
  * Creates a string containing the "status" information about a list of tracks.
  * The singular and plural strings must be used in a direct ngettext call
  * elsewhere in order for them to be marked for translation correctly.
- * 
+ *
  * Returns: the string, which should be freed with g_free.
  **/
 char *
@@ -3230,12 +3208,12 @@ rhythmdb_compute_status_normal (gint n_s
 	char *size_str = NULL;
 	char *ret;
 	const char *minutefmt;
-	const char *hourfmt;	
+	const char *hourfmt;
 	const char *dayfmt;
 
 	songcount = g_strdup_printf (ngettext (singular, plural, n_songs), n_songs);
 
-	days    = duration / (60 * 60 * 24); 
+	days    = duration / (60 * 60 * 24);
 	hours   = (duration / (60 * 60)) - (days * 24);
 	minutes = (duration / 60) - ((days * 24 * 60) + (hours * 60));
 	seconds = duration % 60;
@@ -3269,8 +3247,8 @@ rhythmdb_compute_status_normal (gint n_s
 				time = g_strdup_printf (dayfmt, days);
 			}
 	} else {
-		if (hours > 0) {	
-			if (minutes > 0) {	
+		if (hours > 0) {
+			if (minutes > 0) {
 				char *fmt;
 				/* Translators: the format is "X hours and X minutes" */
 				fmt = g_strdup_printf (_("%s and %s"), hourfmt, minutefmt);
@@ -3279,7 +3257,7 @@ rhythmdb_compute_status_normal (gint n_s
 			} else {
 				time = g_strdup_printf (hourfmt, hours);
 			}
-			
+
 		} else {
 			time = g_strdup_printf (minutefmt, minutes);
 		}
@@ -3304,13 +3282,12 @@ rhythmdb_compute_status_normal (gint n_s
 	return ret;
 }
 
-
 static gboolean
 song_can_sync_metadata (RhythmDB *db, RhythmDBEntry *entry, gpointer data)
 {
 	const char *mimetype;
 
-	mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE);	
+	mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE);
 	return rb_metadata_can_save (db->priv->metadata, mimetype);
 }
 
@@ -3366,7 +3343,7 @@ rhythmdb_entry_register_type (const char
 	type = g_new0 (RhythmDBEntryType_, 1);
 	type->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_false_function;
 	type->sync_metadata = default_sync_metadata;
-	if (name) {
+	if (name != NULL) {
 		type->name = g_strdup (name);
 		g_static_mutex_lock (&entry_type_map_mutex);
 		if (entry_type_map == NULL) {
@@ -3379,6 +3356,71 @@ rhythmdb_entry_register_type (const char
 	return type;
 }
 
+void
+rhythmdb_entry_type_set_post_entry_create_func (RhythmDBEntryType        type,
+						RhythmDBEntryActionFunc  func,
+						gpointer                 data,
+						GDestroyNotify           destroy_func)
+{
+	g_static_mutex_lock (&entry_type_mutex);
+	type->post_entry_create = func;
+	type->post_entry_create_data = data;
+	type->post_entry_create_destroy = destroy_func;
+	g_static_mutex_unlock (&entry_type_map_mutex);
+}
+
+void
+rhythmdb_entry_type_set_pre_entry_destroy_func (RhythmDBEntryType        type,
+						RhythmDBEntryActionFunc  func,
+						gpointer                 data,
+						GDestroyNotify           destroy_func)
+{
+	g_static_mutex_lock (&entry_type_mutex);
+	type->pre_entry_destroy = func;
+	type->pre_entry_destroy_data = data;
+	type->pre_entry_destroy_destroy = destroy_func;
+	g_static_mutex_unlock (&entry_type_map_mutex);
+}
+
+void
+rhythmdb_entry_type_set_get_playback_uri_func (RhythmDBEntryType        type,
+					       RhythmDBEntryStringFunc  func,
+					       gpointer                 data,
+					       GDestroyNotify           destroy_func)
+{
+	g_static_mutex_lock (&entry_type_mutex);
+	type->get_playback_uri = func;
+	type->get_playback_uri_data = data;
+	type->get_playback_uri_destroy = destroy_func;
+	g_static_mutex_unlock (&entry_type_map_mutex);
+}
+
+void
+rhythmdb_entry_type_set_can_sync_metadata_func (RhythmDBEntryType        type,
+						RhythmDBEntryCanSyncFunc func,
+						gpointer                 data,
+						GDestroyNotify           destroy_func)
+{
+	g_static_mutex_lock (&entry_type_mutex);
+	type->can_sync_metadata = func;
+	type->can_sync_metadata_data = data;
+	type->can_sync_metadata_destroy = destroy_func;
+	g_static_mutex_unlock (&entry_type_map_mutex);
+}
+
+void
+rhythmdb_entry_type_set_sync_metadata_func (RhythmDBEntryType        type,
+					    RhythmDBEntrySyncFunc    func,
+					    gpointer                 data,
+					    GDestroyNotify           destroy_func)
+{
+	g_static_mutex_lock (&entry_type_mutex);
+	type->sync_metadata = func;
+	type->sync_metadata_data = data;
+	type->sync_metadata_destroy = destroy_func;
+	g_static_mutex_unlock (&entry_type_map_mutex);
+}
+
 static void
 rhythmdb_entry_register_type_alias (RhythmDBEntryType type, const char *name)
 {
@@ -3394,8 +3436,8 @@ rhythmdb_entry_register_type_alias (Rhyt
  * rhythmdb_entry_type_get_by_name:
  * @name: name of the type to look for
  *
- * Locates a #RhythmDBEntryType by name. Returns 
- * RHYTHMDB_ENTRY_TYPE_INVALID if no entry type 
+ * Locates a #RhythmDBEntryType by name. Returns
+ * RHYTHMDB_ENTRY_TYPE_INVALID if no entry type
  * is registered with the specified name.
  *
  * Returns: the #RhythmDBEntryType
@@ -3417,9 +3459,8 @@ rhythmdb_entry_type_get_by_name (const c
 	return RHYTHMDB_ENTRY_TYPE_INVALID;
 }
 
-
-RhythmDBEntryType 
-rhythmdb_entry_song_get_type (void) 
+RhythmDBEntryType
+rhythmdb_entry_song_get_type (void)
 {
 	static RhythmDBEntryType song_type = RHYTHMDB_ENTRY_TYPE_INVALID;
 
@@ -3434,8 +3475,8 @@ rhythmdb_entry_song_get_type (void) 
 	return song_type;
 }
 
-RhythmDBEntryType 
-rhythmdb_entry_ignore_get_type (void) 
+RhythmDBEntryType
+rhythmdb_entry_ignore_get_type (void)
 {
 	static RhythmDBEntryType ignore_type = RHYTHMDB_ENTRY_TYPE_INVALID;
 
@@ -3448,22 +3489,6 @@ rhythmdb_entry_ignore_get_type (void) 
 	return ignore_type;
 }
 
-RhythmDBEntryType rhythmdb_entry_iradio_get_type (void) 
-{
-	static RhythmDBEntryType iradio_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-       
-	g_static_mutex_lock (&entry_type_mutex);
-	if (iradio_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		iradio_type = rhythmdb_entry_register_type ("iradio");
-		rhythmdb_entry_register_type_alias (iradio_type, "1");
-		iradio_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_true_function;
-		iradio_type->sync_metadata = (RhythmDBEntrySyncFunc)rb_null_function;
-	}
-	g_static_mutex_unlock (&entry_type_mutex);
-
-	return iradio_type;
-}
-
 static char *
 _get_podcast_playback_uri (RhythmDBEntry *entry, gpointer data)
 {
@@ -3482,10 +3507,10 @@ _podcast_data_destroy (RhythmDBEntry *en
 	rb_refstring_unref (podcast->image);
 }
 
-RhythmDBEntryType rhythmdb_entry_podcast_post_get_type (void) 
+RhythmDBEntryType rhythmdb_entry_podcast_post_get_type (void)
 {
 	static RhythmDBEntryType podcast_post_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-       
+
 	g_static_mutex_lock (&entry_type_mutex);
 	if (podcast_post_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
 		podcast_post_type = rhythmdb_entry_register_type ("podcast-post");
@@ -3500,10 +3525,10 @@ RhythmDBEntryType rhythmdb_entry_podcast
 	return podcast_post_type;
 }
 
-RhythmDBEntryType rhythmdb_entry_podcast_feed_get_type (void) 
+RhythmDBEntryType rhythmdb_entry_podcast_feed_get_type (void)
 {
 	static RhythmDBEntryType podcast_feed_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-       
+
 	g_static_mutex_lock (&entry_type_mutex);
 	if (podcast_feed_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
 		podcast_feed_type = rhythmdb_entry_register_type ("podcast-feed");
@@ -3517,14 +3542,14 @@ RhythmDBEntryType rhythmdb_entry_podcast
 	return podcast_feed_type;
 }
 
-RhythmDBEntryType rhythmdb_entry_import_error_get_type (void) 
+RhythmDBEntryType rhythmdb_entry_import_error_get_type (void)
 {
 	static RhythmDBEntryType import_error_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-       
+
 	g_static_mutex_lock (&entry_type_mutex);
 	if (import_error_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
 		import_error_type = rhythmdb_entry_register_type ("import-error");
-		
+
 		import_error_type->get_playback_uri = (RhythmDBEntryStringFunc)rb_null_function;
 	}
 	g_static_mutex_unlock (&entry_type_mutex);
@@ -3533,7 +3558,7 @@ RhythmDBEntryType rhythmdb_entry_import_
 }
 
 static void
-rhythmdb_entry_set_mount_point (RhythmDB *db, RhythmDBEntry *entry, 
+rhythmdb_entry_set_mount_point (RhythmDB *db, RhythmDBEntry *entry,
 				const gchar *realuri)
 {
 	gchar *mount_point;
@@ -3544,27 +3569,27 @@ rhythmdb_entry_set_mount_point (RhythmDB
 		g_value_init (&value, G_TYPE_STRING);
 		g_value_set_string_take_ownership (&value, mount_point);
 		rhythmdb_entry_set_internal (db, entry, FALSE,
-					     RHYTHMDB_PROP_MOUNTPOINT, 
+					     RHYTHMDB_PROP_MOUNTPOINT,
 					     &value);
 		g_value_unset (&value);
 	}
 }
 
 void
-rhythmdb_entry_set_visibility (RhythmDB *db, RhythmDBEntry *entry, 
+rhythmdb_entry_set_visibility (RhythmDB *db, RhythmDBEntry *entry,
 			       gboolean visible)
 {
 	GValue old_val = {0, };
 	gboolean old_visible;
 
 	g_value_init (&old_val, G_TYPE_BOOLEAN);
-	
+
 	rhythmdb_entry_get (db, entry, RHYTHMDB_PROP_HIDDEN, &old_val);
 	old_visible = !g_value_get_boolean (&old_val);
-	
+
 	if ((old_visible && !visible) || (!old_visible && visible)) {
 		GValue new_val = {0, };
-		
+
 		g_value_init (&new_val, G_TYPE_BOOLEAN);
 		g_value_set_boolean (&new_val, !visible);
 		rhythmdb_entry_set_internal (db, entry, TRUE,
@@ -3596,7 +3621,6 @@ rhythmdb_sync_library_location (RhythmDB
 						    (GConfClientNotifyFunc) library_location_changed_cb,
 						    db);
 	}
-	
 
 	if (reload) {
 		rb_debug ("ending monitor of old library directories");
@@ -3700,7 +3724,7 @@ rhythmdb_entry_get_string (RhythmDBEntry
 			return rb_refstring_get (podcast->subtitle);
 		else
 			return NULL;
-	case RHYTHMDB_PROP_SUMMARY: 
+	case RHYTHMDB_PROP_SUMMARY:
 		if (podcast)
 			return rb_refstring_get (podcast->summary);
 		else
@@ -3795,7 +3819,7 @@ rhythmdb_entry_get_ulong (RhythmDBEntry 
 	case RHYTHMDB_PROP_PLAY_COUNT:
 		return entry->play_count;
 	case RHYTHMDB_PROP_BITRATE:
-		return entry->bitrate;		
+		return entry->bitrate;
 	case RHYTHMDB_PROP_DATE:
 		if (g_date_valid (&entry->date))
 			return g_date_get_julian (&entry->date);
@@ -3813,7 +3837,7 @@ rhythmdb_entry_get_ulong (RhythmDBEntry 
 			return 0;
 	case RHYTHMDB_PROP_STATUS:
 		if (podcast)
-			return podcast->status;		
+			return podcast->status;
 		else
 			return 0;
 	default:
@@ -3888,4 +3912,3 @@ rhythmdb_entry_type_get_type (void)
 
 	return type;
 }
-
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.90
diff -p -u -r1.90 rhythmdb.h
--- rhythmdb/rhythmdb.h	7 Jul 2006 03:00:45 -0000	1.90
+++ rhythmdb/rhythmdb.h	10 Jul 2006 22:47:17 -0000
@@ -50,7 +50,6 @@ GType rhythmdb_entry_get_type (void);
 #define RHYTHMDB_ENTRY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY, RhythmDBEntry))
 #define RHYTHMDB_IS_ENTRY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_ENTRY))
 
-
 typedef void (*RhythmDBEntryActionFunc) (RhythmDBEntry *entry, gpointer data);
 typedef char* (*RhythmDBEntryStringFunc) (RhythmDBEntry *entry, gpointer data);
 typedef gboolean (*RhythmDBEntryCanSyncFunc) (RhythmDB *db, RhythmDBEntry *entry, gpointer data);
@@ -89,17 +88,13 @@ GType rhythmdb_entry_type_get_type (void
 #define RHYTHMDB_ENTRY_TYPE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY_TYPE, RhythmDBEntryType_))
 #define RHYTHMDB_IS_ENTRY_TYPE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_ENTRY_TYPE))
 
-
-
 typedef GPtrArray RhythmDBQuery;
 GType rhythmdb_query_get_type (void);
 #define RHYTHMDB_TYPE_QUERY	(rhythmdb_query_get_type ())
 #define RHYTHMDB_QUERY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_QUERY, RhythmDBQuery))
 #define RHYTHMDB_IS_QUERY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_QUERY))
 
-
 #define RHYTHMDB_ENTRY_TYPE_SONG (rhythmdb_entry_song_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_IRADIO_STATION (rhythmdb_entry_iradio_get_type ())
 #define RHYTHMDB_ENTRY_TYPE_PODCAST_POST (rhythmdb_entry_podcast_post_get_type ())
 #define RHYTHMDB_ENTRY_TYPE_PODCAST_FEED (rhythmdb_entry_podcast_feed_get_type ())
 #define RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR (rhythmdb_entry_import_error_get_type ())
@@ -129,8 +124,8 @@ typedef enum
 	RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
 	RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN,
 	RHYTHMDB_QUERY_PROP_YEAR_EQUALS,
-	RHYTHMDB_QUERY_PROP_YEAR_GREATER,   
-	RHYTHMDB_QUERY_PROP_YEAR_LESS,   
+	RHYTHMDB_QUERY_PROP_YEAR_GREATER,
+	RHYTHMDB_QUERY_PROP_YEAR_LESS,
 } RhythmDBQueryType;
 
 /* If you modify this enum, don't forget to modify rhythmdb_prop_get_type */
@@ -189,7 +184,7 @@ typedef enum
 	RHYTHMDB_PROP_POST_TIME,
 
 	RHYTHMDB_PROP_MUSICBRAINZ_TRACKID,
-	
+
 	RHYTHMDB_NUM_PROPERTIES
 } RhythmDBPropType;
 
@@ -229,8 +224,6 @@ gpointer rhythmdb_entry_get_pointer     
 
 RhythmDBEntryType rhythmdb_entry_get_entry_type (RhythmDBEntry *entry);
 
-
-
 typedef enum
 {
 	RHYTHMDB_ERROR_ACCESS_FAILED,
@@ -267,7 +260,7 @@ typedef struct
 
 	void		(*impl_load)		(RhythmDB *db, gboolean *dead);
 	void		(*impl_save)		(RhythmDB *db);
-	
+
 	void		(*impl_entry_new)	(RhythmDB *db, RhythmDBEntry *entry);
 
 	gboolean	(*impl_entry_set)	(RhythmDB *db, RhythmDBEntry *entry,
@@ -281,7 +274,7 @@ typedef struct
 	void            (*impl_entry_delete_by_type) (RhythmDB *db, RhythmDBEntryType type);
 
 	RhythmDBEntry *	(*impl_lookup_by_location)(RhythmDB *db, const char *uri);
-	
+
 	gboolean 	(*impl_evaluate_query)	(RhythmDB *db, GPtrArray *query, RhythmDBEntry *entry);
 
 	void		(*impl_entry_foreach)	(RhythmDB *db, GFunc func, gpointer data);
@@ -291,7 +284,6 @@ typedef struct
 						 gboolean *cancel);
 } RhythmDBClass;
 
-
 GType		rhythmdb_get_type	(void);
 
 RhythmDB *	rhythmdb_new		(const char *name);
@@ -325,12 +317,11 @@ gpointer	rhythmdb_entry_get_type_data (R
 #define		RHYTHMDB_ENTRY_GET_TYPE_DATA(e,t)	((t*)rhythmdb_entry_get_type_data((e),sizeof(t)))
 
 void		rhythmdb_entry_delete	(RhythmDB *db, RhythmDBEntry *entry);
-void            rhythmdb_entry_delete_by_type (RhythmDB *db, 
+void            rhythmdb_entry_delete_by_type (RhythmDB *db,
 					       RhythmDBEntryType type);
 void		rhythmdb_entry_move_to_trash (RhythmDB *db,
 					      RhythmDBEntry *entry);
 
-
 RhythmDBEntry *	rhythmdb_entry_lookup_by_location (RhythmDB *db, const char *uri);
 
 gboolean	rhythmdb_evaluate_query		(RhythmDB *db, GPtrArray *query,
@@ -399,12 +390,32 @@ char *		rhythmdb_compute_status_normal		
 							 const char *singular,
 							 const char *plural);
 
-
-RhythmDBEntryType rhythmdb_entry_register_type          (const char *name);
-RhythmDBEntryType rhythmdb_entry_type_get_by_name       (const char *name);
+RhythmDBEntryType rhythmdb_entry_register_type          (const char              *name);
+void              rhythmdb_entry_type_set_data_size     (RhythmDBEntryType        type,
+                                                         guint                    data_size);
+void              rhythmdb_entry_type_set_post_entry_create_func (RhythmDBEntryType        type,
+                                                                  RhythmDBEntryActionFunc  func,
+                                                                  gpointer                 data,
+                                                                  GDestroyNotify           destroy_func);
+void              rhythmdb_entry_type_set_pre_entry_destroy_func (RhythmDBEntryType        type,
+                                                                  RhythmDBEntryActionFunc  func,
+                                                                  gpointer                 data,
+                                                                  GDestroyNotify           destroy_func);
+void              rhythmdb_entry_type_set_get_playback_uri_func  (RhythmDBEntryType        type,
+                                                                  RhythmDBEntryStringFunc  func,
+                                                                  gpointer                 data,
+                                                                  GDestroyNotify           destroy_func);
+void              rhythmdb_entry_type_set_can_sync_metadata_func (RhythmDBEntryType        type,
+                                                                  RhythmDBEntryCanSyncFunc func,
+                                                                  gpointer                 data,
+                                                                  GDestroyNotify           destroy_func);
+void              rhythmdb_entry_type_set_sync_metadata_func     (RhythmDBEntryType        type,
+                                                                  RhythmDBEntrySyncFunc    func,
+                                                                  gpointer                 data,
+                                                                  GDestroyNotify           destroy_func);
+RhythmDBEntryType rhythmdb_entry_type_get_by_name       (const char              *name);
 
 RhythmDBEntryType rhythmdb_entry_song_get_type          (void);
-RhythmDBEntryType rhythmdb_entry_iradio_get_type        (void);
 RhythmDBEntryType rhythmdb_entry_podcast_post_get_type  (void);
 RhythmDBEntryType rhythmdb_entry_podcast_feed_get_type  (void);
 RhythmDBEntryType rhythmdb_entry_import_error_get_type	(void);
Index: shell/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/Makefile.am,v
retrieving revision 1.85
diff -p -u -r1.85 Makefile.am
--- shell/Makefile.am	10 Jul 2006 02:00:35 -0000	1.85
+++ shell/Makefile.am	10 Jul 2006 22:47:17 -0000
@@ -1,6 +1,6 @@
 ## arch-tag: Automake rules for main Rhythmbox shell
 
-BUILT_SOURCES = 
+BUILT_SOURCES =
 CLEANFILES =
 EXTRA_DIST =
 
@@ -35,7 +35,6 @@ INCLUDES = 						\
 	-I$(top_srcdir)/rhythmdb                       	\
 	-I$(top_srcdir)/widgets                    	\
 	-I$(top_srcdir)/sources                    	\
-	-I$(top_srcdir)/iradio                    	\
 	-I$(top_srcdir)/podcast                    	\
 	-I$(top_builddir)/lib				\
 	-I$(top_srcdir)/plugins				\
@@ -91,13 +90,12 @@ librbshell_la_SOURCES =              			
 	rb-play-order-random-by-rating.c		\
 	rb-play-order-random-by-rating.h		\
 	rb-tray-icon.c					\
-	rb-tray-icon.h				
+	rb-tray-icon.h
 
 rhythmbox_LDADD =					\
 	librbshell.la					\
 	$(top_builddir)/sources/libsources.la	        \
 	$(top_builddir)/sources/libsourcesimpl.la	\
-	$(top_builddir)/iradio/librbiradio.la	        \
 	$(top_builddir)/podcast/librbpodcast.la	        \
 	$(top_builddir)/metadata/librbmetadata.la	\
 	$(top_builddir)/widgets/librbwidgets.la         \
Index: shell/rb-playlist-manager.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-playlist-manager.c,v
retrieving revision 1.109
diff -p -u -r1.109 rb-playlist-manager.c
--- shell/rb-playlist-manager.c	10 Jul 2006 02:00:35 -0000	1.109
+++ shell/rb-playlist-manager.c	10 Jul 2006 22:47:17 -0000
@@ -428,24 +428,17 @@ handle_playlist_entry_cb (TotemPlParser 
 			  const char *genre, RBPlaylistManager *mgr)
 {
 	char *uri = rb_canonicalise_uri (uri_maybe);
-	RhythmDBEntryType entry_type;
+	gboolean handled;
 
 	g_return_if_fail (uri != NULL);
 
-	entry_type = rb_shell_guess_type_for_uri (mgr->priv->shell, uri);
-	if (entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		g_free (uri);
-		return;
-	}
+	handled = rb_shell_add_uri (mgr->priv->shell,
+				    uri,
+				    title,
+				    genre,
+				    NULL);
 
-	rb_shell_add_uri (mgr->priv->shell,
-			  entry_type,
-			  uri,
-			  title,
-			  genre,
-			  NULL);
-
-	if (entry_type == RHYTHMDB_ENTRY_TYPE_SONG) {
+	if (handled) {
 		if (!mgr->priv->loading_playlist) {
 			mgr->priv->loading_playlist =
 				RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, NULL, FALSE));
Index: shell/rb-shell.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.c,v
retrieving revision 1.460
diff -p -u -r1.460 rb-shell.c
--- shell/rb-shell.c	10 Jul 2006 02:00:35 -0000	1.460
+++ shell/rb-shell.c	10 Jul 2006 22:47:17 -0000
@@ -39,12 +39,13 @@
 /*#include <libgnomeui/gnome-stock-icons.h>*/
 #include <libgnome/gnome-init.h>
 #include <libgnome/gnome-program.h>
-/*#include <libgnomeui/gnome-window-icon.h>*/
 #include <libgnomeui/gnome-client.h>
 
 #include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
 #include <libgnomevfs/gnome-vfs-mime-utils.h>
 
+
 #include "rb-shell.h"
 #include "rb-debug.h"
 #include "rb-dialog.h"
@@ -76,7 +77,6 @@
 #include "rb-daap-source.h"
 #include "rb-daap-sharing.h"
 #endif /* WITH_DAAP_SUPPORT */
-#include "rb-iradio-source.h"
 #include "rb-shell-preferences.h"
 #include "rb-playlist-source.h"
 #include "rb-static-playlist-source.h"
@@ -138,7 +138,7 @@ static void source_activated_cb (RBSourc
 				 RBShell *shell);
 static void rb_shell_db_save_error_cb (RhythmDB *db,
 				       const char *uri, const GError *error,
-				       RBShell *shell); 
+				       RBShell *shell);
 static void rb_shell_db_entry_added_cb (RhythmDB *db,
 					RhythmDBEntry *entry,
 					RBShell *shell);
@@ -233,7 +233,7 @@ static gboolean rb_shell_show_popup_cb (
 					RBShell *shell);
 static gboolean tray_destroy_cb (GtkObject *object, RBShell *shell);
 
-static gboolean save_yourself_cb (GnomeClient *client, 
+static gboolean save_yourself_cb (GnomeClient *client,
                                   gint phase,
                                   GnomeSaveStyle save_style,
                                   gboolean shutdown,
@@ -302,7 +302,6 @@ static guint rb_shell_signals[LAST_SIGNA
 
 G_DEFINE_TYPE (RBShell, rb_shell, G_TYPE_OBJECT)
 
-
 struct RBShellPrivate
 {
 	GtkWidget *window;
@@ -326,6 +325,8 @@ struct RBShellPrivate
 
 	GList *sources;
 	GHashTable *sources_hash;
+	GHashTable *mime_handler_hash;
+	GHashTable *scheme_handler_hash;
 
 	guint async_state_save_id;
 	guint save_playlist_id;
@@ -354,7 +355,6 @@ struct RBShellPrivate
 	GList *supported_media_extensions;
 
 	RBLibrarySource *library_source;
-	RBIRadioSource *iradio_source;
 	RBPodcastSource *podcast_source;
 	RBPlaylistSource *queue_source;
 	RBSource *missing_files_source;
@@ -382,7 +382,7 @@ struct RBShellPrivate
 	guint smalldisplay_notify_id;
 
 	glong last_small_time; /* when we last changed small mode */
-	
+
 	/* Cached copies of the gconf keys.
 	 *
 	 * To avoid race conditions, the only time the keys are actually read is at startup
@@ -480,48 +480,48 @@ rb_shell_class_init (RBShellClass *klass
 
 	g_object_class_install_property (object_class,
 					 PROP_ARGC,
-					 g_param_spec_int ("argc", 
-							   "argc", 
-							   "Argument count", 
+					 g_param_spec_int ("argc",
+							   "argc",
+							   "Argument count",
 							   0, 128,
 							   0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_ARGV,
-					 g_param_spec_pointer ("argv", 
-							       "argv", 
-							       "Arguments", 
+					 g_param_spec_pointer ("argv",
+							       "argv",
+							       "Arguments",
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_NO_REGISTRATION,
-					 g_param_spec_boolean ("no-registration", 
-							       "no-registration", 
-							       "Whether or not to register", 
+					 g_param_spec_boolean ("no-registration",
+							       "no-registration",
+							       "Whether or not to register",
 							       FALSE,
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_NO_UPDATE,
-					 g_param_spec_boolean ("no-update", 
-							       "no-update", 
-							       "Whether or not to update the library", 
+					 g_param_spec_boolean ("no-update",
+							       "no-update",
+							       "Whether or not to update the library",
 							       FALSE,
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_DRY_RUN,
-					 g_param_spec_boolean ("dry-run", 
-							       "dry-run", 
-							       "Whether or not this is a dry run", 
+					 g_param_spec_boolean ("dry-run",
+							       "dry-run",
+							       "Whether or not this is a dry run",
 							       FALSE,
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_RHYTHMDB_FILE,
-					 g_param_spec_string ("rhythmdb-file", 
-							      "rhythmdb-file", 
-							      "The RhythmDB file to use", 
+					 g_param_spec_string ("rhythmdb-file",
+							      "rhythmdb-file",
+							      "The RhythmDB file to use",
 #ifdef WITH_RHYTHMDB_TREE
 							      "rhythmdb.xml",
 #elif defined(WITH_RHYTHMDB_GDA)
@@ -531,26 +531,25 @@ rb_shell_class_init (RBShellClass *klass
 
 	g_object_class_install_property (object_class,
 					 PROP_SELECTED_SOURCE,
-					 g_param_spec_object ("selected-source", 
-							      "selected-source", 
-							      "Source which is currently selected", 
+					 g_param_spec_object ("selected-source",
+							      "selected-source",
+							      "Source which is currently selected",
 							      RB_TYPE_SOURCE,
 							      G_PARAM_READABLE));
 
-
 	g_object_class_install_property (object_class,
 					 PROP_DB,
-					 g_param_spec_object ("db", 
-							      "RhythmDB", 
-							      "RhythmDB object", 
+					 g_param_spec_object ("db",
+							      "RhythmDB",
+							      "RhythmDB object",
 							      RHYTHMDB_TYPE,
 							       G_PARAM_READABLE));
 
 	g_object_class_install_property (object_class,
 					 PROP_UI_MANAGER,
-					 g_param_spec_object ("ui-manager", 
-							      "GtkUIManager", 
-							      "GtkUIManager object", 
+					 g_param_spec_object ("ui-manager",
+							      "GtkUIManager",
+							      "GtkUIManager object",
 							      GTK_TYPE_UI_MANAGER,
 							       G_PARAM_READABLE));
 
@@ -584,23 +583,23 @@ rb_shell_class_init (RBShellClass *klass
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_WINDOW,
-					 g_param_spec_object ("window", 
-							      "GtkWindow", 
-							      "GtkWindow object", 
+					 g_param_spec_object ("window",
+							      "GtkWindow",
+							      "GtkWindow object",
 							      GTK_TYPE_WINDOW,
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_PREFS,
-					 g_param_spec_object ("prefs", 
-							      "RBShellPreferences", 
-							      "RBShellPreferences object", 
+					 g_param_spec_object ("prefs",
+							      "RBShellPreferences",
+							      "RBShellPreferences object",
 							      RB_TYPE_SHELL_PREFERENCES,
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_QUEUE_SOURCE,
-					 g_param_spec_object ("queue-source", 
-							      "queue-source", 
-							      "Queue source", 
+					 g_param_spec_object ("queue-source",
+							      "queue-source",
+							      "Queue source",
 							      RB_TYPE_PLAY_QUEUE_SOURCE,
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
@@ -612,23 +611,23 @@ rb_shell_class_init (RBShellClass *klass
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_LIBRARY_SOURCE,
-					 g_param_spec_object ("library-source", 
-							      "library-source", 
-							      "Library source", 
+					 g_param_spec_object ("library-source",
+							      "library-source",
+							      "Library source",
 							      RB_TYPE_LIBRARY_SOURCE,
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_SOURCELIST_MODEL,
-					 g_param_spec_object ("sourcelist-model", 
-							      "sourcelist-model", 
-							      "RBSourcelistModel", 
+					 g_param_spec_object ("sourcelist-model",
+							      "sourcelist-model",
+							      "RBSourcelistModel",
 							      RB_TYPE_SOURCELIST_MODEL,
 							      G_PARAM_READABLE));
 
 	g_object_class_install_property (object_class,
 					 PROP_VISIBILITY,
-					 g_param_spec_boolean ("visibility", 
-							       "visibility", 
+					 g_param_spec_boolean ("visibility",
+							       "visibility",
 							       "Current window visibility",
 							       TRUE,
 							       G_PARAM_READWRITE));
@@ -659,7 +658,7 @@ rb_shell_class_init (RBShellClass *klass
 }
 
 static void
-rb_shell_init (RBShell *shell) 
+rb_shell_init (RBShell *shell)
 {
 	shell->priv = RB_SHELL_GET_PRIVATE (shell);
 
@@ -668,6 +667,11 @@ rb_shell_init (RBShell *shell) 
         rb_shell_session_init (shell);
 
 	eel_gconf_monitor_add (CONF_PREFIX);
+
+	shell->priv->mime_handler_hash = g_hash_table_new (g_str_hash,
+							   g_str_equal);
+	shell->priv->scheme_handler_hash = g_hash_table_new (g_str_hash,
+							     g_str_equal);
 }
 
 static void
@@ -695,7 +699,7 @@ rb_shell_set_property (GObject *object,
 	case PROP_DRY_RUN:
 		shell->priv->dry_run = g_value_get_boolean (value);
 		if (shell->priv->dry_run)
-			shell->priv->no_registration = TRUE;			
+			shell->priv->no_registration = TRUE;
 		break;
 	case PROP_RHYTHMDB_FILE:
 		shell->priv->rhythmdb_file = g_value_dup_string (value);
@@ -760,10 +764,10 @@ rb_shell_get_property (GObject *object,
 		break;
 	case PROP_WINDOW:
 		g_value_set_object (value, shell->priv->window);
-		break;	
+		break;
 	case PROP_PREFS:
 		g_value_set_object (value, shell->priv->prefs);
-		break;	
+		break;
 	case PROP_QUEUE_SOURCE:
 		g_value_set_object (value, shell->priv->queue_source);
 		break;
@@ -776,7 +780,7 @@ rb_shell_get_property (GObject *object,
  	case PROP_SOURCELIST_MODEL:
 		{
 			GtkTreeModel *model = NULL;
-			
+
 			g_object_get (G_OBJECT (shell->priv->sourcelist), "model", &model, NULL);
  			g_value_set_object (value, model);
 		}
@@ -802,7 +806,7 @@ rb_shell_sync_state (RBShell *shell)
 		rb_debug ("load incomplete, not syncing state");
 		return FALSE;
 	}
-	
+
 	rb_debug ("saving playlists");
 	rb_playlist_manager_save_playlists (shell->priv->playlist_manager, TRUE);
 
@@ -815,7 +819,7 @@ static gboolean
 idle_save_rhythmdb (RBShell *shell)
 {
 	rhythmdb_save (shell->priv->db);
-	
+
 	shell->priv->save_db_id = 0;
 
 	return FALSE;
@@ -884,7 +888,7 @@ rb_shell_finalize (GObject *object)
 	g_object_unref (G_OBJECT (shell->priv->removable_media_manager));
 
 	g_object_unref (G_OBJECT (shell->priv->proxy_config));
-	
+
 	rb_debug ("unreffing clipboard shell");
 	g_object_unref (G_OBJECT (shell->priv->clipboard_shell));
 
@@ -900,7 +904,7 @@ rb_shell_finalize (GObject *object)
 
 	rb_debug ("destroying tooltips");
 	gtk_object_destroy (GTK_OBJECT (shell->priv->tooltips));
-	
+
 	g_free (shell->priv->rhythmdb_file);
 
 	rb_debug ("destroying window");
@@ -910,6 +914,8 @@ rb_shell_finalize (GObject *object)
 	shell->priv->sources = NULL;
 
 	g_hash_table_destroy (shell->priv->sources_hash);
+	g_hash_table_destroy (shell->priv->mime_handler_hash);
+	g_hash_table_destroy (shell->priv->scheme_handler_hash);
 
         ((GObjectClass*)rb_shell_parent_class)->finalize (G_OBJECT (shell));
 
@@ -1059,7 +1065,7 @@ construct_widgets (RBShell *shell)
 				 "size-allocate",
 				 G_CALLBACK (paned_size_allocate_cb),
 				 shell, 0);
-	
+
 	shell->priv->queue_source = RB_PLAYLIST_SOURCE (rb_play_queue_source_new (shell));
 	g_object_set (G_OBJECT(shell->priv->player_shell), "queue-source", shell->priv->queue_source, NULL);
 	g_object_set (G_OBJECT(shell->priv->clipboard_shell), "queue-source", shell->priv->queue_source, NULL);
@@ -1080,9 +1086,9 @@ construct_widgets (RBShell *shell)
 
 		shell->priv->queue_paned = gtk_vpaned_new ();
 		gtk_paned_pack1 (GTK_PANED (shell->priv->queue_paned),
-				 shell->priv->sourcelist, 
+				 shell->priv->sourcelist,
 				 FALSE, TRUE);
-		gtk_paned_pack2 (GTK_PANED (shell->priv->queue_paned), 
+		gtk_paned_pack2 (GTK_PANED (shell->priv->queue_paned),
 				 shell->priv->queue_sidebar,
 				 TRUE, TRUE);
 		gtk_container_child_set (GTK_CONTAINER (shell->priv->queue_paned),
@@ -1115,7 +1121,7 @@ construct_widgets (RBShell *shell)
 
 	shell->priv->main_vbox = gtk_vbox_new (FALSE, 0);
 	gtk_container_set_border_width (GTK_CONTAINER (shell->priv->main_vbox), 0);
- 	gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->player_shell), FALSE, TRUE, 6);	
+ 	gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->player_shell), FALSE, TRUE, 6);
 	gtk_widget_show (GTK_WIDGET (shell->priv->player_shell));
 
 	gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), GTK_WIDGET (shell->priv->top_container), FALSE, TRUE, 0);
@@ -1127,7 +1133,7 @@ construct_widgets (RBShell *shell)
 	gtk_container_add (GTK_CONTAINER (win), shell->priv->main_vbox);
 
 	shell->priv->proxy_config = rb_proxy_config_new ();
- 
+
 	rb_profile_end ("constructing widgets");
 }
 
@@ -1138,8 +1144,6 @@ construct_sources (RBShell *shell)
 
 	shell->priv->library_source = RB_LIBRARY_SOURCE (rb_library_source_new (shell));
 	rb_shell_append_source (shell, RB_SOURCE (shell->priv->library_source), NULL);
-	shell->priv->iradio_source = RB_IRADIO_SOURCE (rb_iradio_source_new (shell));
-	rb_shell_append_source (shell, RB_SOURCE (shell->priv->iradio_source), NULL);
 	shell->priv->podcast_source = RB_PODCAST_SOURCE (rb_podcast_source_new (shell));
 	rb_shell_append_source (shell, RB_SOURCE (shell->priv->podcast_source), NULL);
 
@@ -1225,7 +1229,7 @@ construct_load_ui (RBShell *shell)
 	gtk_tool_item_set_expand (tool_item, TRUE);
 	gtk_widget_show (GTK_WIDGET (tool_item));
 	gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, -1);
-	
+
 	tool_item = gtk_tool_item_new ();
 	gtk_container_add (GTK_CONTAINER (tool_item), shell->priv->volume_button);
 	gtk_widget_show_all (GTK_WIDGET (tool_item));
@@ -1236,8 +1240,8 @@ construct_load_ui (RBShell *shell)
 	shell->priv->tooltips = gtk_tooltips_new ();
 	gtk_tooltips_enable (shell->priv->tooltips);
 
-	gtk_tooltips_set_tip (GTK_TOOLTIPS (shell->priv->tooltips), 
-			      GTK_WIDGET (shell->priv->volume_button), 
+	gtk_tooltips_set_tip (GTK_TOOLTIPS (shell->priv->tooltips),
+			      GTK_WIDGET (shell->priv->volume_button),
 			      _("Change the music volume"), NULL);
 
 	if (error != NULL) {
@@ -1261,7 +1265,7 @@ rb_shell_constructor (GType type,
 
 	rb_debug ("Constructing shell");
 	rb_profile_start ("constructing shell");
-  
+
 	shell->priv->actiongroup = gtk_action_group_new ("MainActions");
 	gtk_action_group_set_translation_domain (shell->priv->actiongroup,
 						 GETTEXT_PACKAGE);
@@ -1306,14 +1310,13 @@ rb_shell_constructor (GType type,
 	shell->priv->small_width = eel_gconf_get_integer (CONF_STATE_SMALL_WIDTH);
 	shell->priv->window_maximised = eel_gconf_get_boolean (CONF_STATE_WINDOW_MAXIMIZED);
 	shell->priv->window_small = eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY);
-	shell->priv->queue_as_sidebar = eel_gconf_get_boolean (CONF_UI_QUEUE_AS_SIDEBAR); 
+	shell->priv->queue_as_sidebar = eel_gconf_get_boolean (CONF_UI_QUEUE_AS_SIDEBAR);
 	shell->priv->window_x = eel_gconf_get_integer (CONF_STATE_WINDOW_X_POSITION);
 	shell->priv->window_y = eel_gconf_get_integer (CONF_STATE_WINDOW_Y_POSITION);
 	shell->priv->paned_position = eel_gconf_get_integer (CONF_STATE_PANED_POSITION);
 	shell->priv->sourcelist_height = eel_gconf_get_integer (CONF_STATE_SOURCELIST_HEIGHT);
 	shell->priv->statusbar_hidden = eel_gconf_get_boolean (CONF_UI_STATUSBAR_HIDDEN);
 
-	
 	rb_debug ("shell: syncing with gconf");
 	rb_shell_sync_sidepane_visibility (shell);
 	rb_shell_sync_pane_visibility (shell);
@@ -1341,7 +1344,7 @@ rb_shell_constructor (GType type,
 	/* GO GO GO! */
 	rb_debug ("loading database");
 	rhythmdb_load (shell->priv->db);
-	
+
 	rb_debug ("shell: syncing window state");
 	rb_shell_sync_paned (shell);
 	gtk_widget_show_all (GTK_WIDGET (shell->priv->tray_icon));
@@ -1364,7 +1367,7 @@ rb_shell_constructor (GType type,
 	/* focus play if small, the entry view if not */
 	if (shell->priv->window_small) {
 		GtkWidget *play_button;
-		
+
 		play_button = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/ToolBar/Play");
 		gtk_widget_grab_focus (play_button);
 	} else {
@@ -1445,7 +1448,7 @@ rb_shell_get_visibility (RBShell *shell)
 		return FALSE;
 	if (shell->priv->iconified)
 		return FALSE;
-		
+
 	state = gdk_window_get_state (GTK_WIDGET (shell->priv->window)->window);
 	if (state & (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_ICONIFIED))
 		return FALSE;
@@ -1500,7 +1503,7 @@ rb_shell_set_visibility (RBShell *shell,
 			gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell->priv->window), FALSE);
 		gtk_widget_show (GTK_WIDGET (shell->priv->window));
 		gtk_window_deiconify (GTK_WINDOW (shell->priv->window));
-		
+
 		if (GTK_WIDGET_REALIZED (GTK_WIDGET (shell->priv->window)))
 			rb_shell_present (shell, gtk_get_current_event_time (), NULL);
 		else
@@ -1621,7 +1624,7 @@ rb_shell_sync_window_state (RBShell *she
 						&hints,
 						0);
 	}
-	
+
 	gtk_window_move (GTK_WINDOW (shell->priv->window),
 			 shell->priv->window_x,
 			 shell->priv->window_y);
@@ -1671,7 +1674,7 @@ rb_shell_db_entry_added_cb (RhythmDB *db
 {
 	if (shell->priv->pending_entry == NULL)
 		return;
-	
+
 	rb_debug ("got entry added for %s", entry->location);
 	if (strcmp (entry->location, shell->priv->pending_entry) == 0) {
 		rb_shell_play_entry (shell, entry);
@@ -1694,22 +1697,67 @@ rb_shell_register_entry_type_for_source 
 					 RhythmDBEntryType type)
 {
 	if (shell->priv->sources_hash == NULL) {
-		shell->priv->sources_hash = g_hash_table_new (g_direct_hash, 
+		shell->priv->sources_hash = g_hash_table_new (g_direct_hash,
 							      g_direct_equal);
 	}
 	g_assert (g_hash_table_lookup (shell->priv->sources_hash, type) == NULL);
 	g_hash_table_insert (shell->priv->sources_hash, type, source);
 }
 
+void
+rb_shell_register_source (RBShell  *shell,
+			  RBSource *source)
+{
+	GList *list;
+	GList *l;
 
+	list = rb_source_get_entry_types (source);
+	for (l = list; l != NULL; l = l->next) {
+		RhythmDBEntryType entry_type = l->data;
+
+		if (g_hash_table_lookup (shell->priv->sources_hash, entry_type) == NULL) {
+			rb_shell_register_entry_type_for_source (shell, source, entry_type);
+		}
+	}
+	g_list_free (list);
+
+	list = rb_source_get_mime_types (source);
+	for (l = list; l != NULL; l = l->next) {
+		g_hash_table_insert (shell->priv->mime_handler_hash, l->data, source);
+	}
+	g_list_free (list);
+
+	list = rb_source_get_uri_schemes (source);
+	for (l = list; l != NULL; l = l->next) {
+		g_hash_table_insert (shell->priv->scheme_handler_hash, l->data, source);
+	}
+	g_list_free (list);
+}
+
+void
+rb_shell_unregister_source (RBShell  *shell,
+			    RBSource *source)
+{
+	GList *entry_types;
+	GList *l;
+
+	entry_types = rb_source_get_entry_types (source);
+	for (l = entry_types; l != NULL; l = l->next) {
+		RhythmDBEntryType entry_type = l->data;
+
+		if (shell->priv->sources_hash != NULL) {
+			g_hash_table_remove (shell->priv->sources_hash, entry_type);
+		}
+	}
+	g_list_free (entry_types);
+}
 
 void
 rb_shell_append_source (RBShell *shell,
 			RBSource *source,
 			RBSource *parent)
 {
-	shell->priv->sources
-		= g_list_append (shell->priv->sources, source);
+	shell->priv->sources = g_list_append (shell->priv->sources, source);
 
 	g_signal_connect_object (G_OBJECT (source), "deleted",
 				 G_CALLBACK (rb_shell_source_deleted_cb), shell, 0);
@@ -1769,7 +1817,7 @@ rb_shell_transfer_progress_cb (RBRemovab
 		else
 			s = g_strdup_printf (_("Transferring track %d out of %d"),
 						   done + 1, total);
-			
+
 		rb_statusbar_set_progress (shell->priv->statusbar,
 					   (((double)(done) + fraction)/total),
 					   s);
@@ -1829,7 +1877,7 @@ rb_shell_playing_from_queue_cb (RBShellP
 		RBEntryView *songs;
 		RhythmDBEntry *entry;
 		RhythmDBEntryType entry_type;
-		
+
 		/* if playing from the queue, show the playing entry as playing in the
 		 * registered source for its type, so it makes sense when 'jump to current'
 		 * jumps to it there.
@@ -1880,10 +1928,10 @@ rb_shell_playing_entry_changed_cb (RBShe
 	notifytitle = g_strdup_printf (_("by %s from %s"),
 				       rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST),
 				       rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
-	rb_shell_hidden_notify (shell, 
-				4000, 
-				rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE), 
-				NULL, 
+	rb_shell_hidden_notify (shell,
+				4000,
+				rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE),
+				NULL,
 				notifytitle);
 	g_free (notifytitle);
 }
@@ -1911,15 +1959,15 @@ rb_shell_select_source (RBShell *shell,
 		return;
 
 	rb_debug ("selecting source %p", source);
-	
+
 	if (shell->priv->selected_source) {
 		rb_source_deactivate (shell->priv->selected_source);
 		gtk_ui_manager_remove_ui (shell->priv->ui_manager, shell->priv->source_ui_merge_id);
 	}
-	
+
 	shell->priv->selected_source = source;
 	rb_source_activate (shell->priv->selected_source);
-	
+
 	/* show source */
 	gtk_notebook_set_current_page (GTK_NOTEBOOK (shell->priv->notebook),
 				       gtk_notebook_page_num (GTK_NOTEBOOK (shell->priv->notebook), GTK_WIDGET (source)));
@@ -1932,7 +1980,7 @@ rb_shell_select_source (RBShell *shell,
 	g_signal_handlers_unblock_by_func (G_OBJECT (shell->priv->sourcelist),
 					   G_CALLBACK (source_selected_cb),
 					   shell);
-	
+
 	/* update services */
 	rb_shell_clipboard_set_source (shell->priv->clipboard_shell, source);
 	rb_shell_player_set_selected_source (shell->priv->player_shell, source);
@@ -1965,13 +2013,13 @@ rb_shell_player_elapsed_changed_cb (RBSh
 	rb_shell_set_elapsed (shell, elapsed);
 }
 
-static void 
+static void
 rb_shell_player_stream_song_changed_cb (RBShellPlayer *player,
 					GParamSpec *arg,
 					RBShell *shell)
 {
 	char *song;
-	g_object_get (G_OBJECT (player), "stream-song", &song, NULL);	
+	g_object_get (G_OBJECT (player), "stream-song", &song, NULL);
 	if (song) {
 		rb_shell_hidden_notify (shell, 4000, song, NULL, NULL);
 		g_free (song);
@@ -2015,7 +2063,7 @@ rb_shell_set_window_title (RBShell *shel
 
 		g_free (shell->priv->cached_title);
 		shell->priv->cached_title = NULL;
-		
+
 		gtk_window_set_title (GTK_WINDOW (shell->priv->window),
 				      _("Music Player"));
 	}
@@ -2069,14 +2117,14 @@ rb_shell_view_smalldisplay_changed_cb (G
 				       RBShell *shell)
 {
 	GTimeVal time;
-	
+
 	/* don't change more than once per second, it causes weirdness */
 	g_get_current_time (&time);
 	if (time.tv_sec == shell->priv->last_small_time)
 		return;
 
 	shell->priv->last_small_time = time.tv_sec;
-	
+
 	shell->priv->window_small = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
 	eel_gconf_set_boolean (CONF_UI_SMALL_DISPLAY, shell->priv->window_small);
 }
@@ -2098,14 +2146,14 @@ rb_shell_view_queue_as_sidebar_changed_c
 	shell->priv->queue_as_sidebar = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
 	eel_gconf_set_boolean (CONF_UI_QUEUE_AS_SIDEBAR, shell->priv->queue_as_sidebar);
 
-	if (shell->priv->queue_as_sidebar && 
+	if (shell->priv->queue_as_sidebar &&
 	    shell->priv->selected_source == RB_SOURCE (shell->priv->queue_source)) {
 		/* queue no longer exists as a source, so change to the library */
 		rb_shell_select_source (shell, RB_SOURCE (shell->priv->library_source));
 	}
 
 	rb_shell_playing_from_queue_cb (shell->priv->player_shell, NULL, shell);
-	
+
 	rb_shell_sync_pane_visibility (shell);
 }
 
@@ -2266,14 +2314,13 @@ rb_shell_plugins_response_cb (GtkDialog 
 		gtk_widget_hide (GTK_WIDGET (dialog));
 }
 
-
 static void
 rb_shell_cmd_plugins (GtkAction *action,
 		      RBShell *shell)
 {
 	if (shell->priv->plugins == NULL) {
 		GtkWidget *manager;
-		
+
 		shell->priv->plugins = gtk_dialog_new_with_buttons (_("Configure Plugins"),
 								    GTK_WINDOW (shell->priv->window),
 								    GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -2283,7 +2330,7 @@ rb_shell_cmd_plugins (GtkAction *action,
 	    	gtk_container_set_border_width (GTK_CONTAINER (shell->priv->plugins), 5);
 		gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (shell->priv->plugins)->vbox), 2);
 		gtk_dialog_set_has_separator (GTK_DIALOG (shell->priv->plugins), FALSE);
-								    
+
 		g_signal_connect_object (G_OBJECT (shell->priv->plugins),
 					 "delete_event",
 					 G_CALLBACK (rb_shell_plugins_window_delete_cb),
@@ -2292,13 +2339,13 @@ rb_shell_cmd_plugins (GtkAction *action,
 					 "response",
 					 G_CALLBACK (rb_shell_plugins_response_cb),
 					 NULL, 0);
-		
+
 		manager = rb_plugin_manager_new ();
 		gtk_widget_show_all (GTK_WIDGET (manager));
 		gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell->priv->plugins)->vbox),
 				   manager);
 	}
-	
+
 	gtk_window_present (GTK_WINDOW (shell->priv->plugins));
 }
 
@@ -2307,7 +2354,7 @@ add_to_library_response_cb (GtkDialog *d
 			    int response_id,
 			    RBShell *shell)
 {
-	
+
 	char *current_dir = NULL;
 	GSList *uri_list = NULL, *uris = NULL;
 
@@ -2344,7 +2391,7 @@ rb_shell_cmd_add_folder_to_library (GtkA
 {
 	char * dir = eel_gconf_get_string (CONF_STATE_ADD_DIR);
 	GtkWidget *dialog;
-    
+
 	dialog = rb_file_chooser_new (_("Import Folder into Library"),
 			              GTK_WINDOW (shell->priv->window),
 				      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -2352,7 +2399,6 @@ rb_shell_cmd_add_folder_to_library (GtkA
 	if (dir)
 		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog),
 							 dir);
-	
 
 	g_signal_connect_object (G_OBJECT (dialog),
 				 "response",
@@ -2366,7 +2412,7 @@ rb_shell_cmd_add_file_to_library (GtkAct
 {
 	char * dir = eel_gconf_get_string (CONF_STATE_ADD_DIR);
 	GtkWidget *dialog;
-    
+
 	dialog = rb_file_chooser_new (_("Import File into Library"),
 			              GTK_WINDOW (shell->priv->window),
 				      GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -2374,7 +2420,6 @@ rb_shell_cmd_add_file_to_library (GtkAct
 	if (dir)
 		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog),
 							 dir);
-	
 
 	g_signal_connect_object (G_OBJECT (dialog),
 				 "response",
@@ -2469,11 +2514,10 @@ rb_shell_sync_pane_visibility (RBShell *
 
 	action = gtk_action_group_get_action (shell->priv->actiongroup,
 					      "ViewQueueAsSidebar");
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), 
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
 				      shell->priv->queue_as_sidebar);
 }
 
-
 static void
 rb_shell_sync_toolbar_state (RBShell *shell)
 {
@@ -2601,13 +2645,13 @@ rb_shell_sync_smalldisplay (RBShell *she
 		g_object_set (G_OBJECT (action), "sensitive", FALSE, NULL);
 		g_object_set (G_OBJECT (queue_action), "sensitive", FALSE, NULL);
 		g_object_set (G_OBJECT (party_mode_action), "sensitive", FALSE, NULL);
-  
+
 		gtk_widget_hide (GTK_WIDGET (shell->priv->paned));
 	} else {
 		g_object_set (G_OBJECT (action), "sensitive", TRUE, NULL);
 		g_object_set (G_OBJECT (queue_action), "sensitive", TRUE, NULL);
 		g_object_set (G_OBJECT (party_mode_action), "sensitive", TRUE, NULL);
-  
+
 		gtk_widget_show (GTK_WIDGET (shell->priv->paned));
 	}
 	rb_shell_sync_statusbar_visibility (shell);
@@ -2636,7 +2680,7 @@ sidepane_visibility_changed_cb (GConfCli
 				GConfEntry *entry,
 				RBShell *shell)
 {
-	rb_debug ("sidepane visibility changed"); 
+	rb_debug ("sidepane visibility changed");
 	rb_shell_sync_sidepane_visibility (shell);
 }
 
@@ -2646,7 +2690,7 @@ toolbar_state_changed_cb (GConfClient *c
 			       GConfEntry *entry,
 			       RBShell *shell)
 {
-	rb_debug ("toolbar state changed"); 
+	rb_debug ("toolbar state changed");
 	rb_shell_sync_toolbar_state (shell);
 }
 
@@ -2716,7 +2760,6 @@ rb_shell_cmd_current_song (GtkAction *ac
 	rb_shell_jump_to_current (shell);
 }
 
-
 static void
 rb_shell_cmd_view_all (GtkAction *action,
 		       RBShell *shell)
@@ -2737,12 +2780,12 @@ rb_shell_jump_to_entry_with_source (RBSh
 
 	g_return_if_fail (entry != NULL);
 
-	if ((source == RB_SOURCE (shell->priv->queue_source) && 
+	if ((source == RB_SOURCE (shell->priv->queue_source) &&
 	     shell->priv->queue_as_sidebar) ||
 	     source == NULL) {
 		RhythmDBEntryType entry_type;
 		entry_type = rhythmdb_entry_get_entry_type (entry);
-		source = rb_shell_get_source_by_entry_type (shell, entry_type); 
+		source = rb_shell_get_source_by_entry_type (shell, entry_type);
 	}
 	if (source == NULL)
 		return;
@@ -2797,7 +2840,7 @@ tray_embedded_cb (GtkPlug *plug,
 
 	gdk_window_set_decorations (shell->priv->window->window,
 				    GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
-#endif	
+#endif
 }
 
 static gboolean
@@ -2842,8 +2885,8 @@ rb_shell_hidden_notify (RBShell *shell,
 			     icon, secondary);
 }
 
-static void 
-session_die_cb (GnomeClient *client, 
+static void
+session_die_cb (GnomeClient *client,
                 RBShell *shell)
 {
         rb_debug ("session die");
@@ -2861,7 +2904,7 @@ rb_shell_error_quark (void)
 }
 
 static gboolean
-save_yourself_cb (GnomeClient *client, 
+save_yourself_cb (GnomeClient *client,
                   gint phase,
                   GnomeSaveStyle save_style,
                   gboolean shutdown,
@@ -2881,7 +2924,7 @@ rb_shell_session_init (RBShell *shell)
 
         client = gnome_master_client ();
 
-        g_signal_connect_object (G_OBJECT (client), 
+        g_signal_connect_object (G_OBJECT (client),
 				 "save_yourself",
 				 G_CALLBACK (save_yourself_cb),
 				 shell, 0);
@@ -2892,45 +2935,53 @@ rb_shell_session_init (RBShell *shell)
 				 shell, 0);
 }
 
-RhythmDBEntryType
-rb_shell_guess_type_for_uri (RBShell *shell,
-			     const char *uri)
+RBSource *
+rb_shell_guess_source_for_uri (RBShell    *shell,
+			       const char *uri)
 {
 	GnomeVFSURI *vfs_uri;
-	RhythmDBEntryType entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
-	const char *scheme;
-	const char *path;
-	const char *pathend;
+	const char  *scheme;
+	const char  *mime;
+	GList       *mime_list;
+	GList       *scheme_list;
+	RBSource    *source;
 
-	if (uri == NULL)
+	if (uri == NULL) {
 		return RHYTHMDB_ENTRY_TYPE_INVALID;
+	}
 
 	vfs_uri = gnome_vfs_uri_new (uri);
 	if (vfs_uri == NULL) {
 		rb_debug ("Invalid uri: %s", uri);
-		return RHYTHMDB_ENTRY_TYPE_INVALID;
+		return NULL;
 	}
+
 	scheme = gnome_vfs_uri_get_scheme (vfs_uri);
-	path = gnome_vfs_uri_get_scheme (vfs_uri);
-	pathend = path + strlen (path);
+	mime = gnome_vfs_get_mime_type_from_uri (vfs_uri);
 
-	if (strcmp ("file", scheme) == 0) {
-		entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
-	} else if (strcmp ("http", scheme) == 0) {
-		if ((strcasecmp (".xml", pathend-4) == 0)
-		    || strcasecmp (".rss", pathend-4) == 0)
-			entry_type = RHYTHMDB_ENTRY_TYPE_PODCAST_FEED;
-		else
-			entry_type = RHYTHMDB_ENTRY_TYPE_IRADIO_STATION;
-	} else if ((strcmp ("pnm", scheme) == 0) ||
-		  (strcmp ("rtsp", scheme) == 0) ||
-		  (strcmp ("mms", scheme) == 0) ||
-		  (strcmp ("mmsh", scheme) == 0)) {
-		entry_type = RHYTHMDB_ENTRY_TYPE_IRADIO_STATION;
+	scheme_list = NULL;
+	if (scheme != NULL) {
+		scheme_list = g_hash_table_lookup (shell->priv->scheme_handler_hash, scheme);
 	}
 
-	gnome_vfs_uri_unref (vfs_uri);
-	return entry_type;
+	mime_list = NULL;
+	if (mime != NULL) {
+		mime_list = g_hash_table_lookup (shell->priv->mime_handler_hash, mime);
+	}
+
+	/* FIXME: */
+	if (mime_list != NULL) {
+		source = mime_list->data;
+	} else if (scheme_list != NULL) {
+		source = scheme_list->data;
+	} else {
+		source = NULL;
+	}
+
+	g_list_free (scheme_list);
+	g_list_free (mime_list);
+
+	return source;
 }
 
 /* Load a URI representing an element of the given type, with
@@ -2938,31 +2989,29 @@ rb_shell_guess_type_for_uri (RBShell *sh
  */
 gboolean
 rb_shell_add_uri (RBShell *shell,
-		  RhythmDBEntryType entrytype,
 		  const char *uri,
 		  const char *title,
 		  const char *genre,
 		  GError **error)
 {
 	RBSource *source;
+	gboolean  handled;
 
-	/* FIXME should abstract this... */
-	source = rb_shell_get_source_by_entry_type (shell, entrytype);
-	if (source == RB_SOURCE (shell->priv->iradio_source)) {
-		if (rb_uri_is_local (uri)) {
-			rb_iradio_source_add_from_playlist (shell->priv->iradio_source,
-							    uri);
-		} else {
-			rb_iradio_source_add_station (shell->priv->iradio_source,
-						      uri,
-						      title,
-						      genre);
-		}
+	source = rb_shell_guess_source_for_uri (shell, uri);
+	if (source == NULL) {
+		return FALSE;
+	}
+
+	handled = rb_source_add_uri (source, uri, title, genre);
+
+	if (handled) {
 		return TRUE;
-	} else if (source == RB_SOURCE (shell->priv->podcast_source)) {
+	}
+
+	if (source == RB_SOURCE (shell->priv->podcast_source)) {
 		rb_podcast_source_add_feed (shell->priv->podcast_source, uri);
 		return TRUE;
-	} else if (entrytype == RHYTHMDB_ENTRY_TYPE_SONG) {
+	} else if (source == RB_SOURCE (shell->priv->library_source)) {
 		/* FIXME should be sync... */
 		rhythmdb_add_uri (shell->priv->db, uri);
 		return TRUE;
@@ -2984,20 +3033,21 @@ handle_playlist_entry_cb (TotemPlParser 
 			  const char *genre,
 			  PlaylistParseData *data)
 {
-	RhythmDBEntryType entry_type;
+	RBSource *source;
 
 	g_return_if_fail (uri != NULL);
-	
-	entry_type = rb_shell_guess_type_for_uri (data->shell, uri);
-	
-	if (entry_type != RHYTHMDB_ENTRY_TYPE_IRADIO_STATION)
-		data->iradio_playlist = FALSE;
+
+	source = rb_shell_guess_source_for_uri (data->shell, uri);
+
+	if (source != RB_SOURCE (data->shell->priv->library_source)) {
+		data->iradio_playlist = TRUE;
+	}
 }
 
 /* Load a URI representing a single song, a directory, a playlist, or
  * an internet radio station, and optionally start playing it.
  *
- * For playlists containing only stream URLs, we either add the playlist 
+ * For playlists containing only stream URLs, we either add the playlist
  * itself (if it's remote) or each URL from it (if it's local).  The main
  * reason for this is so clicking on stream playlist links in web browsers
  * works properly - the playlist file will be downloaded to /tmp/, and
@@ -3011,7 +3061,7 @@ rb_shell_load_uri (RBShell *shell,
 		   GError **error)
 {
 	RhythmDBEntry *entry;
-	
+
 	entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
 
 	if (entry == NULL) {
@@ -3026,10 +3076,10 @@ rb_shell_load_uri (RBShell *shell,
 			 */
 			play = FALSE;
 		}
-		
+
 		rb_debug ("adding uri %s", uri);
 		parser = totem_pl_parser_new ();
-		
+
 		g_signal_connect_data (G_OBJECT (parser), "entry",
 				       G_CALLBACK (handle_playlist_entry_cb),
 				       &data, NULL, 0);
@@ -3040,29 +3090,17 @@ rb_shell_load_uri (RBShell *shell,
 
 		result = totem_pl_parser_parse (parser, uri, FALSE);
 		g_object_unref (parser);
-		
+
 		if (result == TOTEM_PL_PARSER_RESULT_SUCCESS && data.iradio_playlist == FALSE) {
 			rb_debug ("adding %s as a static playlist", uri);
 			if (!rb_playlist_manager_parse_file (shell->priv->playlist_manager,
 							     uri, error))
 				return FALSE;
 		} else {
-			RhythmDBEntryType entrytype;
-
-			if (result == TOTEM_PL_PARSER_RESULT_SUCCESS) {
-				rb_debug ("adding %s as an iradio playlist", uri);
-				entrytype = RHYTHMDB_ENTRY_TYPE_IRADIO_STATION;
-			} else {
-				rb_debug ("%s didn't parse as a playlist", uri);
-				entrytype = rb_shell_guess_type_for_uri (shell, uri);
-				if (entrytype < 0)
-					return FALSE;
-			}
-
-			rb_shell_add_uri (shell, entrytype, uri, NULL, NULL, NULL);
+			rb_shell_add_uri (shell, uri, NULL, NULL, NULL);
 		}
 	}
-	
+
 	if (play) {
 		if (entry == NULL)
 			entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
@@ -3122,7 +3160,7 @@ rb_shell_add_to_queue (RBShell *shell,
 		       const gchar *uri,
 		       GError **error)
 {
-	rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (shell->priv->queue_source), 
+	rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (shell->priv->queue_source),
 						uri, -1);
 	return TRUE;
 }
@@ -3146,7 +3184,6 @@ rb_shell_clear_queue (RBShell *shell,
 	return TRUE;
 }
 
-
 gboolean
 rb_shell_present (RBShell *shell,
 		  guint32 timestamp,
@@ -3158,7 +3195,7 @@ rb_shell_present (RBShell *shell,
 	gtk_widget_show (GTK_WIDGET (shell->priv->window));
 #if GTK_MINOR_VERSION >= 8
 	gtk_window_present_with_time (GTK_WINDOW (shell->priv->window), timestamp);
-#else	
+#else
 	gtk_window_present (GTK_WINDOW (shell->priv->window));
 	gdk_window_focus (GTK_WIDGET (shell->priv->window)->window, timestamp);
 #endif
@@ -3185,7 +3222,7 @@ rb_shell_get_song_properties (RBShell *s
 	RhythmDBEntry *entry;
 	GEnumClass *klass;
 	guint i;
-	
+
 	entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
 
 	if (entry == NULL) {
@@ -3221,7 +3258,7 @@ rb_shell_get_song_properties (RBShell *s
 		default:
 			continue;
 		}
-		
+
 		value = g_new0 (GValue, 1);
 		g_value_init (value, value_type);
 		rhythmdb_entry_get (shell->priv->db, entry, prop, value);
@@ -3244,7 +3281,7 @@ rb_shell_set_song_property (RBShell *she
 	RhythmDBEntry *entry;
 	GType proptype;
 	int propid;
-	
+
 	entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
 
 	if (entry == NULL) {
@@ -3285,8 +3322,8 @@ rb_shell_volume_widget_changed_cb (Bacon
 				   RBShell *shell)
 {
 	if (!shell->priv->syncing_volume)
-		g_object_set (shell->priv->player_shell, 
-			      "volume", bacon_volume_button_get_value (vol), 
+		g_object_set (shell->priv->player_shell,
+			      "volume", bacon_volume_button_get_value (vol),
 			      NULL);
 }
 
@@ -3298,7 +3335,7 @@ rb_shell_player_volume_changed_cb (RBShe
 	float volume;
 	g_object_get (G_OBJECT (player), "volume", &volume, NULL);
 	shell->priv->syncing_volume = TRUE;
-	bacon_volume_button_set_value (BACON_VOLUME_BUTTON (shell->priv->volume_button), 
+	bacon_volume_button_set_value (BACON_VOLUME_BUTTON (shell->priv->volume_button),
 				       volume);
 	shell->priv->syncing_volume = FALSE;
 
@@ -3376,4 +3413,3 @@ rb_shell_ui_location_get_type (void)
 
 	return etype;
 }
-
Index: shell/rb-shell.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.h,v
retrieving revision 1.34
diff -p -u -r1.34 rb-shell.h
--- shell/rb-shell.h	29 May 2006 01:16:07 -0000	1.34
+++ shell/rb-shell.h	10 Jul 2006 22:47:17 -0000
@@ -1,5 +1,4 @@
-/*
- *  arch-tag: Header for main Rhythmbox shell
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  *  Copyright (C) 2002 Jorn Baayen
  *  Copyright (C) 2004 Colin Walters <walters@redhat.com>
@@ -17,7 +16,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
- *  
+ *
  */
 
 #ifndef __RB_SHELL_H
@@ -78,78 +77,94 @@ typedef struct
 	void	(*create_song_info)	(RBShell *shell, RBSongInfo *song_info, gboolean multi);
 } RBShellClass;
 
-GType		rb_shell_get_type	(void);
-
-RBShell *	rb_shell_new		(int argc, char **argv,
-					 gboolean no_registration,
-					 gboolean no_update,
-					 gboolean dry_run,
-					 char *rhythmdb);
-
-gboolean        rb_shell_present        (RBShell *shell, guint32 timestamp, GError **error);
-
-RhythmDBEntryType rb_shell_guess_type_for_uri (RBShell *shell, const char *uri);
-
-gboolean        rb_shell_add_uri        (RBShell *shell,
-					 RhythmDBEntryType entry_type,
-					 const char *uri,
-					 const char *title,
-					 const char *genre,
-					 GError **error);
-
-gboolean        rb_shell_load_uri       (RBShell *shell, const char *uri, gboolean play, GError **error);
-
-GObject *       rb_shell_get_player     (RBShell *shell);
-const char *    rb_shell_get_player_path(RBShell *shell);
-GObject *	rb_shell_get_playlist_manager (RBShell *shell);
-const char *	rb_shell_get_playlist_manager_path (RBShell *shell);
-GObject *	rb_shell_get_ui_manager (RBShell *shell);
-
-void            rb_shell_toggle_visibility (RBShell *shell);
-
-gboolean        rb_shell_get_song_properties (RBShell *shell,
-					      const char *uri,
-					      GHashTable **properties,
-					      GError **error);
-
-gboolean        rb_shell_set_song_property (RBShell *shell,
-					    const char *uri,
-					    const char *propname,
-					    const GValue *value,
-					    GError **error);
-
-gboolean	rb_shell_add_to_queue (RBShell *shell,
-				       const gchar *uri,
-				       GError **error);
-
-gboolean	rb_shell_remove_from_queue (RBShell *shell,
-					    const gchar *uri,
-					    GError **error);
-
-gboolean	rb_shell_clear_queue (RBShell *shell,
-				      GError **error);
-
-gboolean	rb_shell_quit (RBShell *shell,
-			       GError **error);
-
-void            rb_shell_hidden_notify  (RBShell *shell,
-					 guint timeout,
-					 const char *primary,
-					 GtkWidget *icon,
-					 const char *secondary);
-
-void            rb_shell_register_entry_type_for_source (RBShell *shell,
-							 RBSource *source,
-							 RhythmDBEntryType type);
-RBSource * rb_shell_get_source_by_entry_type (RBShell *shell,
-					      RhythmDBEntryType type);
-
-gboolean        rb_shell_get_party_mode (RBShell *shell);
-
-void rb_shell_append_source (RBShell *shell, RBSource *source, RBSource *parent);
+GType		  rb_shell_get_type	                    (void);
 
-void rb_shell_add_widget (RBShell *shell, GtkWidget *widget, RBShellUILocation location);
-void rb_shell_remove_widget (RBShell *shell, GtkWidget *widget, RBShellUILocation location);
+RBShell *	  rb_shell_new		                    (int argc,
+							     char **argv,
+							     gboolean no_registration,
+							     gboolean no_update,
+							     gboolean dry_run,
+							     char *rhythmdb);
+
+gboolean          rb_shell_present                          (RBShell *shell,
+							     guint32 timestamp,
+							     GError **error);
+
+RBSource *        rb_shell_guess_source_for_uri             (RBShell *shell,
+							     const char *uri);
+
+gboolean          rb_shell_add_uri                          (RBShell *shell,
+							     const char *uri,
+							     const char *title,
+							     const char *genre,
+							     GError **error);
+
+gboolean           rb_shell_load_uri                        (RBShell *shell,
+							     const char *uri,
+							     gboolean play,
+							     GError **error);
+
+GObject *          rb_shell_get_player                      (RBShell *shell);
+const char *       rb_shell_get_player_path                 (RBShell *shell);
+GObject *	   rb_shell_get_playlist_manager            (RBShell *shell);
+const char *	   rb_shell_get_playlist_manager_path       (RBShell *shell);
+GObject *	   rb_shell_get_ui_manager                  (RBShell *shell);
+
+void               rb_shell_toggle_visibility               (RBShell *shell);
+
+gboolean           rb_shell_get_song_properties             (RBShell *shell,
+							     const char *uri,
+							     GHashTable **properties,
+							     GError **error);
+
+gboolean           rb_shell_set_song_property               (RBShell *shell,
+							     const char *uri,
+							     const char *propname,
+							     const GValue *value,
+							     GError **error);
+
+gboolean	   rb_shell_add_to_queue                    (RBShell *shell,
+							     const gchar *uri,
+							     GError **error);
+
+gboolean	   rb_shell_remove_from_queue               (RBShell *shell,
+							     const gchar *uri,
+							     GError **error);
+
+gboolean	   rb_shell_clear_queue                     (RBShell *shell,
+							     GError **error);
+
+gboolean	   rb_shell_quit                            (RBShell *shell,
+							     GError **error);
+
+void               rb_shell_hidden_notify                   (RBShell *shell,
+							     guint timeout,
+							     const char *primary,
+							     GtkWidget *icon,
+							     const char *secondary);
+
+gboolean           rb_shell_get_party_mode                  (RBShell *shell);
+
+RBSource *         rb_shell_get_source_by_entry_type        (RBShell *shell,
+							     RhythmDBEntryType type);
+void               rb_shell_register_entry_type_for_source  (RBShell *shell,
+							     RBSource *source,
+							     RhythmDBEntryType type);
+void               rb_shell_register_source                 (RBShell *shell,
+							     RBSource *source);
+void               rb_shell_unregister_source               (RBShell *shell,
+							     RBSource *source);
+
+void               rb_shell_append_source                   (RBShell *shell,
+							     RBSource *source,
+							     RBSource *parent);
+
+void               rb_shell_add_widget                      (RBShell *shell,
+							     GtkWidget *widget,
+							     RBShellUILocation location);
+void               rb_shell_remove_widget                   (RBShell *shell,
+							     GtkWidget *widget,
+							     RBShellUILocation location);
 
 G_END_DECLS
 
Index: sources/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/Makefile.am,v
retrieving revision 1.42
diff -p -u -r1.42 Makefile.am
--- sources/Makefile.am	10 Jul 2006 02:00:36 -0000	1.42
+++ sources/Makefile.am	10 Jul 2006 22:47:17 -0000
@@ -12,8 +12,6 @@ libsourcesimpl_la_SOURCES =		\
 	rb-browser-source.h	\
 	rb-library-source.c		\
 	rb-library-source.h		\
-	rb-iradio-source.c		\
-	rb-iradio-source.h		\
 	rb-podcast-source.c		\
 	rb-podcast-source.h		\
 	rb-removable-media-source.c	\
@@ -44,8 +42,6 @@ INCLUDES =						\
 	-I$(top_srcdir)/metadata 			\
 	-I$(top_srcdir)/widgets 			\
 	-I$(top_srcdir)/library 			\
-	-I$(top_srcdir)/player	 			\
-	-I$(top_srcdir)/iradio				\
 	-I$(top_srcdir)/podcast				\
 	-I$(top_srcdir)/shell				\
 	-I$(top_srcdir)/daapsharing			\
Index: sources/rb-audiocd-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-audiocd-source.c,v
retrieving revision 1.40
diff -p -u -r1.40 rb-audiocd-source.c
--- sources/rb-audiocd-source.c	5 Jul 2006 14:25:18 -0000	1.40
+++ sources/rb-audiocd-source.c	10 Jul 2006 22:47:17 -0000
@@ -184,12 +184,12 @@ rb_audiocd_source_new (RBShell *shell,
 
 	g_free (device_path);
 
-	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
+	rb_shell_register_source (shell, RB_SOURCE (source));
 
 	return RB_REMOVABLE_MEDIA_SOURCE (source);
 }
 
-static void 
+static void
 entry_set_string_prop (RhythmDB *db,
 		       RhythmDBEntry *entry,
 		       gboolean is_inserted,
Index: sources/rb-daap-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-daap-source.c,v
retrieving revision 1.37
diff -p -u -r1.37 rb-daap-source.c
--- sources/rb-daap-source.c	19 Jun 2006 04:40:04 -0000	1.37
+++ sources/rb-daap-source.c	10 Jul 2006 22:47:17 -0000
@@ -329,8 +329,7 @@ rb_daap_source_new (RBShell *shell,
 		g_object_unref (icon);
 	}
 
-	rb_shell_register_entry_type_for_source (shell, source,
-						 type);
+	rb_shell_register_source (shell, source);
 
 	return source;
 }
Index: sources/rb-ipod-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.c,v
retrieving revision 1.57
diff -p -u -r1.57 rb-ipod-source.c
--- sources/rb-ipod-source.c	5 Jul 2006 14:25:18 -0000	1.57
+++ sources/rb-ipod-source.c	10 Jul 2006 22:47:17 -0000
@@ -205,7 +205,7 @@ rb_ipod_source_new (RBShell *shell, Gnom
 
 	g_assert (rb_ipod_is_volume_ipod (volume));
 
-	entry_type =  rhythmdb_entry_register_type (NULL);
+	entry_type = rhythmdb_entry_register_type (NULL);
 
 	source = RB_IPOD_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
 					  "entry-type", entry_type,
@@ -214,12 +214,12 @@ rb_ipod_source_new (RBShell *shell, Gnom
 					  "sourcelist-group", RB_SOURCELIST_GROUP_REMOVABLE,
 					  NULL));
 
-	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
+	rb_shell_register_source (shell, RB_SOURCE (source));
 
 	return RB_REMOVABLE_MEDIA_SOURCE (source);
 }
 
-static void 
+static void
 entry_set_string_prop (RhythmDB *db, RhythmDBEntry *entry,
 		       RhythmDBPropType propid, const char *str)
 {
Index: sources/rb-iradio-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-iradio-source.c,v
retrieving revision 1.123
diff -p -u -r1.123 rb-iradio-source.c
--- sources/rb-iradio-source.c	5 Jul 2006 14:25:18 -0000	1.123
+++ sources/rb-iradio-source.c	10 Jul 2006 22:47:18 -0000
@@ -1,6 +1,4 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- * 
- *  arch-tag: Implementation of Internet Radio source object
  *
  *  Copyright (C) 2002,2003 Colin Walters <walters@debian.org>
  *
@@ -24,11 +22,11 @@
 
 #include <string.h>
 
+#include <libxml/tree.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <glade/glade.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
-#include <libxml/tree.h>
 
 #include "rb-iradio-source.h"
 
@@ -94,6 +92,7 @@ static void impl_song_properties (RBSour
 static RBSourceEOFType impl_handle_eos (RBSource *asource);
 static gboolean impl_show_popup (RBSource *source);
 static GList *impl_get_ui_actions (RBSource *source);
+static GList *impl_get_entry_types (RBSource *source);
 
 static void rb_iradio_source_do_query (RBIRadioSource *source);
 
@@ -137,7 +136,7 @@ struct RBIRadioSourcePrivate
 	char *selected_genre;
 
 	gboolean firstrun_done;
-	
+
 	RhythmDBEntryType entry_type;
 };
 
@@ -181,9 +180,12 @@ rb_iradio_source_class_init (RBIRadioSou
 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_can_pause = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_can_search = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_add_uri = impl_add_uri;
 	source_class->impl_delete = impl_delete;
 	source_class->impl_get_browser_key  = impl_get_browser_key;
 	source_class->impl_get_entry_view = impl_get_entry_view;
+	source_class->impl_get_entry_types = impl_get_entry_types;
+	source_class->impl_get_uri_schemes = impl_get_uri_schemes;
 	source_class->impl_get_status  = impl_get_status;
 	source_class->impl_get_ui_actions = impl_get_ui_actions;
 	source_class->impl_handle_eos = impl_handle_eos;
@@ -216,7 +218,7 @@ rb_iradio_source_init (RBIRadioSource *s
 	source->priv->vbox = gtk_vbox_new (FALSE, 5);
 
 	gtk_container_add (GTK_CONTAINER (source), source->priv->vbox);
-	
+
 	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
 	pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
 					   "stock_channel",
@@ -301,7 +303,7 @@ rb_iradio_source_constructor (GType type
 				 "sort-order-changed",
 				 G_CALLBACK (rb_iradio_source_songs_view_sort_order_changed_cb),
 				 source, 0);
-	
+
 	/* set up drag and drop for the song tree view.
 	 * we don't use RBEntryView's DnD support because it does too much.
 	 * we just want to be able to drop stations in to add them.
@@ -321,7 +323,7 @@ rb_iradio_source_constructor (GType type
 				 source, 0);
 	g_signal_connect_object (G_OBJECT (source->priv->stations), "show_popup",
 				 G_CALLBACK (rb_iradio_source_songs_show_popup_cb), source, 0);
-	
+
 	/* set up genre entry view */
 	source->priv->genres = rb_property_view_new (source->priv->db,
 						     RHYTHMDB_PROP_GENRE,
@@ -404,14 +406,26 @@ RBSource *
 rb_iradio_source_new (RBShell *shell)
 {
 	RBSource *source;
+	RhythmDBEntryType entry_type;
+
+	entry_type = rhythmdb_entry_register_type_full ("iradio");
+	rhythmdb_entry_type_set_can_sync_metadata_func (entry_type,
+							(RhythmDBEntryCanSyncFunc)rb_true_function,
+							NULL,
+							NULL);
+	rhythmdb_entry_type_set_sync_metadata_func (entry_type,
+						    (RhythmDBEntrySyncFunc)rb_null_function,
+						    NULL,
+						    NULL);
 
 	source = RB_SOURCE (g_object_new (RB_TYPE_IRADIO_SOURCE,
+					  "entry-type", entry_type,
 					  "name", _("Radio"),
 					  "shell", shell,
+					  "sourcelist-group", RB_SOURCELIST_GROUP_FIXED,
 					  NULL));
 
-	rb_shell_register_entry_type_for_source (shell, source, 
-						 RHYTHMDB_ENTRY_TYPE_IRADIO_STATION);
+	rb_shell_register_source (shell, source);
 
 	return source;
 }
@@ -420,7 +434,7 @@ static char *
 guess_uri_scheme (const char *uri)
 {
 	const char *scheme;
-	
+
 	/* if the URI has no scheme, it might be an absolute path, or it might be
 	 * host:port for HTTP.
 	 */
@@ -470,24 +484,44 @@ rb_iradio_source_add_station (RBIRadioSo
 
 	rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_TITLE, &val);
 	g_value_reset (&val);
-		
+
 	if ((!genre) || (strcmp (genre, "") == 0))
 		genre = _("Unknown");
 	g_value_set_string (&val, genre);
 	rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_GENRE, &val);
 	g_value_unset (&val);
-	
+
 	g_value_init (&val, G_TYPE_DOUBLE);
 	g_value_set_double (&val, 0.0);
 	rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_RATING, &val);
 	g_value_unset (&val);
-	
+
 	rhythmdb_commit (source->priv->db);
 
 	g_free (real_uri);
 }
 
 static void
+impl_add_uri (RBSource   *asource,
+	      const char *uri,
+	      const char *title,
+	      const char *genre)
+{
+	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);
+
+	if (rb_uri_is_local (uri)) {
+		rb_iradio_source_add_from_playlist (source,
+						    uri);
+	} else {
+		rb_iradio_source_add_station (source,
+					      uri,
+					      title,
+					      genre);
+	}
+	return TRUE;
+}
+
+static void
 impl_search (RBSource *asource, const char *search_text)
 {
 	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);
@@ -518,6 +552,32 @@ impl_get_entry_view (RBSource *asource)
 	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);
 
 	return source->priv->stations;
+}
+
+static GList *
+impl_get_entry_types (RBSource *asource)
+{
+	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);
+	GList          *list = NULL;
+
+	list = g_list_prepend (list, source->priv->entry_type);
+
+	return list;
+}
+
+static GList *
+impl_get_uri_schemes (RBSource *asource)
+{
+	RBIRadioSource    *source = RB_IRADIO_SOURCE (asource);
+	static const char *schemes[] = { "http", "pnm", "rtsp", "mms", "mmsh" };
+	GList             *list = NULL;
+	int                i;
+
+	for (i = 0; i < G_N_ELEMENTS (schemes); i++) {
+		list = g_list_prepend (list, schemes[i]);
+	}
+
+	return list;
 }
 
 static RBSourceEOFType
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.175
diff -p -u -r1.175 rb-library-source.c
--- sources/rb-library-source.c	30 Jun 2006 04:22:27 -0000	1.175
+++ sources/rb-library-source.c	10 Jul 2006 22:47:18 -0000
@@ -309,8 +309,8 @@ rb_library_source_new (RBShell *shell)
 					  "shell", shell,
 					  "icon", icon,
 					  NULL));
-	rb_shell_register_entry_type_for_source (shell, source,
-						 RHYTHMDB_ENTRY_TYPE_SONG);
+
+	rb_shell_register_source (shell, source);
 
 	return source;
 }
Index: sources/rb-podcast-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-podcast-source.c,v
retrieving revision 1.70
diff -p -u -r1.70 rb-podcast-source.c
--- sources/rb-podcast-source.c	19 Jun 2006 04:40:04 -0000	1.70
+++ sources/rb-podcast-source.c	10 Jul 2006 22:47:18 -0000
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- * 
+ *
  *  arch-tag: Implementation of Internet Podcast source object
  *
  *  Copyright (C) 2005 Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
@@ -66,7 +66,7 @@ static void rb_podcast_source_class_init
 
 static void rb_podcast_source_init 			(RBPodcastSource *source);
 
-static GObject *rb_podcast_source_constructor 		(GType type, 
+static GObject *rb_podcast_source_constructor 		(GType type,
 							 guint n_construct_properties,
 					      		 GObjectConstructParam *construct_properties);
 
@@ -94,7 +94,7 @@ static void rb_podcast_source_feeds_show
 static void paned_size_allocate_cb 			(GtkWidget *widget,
 				    			 GtkAllocation *allocation,
 		                    			 RBPodcastSource *source);
-				    
+
 static void rb_podcast_source_state_pref_changed 	(GConfClient *client,
 						 	 guint cnxn_id,
 						 	 GConfEntry *entry,
@@ -105,29 +105,26 @@ static void rb_podcast_source_show_brows
 
 static void rb_podcast_source_state_prefs_sync 		(RBPodcastSource *source);
 
-
-static void feed_select_change_cb 			(RBPropertyView *propview, 
+static void feed_select_change_cb 			(RBPropertyView *propview,
 							 GList *feeds,
 			 			       	 RBPodcastSource *podcast_source);
-							 
 
-static void rb_podcast_source_posts_view_sort_order_changed_cb (RBEntryView *view, 
+static void rb_podcast_source_posts_view_sort_order_changed_cb (RBEntryView *view,
 								RBPodcastSource *source);
 
-static void rb_podcast_source_download_status_changed_cb(RBPodcastManager *download, 
-							 RhythmDBEntry *entry, 
-							 gulong status, 
+static void rb_podcast_source_download_status_changed_cb(RBPodcastManager *download,
+							 RhythmDBEntry *entry,
+							 gulong status,
 							 RBPodcastSource *source);
 
-static void rb_podcast_source_btn_file_change_cb 	(GtkFileChooserButton *widget, 
+static void rb_podcast_source_btn_file_change_cb 	(GtkFileChooserButton *widget,
 							 const char *key);
 
-
 static void posts_view_drag_data_received_cb 		(GtkWidget *widget,
 					      		 GdkDragContext *dc,
   				              		 gint x,
 							 gint y,
-				              		 GtkSelectionData *selection_data, 
+				              		 GtkSelectionData *selection_data,
 				              		 guint info,
 							 guint time,
 				              		 RBPodcastSource *source);
@@ -186,15 +183,15 @@ static void rb_podcast_source_feed_title
 							 GtkTreeIter *iter,
 						     	 RBPodcastSource *source);
 
-static void rb_podcast_source_start_download_cb 	(RBPodcastManager *pd, 
+static void rb_podcast_source_start_download_cb 	(RBPodcastManager *pd,
 							 RhythmDBEntry *entry,
 							 RBPodcastSource *source);
-	
-static void rb_podcast_source_finish_download_cb 	(RBPodcastManager *pd, 
+
+static void rb_podcast_source_finish_download_cb 	(RBPodcastManager *pd,
 							 RhythmDBEntry *entry,
 							 RBPodcastSource *source);
 
-static void rb_podcast_source_feed_updates_avaliable_cb (RBPodcastManager *pd, 
+static void rb_podcast_source_feed_updates_avaliable_cb (RBPodcastManager *pd,
 							 RhythmDBEntry *entry,
 							 RBPodcastSource *source);
 
@@ -225,25 +222,21 @@ static void rb_podcast_source_do_query		
 							 RBPodcastQueryType type);
 static GtkWidget *impl_get_config_widget 		(RBSource *source,
 							 RBShellPreferences *prefs);
-static gboolean impl_receive_drag 			(RBSource *source, 
+static gboolean impl_receive_drag 			(RBSource *source,
 							 GtkSelectionData *data);
 static gboolean impl_can_add_to_queue			(RBSource *source);
 static void impl_add_to_queue				(RBSource *source, RBSource *queue);
 static GList *impl_get_ui_actions			(RBSource *source);
 static GList *impl_get_search_actions			(RBSource *source);
-static void impl_get_status				(RBSource *source, 
-							 char **text, 
-							 char **progress_text, 
+static void impl_get_status				(RBSource *source,
+							 char **text,
+							 char **progress_text,
 							 float *progress);
 
-
-
-
 #define CMD_PATH_SHOW_BROWSER "/commands/ShowBrowser"
 #define CMD_PATH_CURRENT_STATION "/commands/CurrentStation"
 #define CMD_PATH_SONG_INFO    "/commands/SongInfo"
 
-
 #define CONF_UI_PODCAST_DIR 			CONF_PREFIX "/ui/podcast"
 #define CONF_UI_PODCAST_COLUMNS_SETUP 		CONF_PREFIX "/ui/podcast/columns_setup"
 #define CONF_STATE_PODCAST_PREFIX		CONF_PREFIX "/state/podcast"
@@ -258,7 +251,7 @@ static void impl_get_status				(RBSource
 struct RBPodcastSourcePrivate
 {
 	gboolean disposed;
-	
+
 	RhythmDB *db;
 
 	guint toolbar_ui_merge_id;
@@ -266,7 +259,7 @@ struct RBPodcastSourcePrivate
 	GtkWidget *vbox;
 	GtkWidget *config_widget;
 	GtkWidget *paned;
-	
+
 	RBPropertyView *feeds;
 	RBEntryView *posts;
 	GtkActionGroup *action_group;
@@ -277,9 +270,9 @@ struct RBPodcastSourcePrivate
 	RhythmDBPropType search_prop;
 
 	gboolean initialized;
-	
+
 	RhythmDBEntryType entry_type;
-	RBPodcastManager *podcast_mg;	
+	RBPodcastManager *podcast_mg;
 };
 
 #define RB_PODCAST_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PODCAST_SOURCE, RBPodcastSourcePrivate))
@@ -323,7 +316,6 @@ static const GtkTargetEntry posts_view_d
 	{  "application/rss+xml", 0, 2 },
 };
 
-
 enum
 {
 	PROP_0,
@@ -333,7 +325,6 @@ enum
 
 G_DEFINE_TYPE (RBPodcastSource, rb_podcast_source, RB_TYPE_SOURCE)
 
-
 static void
 rb_podcast_source_class_init (RBPodcastSourceClass *klass)
 {
@@ -369,7 +360,7 @@ rb_podcast_source_class_init (RBPodcastS
 	source_class->impl_show_popup = impl_show_popup;
 	source_class->impl_song_properties = impl_song_properties;
 	source_class->impl_get_status = impl_get_status;
-	
+
 	g_object_class_install_property (object_class,
 					 PROP_ENTRY_TYPE,
 					 g_param_spec_boxed ("entry-type",
@@ -404,7 +395,7 @@ rb_podcast_source_init (RBPodcastSource 
 	source->priv->vbox = gtk_vbox_new (FALSE, 5);
 
 	gtk_container_add (GTK_CONTAINER (source), source->priv->vbox);
-	
+
 	pixbuf = gtk_widget_render_icon (dummy,
 					 RB_STOCK_PODCAST,
 					 GTK_ICON_SIZE_LARGE_TOOLBAR,
@@ -428,7 +419,7 @@ rb_podcast_source_dispose (GObject *obje
 
 	if (source->priv->disposed)
 		return;
-	
+
 	source->priv->disposed = TRUE;
 }
 
@@ -451,7 +442,7 @@ rb_podcast_source_finalize (GObject *obj
 	if (source->priv->selected_feeds) {
 		g_list_foreach (source->priv->selected_feeds, (GFunc) g_free, NULL);
 	        g_list_free (source->priv->selected_feeds);
-	}	
+	}
 
        if (source->priv->cached_all_query)
 		g_object_unref (G_OBJECT (source->priv->cached_all_query));
@@ -470,7 +461,7 @@ search_action_to_prop (GtkAction *action
 	if (name == NULL) {
 		prop = RHYTHMDB_PROP_SEARCH_MATCH;
 	} else if (strcmp (name, "PodcastSearchAll") == 0) {
-		prop = RHYTHMDB_PROP_SEARCH_MATCH;		
+		prop = RHYTHMDB_PROP_SEARCH_MATCH;
 	} else if (strcmp (name, "PodcastSearchFeeds") == 0) {
 		prop = RHYTHMDB_PROP_ALBUM_FOLDED;
 	} else if (strcmp (name, "PodcastSearchEpisodes") == 0) {
@@ -537,16 +528,15 @@ rb_podcast_source_constructor (GType typ
 					    shell);
 
 	source->priv->paned = gtk_vpaned_new ();
-	
+
 	gtk_idle_add ((GtkFunction) rb_podcast_source_load_finish_cb, source);
 
 	source->priv->podcast_mg = rb_podcast_manager_new (source->priv->db);
 
 	g_object_unref (shell);
-	
 
 	/* set up posts view */
-	source->priv->posts = rb_entry_view_new (source->priv->db, 
+	source->priv->posts = rb_entry_view_new (source->priv->db,
 						 rb_shell_get_player (shell),
 						 CONF_STATE_PODCAST_SORTING_POSTS,
 						 TRUE, FALSE);
@@ -555,11 +545,10 @@ rb_podcast_source_constructor (GType typ
 				 G_CALLBACK (rb_podcast_source_entry_activated_cb),
 				 source, 0);
 
-
 	/* Podcast date column */
 	column = gtk_tree_view_column_new ();
 	renderer = gtk_cell_renderer_text_new();
-	
+
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
 	gtk_tree_view_column_set_clickable (column, TRUE);
@@ -572,48 +561,45 @@ rb_podcast_source_constructor (GType typ
 		sample_strings[2] = NULL;
 		rb_entry_view_set_fixed_column_width (source->priv->posts, column, renderer, sample_strings);
 	}
-	
+
 	gtk_tree_view_column_set_cell_data_func (column, renderer,
 						 (GtkTreeCellDataFunc) rb_podcast_source_post_date_cell_data_func,
 						 source, NULL);
-	
-	rb_entry_view_append_column_custom (source->priv->posts, column, 
-					    _("_Date"), "Date", 
+
+	rb_entry_view_append_column_custom (source->priv->posts, column,
+					    _("_Date"), "Date",
 					    (GCompareDataFunc) rb_podcast_source_post_date_cell_sort_func, 0);
-						    
 
 	rb_entry_view_append_column (source->priv->posts, RB_ENTRY_VIEW_COL_TITLE, TRUE);
-	
+
 	/* COLUMN FEED */
 	column = gtk_tree_view_column_new ();
 	renderer = gtk_cell_renderer_text_new();
-	
+
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
 	gtk_tree_view_column_set_clickable (column, TRUE);
 	gtk_tree_view_column_set_resizable (column, TRUE);
 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
 	gtk_tree_view_column_set_expand (column, TRUE);
-	
+
 	gtk_tree_view_column_set_cell_data_func (column, renderer,
 						 (GtkTreeCellDataFunc) rb_podcast_source_post_feed_cell_data_func,
 						 source, NULL);
-	
-	rb_entry_view_append_column_custom (source->priv->posts, column, 
-					    _("_Feed"), "Feed", 
+
+	rb_entry_view_append_column_custom (source->priv->posts, column,
+					    _("_Feed"), "Feed",
 					    (GCompareDataFunc) rb_podcast_source_post_feed_cell_sort_func, 0);
 
-	
 	rb_entry_view_append_column (source->priv->posts, RB_ENTRY_VIEW_COL_DURATION, FALSE);
 	rb_entry_view_append_column (source->priv->posts, RB_ENTRY_VIEW_COL_RATING, FALSE);
 	rb_entry_view_append_column (source->priv->posts, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
 	rb_entry_view_append_column (source->priv->posts, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
 
-
 	/* Status column */
 	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);
@@ -627,19 +613,19 @@ rb_podcast_source_constructor (GType typ
 		status_strings[3] = _("Failed");
 		status_strings[4] = "100 %";
 		status_strings[5] = NULL;
-		
-		rb_entry_view_set_fixed_column_width (source->priv->posts, 
-						      column, 
-						      renderer, 
+
+		rb_entry_view_set_fixed_column_width (source->priv->posts,
+						      column,
+						      renderer,
 						      status_strings);
 	}
-	
+
 	gtk_tree_view_column_set_cell_data_func (column, renderer,
 						 (GtkTreeCellDataFunc) rb_podcast_source_post_status_cell_data_func,
 						 source, NULL);
-	
-	rb_entry_view_append_column_custom (source->priv->posts, column, 
-					    _("Status"), "Status", 
+
+	rb_entry_view_append_column_custom (source->priv->posts, column,
+					    _("Status"), "Status",
 					    (GCompareDataFunc) rb_podcast_source_post_status_cell_sort_func, 0);
 
 	g_signal_connect_object (G_OBJECT (source->priv->posts),
@@ -647,69 +633,66 @@ rb_podcast_source_constructor (GType typ
 				 G_CALLBACK (rb_podcast_source_posts_view_sort_order_changed_cb),
 				 source, 0);
 
-
-
 	g_signal_connect (G_OBJECT (source->priv->podcast_mg),
 			  "status_changed",
 			  G_CALLBACK (rb_podcast_source_download_status_changed_cb),
 			  source);
-	
-	g_signal_connect_object (G_OBJECT (source->priv->podcast_mg), 
+
+	g_signal_connect_object (G_OBJECT (source->priv->podcast_mg),
 			  	 "process_error",
 			 	 G_CALLBACK (rb_podcast_source_download_process_error_cb),
 			  	 source, 0);
-	
+
 	g_signal_connect_object (G_OBJECT (source->priv->posts),
 				 "size_allocate",
 				 G_CALLBACK (paned_size_allocate_cb),
 				 source, 0);
-	
+
 	g_signal_connect_object (G_OBJECT (source->priv->posts), "show_popup",
 				 G_CALLBACK (rb_podcast_source_songs_show_popup_cb), source, 0);
-	
 
 	/* configure feed view */
-	source->priv->feeds = rb_property_view_new (source->priv->db,  RHYTHMDB_PROP_LOCATION, _("Feed"));	
+	source->priv->feeds = rb_property_view_new (source->priv->db,  RHYTHMDB_PROP_LOCATION, _("Feed"));
 	rb_property_view_set_selection_mode (RB_PROPERTY_VIEW (source->priv->feeds), GTK_SELECTION_MULTIPLE);
-	
+
 	query_model = rhythmdb_query_model_new_empty (source->priv->db);
 	feed_model = rb_property_view_get_model (RB_PROPERTY_VIEW (source->priv->feeds));
 	g_object_set (G_OBJECT (feed_model), "query-model", query_model, NULL);
 	g_object_unref (G_OBJECT (feed_model));
-	
+
 	if (source->priv->entry_type == RHYTHMDB_ENTRY_TYPE_INVALID ||
 	    source->priv->entry_type == NULL)
 		source->priv->entry_type = RHYTHMDB_ENTRY_TYPE_PODCAST_POST;
-	
+
 	query = rhythmdb_query_parse (source->priv->db,
 				      RHYTHMDB_QUERY_PROP_EQUALS,
 				      RHYTHMDB_PROP_TYPE,
 				      RHYTHMDB_ENTRY_TYPE_PODCAST_FEED,
 				      RHYTHMDB_QUERY_END);
-	rhythmdb_do_full_query_parsed (source->priv->db, 
-				       RHYTHMDB_QUERY_RESULTS (query_model), 
+	rhythmdb_do_full_query_parsed (source->priv->db,
+				       RHYTHMDB_QUERY_RESULTS (query_model),
 				       query);
 
 	rhythmdb_query_free (query);
-	
+
 	/* column title */
 	column = gtk_tree_view_column_new ();
 	renderer = gtk_cell_renderer_text_new ();
 
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
-	gtk_tree_view_column_set_cell_data_func (column, 
+	gtk_tree_view_column_set_cell_data_func (column,
 						 renderer,
 						 (GtkTreeCellDataFunc) rb_podcast_source_feed_title_cell_data_func,
 						 source, NULL);
-	
+
 	gtk_tree_view_column_set_title (column, _("Feed"));
 	gtk_tree_view_column_set_reorderable (column, FALSE);
 	gtk_tree_view_column_set_visible (column, TRUE);
 	rb_property_view_append_column_custom (source->priv->feeds, column);
 
 	g_signal_connect_object (G_OBJECT (source->priv->feeds), "show_popup",
-				 G_CALLBACK (rb_podcast_source_feeds_show_popup_cb), 
+				 G_CALLBACK (rb_podcast_source_feeds_show_popup_cb),
 				 source, 0);
 
 	g_signal_connect_object (G_OBJECT (source->priv->feeds),
@@ -725,7 +708,7 @@ rb_podcast_source_constructor (GType typ
 	g_object_ref (G_OBJECT (source->priv->feeds));
 
 	/* set up drag and drop */
-	g_signal_connect_object (G_OBJECT (source->priv->feeds), 
+	g_signal_connect_object (G_OBJECT (source->priv->feeds),
 				 "drag_data_received",
 				 G_CALLBACK (posts_view_drag_data_received_cb),
 				 source, 0);
@@ -734,8 +717,8 @@ rb_podcast_source_constructor (GType typ
 			   GTK_DEST_DEFAULT_ALL,
 			   posts_view_drag_types, 2,
 			   GDK_ACTION_COPY | GDK_ACTION_MOVE);
-	
-	g_signal_connect_object (G_OBJECT (source->priv->posts), 
+
+	g_signal_connect_object (G_OBJECT (source->priv->posts),
 				 "drag_data_received",
 				 G_CALLBACK (posts_view_drag_data_received_cb),
 				 source, 0);
@@ -746,24 +729,21 @@ rb_podcast_source_constructor (GType typ
 			   GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
 	/* set up propiets page */
-	
+
 	gtk_paned_pack2 (GTK_PANED (source->priv->paned),
 			 GTK_WIDGET (source->priv->posts), TRUE, FALSE);
 
 	gtk_box_pack_start_defaults (GTK_BOX (source->priv->vbox), source->priv->paned);
 
-
 	rb_podcast_source_state_prefs_sync (source);
-	
-	
+
 	eel_gconf_notification_add (CONF_STATE_PODCAST_PREFIX,
 				    (GConfClientNotifyFunc) rb_podcast_source_state_pref_changed,
 				    source);
-	
+
 	gtk_widget_show_all (GTK_WIDGET (source));
 
 	rb_podcast_source_do_query (source, RB_PODCAST_QUERY_TYPE_ALL);
-	
 
 	return G_OBJECT (source);
 }
@@ -782,7 +762,7 @@ rb_podcast_source_set_property (GObject 
 		break;
 	case PROP_PODCAST_MANAGER:
 		source->priv->podcast_mg = g_value_get_object (value);
-		break;		
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -803,7 +783,7 @@ rb_podcast_source_get_property (GObject 
 		break;
 	case PROP_PODCAST_MANAGER:
 		g_value_set_object (value, source->priv->podcast_mg);
-	        break;	
+	        break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -819,11 +799,13 @@ rb_podcast_source_new (RBShell *shell)
 					  "shell", shell,
 					  NULL));
 
-	rb_shell_register_entry_type_for_source (shell, source, 
+	rb_shell_register_source (shell, source);
+
+	rb_shell_register_entry_type_for_source (shell, source,
 						 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED);
-	rb_shell_register_entry_type_for_source (shell, source, 
+	rb_shell_register_entry_type_for_source (shell, source,
 						 RHYTHMDB_ENTRY_TYPE_PODCAST_POST);
-	
+
 	return source;
 }
 
@@ -887,11 +869,11 @@ impl_delete (RBSource *asource)
 	RBShell *shell;
 
 	rb_debug ("Delete episode action");
-	
+
 	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 	g_object_get (G_OBJECT (shell), "window", &window, NULL);
 	g_object_unref (G_OBJECT (shell));
-	
+
 	dialog = gtk_message_dialog_new (window,
 			                 GTK_DIALOG_DESTROY_WITH_PARENT,
 					 GTK_MESSAGE_WARNING,
@@ -906,16 +888,16 @@ impl_delete (RBSource *asource)
 
 	gtk_window_set_title (GTK_WINDOW (dialog), "");
 
-	gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
-	                        _("Delete _Episode Only"), 
+	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+	                        _("Delete _Episode Only"),
 	                        GTK_RESPONSE_NO,
-	                        GTK_STOCK_CANCEL, 
-	                        GTK_RESPONSE_CANCEL, 
+	                        GTK_STOCK_CANCEL,
+	                        GTK_RESPONSE_CANCEL,
 	                        NULL);
 	button = gtk_dialog_add_button (GTK_DIALOG (dialog),
 	                                _("_Delete Episode And File"),
 			                GTK_RESPONSE_YES);
-	
+
 	gtk_window_set_focus (GTK_WINDOW (dialog), button);
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
 
@@ -925,9 +907,9 @@ impl_delete (RBSource *asource)
 	if (ret == GTK_RESPONSE_CANCEL || ret == GTK_RESPONSE_DELETE_EVENT)
 		return;
 
-	rb_podcast_manager_set_remove_files (source->priv->podcast_mg, 
+	rb_podcast_manager_set_remove_files (source->priv->podcast_mg,
 					     (ret == GTK_RESPONSE_YES));
-	
+
 	for (l = rb_entry_view_get_selected_entries (source->priv->posts); l != NULL;
 	     l = g_list_next (l)) {
 		rhythmdb_entry_delete (source->priv->db, l->data);
@@ -996,7 +978,6 @@ rb_podcast_source_download_status_change
 
 }
 
-
 static void
 rb_podcast_source_songs_show_popup_cb (RBEntryView *view,
 				       gboolean over_entry,
@@ -1024,7 +1005,7 @@ rb_podcast_source_songs_show_popup_cb (R
 			else if (status == RHYTHMDB_PODCAST_STATUS_PAUSED ||
 				 status == RHYTHMDB_PODCAST_STATUS_ERROR)
 				 downloadable = TRUE;
-					
+
 			lst = lst->next;
 		}
 
@@ -1038,7 +1019,6 @@ rb_podcast_source_songs_show_popup_cb (R
 	}
 }
 
-
 static void
 rb_podcast_source_feeds_show_popup_cb (RBPropertyView *view,
 				       RBPodcastSource *source)
@@ -1056,7 +1036,7 @@ rb_podcast_source_feeds_show_popup_cb (R
 		act_update = gtk_action_group_get_action (source->priv->action_group, "PodcastFeedUpdate");
 		act_properties = gtk_action_group_get_action (source->priv->action_group, "PodcastFeedProperties");
 		act_delete = gtk_action_group_get_action (source->priv->action_group, "PodcastFeedDelete");
-		
+
 		if (lst) {
 			gtk_action_set_visible (act_properties, TRUE);
 			gtk_action_set_visible (act_delete, TRUE);
@@ -1070,8 +1050,6 @@ rb_podcast_source_feeds_show_popup_cb (R
 	}
 }
 
-
-
 static void
 feed_select_change_cb (RBPropertyView *propview,
 		       GList *feeds,
@@ -1079,25 +1057,23 @@ feed_select_change_cb (RBPropertyView *p
 {
 	if (rb_string_list_equal (feeds, source->priv->selected_feeds))
 		return;
-	
+
 	if (source->priv->selected_feeds) {
 		g_list_foreach (source->priv->selected_feeds, (GFunc) g_free, NULL);
 	        g_list_free (source->priv->selected_feeds);
-	}	
+	}
 
 	source->priv->selected_feeds = rb_string_list_copy (feeds);
-	
+
 	rb_podcast_source_do_query (source, RB_PODCAST_QUERY_TYPE_ALBUM);
 	rb_source_notify_filter_changed (RB_SOURCE (source));
 }
 
-
-
 static void
 rb_podcast_source_show_browser (RBPodcastSource *source,
 			       gboolean show)
 {
-	
+
 	GtkWidget *feedswidget = GTK_WIDGET (source->priv->feeds);
 
 	if (show == TRUE) {
@@ -1108,12 +1084,11 @@ rb_podcast_source_show_browser (RBPodcas
 		gtk_widget_hide (feedswidget);
 		if (g_list_find (children, feedswidget))
 		    gtk_container_remove (GTK_CONTAINER (source->priv->paned), feedswidget);
-		
+
 		g_list_free (children);
 	}
 }
 
-
 static GPtrArray *
 construct_query_from_selection (RBPodcastSource *source)
 {
@@ -1158,8 +1133,8 @@ construct_query_from_selection (RBPodcas
 	}
 
 	if (source->priv->selected_feeds) {
-		GPtrArray *subquery = g_ptr_array_new ();	
-		GList *l;	       
+		GPtrArray *subquery = g_ptr_array_new ();
+		GList *l;
 
 		for (l = source->priv->selected_feeds; l != NULL; l = g_list_next (l)) {
 			const char *location;
@@ -1177,7 +1152,7 @@ construct_query_from_selection (RBPodcas
 				rhythmdb_query_append (source->priv->db, subquery,
 						       RHYTHMDB_QUERY_DISJUNCTION);
 		}
-		
+
 		rhythmdb_query_append (source->priv->db, query,
 				       RHYTHMDB_QUERY_SUBQUERY, subquery,
 				       RHYTHMDB_QUERY_END);
@@ -1194,7 +1169,7 @@ rb_podcast_source_do_query (RBPodcastSou
 	gboolean is_all_query;
 
 	rb_debug ("select entry filter");
-	
+
 	is_all_query  = ((qtype == RB_PODCAST_QUERY_TYPE_ALL) ||
 			 ((source->priv->selected_feeds == NULL) &&
 			 (source->priv->search_text == NULL)));
@@ -1219,9 +1194,9 @@ rb_podcast_source_do_query (RBPodcastSou
 	rhythmdb_do_full_query_async_parsed (source->priv->db,
 					     RHYTHMDB_QUERY_RESULTS (query_model),
 					     query);
-		
+
 	rhythmdb_query_free (query);
-	
+
 	if (!is_all_query)
 		g_object_unref (G_OBJECT (query_model));
 }
@@ -1233,7 +1208,6 @@ impl_show_popup (RBSource *source)
 	return TRUE;
 }
 
-
 static GtkWidget *
 impl_get_config_widget (RBSource *asource, RBShellPreferences *prefs)
 {
@@ -1246,13 +1220,12 @@ impl_get_config_widget (RBSource *asourc
 	if (source->priv->config_widget)
 		return source->priv->config_widget;
 
-
 	xml = rb_glade_xml_new ("podcast-prefs.glade", "podcast_vbox", source);
 	source->priv->config_widget = glade_xml_get_widget (xml, "podcast_vbox");
-	
+
 	btn_file = glade_xml_get_widget (xml, "location_chooser");
 	download_dir = rb_podcast_manager_get_podcast_dir (source->priv->podcast_mg);
-	gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (btn_file), 
+	gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (btn_file),
 						 download_dir);
 	g_free (download_dir);
 
@@ -1268,26 +1241,25 @@ impl_get_config_widget (RBSource *asourc
 			  "changed",
 			  G_CALLBACK (rb_podcast_source_cb_interval_changed_cb),
 			  source);
-				
+
 	return source->priv->config_widget;
 }
 
-static void 
+static void
 rb_podcast_source_btn_file_change_cb (GtkFileChooserButton *widget, const char *key)
 {
 	char *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (widget));
-	
+
 	eel_gconf_set_string (key, gnome_vfs_get_local_path_from_uri (uri));
 	g_free (uri);
 }
 
-
 static void
 posts_view_drag_data_received_cb (GtkWidget *widget,
 				  GdkDragContext *dc,
 				  gint x,
 				  gint y,
-				  GtkSelectionData *selection_data, 
+				  GtkSelectionData *selection_data,
 				  guint info,
 				  guint time,
 				  RBPodcastSource *source)
@@ -1295,7 +1267,7 @@ posts_view_drag_data_received_cb (GtkWid
 	impl_receive_drag (RB_SOURCE (source), selection_data);
 }
 
-void 
+void
 rb_podcast_source_add_feed (RBPodcastSource *source, const char *uri)
 {
 	rb_podcast_manager_subscribe_feed (source->priv->podcast_mg, uri);
@@ -1308,10 +1280,10 @@ rb_podcast_source_cmd_download_post (Gtk
 	GList *lst;
 	GValue val = {0, };
 	RBEntryView *posts;
-	
+
 	rb_debug ("Add to download action");
 	posts = source->priv->posts;
-	
+
 	lst = rb_entry_view_get_selected_entries (posts);
 	g_value_init (&val, G_TYPE_ULONG);
 
@@ -1325,7 +1297,7 @@ rb_podcast_source_cmd_download_post (Gtk
 			rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_STATUS, &val);
 			rb_podcast_manager_download_entry (source->priv->podcast_mg, entry);
 		}
-			
+
 		lst = lst->next;
 	}
 	g_value_unset (&val);
@@ -1339,10 +1311,10 @@ rb_podcast_source_cmd_cancel_download (G
 	GList *lst;
 	GValue val = {0, };
 	RBEntryView *posts;
-	
+
 	rb_debug ("Add to download action");
 	posts = source->priv->posts;
-	
+
 	lst = rb_entry_view_get_selected_entries (posts);
 	g_value_init (&val, G_TYPE_ULONG);
 
@@ -1356,7 +1328,7 @@ rb_podcast_source_cmd_cancel_download (G
 			rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_STATUS, &val);
 			rb_podcast_manager_cancel_download (source->priv->podcast_mg, entry);
 		}
-			
+
 		lst = lst->next;
 	}
 	g_value_unset (&val);
@@ -1391,29 +1363,29 @@ rb_podcast_source_cmd_delete_feed (GtkAc
 						    "they will be permanently lost.  Please note that "
 						    "you can delete the feed but keep the downloaded "
 						    "files by choosing to delete the feed only."));
-	
+
 	gtk_window_set_title (GTK_WINDOW (dialog), "");
 
-	gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
-	                        _("Delete _Feed Only"), 
+	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+	                        _("Delete _Feed Only"),
 	                        GTK_RESPONSE_NO,
-	                        GTK_STOCK_CANCEL, 
-	                        GTK_RESPONSE_CANCEL, 
+	                        GTK_STOCK_CANCEL,
+	                        GTK_RESPONSE_CANCEL,
 	                        NULL);
 
 	button = gtk_dialog_add_button (GTK_DIALOG (dialog),
 	                                _("_Delete Feed And Files"),
 			                GTK_RESPONSE_YES);
-	
+
 	gtk_window_set_focus (GTK_WINDOW (dialog), button);
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
-	
+
 	ret = gtk_dialog_run (GTK_DIALOG (dialog));
 	gtk_widget_destroy (dialog);
 
 	if (ret == GTK_RESPONSE_CANCEL || ret == GTK_RESPONSE_DELETE_EVENT)
 		return;
-	
+
 	feeds = rb_string_list_copy (source->priv->selected_feeds);
 	for (l = feeds; l != NULL; l = g_list_next (l)) {
 		const char *location = l->data;
@@ -1437,7 +1409,7 @@ rb_podcast_source_cmd_properties_feed (G
 
 	location = (char *) source->priv->selected_feeds->data;
 
-	entry = rhythmdb_entry_lookup_by_location (source->priv->db, 
+	entry = rhythmdb_entry_lookup_by_location (source->priv->db,
 						   location);
 
 	if (entry != NULL) {
@@ -1449,13 +1421,13 @@ rb_podcast_source_cmd_properties_feed (G
 			rb_debug ("no selection!");
 	}
 }
-	
+
 static void
 rb_podcast_source_cmd_update_feed (GtkAction *action,
 			     	   RBPodcastSource *source)
 {
 	GList *feeds, *l;
-	
+
 	rb_debug ("Update action");
 
 	feeds = rb_string_list_copy (source->priv->selected_feeds);
@@ -1491,7 +1463,7 @@ rb_podcast_source_post_status_cell_data_
 	switch (rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_STATUS)) {
 	case RHYTHMDB_PODCAST_STATUS_COMPLETE:
 		g_object_set (G_OBJECT (renderer), "text", _("Downloaded"), NULL);
-		value = 100;  
+		value = 100;
 		break;
 	case RHYTHMDB_PODCAST_STATUS_ERROR:
 		g_object_set (G_OBJECT (renderer), "text", _("Failed"), NULL);
@@ -1511,7 +1483,7 @@ rb_podcast_source_post_status_cell_data_
 
 			value = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_STATUS);
 			s = g_strdup_printf ("%u %%", value);
-			
+
 			g_object_set (G_OBJECT (renderer), "text", s, NULL);
 			g_free (s);
 		}
@@ -1537,7 +1509,7 @@ rb_podcast_source_post_feed_cell_data_fu
 
 	gtk_tree_model_get (tree_model, iter, 0, &entry, -1);
 	album = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
-		
+
 	g_object_set (G_OBJECT (renderer), "text", album, NULL);
 }
 
@@ -1618,7 +1590,6 @@ rb_podcast_source_feed_title_cell_data_f
 	g_free (title);
 }
 
-
 static void
 rb_podcast_source_post_date_cell_data_func (GtkTreeViewColumn *column,
 					    GtkCellRenderer *renderer,
@@ -1642,14 +1613,11 @@ rb_podcast_source_post_date_cell_data_fu
 		localtime_r (&time, &time_tm);
 		str = eel_strdup_strftime (_("%Y-%m-%d %H:%M"), &time_tm);
 	}
-	
+
 	g_object_set (G_OBJECT (renderer), "text", str, NULL);
 	g_free (str);
 }
 
-
-
-
 static void
 rb_podcast_source_cb_interval_changed_cb (GtkComboBox *box, gpointer cb_data)
 {
@@ -1660,13 +1628,13 @@ rb_podcast_source_cb_interval_changed_cb
 	rb_podcast_manager_start_sync (RB_PODCAST_SOURCE (cb_data)->priv->podcast_mg);
 }
 
-static gboolean 
+static gboolean
 rb_podcast_source_load_finish_cb  (gpointer cb_data)
 {
 	RBPodcastSource *source  = RB_PODCAST_SOURCE (cb_data);
-	
+
 	rb_podcast_manager_start_sync (source->priv->podcast_mg);
-	
+
 	g_signal_connect_after (G_OBJECT (source->priv->podcast_mg),
 	 		        "start_download",
 			  	G_CALLBACK (rb_podcast_source_start_download_cb),
@@ -1721,9 +1689,9 @@ impl_receive_drag (RBSource *asource, Gt
 			if (i == NULL)
 				break;
 		}
-		
+
 		uri = i->data;
-		if ((uri != NULL) && 
+		if ((uri != NULL) &&
 		    (!rhythmdb_entry_lookup_by_location (source->priv->db, uri))) {
 			rb_podcast_source_add_feed (source, uri);
 		}
@@ -1738,7 +1706,6 @@ impl_receive_drag (RBSource *asource, Gt
 	return TRUE;
 }
 
-
 static void
 rb_podcast_source_start_download_cb (RBPodcastManager *pd,
 				     RhythmDBEntry *entry,
@@ -1784,7 +1751,7 @@ rb_podcast_source_get_shell (RBPodcastSo
 	return shell;
 }
 
-void 
+void
 rb_podcast_source_shutdown	(RBPodcastSource *source)
 {
 	rb_debug ("podcast source shutdown");
@@ -1874,11 +1841,11 @@ static void rb_podcast_source_entry_acti
 						  RBPodcastSource *source)
 {
 	GValue val = {0,};
-	
+
 	/* check to see if it has already been downloaded */
 	if (rb_podcast_manager_entry_downloaded (entry))
 		return;
-	
+
 	g_value_init (&val, G_TYPE_ULONG);
 	g_value_set_ulong (&val, RHYTHMDB_PODCAST_STATUS_WAITING);
 	rhythmdb_entry_set (source->priv->db, entry, RHYTHMDB_PROP_STATUS, &val);
@@ -1896,7 +1863,7 @@ impl_can_add_to_queue (RBSource *source)
 	GList *iter;
 	gboolean ok = FALSE;
 
-	if (selection == NULL) 
+	if (selection == NULL)
 		return FALSE;
 
 	/* If at least one entry has been downloaded, enable add to queue.
@@ -1918,14 +1885,14 @@ impl_add_to_queue (RBSource *source, RBS
 	GList *selection = rb_entry_view_get_selected_entries (songs);
 	GList *iter;
 
-	if (selection == NULL) 
+	if (selection == NULL)
 		return;
 
 	for (iter = selection; iter; iter = iter->next) {
 		RhythmDBEntry *entry = (RhythmDBEntry *)iter->data;
 		if (!rb_podcast_manager_entry_downloaded (entry))
 			continue;
-		rb_static_playlist_source_add_entry (RB_STATIC_PLAYLIST_SOURCE (queue), 
+		rb_static_playlist_source_add_entry (RB_STATIC_PLAYLIST_SOURCE (queue),
 						     entry, -1);
 	}
 
@@ -1961,7 +1928,7 @@ rb_podcast_source_cmd_new_podcast (GtkAc
 {
 	GtkWidget *dialog;
 	GObject *object;
-	
+
 	rb_debug ("Got new podcast command");
 	g_object_get (G_OBJECT (source), "podcast-manager", &object, NULL);
 	dialog = rb_new_podcast_dialog_new (RB_PODCAST_MANAGER (object));
@@ -1981,8 +1948,8 @@ impl_get_status (RBSource *source, char 
 
 	g_object_get (G_OBJECT (source), "query-model", &query_model, NULL);
 	if (query_model) {
-		*text = rhythmdb_query_model_compute_status_normal (query_model, 
-								    "%d episode", 
+		*text = rhythmdb_query_model_compute_status_normal (query_model,
+								    "%d episode",
 								    "%d episodes");
 		if (rhythmdb_query_model_has_pending_changes (query_model))
 			*progress = -1.0f;
@@ -1991,4 +1958,3 @@ impl_get_status (RBSource *source, char 
 		*text = g_strdup ("");
 	}
 }
-
Index: sources/rb-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.c,v
retrieving revision 1.72
diff -p -u -r1.72 rb-source.c
--- sources/rb-source.c	20 Jun 2006 12:10:18 -0000	1.72
+++ sources/rb-source.c	10 Jul 2006 22:47:18 -0000
@@ -51,6 +51,9 @@ static void rb_source_get_property (GObj
 
 static char * default_get_browser_key (RBSource *source);
 static GList *default_get_property_views (RBSource *source);
+static GList *default_get_entry_types (RBSource *source);
+static GList *default_get_mime_types (RBSource *source);
+static GList *default_get_uri_schemes (RBSource *source);
 static gboolean default_can_rename (RBSource *source);
 static gboolean default_can_search (RBSource *source);
 static GList *default_copy (RBSource *source);
@@ -82,7 +85,7 @@ G_DEFINE_ABSTRACT_TYPE (RBSource, rb_sou
 struct _RBSourcePrivate
 {
 	char *name;
-	
+
 	RBShell *shell;
 	gboolean visible;
 	RhythmDBQueryModel *query_model;
@@ -122,10 +125,14 @@ rb_source_class_init (RBSourceClass *kla
 	object_class->set_property = rb_source_set_property;
 	object_class->get_property = rb_source_get_property;
 
+	klass->impl_add_uri = NULL;
 	klass->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
 	klass->impl_get_browser_key = default_get_browser_key;
 	klass->impl_browser_toggled = NULL;
 	klass->impl_get_property_views = default_get_property_views;
+	klass->impl_get_entry_types = default_get_entry_types;
+	klass->impl_get_mime_types = default_get_mime_types;
+	klass->impl_get_uri_schemes = default_get_uri_schemes;
 	klass->impl_can_rename = default_can_rename;
 	klass->impl_can_search = default_can_search;
 	klass->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
@@ -249,7 +256,7 @@ rb_source_class_init (RBSourceClass *kla
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE,
 			      0);
-	
+
 	g_type_class_add_private (object_class, sizeof (RBSourcePrivate));
 }
 
@@ -264,7 +271,7 @@ rb_source_finalize (GObject *object)
 {
 	RBSource *source;
 	RBSourcePrivate *priv;
-	
+
 	g_return_if_fail (object != NULL);
 	g_return_if_fail (RB_IS_SOURCE (object));
 
@@ -327,12 +334,12 @@ rb_source_set_property (GObject *object,
 		break;
 	case PROP_VISIBLE:
 		priv->visible = g_value_get_boolean (value);
-		rb_debug ("Setting %s visibility to %u", 
-			  priv->name, 
+		rb_debug ("Setting %s visibility to %u",
+			  priv->name,
 			  priv->visible);
 		break;
 	case PROP_QUERY_MODEL:
-		model = g_value_get_object (value); 
+		model = g_value_get_object (value);
 		if (priv->query_model == model)
 			return;
 
@@ -345,7 +352,7 @@ rb_source_set_property (GObject *object,
 							      source);
 			g_object_unref (G_OBJECT (priv->query_model));
 		}
-		
+
 		priv->query_model = model;
 		if (priv->query_model) {
 			g_object_ref (G_OBJECT (model));
@@ -369,7 +376,7 @@ rb_source_set_property (GObject *object,
 	}
 }
 
-static void 
+static void
 rb_source_get_property (GObject *object,
 			guint prop_id,
 			GValue *value,
@@ -393,7 +400,7 @@ rb_source_get_property (GObject *object,
 	case PROP_UI_MANAGER:
 	{
 		GtkUIManager *manager;
-		g_object_get (G_OBJECT (priv->shell), 
+		g_object_get (G_OBJECT (priv->shell),
 			      "ui-manager", &manager,
 			      NULL);
 		g_value_set_object (value, manager);
@@ -412,6 +419,21 @@ rb_source_get_property (GObject *object,
 	}
 }
 
+gboolean
+rb_source_add_uri (RBSource   *source,
+		   const char *uri,
+		   const char *title,
+		   const char *genre)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	if (klass->impl_add_uri) {
+		return klass->impl_add_uri (source, uri, title, genre);
+	} else {
+		return FALSE;
+	}
+}
+
 static void
 default_get_status (RBSource *source, char **text, char **progress_text, float *progress)
 {
@@ -421,8 +443,8 @@ default_get_status (RBSource *source, ch
 		ngettext ("%d song", "%d songs", 0);
 	}
 	if (priv->query_model) {
-		*text = rhythmdb_query_model_compute_status_normal (priv->query_model, 
-								    "%d song", 
+		*text = rhythmdb_query_model_compute_status_normal (priv->query_model,
+								    "%d song",
 								    "%d songs");
 		if (rhythmdb_query_model_has_pending_changes (priv->query_model))
 			*progress = -1.0f;
@@ -510,7 +532,7 @@ rb_source_update_play_statistics (RBSour
 	/* Increment current play count */
 	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_PLAY_COUNT, &value);
 	g_value_unset (&value);
-	
+
 	/* Reset the last played time */
 	time (&now);
 
@@ -536,6 +558,24 @@ default_get_property_views (RBSource *so
 	return NULL;
 }
 
+static GList *
+default_get_entry_types (RBSource *source)
+{
+	return NULL;
+}
+
+static GList *
+default_get_mime_types (RBSource *source)
+{
+	return NULL;
+}
+
+static GList *
+default_get_uri_schemes (RBSource *source)
+{
+	return NULL;
+}
+
 GList *
 rb_source_get_property_views (RBSource *source)
 {
@@ -544,6 +584,30 @@ rb_source_get_property_views (RBSource *
 	return klass->impl_get_property_views (source);
 }
 
+GList *
+rb_source_get_entry_types (RBSource *source)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	return klass->impl_get_entry_types (source);
+}
+
+GList *
+rb_source_get_mime_types (RBSource *source)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	return klass->impl_get_mime_types (source);
+}
+
+GList *
+rb_source_get_uri_schemes (RBSource *source)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	return klass->impl_get_uri_schemes (source);
+}
+
 static gboolean
 default_can_rename (RBSource *source)
 {
@@ -662,7 +726,7 @@ default_copy (RBSource *source)
 {
 	return rb_entry_view_get_selected_entries (rb_source_get_entry_view (source));
 }
-	
+
 GList *
 rb_source_copy (RBSource *source)
 {
@@ -693,11 +757,11 @@ default_add_to_queue (RBSource *source, 
 	GList *selection = rb_entry_view_get_selected_entries (songs);
 	GList *iter;
 
-	if (selection == NULL) 
+	if (selection == NULL)
 		return;
 
 	for (iter = selection; iter; iter = iter->next) {
-		rb_static_playlist_source_add_entry (RB_STATIC_PLAYLIST_SOURCE (queue), 
+		rb_static_playlist_source_add_entry (RB_STATIC_PLAYLIST_SOURCE (queue),
 						     (RhythmDBEntry *)iter->data, -1);
 	}
 
@@ -878,17 +942,20 @@ default_get_entry_view (RBSource *source
 	return NULL;
 }
 
-static void default_activate (RBSource *source)
+static void
+default_activate (RBSource *source)
 {
 	return;
 }
 
-static void default_deactivate (RBSource *source)
+static void
+default_deactivate (RBSource *source)
 {
 	return;
 }
 
-void rb_source_activate (RBSource *source)
+void
+rb_source_activate (RBSource *source)
 {
 	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
 
@@ -897,7 +964,8 @@ void rb_source_activate (RBSource *sourc
 	return;
 }
 
-void rb_source_deactivate (RBSource *source)
+void
+rb_source_deactivate (RBSource *source)
 {
 	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
 
@@ -973,7 +1041,7 @@ rb_source_gather_selected_properties (RB
 	}
 
 	g_list_free (selected);
-	
+
 	tem = NULL;
 	g_hash_table_foreach (selected_set, (GHFunc) rb_source_gather_hash_keys,
 			      &tem);
Index: sources/rb-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.h,v
retrieving revision 1.46
diff -p -u -r1.46 rb-source.h
--- sources/rb-source.h	4 Jun 2006 10:19:22 -0000	1.46
+++ sources/rb-source.h	10 Jul 2006 22:47:18 -0000
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
  *  arch-tag: Header for the abstract base class of all sources
  *
  *  Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
@@ -77,7 +78,7 @@ struct _RBSource
 struct _RBSourceClass
 {
 	GtkHBoxClass parent;
-	
+
 	/* signals */
 	void (*status_changed)	(RBSource *source);
 	void (*filter_changed)	(RBSource *source);
@@ -85,6 +86,10 @@ struct _RBSourceClass
 	void (*artistalbum_changed)	(RBSource *source);
 
 	/* methods */
+	gboolean        (*impl_add_uri)         (RBSource   *source,
+                                                 const char *uri,
+                                                 const char *title,
+                                                 const char *genre);
 	void		(*impl_get_status)	(RBSource *source, char **text, char **progress_text, float *progress);
 
 	gboolean	(*impl_can_browse)	(RBSource *source);
@@ -93,6 +98,9 @@ struct _RBSourceClass
 
 	RBEntryView *	(*impl_get_entry_view)	(RBSource *source);
 	GList *		(*impl_get_property_views)	(RBSource *source);
+	GList *		(*impl_get_entry_types) (RBSource *source);
+	GList *		(*impl_get_mime_types)  (RBSource *source);
+	GList *		(*impl_get_uri_schemes) (RBSource *source);
 
 	gboolean	(*impl_can_rename)	(RBSource *source);
 
@@ -108,7 +116,7 @@ struct _RBSourceClass
 	gboolean	(*impl_can_copy)	(RBSource *source);
 	gboolean	(*impl_can_paste)	(RBSource *source);
 	gboolean	(*impl_can_add_to_queue)(RBSource *source);
-	
+
 	GList *		(*impl_cut)		(RBSource *source);
 	GList *		(*impl_copy)		(RBSource *source);
 	void		(*impl_paste)		(RBSource *source, GList *entries);
@@ -122,11 +130,11 @@ struct _RBSourceClass
 
 	gboolean	(*impl_can_pause)	(RBSource *source);
 	RBSourceEOFType	(*impl_handle_eos)	(RBSource *source);
-	
+
 	gboolean	(*impl_have_url)	(RBSource *source);
 	gboolean	(*impl_receive_drag)	(RBSource *source, GtkSelectionData *data);
 	gboolean	(*impl_show_popup)	(RBSource *source);
-				   
+
 	void		(*impl_delete_thyself)	(RBSource *source);
 	void		(*impl_activate)	(RBSource *source);
 	void		(*impl_deactivate)	(RBSource *source);
@@ -144,6 +152,10 @@ void		rb_source_update_play_statistics(R
 						 RhythmDBEntry *entry);
 
 /* general interface */
+gboolean        rb_source_add_uri               (RBSource   *source,
+                                                 const char *uri,
+                                                 const char *title,
+                                                 const char *genre);
 void	        rb_source_set_pixbuf		(RBSource *source, GdkPixbuf *pixbuf);
 void	        rb_source_get_status		(RBSource *source, char **text, char **progress_text, float *progress);
 
@@ -154,6 +166,9 @@ void		rb_source_browser_toggled	(RBSourc
 RBEntryView *	rb_source_get_entry_view	(RBSource *source);
 
 GList *		rb_source_get_property_views	(RBSource *source);
+GList *		rb_source_get_entry_types	(RBSource *source);
+GList *		rb_source_get_mime_types	(RBSource *source);
+GList *		rb_source_get_uri_schemes	(RBSource *source);
 
 gboolean	rb_source_can_rename		(RBSource *source);
 
