[rhythmbox] add libmediaplayerid



commit c439e1cd2f1b47de2ff860fe6334d1575173a751
Author: Jonathan Matthew <jonathan d14n org>
Date:   Tue Aug 4 22:59:45 2009 +1000

    add libmediaplayerid
    
    This library is responsible for retrieving media player device
    information.  It uses GUdev and a set of media player info files,
    or if built without GUdev, it can use HAL.
    
    libmediaplayerid may be split out into its own repository somewhere,
    depending on whether others find it useful.

 configure.ac                         |    3 +
 lib/Makefile.am                      |    2 +
 lib/libmediaplayerid/Makefile.am     |   44 ++++
 lib/libmediaplayerid/mediaplayerid.h |  104 +++++++++
 lib/libmediaplayerid/mpid-device.c   |  409 ++++++++++++++++++++++++++++++++++
 lib/libmediaplayerid/mpid-dummy.c    |   27 +++
 lib/libmediaplayerid/mpid-files.c    |   98 ++++++++
 lib/libmediaplayerid/mpid-hal.c      |  256 +++++++++++++++++++++
 lib/libmediaplayerid/mpid-private.h  |   42 ++++
 lib/libmediaplayerid/mpid-udev.c     |   78 +++++++
 lib/libmediaplayerid/mpid-util.c     |  257 +++++++++++++++++++++
 lib/libmediaplayerid/testmpid.c      |   52 +++++
 12 files changed, 1372 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e12970e..b353f42 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,10 +79,12 @@ PKG_CHECK_EXISTS(gtk+-2.0 >= 2.16, [
 AM_CONDITIONAL(USE_GTK_STATUS_ICON, test x"$use_gtk_status_icon" = xyes)
 
 
+dnl  note: gio-unix-2.0 is here for libmediaplayerid
 PKG_CHECK_MODULES(RHYTHMBOX,				\
 		  gtk+-2.0 >= $GTK_REQS			\
 		  glib-2.0 >= $GLIB_REQS		\
 		  gio-2.0 >= $GLIB_REQS			\
+		  gio-unix-2.0 >= $GLIB_REQS		\
 		  gnome-media-profiles >= $GNOME_MEDIA_PROFILES_REQS \
 		  libsoup-2.4 >= $LIBSOUP_REQS		\
 		  libsoup-gnome-2.4 >= $LIBSOUP_REQS	\
@@ -768,6 +770,7 @@ AC_OUTPUT([
 Makefile
 macros/Makefile
 lib/Makefile
+lib/libmediaplayerid/Makefile
 metadata/Makefile
 rhythmdb/Makefile
 widgets/Makefile
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 45bdeb1..18b85ae 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,4 +1,6 @@
 
+SUBDIRS = libmediaplayerid
+
 noinst_LTLIBRARIES = librb.la
 
 if MKDTEMP_MISSING
diff --git a/lib/libmediaplayerid/Makefile.am b/lib/libmediaplayerid/Makefile.am
new file mode 100644
index 0000000..da06717
--- /dev/null
+++ b/lib/libmediaplayerid/Makefile.am
@@ -0,0 +1,44 @@
+
+noinst_LTLIBRARIES = libmediaplayerid.la
+
+libmediaplayerid_la_SOURCES =		\
+	mediaplayerid.h			\
+	mpid-private.h			\
+	mpid-device.c			\
+	mpid-files.c			\
+	mpid-util.c
+
+INCLUDES =				\
+	-I$(top_srcdir)			\
+	$(RHYTHMBOX_CFLAGS)
+
+# use the GUdev/media-player-id implementation if possible,
+# otherwise HAL.
+
+if USE_GUDEV
+
+libmediaplayerid_la_SOURCES += mpid-udev.c
+EXTRA_DIST = mpid-hal.c mpid-dummy.c
+
+INCLUDES += $(GUDEV_CFLAGS)
+libmediaplayerid_la_LIBADD = $(GUDEV_LIBS)
+
+else
+
+if HAVE_HAL
+
+libmediaplayerid_la_SOURCES += mpid-hal.c
+EXTRA_DIST = mpid-udev.c mpid-dummy.c
+
+INCLUDES += $(HAL_CFLAGS)
+libmediaplayerid_la_LIBADD = $(HAL_LIBS)
+
+else
+
+libmediaplayerid_la_SOURCES += mpid-dummy.c
+EXTRA_DIST = mpid-udev.c mpid-hal.c
+
+endif #  HAVE_HAL
+
+endif #  HAVE_GUDEV
+
diff --git a/lib/libmediaplayerid/mediaplayerid.h b/lib/libmediaplayerid/mediaplayerid.h
new file mode 100644
index 0000000..53a21f7
--- /dev/null
+++ b/lib/libmediaplayerid/mediaplayerid.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifndef MEDIA_PLAYER_ID__H
+#define MEDIA_PLAYER_ID__H
+
+G_BEGIN_DECLS
+
+#define MPID_PROTOCOL_IPOD		"ipod"
+#define MPID_PROTOCOL_GENERIC		"storage"
+
+/* enum types */
+
+typedef enum {
+	MPID_ERROR_NONE,
+	MPID_ERROR_NO_DEVICE_PATH,			/* unable to find the device path */
+	MPID_ERROR_MECHANISM_FAILED,			/* mechanism (udev, hal) not available */
+	MPID_ERROR_NOT_MEDIA_PLAYER,			/* device is not a media player */
+	MPID_ERROR_DEVICE_INFO_MISSING			/* the device info file is missing */
+} MPIDError;
+
+typedef enum {
+	MPID_SOURCE_NONE,
+	MPID_SOURCE_SYSTEM,
+	MPID_SOURCE_OVERRIDE
+} MPIDSource;
+
+GType mpid_error_get_type (void);
+GType mpid_source_get_type (void);
+
+#define MPID_TYPE_ERROR (mpid_error_get_type ())
+#define MPID_TYPE_SOURCE (mpid_source_get_type ())
+
+
+/* device object */
+
+#define MPID_TYPE_DEVICE		(mpid_device_get_type ())
+#define MPID_DEVICE(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), MPID_TYPE_DEVICE, MPIDDevice))
+#define MPID_DEVICE_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), MPID_TYPE_DEVICE, MPIDDeviceClass))
+#define MPID_IS_DEVICE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), MPID_TYPE_DEVICE))
+#define MPID_IS_DEVICE_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), MPID_TYPE_DEVICE))
+#define MPID_DEVICE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), MPID_TYPE_DEVICE, MPIDDeviceClass))
+
+typedef struct _MPIDDevice MPIDDevice;
+typedef struct _MPIDDeviceClass MPIDDeviceClass;
+
+struct _MPIDDeviceClass
+{
+	GObjectClass parent_class;
+};
+
+struct _MPIDDevice
+{
+	GObject parent;
+
+	char *input_path;
+
+	MPIDError error;
+	MPIDSource source;
+
+	char *model;
+	char *vendor;
+	char *drive_type;
+	gboolean requires_eject;
+
+	char **access_protocols;
+
+	char **output_formats;
+	char **input_formats;
+	char **playlist_formats;
+
+	char *playlist_path;
+	char **audio_folders;
+	int folder_depth;
+};
+
+GType			mpid_device_get_type (void);
+
+void			mpid_enable_debug (gboolean debug);
+
+MPIDDevice *		mpid_device_new (const char *path);
+
+G_END_DECLS
+
+#endif /* MEDIA_PLAYER_ID__H */
diff --git a/lib/libmediaplayerid/mpid-device.c b/lib/libmediaplayerid/mpid-device.c
new file mode 100644
index 0000000..e6fa35c
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-device.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gunixmounts.h>
+
+#include "mediaplayerid.h"
+#include "mpid-private.h"
+
+
+enum
+{
+	PROP_0,
+	PROP_INPUT_PATH,
+	PROP_ERROR,
+	PROP_SOURCE,
+	PROP_MODEL,
+	PROP_VENDOR,
+	PROP_DRIVE_TYPE,
+	PROP_REQUIRES_EJECT,
+	PROP_ACCESS_PROTOCOLS,
+	PROP_OUTPUT_FORMATS,
+	PROP_INPUT_FORMATS,
+	PROP_PLAYLIST_FORMATS,
+	PROP_PLAYLIST_PATH,
+	PROP_AUDIO_FOLDERS,
+	PROP_FOLDER_DEPTH
+};
+
+static void	mpid_device_class_init (MPIDDeviceClass *klass);
+static void	mpid_device_init (MPIDDevice *config);
+
+G_DEFINE_TYPE (MPIDDevice, mpid_device, G_TYPE_OBJECT)
+
+
+void
+mpid_device_debug (MPIDDevice *device, const char *what)
+{
+	mpid_debug ("device information (%s)\n", what);
+	switch (device->source) {
+	case MPID_SOURCE_NONE:
+		mpid_debug ("no information source\n");
+		break;
+	case MPID_SOURCE_SYSTEM:
+		mpid_debug ("information read from system device database\n");
+		break;
+	case MPID_SOURCE_OVERRIDE:
+		mpid_debug ("information read from device override file\n");
+		break;
+	}
+	mpid_debug_str ("model", device->model);
+	mpid_debug_str ("vendor", device->vendor);
+	mpid_debug_str ("drive type", device->drive_type);
+	mpid_debug ("requires eject: %s\n", device->requires_eject ? "true" : "false");
+	mpid_debug_strv ("access protocols", device->access_protocols);
+	mpid_debug_strv ("output formats", device->output_formats);
+	mpid_debug_strv ("input formats", device->input_formats);
+	mpid_debug_strv ("playlist formats", device->playlist_formats);
+	mpid_debug_str ("playlist path", device->playlist_path);
+	mpid_debug_strv ("audio folders", device->audio_folders);
+	mpid_debug ("folder depth: %d\n", device->folder_depth);
+}
+
+char *
+mpid_device_get_mount_point (MPIDDevice *device)
+{
+	char *mount_path = NULL;
+	GUnixMountEntry *mount;
+	GList *mounts;
+	GList *i;
+
+	if (device->input_path == NULL) {
+		mpid_debug ("no input path specified, can't find mount point");
+		return NULL;
+	}
+
+	mount = g_unix_mount_at (device->input_path, NULL);
+	if (mount != NULL) {
+		/* path is the mount point */
+		g_unix_mount_free (mount);
+		mpid_debug ("%s is already a mount point\n", device->input_path);
+		return g_strdup (device->input_path);
+	}
+
+	mounts = g_unix_mounts_get (NULL);
+	for (i = mounts; i != NULL; i = i->next) {
+		mount = i->data;
+
+		if (g_str_equal (g_unix_mount_get_device_path (mount), device->input_path)) {
+			mount_path = g_strdup (g_unix_mount_get_mount_path (mount));
+			mpid_debug ("found mount point %s for device path %s\n", mount_path, device->input_path);
+		}
+		g_unix_mount_free (mount);
+	}
+	g_list_free (mounts);
+
+	if (mount_path == NULL) {
+		mpid_debug ("unable to find mount point for device path %s\n", device->input_path);
+	}
+
+	return mount_path;
+}
+
+char *
+mpid_device_get_device_path (MPIDDevice *device)
+{
+	GUnixMountEntry *mount;
+	char *mount_path;
+	char *device_path = NULL;
+	GList *mounts;
+	GList *i;
+
+	if (device->input_path == NULL) {
+		mpid_debug ("no input path specified, can't find device path\n");
+		return NULL;
+	}
+
+	mount_path = g_strdup (device->input_path);
+	if (mount_path[strlen (mount_path) - 1] == '/') {
+		mount_path[strlen (mount_path) - 1] = '\0';
+	}
+
+	mount = g_unix_mount_at (mount_path, NULL);
+	if (mount != NULL) {
+		device_path = g_strdup (g_unix_mount_get_device_path (mount));
+		g_unix_mount_free (mount);
+		mpid_debug ("found device path %s for mount %s\n", device_path, mount_path);
+		g_free (mount_path);
+		return device_path;
+	}
+	g_free (mount_path);
+
+	/* it's not a mount point, so check if it's the path to a mounted device */
+	mounts = g_unix_mounts_get (NULL);
+	for (i = mounts; i != NULL; i = i->next) {
+		mount = i->data;
+
+		if (g_str_equal (g_unix_mount_get_device_path (mount), mount_path)) {
+			device_path = g_strdup (mount_path);
+			mpid_debug ("%s is already a device path\n", device_path);
+		}
+		g_unix_mount_free (mount);
+	}
+	g_list_free (mounts);
+
+	if (device_path == NULL) {
+		mpid_debug ("unable to find device path for mount point %s\n", device->input_path);
+	}
+
+	return device_path;
+}
+
+
+
+static void
+mpid_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	MPIDDevice *device = MPID_DEVICE (object);
+
+	switch (prop_id) {
+	case PROP_INPUT_PATH:
+		device->input_path = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+mpid_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	MPIDDevice *device = MPID_DEVICE (object);
+
+	switch (prop_id) {
+	case PROP_INPUT_PATH:
+		g_value_set_string (value, device->input_path);
+		break;
+	case PROP_ERROR:
+		g_value_set_enum (value, device->error);
+		break;
+	case PROP_SOURCE:
+		g_value_set_enum (value, device->source);
+		break;
+	case PROP_MODEL:
+		g_value_set_string (value, device->model);
+		break;
+	case PROP_VENDOR:
+		g_value_set_string (value, device->vendor);
+		break;
+	case PROP_DRIVE_TYPE:
+		g_value_set_string (value, device->drive_type);
+		break;
+	case PROP_REQUIRES_EJECT:
+		g_value_set_boolean (value, device->requires_eject);
+		break;
+	case PROP_ACCESS_PROTOCOLS:
+		g_value_set_boxed (value, device->access_protocols);
+		break;
+	case PROP_OUTPUT_FORMATS:
+		g_value_set_boxed (value, device->output_formats);
+		break;
+	case PROP_INPUT_FORMATS:
+		g_value_set_boxed (value, device->input_formats);
+		break;
+	case PROP_PLAYLIST_FORMATS:
+		g_value_set_boxed (value, device->playlist_formats);
+		break;
+	case PROP_PLAYLIST_PATH:
+		g_value_set_string (value, device->playlist_path);
+		break;
+	case PROP_AUDIO_FOLDERS:
+		g_value_set_boxed (value, device->audio_folders);
+		break;
+	case PROP_FOLDER_DEPTH:
+		g_value_set_int (value, device->folder_depth);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+mpid_device_finalize (GObject *object)
+{
+	MPIDDevice *device = MPID_DEVICE (object);
+
+	g_free (device->model);
+	g_free (device->vendor);
+	g_free (device->drive_type);
+
+	g_strfreev (device->access_protocols);
+
+	g_strfreev (device->output_formats);
+	g_strfreev (device->input_formats);
+	g_strfreev (device->playlist_formats);
+
+	g_free (device->playlist_path);
+	g_strfreev (device->audio_folders);
+
+	G_OBJECT_CLASS (mpid_device_parent_class)->finalize (object);
+}
+
+static void
+mpid_device_init (MPIDDevice *device)
+{
+}
+
+static GObject *
+mpid_device_constructor (GType type, guint n_properties, GObjectConstructParam *properties)
+{
+	GObjectClass *parent_class = G_OBJECT_CLASS (mpid_device_parent_class);
+	MPIDDevice *device;
+
+	device = MPID_DEVICE (parent_class->constructor (type, n_properties, properties));
+
+	mpid_device_db_lookup (device);
+	if (device->source == MPID_SOURCE_SYSTEM) {
+		mpid_device_debug (device, "system database");
+	}
+
+	mpid_device_read_override_file (device);
+	if (device->source == MPID_SOURCE_OVERRIDE) {
+		mpid_device_debug (device, "override file");
+	}
+
+	return G_OBJECT (device);
+}
+
+static void
+mpid_device_class_init (MPIDDeviceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->constructor = mpid_device_constructor;
+	object_class->finalize = mpid_device_finalize;
+	object_class->get_property = mpid_device_get_property;
+	object_class->set_property = mpid_device_set_property;
+
+	/* install properties */
+	g_object_class_install_property (object_class,
+					 PROP_INPUT_PATH,
+					 g_param_spec_string ("input-path",
+							      "input path",
+							      "Input path (either a device path or a mount point)",
+							      NULL,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (object_class,
+					 PROP_ERROR,
+					 g_param_spec_enum ("error",
+						 	    "error",
+							    "error code",
+							    MPID_TYPE_ERROR,
+							    MPID_ERROR_NONE,
+							    G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_SOURCE,
+					 g_param_spec_enum ("source",
+						 	    "information source",
+							    "information source",
+							    MPID_TYPE_SOURCE,
+							    MPID_SOURCE_NONE,
+							    G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_MODEL,
+					 g_param_spec_string ("model",
+							      "device model",
+							      "device model name",
+							      NULL,
+							      G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_VENDOR,
+					 g_param_spec_string ("vendor",
+							      "device vendor",
+							      "device vendor name",
+							      NULL,
+							      G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_DRIVE_TYPE,
+					 g_param_spec_string ("drive-type",
+							      "drive type",
+							      "drive type",
+							      NULL,
+							      G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_REQUIRES_EJECT,
+					 g_param_spec_boolean ("requires-eject",
+							       "requires eject",
+							       "flag indicating whether the device requires ejection",
+							       FALSE,
+							       G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_ACCESS_PROTOCOLS,
+					 g_param_spec_boxed ("access-protocols",
+							     "access protocols",
+							     "names of protocols supported by the device",
+							     G_TYPE_STRV,
+							     G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_OUTPUT_FORMATS,
+					 g_param_spec_boxed ("output-formats",
+							     "output formats",
+							     "MIME types playable by the device",
+							     G_TYPE_STRV,
+							     G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_INPUT_FORMATS,
+					 g_param_spec_boxed ("input-formats",
+							     "input formats",
+							     "MIME types recorded by the device",
+							     G_TYPE_STRV,
+							     G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_PLAYLIST_FORMATS,
+					 g_param_spec_boxed ("playlist-formats",
+							     "playlist formats",
+							     "playlist MIME supported by the device",
+							     G_TYPE_STRV,
+							     G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_PLAYLIST_PATH,
+					 g_param_spec_string ("playlist-path",
+							      "playlist path",
+							      "playlist path",
+							      NULL,
+							      G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_AUDIO_FOLDERS,
+					 g_param_spec_boxed ("audio-folders",
+							     "audio folders",
+							     "names of folders in which audio files are stored on the device",
+							     G_TYPE_STRV,
+							     G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_FOLDER_DEPTH,
+					 g_param_spec_int ("folder-depth",
+						 	   "folder depth",
+							   "number of levels of folder nesting supported by the device",
+							   -1, G_MAXINT, -1,
+							   G_PARAM_READABLE));
+}
+
+MPIDDevice *
+mpid_device_new (const char *path)
+{
+	return g_object_new (MPID_TYPE_DEVICE, "input-path", path, NULL);
+}
+
+
diff --git a/lib/libmediaplayerid/mpid-dummy.c b/lib/libmediaplayerid/mpid-dummy.c
new file mode 100644
index 0000000..4ccdc18
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-dummy.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mediaplayerid.h"
+
+void
+mpid_device_db_lookup (MPIDDevice *device)
+{
+	/* nothing */
+}
+
diff --git a/lib/libmediaplayerid/mpid-files.c b/lib/libmediaplayerid/mpid-files.c
new file mode 100644
index 0000000..5b56ed9
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-files.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "mediaplayerid.h"
+#include "mpid-private.h"
+
+void
+mpid_read_device_file (MPIDDevice *device, const char *device_info_path)
+{
+	GError *error = NULL;
+	GKeyFile *keyfile;
+
+	keyfile = g_key_file_new ();
+	if (g_key_file_load_from_file (keyfile, device_info_path, G_KEY_FILE_NONE, &error) == FALSE) {
+		mpid_debug ("unable to read device info file %s: %s\n", device_info_path, error->message);
+		g_clear_error (&error);
+		device->error = MPID_ERROR_DEVICE_INFO_MISSING;
+		return;
+	}
+
+	mpid_override_strv_from_keyfile (&device->access_protocols, keyfile, "Device", "AccessProtocol");
+
+	mpid_override_strv_from_keyfile (&device->output_formats, keyfile, "Media", "OutputFormats");
+	mpid_override_strv_from_keyfile (&device->input_formats, keyfile, "Media", "InputFormats");
+
+	mpid_override_strv_from_keyfile (&device->playlist_formats, keyfile, "Playlist", "Formats");
+
+	mpid_override_strv_from_keyfile (&device->audio_folders, keyfile, "storage", "AudioFolders");
+
+	mpid_override_string_from_keyfile (&device->playlist_path, keyfile, "storage", "PlaylistPath");
+	mpid_override_string_from_keyfile (&device->drive_type, keyfile, "storage", "DriveType");
+
+	if (g_key_file_has_key (keyfile, "storage", "RequiresEject", NULL)) {
+		device->requires_eject = g_key_file_get_boolean (keyfile, "storage", "RequiresEject", NULL);
+	}
+
+	mpid_override_string_from_keyfile (&device->model, keyfile, "Device", "Model");
+	mpid_override_string_from_keyfile (&device->vendor, keyfile, "Vendor", "Model");
+
+	if (g_key_file_has_key (keyfile, "storage", "FolderDepth", NULL)) {
+		int val = g_key_file_get_integer (keyfile, "storage", "FolderDepth", &error);
+		if (error == NULL) {
+			device->folder_depth = val;
+		} else {
+			g_clear_error (&error);
+			device->folder_depth = -1;	/* hmm. */
+		}
+	}
+
+	g_key_file_free (keyfile);
+}
+
+void
+mpid_find_and_read_device_file (MPIDDevice *device, const char *device_file)
+{
+	const char * const *data_dirs;
+	int i;
+
+	data_dirs = g_get_system_data_dirs ();
+	for (i = 0; data_dirs[i] != NULL; i++) {
+		char *filename;
+		char *path;
+
+		filename = g_strdup_printf ("%s.mpi", device_file);
+		path = g_build_filename (data_dirs[i], "media-player-id", filename, NULL);
+		g_free (filename);
+		if (g_file_test (path, G_FILE_TEST_EXISTS)) {
+			device->source = MPID_SOURCE_SYSTEM;
+			mpid_read_device_file (device, path);
+			g_free (path);
+			return;
+		}
+	}
+
+	/* device info file is missing */
+	mpid_debug ("unable to find device info file %s\n", device_file);
+	device->error = MPID_ERROR_DEVICE_INFO_MISSING;
+}
+
+
diff --git a/lib/libmediaplayerid/mpid-hal.c b/lib/libmediaplayerid/mpid-hal.c
new file mode 100644
index 0000000..1964769
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-hal.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <dbus/dbus.h>
+#include <libhal.h>
+
+#include "mediaplayerid.h"
+#include "mpid-private.h"
+
+static void
+free_dbus_error (const char *what, DBusError *error)
+{
+	if (dbus_error_is_set (error)) {
+		mpid_debug ("%s: %s\n", what, error->message);
+		dbus_error_free (error);
+	}
+}
+
+static LibHalContext *
+create_hal_context ()
+{
+	LibHalContext *ctx = NULL;
+	DBusConnection *conn = NULL;
+	DBusError error;
+	gboolean result = FALSE;
+
+	dbus_error_init (&error);
+	ctx = libhal_ctx_new ();
+	if (ctx == NULL) {
+		mpid_debug ("unable to create hal context\n");
+		return NULL;
+	}
+
+	conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+	if (conn != NULL && !dbus_error_is_set (&error)) {
+		libhal_ctx_set_dbus_connection (ctx, conn);
+		if (libhal_ctx_init (ctx, &error))
+			result = TRUE;
+	}
+
+	if (dbus_error_is_set (&error)) {
+		free_dbus_error ("setting up hal context", &error);
+		result = FALSE;
+	}
+
+	if (!result) {
+		libhal_ctx_free (ctx);
+		ctx = NULL;
+	}
+	return ctx;
+}
+
+static void
+destroy_hal_context (LibHalContext *ctx)
+{
+	DBusError error;
+	if (ctx == NULL)
+		return;
+
+	dbus_error_init (&error);
+	libhal_ctx_shutdown (ctx, &error);
+	libhal_ctx_free (ctx);
+	free_dbus_error ("cleaning up hal context", &error);
+}
+
+static char *
+find_portable_audio_player_udi (LibHalContext *context, MPIDDevice *device, const char *device_path)
+{
+	char *udi;
+	char **udis;
+	int num_udis;
+	DBusError error;
+
+	udis = libhal_manager_find_device_string_match (context,
+							"block.device", device_path,
+							&num_udis, NULL);
+	if (udis == NULL || num_udis < 1) {
+		mpid_debug ("unable to find hal UDI for device %s", device_path);
+		device->error = MPID_ERROR_MECHANISM_FAILED;
+		libhal_free_string_array (udis);
+		destroy_hal_context (context);
+		return NULL;
+	}
+
+	udi = g_strdup (udis[0]);
+	libhal_free_string_array (udis);
+
+	/* walk up the device hierarchy until we find something with the portable_audio_player
+	 * capability.  if we don't find anything, give up.
+	 */
+	dbus_error_init (&error);
+	while (!libhal_device_query_capability (context, udi, "portable_audio_player", &error) && !dbus_error_is_set (&error)) {
+		char *new_udi;
+
+		new_udi = libhal_device_get_property_string (context, udi, "info.parent", &error);
+		if (dbus_error_is_set (&error))
+			break;
+
+		g_free (udi);
+		udi = NULL;
+
+		if (new_udi == NULL) {
+			break;
+		} else if (g_str_equal (new_udi, "/")) {
+			libhal_free_string (new_udi);
+			break;
+		}
+
+		udi = g_strdup (new_udi);
+		libhal_free_string (new_udi);
+	}
+	free_dbus_error ("finding portable_audio_player device", &error);
+
+	if (udi == NULL) {
+		mpid_debug ("unable to find portable_audio_player device in hal\n");
+		device->error = MPID_ERROR_NOT_MEDIA_PLAYER;
+	}
+	return udi;
+}
+
+static char **
+get_property_list (LibHalContext *context, const char *udi, const char *hal_property)
+{
+	DBusError error;
+	char **hal_proplist;
+	char **proplist = NULL;
+
+	dbus_error_init (&error);
+
+	hal_proplist = libhal_device_get_property_strlist (context, udi, hal_property, &error);
+	if (hal_proplist) {
+		if (!dbus_error_is_set (&error)) {
+			proplist = g_strdupv (hal_proplist);
+		}
+		libhal_free_string_array (hal_proplist);
+	}
+	free_dbus_error ("getting string list property", &error);
+	return proplist;
+}
+
+static char *
+get_property_string (LibHalContext *context, const char *udi, const char *hal_property)
+{
+	DBusError error;
+	char *hal_prop;
+	char *prop = NULL;
+
+	dbus_error_init (&error);
+
+	hal_prop = libhal_device_get_property_string (context, udi, hal_property, &error);
+	if (hal_prop) {
+		if (!dbus_error_is_set (&error)) {
+			prop = g_strdup (hal_prop);
+		}
+		libhal_free_string (hal_prop);
+	}
+	free_dbus_error ("getting string property", &error);
+	return prop;
+}
+
+static int
+get_property_int (LibHalContext *context, const char *udi, const char *hal_property)
+{
+	DBusError error;
+	int value = 0;
+
+	dbus_error_init (&error);
+
+	value = libhal_device_get_property_int (context, udi, hal_property, &error);
+	free_dbus_error ("getting int property", &error);
+	return value;
+}
+
+static gboolean
+get_property_boolean (LibHalContext *context, const char *udi, const char *hal_property)
+{
+	DBusError error;
+	dbus_bool_t hal_value;
+
+	dbus_error_init (&error);
+
+	hal_value = libhal_device_get_property_bool (context, udi, hal_property, &error);
+	free_dbus_error ("getting int property", &error);
+	return (hal_value != 0);
+}
+
+void
+mpid_device_db_lookup (MPIDDevice *device)
+{
+	LibHalContext *context;
+	char *devpath;
+	char *udi;
+
+	devpath = mpid_device_get_device_path (device);
+	if (devpath == NULL) {
+		device->error = MPID_ERROR_NO_DEVICE_PATH;
+		return;
+	}
+
+	context = create_hal_context ();
+	if (context != NULL) {
+		udi = find_portable_audio_player_udi (context, device, devpath);
+		if (udi != NULL) {
+			device->source = MPID_SOURCE_SYSTEM;
+			mpid_debug ("reading device info from hal udi %s", udi);
+
+			device->model = get_property_string (context, udi, "storage.model");
+			device->vendor = get_property_string (context, udi, "storage.vendor");
+			device->drive_type = get_property_string (context, udi, "storage.drive_type");
+			device->requires_eject = get_property_boolean (context, udi, "storage.requires_eject");
+
+			device->access_protocols = get_property_list (context, udi, "portable_audio_player.access_method.protocols");
+
+			device->output_formats = get_property_list (context, udi, "portable_audio_player.output_formats");
+			device->input_formats = get_property_list (context, udi, "portable_audio_player.input_formats");
+			device->playlist_formats = get_property_list (context, udi, "portable_audio_player.playlist_format");
+
+			/* need to try both string and strlist for playlist path */
+			device->playlist_path = get_property_string (context, udi, "portable_audio_player.playlist_path");
+			if (device->playlist_path == NULL) {
+				char **pp = get_property_list (context, udi, "portable_audio_player.playlist_path");
+				if (pp != NULL) {
+					device->playlist_path = g_strdup (pp[0]);
+					g_strfreev (pp);
+				}
+			}
+
+			device->audio_folders = get_property_list (context, udi, "portable_audio_player.audio_folders");
+			device->folder_depth = get_property_int (context, udi, "portable_audio_player.folder_depth");
+		} else {
+			device->error = MPID_ERROR_NOT_MEDIA_PLAYER;
+		}
+	} else {
+		device->error = MPID_ERROR_MECHANISM_FAILED;
+	}
+
+	destroy_hal_context (context);
+
+	g_free (devpath);
+}
diff --git a/lib/libmediaplayerid/mpid-private.h b/lib/libmediaplayerid/mpid-private.h
new file mode 100644
index 0000000..ce80c69
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-private.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MPID_PRIVATE_H
+#define __MPID_PRIVATE_H
+
+void		mpid_debug (const char *format, ...) G_GNUC_PRINTF (1, 2);
+void		mpid_debug_strv (const char *what, char **strv);
+void		mpid_debug_str (const char *what, const char *str);
+
+void		mpid_device_db_lookup (MPIDDevice *device);
+void		mpid_device_read_override_file (MPIDDevice *device);
+
+char *		mpid_device_get_mount_point (MPIDDevice *device);
+char *		mpid_device_get_device_path (MPIDDevice *device);
+
+void		mpid_override_string_from_keyfile (char **str, GKeyFile *keyfile, const char *group, const char *key);
+void		mpid_override_strv_from_keyfile (char ***strv, GKeyFile *keyfile, const char *group, const char *key);
+
+void		mpid_read_device_file (MPIDDevice *device, const char *device_info_path);
+void		mpid_find_and_read_device_file (MPIDDevice *device, const char *device_file);
+
+void		mpid_device_debug (MPIDDevice *device, const char *what);
+
+#endif /* __MPID_PRIVATE_H */
+
diff --git a/lib/libmediaplayerid/mpid-udev.c b/lib/libmediaplayerid/mpid-udev.c
new file mode 100644
index 0000000..c305108
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-udev.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mediaplayerid.h"
+#include "mpid-private.h"
+
+void
+mpid_device_db_lookup (MPIDDevice *device)
+{
+	GUdevClient *client;
+	GUdevDevice *udevice = NULL;
+	char *devpath;
+	const char *device_file;
+	char *subsystems[] = { "usb", NULL };
+
+	devpath = mpid_device_get_device_path (device);
+	if (devpath == NULL) {
+		device->error = MPID_ERROR_NO_DEVICE_PATH;
+		return;
+	}
+	
+	client = g_udev_client_new ((const char * const *)subsystems);
+	if (client != NULL) {
+		udevice = g_udev_client_query_by_device_file (client, devpath);
+		if (udevice != NULL) {
+
+			/* get vendor and model names */
+			device->model = g_strdup (g_udev_device_get_property (udevice, "ID_MODEL"));
+			device->vendor = g_strdup (g_udev_device_get_property (udevice, "ID_VENDOR"));
+
+			/* get media player information */
+			device_file = g_udev_device_get_property (udevice, "ID_MEDIA_PLAYER");
+			if (device_file != NULL) {
+				mpid_debug ("found ID_MEDIA_PLAYER tag %s for device %s\n", device_file, devpath);
+				mpid_find_and_read_device_file (device, device_file);
+			} else {
+				mpid_debug ("device %s has no ID_MEDIA_PLAYER tag in udev\n", devpath);
+				device->error = MPID_ERROR_NOT_MEDIA_PLAYER;
+			}
+		} else {
+			mpid_debug ("unable to find device %s in udev\n", devpath);
+			device->error = MPID_ERROR_MECHANISM_FAILED;
+		}
+	} else {
+		mpid_debug ("unable to create udev client\n");
+		device->error = MPID_ERROR_MECHANISM_FAILED;
+	}
+
+	g_free (devpath);
+	if (udevice != NULL) {
+		g_object_unref (udevice);
+	}
+	if (client != NULL) {
+		g_object_unref (client);
+	}
+}
+
diff --git a/lib/libmediaplayerid/mpid-util.c b/lib/libmediaplayerid/mpid-util.c
new file mode 100644
index 0000000..5486b85
--- /dev/null
+++ b/lib/libmediaplayerid/mpid-util.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib-object.h>
+
+#include "mediaplayerid.h"
+#include "mpid-private.h"
+
+static gboolean debug_enabled = FALSE;
+
+#define ENUM_ENTRY(name, nick) { name, "" #name "", nick }
+
+GType
+mpid_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			ENUM_ENTRY(MPID_ERROR_NONE, "OK"),
+			ENUM_ENTRY(MPID_ERROR_NO_DEVICE_PATH, "No such device"),
+			ENUM_ENTRY(MPID_ERROR_MECHANISM_FAILED, "Failed to access device database"),
+			ENUM_ENTRY(MPID_ERROR_NOT_MEDIA_PLAYER, "Device is not a media player"),
+			ENUM_ENTRY(MPID_ERROR_DEVICE_INFO_MISSING, "Device information is missing from database"),
+			{ 0, 0, 0 }
+		};
+
+		etype = g_enum_register_static ("MPIDErrorType", values);
+	}
+
+	return etype;
+}
+
+GType
+mpid_source_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			ENUM_ENTRY(MPID_SOURCE_NONE, "No device information"),
+			ENUM_ENTRY(MPID_SOURCE_SYSTEM, "Device information from system database"),
+			ENUM_ENTRY(MPID_SOURCE_OVERRIDE, "Device information from override file"),
+			{ 0, 0, 0 }
+		};
+
+		etype = g_enum_register_static ("MPIDSourceType", values);
+	}
+
+	return etype;
+}
+
+void
+mpid_enable_debug (gboolean debug)
+{
+	debug_enabled = debug;
+}
+
+void
+mpid_debug (const char *format, ...)
+{
+	va_list args;
+	va_start (args, format);
+	if (debug_enabled)
+		g_vprintf (format, args);
+	va_end (args);
+}
+
+void
+mpid_debug_strv (const char *what, char **strv)
+{
+	int i;
+	if (strv != NULL) {
+		mpid_debug ("%s:\n", what);
+		for (i = 0; strv[i] != NULL; i++) {
+			mpid_debug ("\t%s\n", strv[i]);
+		}
+	} else {
+		mpid_debug ("%s: (none)\n", what);
+	}
+}
+
+void
+mpid_debug_str (const char *what, const char *str)
+{
+	if (str != NULL) {
+		mpid_debug ("%s: %s\n", what, str);
+	} else {
+		mpid_debug ("%s: (none)\n", what);
+	}
+}
+
+static GKeyFile *
+read_fake_keyfile (const char *path)
+{
+	const char *fake_group = "[mpid-data]\n";
+	char *data;
+	char *munged;
+	gsize data_size;
+	gsize munged_data_size;
+	GKeyFile *keyfile;
+	GError *error = NULL;
+
+	if (g_file_get_contents (path, &data, &data_size, &error) == FALSE) {
+		mpid_debug ("unable to read contents of file %s: %s\n", path, error->message);
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	/* prepend a group name to the file contents */
+	munged_data_size = data_size + strlen (fake_group);
+	munged = g_malloc0 (munged_data_size + 1);
+	strcpy (munged, fake_group);
+	memcpy (munged + strlen (fake_group), data, data_size);
+
+	keyfile = g_key_file_new ();
+	if (g_key_file_load_from_data (keyfile, munged, munged_data_size, G_KEY_FILE_NONE, &error) == FALSE) {
+		mpid_debug ("unable to parse contents of file %s: %s\n", path, error->message);
+		g_key_file_free (keyfile);
+		keyfile = NULL;
+
+		/* probably do something with this error too */
+		g_clear_error (&error);
+	}
+
+	g_free (munged);
+	return keyfile;
+}
+
+void
+mpid_override_string_from_keyfile (char **str, GKeyFile *keyfile, const char *group, const char *key)
+{
+	char *v;
+	v = g_key_file_get_string (keyfile, group, key, NULL);
+	if (v != NULL) {
+		g_free (*str);
+		*str = v;
+	}
+}
+
+void
+mpid_override_strv_from_keyfile (char ***strv, GKeyFile *keyfile, const char *group, const char *key)
+{
+	char **v;
+	v = g_key_file_get_string_list (keyfile, group, key, NULL, NULL);
+	if (v != NULL) {
+		g_strfreev (*strv);
+		*strv = v;
+	}
+}
+
+void
+mpid_device_read_override_file (MPIDDevice *device)
+{
+	GKeyFile *keyfile;
+	GError *error = NULL;
+	char *mountpoint;
+	char *override_path;
+	char *start_group;
+	char *str;
+	int val;
+
+	mountpoint = mpid_device_get_mount_point (device);
+	if (mountpoint == NULL) {
+		/* maybe set an error if not already set? */
+		return;
+	}
+
+	override_path = g_build_filename (mountpoint, ".audio_player.mpi", NULL);
+	if (g_file_test (override_path, G_FILE_TEST_EXISTS)) {
+		mpid_debug ("found override file %s on mount %s\n", override_path, mountpoint);
+
+		device->error = MPID_ERROR_NONE;
+		mpid_read_device_file (device, override_path);
+		device->source = MPID_SOURCE_OVERRIDE;
+		g_free (override_path);
+		g_free (mountpoint);
+		return;
+	}
+
+	override_path = g_build_filename (mountpoint, ".is_audio_player", NULL);
+	if (g_file_test (override_path, G_FILE_TEST_EXISTS) == FALSE) {
+		mpid_debug ("override file %s not found on mount %s\n", override_path, mountpoint);
+		g_free (override_path);
+		g_free (mountpoint);
+		return;
+	}
+
+	keyfile = read_fake_keyfile (override_path);
+	g_free (override_path);
+	g_free (mountpoint);
+
+	if (keyfile == NULL) {
+		/* maybe set an error? */
+		return;
+	}
+
+	/* forget any previous error */
+	device->error = MPID_ERROR_NONE;
+	device->source = MPID_SOURCE_OVERRIDE;
+
+	/* ensure we at least have 'storage' protocol and mp3 output.
+	 * for mp3-only devices with no playlists, an empty override file should suffice.
+	 */
+	if (device->access_protocols == NULL) {
+		char *p[] = { MPID_PROTOCOL_GENERIC, NULL };
+		device->access_protocols = g_strdupv (p);
+	}
+
+	if (device->output_formats == NULL) {
+		char *f[] = { "audio/mpeg", NULL };
+		device->output_formats = g_strdupv (f);
+	}
+
+	/* now apply information from the override file */
+	start_group = g_key_file_get_start_group (keyfile);
+	g_key_file_set_list_separator (keyfile, ',');
+
+	mpid_override_strv_from_keyfile (&device->output_formats, keyfile, start_group, "output_formats");
+	mpid_override_strv_from_keyfile (&device->input_formats, keyfile, start_group, "input_formats");
+	mpid_override_strv_from_keyfile (&device->audio_folders, keyfile, start_group, "audio_folders");
+
+	str = g_key_file_get_string (keyfile, start_group, "playlist_path", NULL);
+	if (str != NULL) {
+		g_free (device->playlist_path);
+		device->playlist_path = str;
+	}
+
+	val = g_key_file_get_integer (keyfile, start_group, "folder_depth", &error);
+	if (error == NULL) {
+		device->folder_depth = val;
+	} else {
+		g_clear_error (&error);
+	}
+
+	g_key_file_free (keyfile);
+}
+
diff --git a/lib/libmediaplayerid/testmpid.c b/lib/libmediaplayerid/testmpid.c
new file mode 100644
index 0000000..7471523
--- /dev/null
+++ b/lib/libmediaplayerid/testmpid.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Jonathan Matthew  <jonathan d14n org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mediaplayerid.h"
+
+int
+main (int argc, char **argv)
+{
+	MPIDDevice *device;
+
+	g_type_init ();
+
+	mpid_enable_debug (TRUE);
+	device = mpid_device_new (argv[1]);
+
+	switch (device->error) {
+	case MPID_ERROR_NONE:
+		break;
+	case MPID_ERROR_NO_DEVICE_PATH:
+		g_print ("unable to get device path\n");
+		break;
+	case MPID_ERROR_MECHANISM_FAILED:
+		g_print ("device database mechanism failed\n");
+		break;
+	case MPID_ERROR_NOT_MEDIA_PLAYER:
+		g_print ("device is not a media player\n");
+		break;
+	case MPID_ERROR_DEVICE_INFO_MISSING:
+		g_print ("device info is missing from database\n");
+		break;
+	}
+
+	g_object_unref (device);
+	return 0;
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]