Index: configure.ac
===================================================================
--- configure.ac	(revision 5037)
+++ configure.ac	(working copy)
@@ -132,7 +132,32 @@
 fi
 AM_CONDITIONAL(USE_IPOD, test x"$use_ipod" = xyes)
 
+dnl NJB device support
 
+AC_ARG_WITH(njb,
+            AC_HELP_STRING([--with-njb],
+			   [Enable NJB device support]),,
+	      with_njb=auto)
+if test "x$with_njb" != "xno"; then
+	PKG_CHECK_MODULES(NJB, libnjb, have_libnjb=yes, have_libnjb=no)
+	if test "x$have_libnjb" = "xno" -a "x$with_njb" = "xyes"; then
+	  AC_MSG_ERROR([NJB device explicitly requested but libnjb couldn't be found])
+	fi
+	if test "x$have_libnjb" = "xyes"; then
+          if test "x$with_hal" = xyes && test "x$enable_hal" = xno; then
+	     AC_MSG_ERROR([NJB device explicitly requested but HAL not found or too old])
+	  fi
+          if test "x$enable_hal" = xyes; then
+	     AC_DEFINE(WITH_NJB, 1, [Define if NJB device support is enabled])
+	     use_njb=yes
+	  fi
+	  AC_SUBST(NJB_CFLAGS)
+	  AC_SUBST(NJB_LIBS)
+	fi
+fi
+AM_CONDITIONAL(USE_NJB, test x"$use_njb" = xyes)
+
+
 dnl ipod writing
 AC_ARG_ENABLE(ipod-writing,
 	      AC_HELP_STRING([--disable-ipod-writing],
@@ -929,6 +954,7 @@
 plugins/iradio/Makefile
 plugins/lirc/Makefile
 plugins/lyrics/Makefile
+plugins/njb/Makefile
 plugins/sample-python/Makefile
 plugins/sample-vala/Makefile
 plugins/pythonconsole/Makefile
@@ -1006,6 +1032,11 @@
 else
 	AC_MSG_NOTICE([   iPod integration disabled])
 fi
+if test x"$use_njb" = xyes; then
+	AC_MSG_NOTICE([** NJB device integration enabled])
+else
+	AC_MSG_NOTICE([   NJB device integration disabled])
+fi
 if test x"$enable_cd_burning" != xno; then
 	AC_MSG_NOTICE([** CD burning support enabled])
 else
Index: plugins/Makefile.am
===================================================================
--- plugins/Makefile.am	(revision 5037)
+++ plugins/Makefile.am	(working copy)
@@ -36,6 +36,10 @@
 SUBDIRS += ipod
 endif
 
+if USE_NJB
+SUBDIRS += njb
+endif
+
 if USE_CD_BURNING
 SUBDIRS += 						\
 	audiocd						\
Index: plugins/njb/njb-ui.xml
===================================================================
--- plugins/njb/njb-ui.xml	(revision 0)
+++ plugins/njb/njb-ui.xml	(revision 0)
@@ -0,0 +1,2 @@
+<ui>
+</ui>
Index: plugins/njb/njb.rb-plugin.desktop.in
===================================================================
--- plugins/njb/njb.rb-plugin.desktop.in	(revision 0)
+++ plugins/njb/njb.rb-plugin.desktop.in	(revision 0)
@@ -0,0 +1,8 @@
+[RB Plugin]
+Module=njb
+IAge=1
+_Name=Portable Players - NJB
+_Description=Support for NJB devices (show the content, play from device)
+Authors=James Livingston
+Copyright=Copyright © 2006 James Livingston
+Website=http://www.rhythmbox.org/
Index: plugins/njb/rb-njb-plugin.c
===================================================================
--- plugins/njb/rb-njb-plugin.c	(revision 0)
+++ plugins/njb/rb-njb-plugin.c	(revision 0)
@@ -0,0 +1,225 @@
+/*
+ * rb-njb-plugin.c
+ * 
+ * Copyright (C) 2006 James Livingston <doclivingston@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+#include "rb-removable-media-manager.h"
+#include "rb-source.h"
+#include "rb-njb-source.h"
+#include "rb-plugin.h"
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+#include "rb-util.h"
+#include "rb-shell.h"
+
+
+#define RB_TYPE_NJB_PLUGIN		(rb_njb_plugin_get_type ())
+#define RB_NJB_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_NJB_PLUGIN, RBNjbPlugin))
+#define RB_NJB_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_NJB_PLUGIN, RBNjbPluginClass))
+#define RB_IS_NJB_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_NJB_PLUGIN))
+#define RB_IS_NJB_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_NJB_PLUGIN))
+#define RB_NJB_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_NJB_PLUGIN, RBNjbPluginClass))
+
+typedef struct
+{
+	RBPlugin parent;
+
+	RBShell *shell;
+	GtkActionGroup *action_group;
+	guint ui_merge_id;
+
+	guint scan_id;
+	GHashTable *njb_sources;
+} RBNjbPlugin;
+
+typedef struct
+{
+	RBPluginClass parent_class;
+} RBNjbPluginClass;
+
+
+G_MODULE_EXPORT GType register_rb_plugin (GTypeModule *module);
+GType	rb_njb_plugin_get_type		(void) G_GNUC_CONST;
+
+static void rb_njb_plugin_init (RBNjbPlugin *plugin);
+static void rb_njb_plugin_finalize (GObject *object);
+static void impl_activate (RBPlugin *plugin, RBShell *shell);
+static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
+
+
+static gboolean njb_scan (RBNjbPlugin *plugin);
+
+RB_PLUGIN_REGISTER(RBNjbPlugin, rb_njb_plugin)
+
+
+static GtkActionEntry rb_njb_plugin_actions [] =
+{
+	/**/
+};
+
+
+static void
+rb_njb_plugin_class_init (RBNjbPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBPluginClass *plugin_class = RB_PLUGIN_CLASS (klass);
+
+	object_class->finalize = rb_njb_plugin_finalize;
+	
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+
+	/* register types used by the plugin */
+	RB_PLUGIN_REGISTER_TYPE(rb_njb_source);
+}
+
+static void
+rb_njb_plugin_init (RBNjbPlugin *plugin)
+{
+	rb_debug ("RBNjbPlugin initialising");
+}
+
+static void
+rb_njb_plugin_finalize (GObject *object)
+{
+	/*RBNjbPlugin *plugin = RB_NJB_PLUGIN (object);*/
+
+	rb_debug ("RBNjbPlugin finalising");
+
+	G_OBJECT_CLASS (rb_njb_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (RBPlugin *bplugin,
+	       RBShell *shell)
+{
+	RBNjbPlugin *plugin = RB_NJB_PLUGIN (bplugin);
+	GtkUIManager *uimanager = NULL;
+	char *file;
+	
+	NJB_Set_Unicode (NJB_UC_UTF8);
+
+	plugin->shell = shell;
+
+	/* add njb UI */
+	g_object_get (G_OBJECT (shell),
+		      "ui-manager", &uimanager, 
+		      NULL);
+
+	plugin->action_group = gtk_action_group_new ("NjbActions");
+	gtk_action_group_set_translation_domain (plugin->action_group,
+						 GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (plugin->action_group,
+				      rb_njb_plugin_actions, G_N_ELEMENTS (rb_njb_plugin_actions),
+				      plugin);
+	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
+	file = rb_plugin_find_file (bplugin, "njb-ui.xml");
+	plugin->ui_merge_id = gtk_ui_manager_add_ui_from_file (uimanager,
+							       file,
+							       NULL);
+	g_free (file);
+	g_object_unref (G_OBJECT (uimanager));
+
+	plugin->njb_sources = g_hash_table_new (g_direct_hash, g_direct_equal);
+	plugin->scan_id = g_timeout_add (30000, (GSourceFunc)njb_scan, plugin);
+	njb_scan (plugin);
+
+}
+
+static void
+_remove_source (njb_t *device, RBSource *source, gpointer unused)
+{
+	rb_source_delete_thyself (source);
+}
+
+static gboolean
+rb_hash_table_value_equal (gpointer key, gpointer value, gpointer data)
+{
+	return (value == data);
+}
+
+static void
+impl_deactivate	(RBPlugin *bplugin,
+		 RBShell *shell)
+{
+	RBNjbPlugin *plugin = RB_NJB_PLUGIN (bplugin);
+	GtkUIManager *uimanager = NULL;
+
+	g_object_get (G_OBJECT (shell),
+		      "ui-manager", &uimanager, 
+		      NULL);
+
+	gtk_ui_manager_remove_ui (uimanager, plugin->ui_merge_id);
+	gtk_ui_manager_remove_action_group (uimanager, plugin->action_group);
+	
+	if (plugin->scan_id != 0) {
+		g_source_remove (plugin->scan_id);
+		plugin->scan_id = 0;
+	}
+
+	g_hash_table_foreach (plugin->njb_sources, (GHFunc)_remove_source, NULL);
+	g_hash_table_destroy (plugin->njb_sources);
+	plugin->njb_sources = NULL;
+
+	g_object_unref (G_OBJECT (uimanager));
+}
+
+static void
+rb_njb_plugin_source_deleted (RBNjbSource *source, RBNjbPlugin *plugin)
+{
+	g_hash_table_foreach_remove (plugin->njb_sources, rb_hash_table_value_equal, source);
+}
+
+static gboolean
+njb_scan (RBNjbPlugin *plugin)
+{
+	njb_t njbs[NJB_MAX_DEVICES];
+	int count;
+	int i;
+
+	if (NJB_Discover (njbs, NJB_MAX_DEVICES, &count) < 0)
+		return TRUE;
+
+	for (i = 0; i < count; i++) {
+		if (!g_hash_table_lookup (plugin->njb_sources, njbs[i].device)) {
+			RBRemovableMediaSource *source;
+
+			source = rb_njb_source_new (plugin->shell, &njbs[i]);
+			g_hash_table_insert (plugin->njb_sources, njbs[i].device, source);
+			
+			rb_shell_append_source (plugin->shell, RB_SOURCE (source), NULL);
+			
+			g_signal_connect_object (G_OBJECT (source),
+						 "deleted", G_CALLBACK (rb_njb_plugin_source_deleted),
+						 plugin, 0);
+		}
+	}
+
+	return TRUE;
+}
Index: plugins/njb/Makefile.am
===================================================================
--- plugins/njb/Makefile.am	(revision 0)
+++ plugins/njb/Makefile.am	(revision 0)
@@ -0,0 +1,48 @@
+plugindir = $(PLUGINDIR)/njb
+plugin_LTLIBRARIES = libnjb.la
+
+libnjb_la_SOURCES = \
+	rb-njb-plugin.c			\
+	rb-njb-source.c			\
+	rb-njb-source.h
+
+libnjb_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libnjb_la_LIBADD = 					\
+	$(top_builddir)/lib/librb.la			\
+	$(HAL_LIBS)					\
+	$(NJB_LIBS)
+
+INCLUDES = 						\
+        -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DG_LOG_DOMAIN=\"Rhythmbox\"		 	\
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/lib                        	\
+	-I$(top_srcdir)/metadata                       	\
+	-I$(top_srcdir)/player                       	\
+	-I$(top_srcdir)/rhythmdb                       	\
+	-I$(top_srcdir)/widgets                    	\
+	-I$(top_srcdir)/sources                    	\
+	-I$(top_srcdir)/iradio                    	\
+	-I$(top_srcdir)/podcast                    	\
+	-I$(top_srcdir)/plugins				\
+	-I$(top_srcdir)/shell				\
+	-DPIXMAP_DIR=\""$(datadir)/pixmaps"\"		\
+	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
+	-DDATADIR=\""$(datadir)"\"			\
+	$(RHYTHMBOX_CFLAGS)				\
+	$(WARN_CFLAGS)					\
+	$(HAL_CFLAGS)					\
+	$(NJB_CFLAGS)					\
+	-D_XOPEN_SOURCE -D_BSD_SOURCE
+
+plugin_in_files = njb.rb-plugin.desktop.in
+
+%.rb-plugin: %.rb-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.rb-plugin.desktop.in=.rb-plugin)	\
+	njb-ui.xml
+
+EXTRA_DIST = $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
Index: plugins/njb/rb-njb-source.c
===================================================================
--- plugins/njb/rb-njb-source.c	(revision 0)
+++ plugins/njb/rb-njb-source.c	(revision 0)
@@ -0,0 +1,410 @@
+/*
+ *  arch-tag: Implementation of njb source object
+ *
+ *  Copyright (C) 2006 James Livingston  <doclivingston@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libnjb.h>
+
+#include "rb-njb-source.h"
+#include "rb-static-playlist-source.h"
+#include "rb-debug.h"
+#include "rb-plugin.h"
+#include "rb-util.h"
+#include "rhythmdb.h"
+
+
+static GObject *rb_njb_source_constructor (GType type, guint n_construct_properties,
+			       GObjectConstructParam *construct_properties);
+static void rb_njb_source_dispose (GObject *object);
+static void rb_njb_source_finalize (GObject *object);
+static void rb_njb_source_set_property (GObject *object,
+					guint prop_id,
+					const GValue *value,
+					GParamSpec *pspec);
+static void rb_njb_source_get_property (GObject *object,
+					guint prop_id,
+					GValue *value,
+					GParamSpec *pspec);
+
+static gboolean rb_njb_load_songs (RBNjbSource *source);
+static gboolean rb_njb_ping (RBNjbSource *source);
+
+typedef struct
+{
+	njb_t *device;
+	GHashTable *playlists;
+
+	guint load_idle_id;
+	guint ping_id;
+} RBNjbSourcePrivate;
+
+RB_PLUGIN_DEFINE_TYPE(RBNjbSource,
+		      rb_njb_source,
+		      RB_TYPE_REMOVABLE_MEDIA_SOURCE)
+
+
+enum {
+	PROP_0,
+	PROP_DEVICE,
+};
+
+#define NJB_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_NJB_SOURCE, RBNjbSourcePrivate))
+
+static void
+rb_njb_source_class_init (RBNjbSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->constructor = rb_njb_source_constructor;
+	object_class->dispose = rb_njb_source_dispose;
+	object_class->finalize = rb_njb_source_finalize;
+	object_class->set_property = rb_njb_source_set_property;
+	object_class->get_property = rb_njb_source_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_DEVICE,
+					 g_param_spec_pointer ("device",
+							       "device",
+							       "njb_t*",
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_type_class_add_private (klass, sizeof (RBNjbSourcePrivate));
+}
+
+static void
+rb_njb_source_init (RBNjbSource *source)
+{
+	/**/
+}
+
+static GObject *
+rb_njb_source_constructor (GType type, guint n_construct_properties,
+			    GObjectConstructParam *construct_properties)
+{
+	RBNjbSource *source;
+	RBEntryView *songs;
+	RBNjbSourcePrivate *priv;
+
+	source = RB_NJB_SOURCE (G_OBJECT_CLASS (rb_njb_source_parent_class)->
+			constructor (type, n_construct_properties, construct_properties));
+	priv = NJB_SOURCE_GET_PRIVATE (source);
+
+	songs = rb_source_get_entry_view (RB_SOURCE (source));
+	rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_RATING, FALSE);
+	rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
+
+	priv->playlists = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+						 (GDestroyNotify)NJB_Playlist_Destroy, (GDestroyNotify)rb_source_delete_thyself);
+
+	priv->load_idle_id = g_idle_add ((GSourceFunc)rb_njb_load_songs, source);
+	priv->ping_id = g_timeout_add (5 * 60 * 1000, (GSourceFunc)rb_njb_ping, source);
+
+	return G_OBJECT (source);
+}
+
+static void
+rb_njb_source_dispose (GObject *object)
+{
+	RBNjbSourcePrivate *priv = NJB_SOURCE_GET_PRIVATE (object);
+
+	if (priv->load_idle_id != 0) {
+		g_source_remove (priv->load_idle_id);
+		priv->load_idle_id = 0;
+	}
+
+	if (priv->ping_id != 0) {
+		g_source_remove (priv->ping_id);
+		priv->ping_id = 0;
+	}
+
+	/* purge the playlists */
+	g_hash_table_foreach_remove (priv->playlists, (GHRFunc)rb_true_function, NULL);
+
+	if (priv->device != NULL) {
+		g_object_set (object, "device", NULL, NULL);
+ 	}
+
+	G_OBJECT_CLASS (rb_njb_source_parent_class)->dispose (object);
+}
+
+static void
+rb_njb_source_finalize (GObject *object)
+{
+	RBNjbSourcePrivate *priv = NJB_SOURCE_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->playlists);
+
+	G_OBJECT_CLASS (rb_njb_source_parent_class)->finalize (object);
+}
+
+static void
+rb_njb_source_set_property (GObject *object,
+			    guint prop_id,
+			    const GValue *value,
+			    GParamSpec *pspec)
+{
+	RBNjbSourcePrivate *priv = NJB_SOURCE_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_DEVICE:
+		if (priv->device != NULL) {
+			NJB_Release (priv->device);
+			if (NJB_Release (priv->device) < 0) {
+				rb_debug ("capturing NJB device failed: %s", NJB_Error_Geterror (priv->device));
+			}
+			NJB_Close (priv->device);
+	 	}
+		priv->device = g_value_get_pointer (value);
+		if (priv->device) {
+			if (NJB_Open (priv->device) < 0) {
+				rb_debug ("opening NJB device failed");
+			} else  if (NJB_Capture (priv->device) < 0) {
+				rb_debug ("capturing NJB device failed: %s", NJB_Error_Geterror (priv->device));
+			}
+			rb_debug ("NJB device captured");
+		}
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_njb_source_get_property (GObject *object,
+			    guint prop_id,
+			    GValue *value,
+			    GParamSpec *pspec)
+{
+	RBNjbSourcePrivate *priv = NJB_SOURCE_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_DEVICE:
+		g_value_set_pointer (value, priv->device);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+RBRemovableMediaSource *
+rb_njb_source_new (RBShell *shell,
+                   njb_t *device)
+{
+	RBNjbSource *source;
+	RhythmDBEntryType entry_type;
+	RhythmDB *db;
+
+	g_object_get (shell, "db", &db, NULL);
+	entry_type =  rhythmdb_entry_register_type (db, NULL);
+	entry_type->save_to_disk = FALSE;
+	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
+	g_object_unref (db);
+
+	source = RB_NJB_SOURCE (g_object_new (RB_TYPE_NJB_SOURCE,
+					  "entry-type", entry_type,
+					  "shell", shell,
+					  "source-group", RB_SOURCE_GROUP_DEVICES,
+					  "device", device,
+					  NULL));
+
+	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
+
+	return RB_REMOVABLE_MEDIA_SOURCE (source);
+}
+
+static gboolean
+rb_njb_load_songs (RBNjbSource *source)
+{
+	RBNjbSourcePrivate *priv = NJB_SOURCE_GET_PRIVATE (source);
+	RBShell *shell;
+	RhythmDB *db;
+	RhythmDBEntryType entry_type;
+	njb_playlist_t *playlist;
+	njb_songid_t *track;
+
+	if (priv->device == NULL)
+		return FALSE;
+
+	g_object_get (source,
+		      "shell", &shell,
+		      "db", &db,
+		      "entry-type", &entry_type,
+		      NULL);
+
+	NJB_Reset_Get_Track_Tag (priv->device);
+	do {
+		RhythmDBEntry *entry;
+		njb_songid_frame_t *frame;
+		char *uri;
+
+		track = NJB_Get_Track_Tag (priv->device);
+
+		/* fixme: need URI handler for gstreamer */
+		uri = g_strdup_printf ("x-rb-njb://%d", track->trid);
+		entry = rhythmdb_entry_new (db, entry_type, uri);
+		g_free (uri);
+
+		NJB_Songid_Reset_Getframe (track);
+		do {
+			RhythmDBPropType prop = RHYTHMDB_PROP_TYPE;
+			GValue val = {0,};
+
+			frame = NJB_Songid_Getframe (track);
+
+			if (strcmp (frame->label, FR_SIZE)) {
+				prop = RHYTHMDB_PROP_FILE_SIZE;
+				g_value_init (&val, G_TYPE_UINT64);
+				g_value_set_uint64 (&val, frame->data.u_int64_val);
+			} if (strcmp (frame->label, FR_CODEC)) {
+				/* FIXME: todo */
+				/*NJB_CODEC_MP3
+				  NJB_CODEC_WMA
+				  NJB_CODEC_WAV
+				  NJB_CODEC_AA
+				 */
+			} if (strcmp (frame->label, FR_TITLE)) {
+				prop = RHYTHMDB_PROP_TITLE;
+				g_value_init (&val, G_TYPE_STRING);
+				g_value_set_string (&val, frame->data.strval);
+			} if (strcmp (frame->label, FR_ALBUM)) {
+				prop = RHYTHMDB_PROP_ALBUM;
+				g_value_init (&val, G_TYPE_STRING);
+				g_value_set_string (&val, frame->data.strval);
+			} if (strcmp (frame->label, FR_GENRE)) {
+				prop = RHYTHMDB_PROP_GENRE;
+				g_value_init (&val, G_TYPE_STRING);
+				g_value_set_string (&val, frame->data.strval);
+			} if (strcmp (frame->label, FR_ARTIST)) {
+				prop = RHYTHMDB_PROP_ARTIST;
+				g_value_init (&val, G_TYPE_STRING);
+				g_value_set_string (&val, frame->data.strval);
+			} if (strcmp (frame->label, FR_TRACK)) {
+				prop = RHYTHMDB_PROP_TRACK_NUMBER;
+				g_value_init (&val, G_TYPE_STRING);
+				g_value_set_string (&val, frame->data.strval);
+			} if (strcmp (frame->label, FR_FNAME)) {
+				/* ignore */
+			} if (strcmp (frame->label, FR_YEAR)) {
+				/* FIXME: todo */
+			} if (strcmp (frame->label, FR_PROTECTED)) {
+				/* ignore */
+			} if (strcmp (frame->label, FR_BITRATE)) {
+				prop = RHYTHMDB_PROP_BITRATE;
+				g_value_init (&val, G_TYPE_UINT);
+				g_value_set_uint (&val, frame->data.u_int32_val);
+			} if (strcmp (frame->label, FR_COMMENT)) {
+				/* ignore */
+			} if (strcmp (frame->label, FR_FOLDER)) {
+				/* ignore */
+			} else {
+				rb_debug ("unknown frame '%s' of type %d", frame->label, frame->type);
+			}
+
+			if (prop != RHYTHMDB_PROP_TYPE) {
+				rhythmdb_entry_set (db, entry, prop, &val);
+				g_value_unset (&val);
+			}
+		} while (frame != NULL);
+
+		rhythmdb_commit (db);
+	} while (track != NULL);
+
+	NJB_Reset_Get_Playlist (priv->device);
+	do {
+		RBSource *plsource;
+		njb_playlist_track_t *pltrack;
+
+		playlist = NJB_Get_Playlist (priv->device);
+		plsource = rb_static_playlist_source_new (shell, playlist->name, FALSE, entry_type);
+
+		NJB_Playlist_Reset_Gettrack(playlist);
+		do {
+			pltrack = NJB_Playlist_Gettrack (playlist);
+			/**/
+		} while (pltrack != NULL);
+
+		g_hash_table_insert (priv->playlists, playlist, plsource);
+		rb_shell_append_source (shell, plsource, RB_SOURCE (source));
+	} while (playlist != NULL);
+
+	g_object_unref (shell);
+	g_object_unref (db);
+	
+	return FALSE;
+}
+
+
+static gboolean
+rb_njb_ping (RBNjbSource *source)
+{
+	/* FIXME: ping the device, remove if it's gone */
+
+	return TRUE;
+}
+
+/*
+int     NJB_Get_Disk_Usage (njb_t *njb, u_int64_t *btotal, u_int64_t *bfree);
+char * 	NJB_Get_Owner_String (njb_t *njb);
+int 	NJB_Set_Owner_String (njb_t *njb, const char *name);
+int 	NJB_Get_Bitmap_Dimensions (njb_t *njb, int *x, int *y, int *bytes);
+int 	NJB_Set_Bitmap (njb_t *njb, const unsigned char *bitmap);
+njb_keyval_t * 	NJB_Get_Keys (njb_t *njb);
+u_int64_t 	NJB_Get_NJB1_Libcounter (njb_t *njb);
+int 	NJB_Send_Firmware (njb_t *njb, const char *path, NJB_Xfer_Callback *callback, void *data);
+int 	NJB_Get_Battery_Level (njb_t *njb);
+int 	NJB_Get_Battery_Charging (njb_t *njb);
+int 	NJB_Get_Auxpower (njb_t *njb);
+int 	NJB_Get_SDMI_ID (njb_t *njb, u_int8_t *sdmiid);
+const char * 	NJB_Get_Device_Name (njb_t *njb, int type);
+int 	NJB_Get_Firmware_Revision (njb_t *njb, u_int8_t *major, u_int8_t *minor, u_int8_t *release);
+int 	NJB_Get_Hardware_Revision (njb_t *njb, u_int8_t *major, u_int8_t *minor, u_int8_t *release);
+
+NJB_Playlist_Set_Name  	(   	njb_playlist_t *   	 pl,
+		const char *  	name
+	)
+	
+	int NJB_Update_Playlist  	(   	njb_t *   	 njb,
+		njb_playlist_t *  	pl
+	)  	
+	
+	void NJB_Playlist_Deltrack_TrackID  	(   	njb_playlist_t *   	 pl,
+		u_int32_t  	trackid
+	)  	
+	
+	void NJB_Playlist_Deltrack  	(   	njb_playlist_t *   	 pl,
+		unsigned int  	pos
+	)  
+	
+	void NJB_Playlist_Addtrack  	(   	njb_playlist_t *   	 pl,
+		njb_playlist_track_t *  	track,
+		unsigned int  	pos
+	)  	
+	
+	int NJB_Delete_Playlist  	(   	njb_t *   	 njb,
+		u_int32_t  	plid
+	) 
+*/
Index: plugins/njb/rb-njb-source.h
===================================================================
--- plugins/njb/rb-njb-source.h	(revision 0)
+++ plugins/njb/rb-njb-source.h	(revision 0)
@@ -0,0 +1,56 @@
+/*
+ *  arch-tag: Header for Njb source object
+ *
+ *  Copyright (C) 2006 James Livingston  <doclivingston@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_NJB_SOURCE_H
+#define __RB_NJB_SOURCE_H
+
+#include <libnjb.h>
+
+#include "rb-shell.h"
+#include "rb-removable-media-source.h"
+#include "rhythmdb.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_NJB_SOURCE         (rb_njb_source_get_type ())
+#define RB_NJB_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_NJB_SOURCE, RBNjbSource))
+#define RB_NJB_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_NJB_SOURCE, RBNjbSourceClass))
+#define RB_IS_NJB_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_NJB_SOURCE))
+#define RB_IS_NJB_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_NJB_SOURCE))
+#define RB_NJB_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_NJB_SOURCE, RBNjbSourceClass))
+
+typedef struct
+{
+	RBRemovableMediaSource parent;
+} RBNjbSource;
+
+typedef struct
+{
+	RBRemovableMediaSourceClass parent;
+} RBNjbSourceClass;
+
+RBRemovableMediaSource *	rb_njb_source_new		(RBShell *shell, njb_t *device);
+GType			rb_njb_source_get_type		(void);
+GType                   rb_njb_source_register_type    (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __RB_NJB_SOURCE_H */
