Blob Blame History Raw
/* Copyright (c) 2007, 2010 Christophe Fergeau  <teuf@gnome.org>
 * Part of the libgpod project.
 * 
 * URL: http://www.gtkpod.org/
 * URL: http://gtkpod.sourceforge.net/
 *
 * The code contained in this file 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.1 of the License, or (at your option) any later version.
 *
 * This file 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 code; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * iTunes and iPod are trademarks of Apple
 *
 * This product is not supported/written/published by Apple!
 *
 */
#include "config.h"
#include "backends.h"

#include <libhal.h>
#include <itdb_device.h>
#include <glib-object.h>
#include <string.h>

#define LIBGPOD_HAL_NS "org.libgpod."

struct _HalBackend {
	ItdbBackend parent;
	LibHalContext *ctx;
	char *udi;
};
typedef struct _HalBackend HalBackend;


static void hal_backend_destroy (ItdbBackend *itdb_backend)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
	g_free (backend->udi);
	libhal_ctx_free(backend->ctx);
	g_free (backend);
}

static gboolean
hal_backend_set_version (ItdbBackend *itdb_backend, unsigned int version)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
        libhal_device_set_property_int (backend->ctx, backend->udi, 
			                LIBGPOD_HAL_NS"version", 1, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_is_unknown (ItdbBackend *itdb_backend, gboolean unknown)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
	libhal_device_set_property_bool (backend->ctx, backend->udi,
					 LIBGPOD_HAL_NS"ipod.is_unknown", 
					 TRUE, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_icon_name (ItdbBackend *itdb_backend, const char *icon_name)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
	libhal_device_set_property_string (backend->ctx, backend->udi,
					   "info.desktop.icon",
					   icon_name, NULL);

	return TRUE;
}

static gboolean
hal_backend_set_firewire_id (ItdbBackend *itdb_backend, const char *fwid)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
     	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.firewire_id",
					   fwid, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_serial_number (ItdbBackend *itdb_backend, const char *serial_number)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.serial_number",
					   serial_number,
					   NULL);
	return TRUE;
}

static gboolean hal_backend_set_firmware_version (ItdbBackend *itdb_backend,
						  const char *firmware_version)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.firmware_version",
					   firmware_version,
					   NULL);
	return TRUE;
}

static gboolean
hal_backend_set_model_name (ItdbBackend *itdb_backend, const char *model_name)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.model.device_class",
					   model_name,
					   NULL);
	return TRUE;
}

static gboolean
hal_backend_set_generation (ItdbBackend *itdb_backend, gdouble generation)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_double (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.model.generation",
					   generation,
					   NULL);
	return TRUE;
}

static gboolean
hal_backend_set_color (ItdbBackend *itdb_backend, const char *color_name)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.model.shell_color",
					   color_name,
					   NULL);
	return TRUE;
}

static gboolean
hal_backend_set_factory_id (ItdbBackend *itdb_backend,
			    const char *factory_id)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.production.factory_id",
					   factory_id,
					   NULL);
	return TRUE;
}

static gboolean
hal_backend_set_production_year (ItdbBackend *itdb_backend, guint year)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_int (backend->ctx, backend->udi, 
					LIBGPOD_HAL_NS"ipod.production.year",
					year, NULL);
	return TRUE;
}

static gboolean 
hal_backend_set_production_week (ItdbBackend *itdb_backend, guint week)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_int (backend->ctx, backend->udi, 
					LIBGPOD_HAL_NS"ipod.production.week",
					week, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_production_index (ItdbBackend *itdb_backend, guint index)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_int (backend->ctx, backend->udi, 
					LIBGPOD_HAL_NS"ipod.production.number",
					index, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_control_path (ItdbBackend *itdb_backend, const char *control_path)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   LIBGPOD_HAL_NS"ipod.model.control_path",
					   control_path, NULL);
	return TRUE;
}

static gboolean
hal_backend_set_name (ItdbBackend *itdb_backend, const char *name)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	libhal_device_set_property_string (backend->ctx, backend->udi,
					   "info.desktop.name",
					   name, NULL);
	return TRUE;
}

static char *
get_format_string (const Itdb_ArtworkFormat *format, enum ArtworkType type)
{
	const char *format_name;
	const char *artwork_type;

	g_return_val_if_fail (format != NULL, NULL);
	switch (format->format) {
            case THUMB_FORMAT_UYVY_BE:
		    format_name = "iyuv";
		    break;
            case THUMB_FORMAT_RGB565_BE:
		    format_name = "rgb565_be";
		    break;		 
	    case THUMB_FORMAT_RGB565_LE:
		    format_name = "rgb565";
		    break;
	    case THUMB_FORMAT_I420_LE:
		    format_name = "iyuv420";
		    break;
	    default:
		    g_return_val_if_reached (NULL);
	}

	switch (type) {
            case UNKNOWN:
		    artwork_type = "unknown";
		    break;
            case PHOTO:
	            artwork_type = "photo";
		    break;
	    case ALBUM:
		    artwork_type = "album";
		    break;
	    case CHAPTER:
		    artwork_type = "chapter";
		    break;
	    default:
		    g_return_val_if_reached (NULL);
	}

	return g_strdup_printf ("corr_id=%u,width=%u,height=%u,rotation=%u,pixel_format=%s,image_type=%s",
  		                format->format_id, 
				format->width, format->height, 
			        format->rotation, format_name, artwork_type);
}

static gboolean hal_backend_set_artwork_type_supported (ItdbBackend *itdb_backend,
							enum ArtworkType type,
							gboolean supported)
{
	HalBackend *backend = (HalBackend *)itdb_backend;
    	char *propname;
	switch (type) {
	    case ALBUM:
		propname = LIBGPOD_HAL_NS"ipod.images.album_art_supported";
		break;
	    case PHOTO:
		propname = LIBGPOD_HAL_NS"ipod.images.photos_supported";
		break;
	    case CHAPTER:
		propname = LIBGPOD_HAL_NS"ipod.images.chapter_images_supported";
		break;
	    default:
		g_return_val_if_reached (FALSE);
	}
        libhal_device_set_property_bool (backend->ctx, backend->udi,
                                         propname, supported, NULL);
	return TRUE;
}

static gboolean hal_backend_set_artwork_formats (ItdbBackend *itdb_backend,
						 enum ArtworkType type,
						 const GList *formats)
{
	HalBackend *backend = (HalBackend *)itdb_backend;

	const GList *it;
	hal_backend_set_artwork_type_supported (itdb_backend, type,
					       	(formats != NULL));

        for (it = formats; it != NULL; it = it->next) {
                char *format_str;

                format_str = get_format_string (it->data, type);
                libhal_device_property_strlist_append (backend->ctx, backend->udi,
                                                       LIBGPOD_HAL_NS"ipod.images.formats",
                                                       format_str, 
                                                       NULL);
                g_free (format_str);
        }

	return TRUE;
}

/* taken from libipoddevice proper */
static ItdbBackend *hal_backend_new (void) 
{
	LibHalContext *hal_context;
	HalBackend *backend;
	const char *udi;
	DBusError error;
	DBusConnection *dbus_connection;

        udi = g_getenv ("UDI");
	if (udi == NULL) {
	    	return NULL;
	}

	hal_context = libhal_ctx_new();
	if(hal_context == NULL) {
		return NULL;
	}

	dbus_error_init(&error);
	dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	if (dbus_error_is_set(&error)) {
		dbus_error_free(&error);
		libhal_ctx_free(hal_context);
		return NULL;
	}

	libhal_ctx_set_dbus_connection(hal_context, dbus_connection);

	if(!libhal_ctx_init(hal_context, &error)) {
		if (dbus_error_is_set(&error)) {
			dbus_error_free(&error);
		}
		libhal_ctx_free(hal_context);
		return NULL;
	}

	backend = g_new0 (HalBackend, 1);
	backend->ctx = hal_context;
	backend->udi = g_strdup (udi);

	backend->parent.destroy = hal_backend_destroy;
	backend->parent.set_version = hal_backend_set_version;
	backend->parent.set_is_unknown = hal_backend_set_is_unknown;
	backend->parent.set_icon_name = hal_backend_set_icon_name;
	backend->parent.set_firewire_id = hal_backend_set_firewire_id;
	backend->parent.set_serial_number = hal_backend_set_serial_number;
	backend->parent.set_firmware_version = hal_backend_set_firmware_version;
	backend->parent.set_model_name = hal_backend_set_model_name;
	backend->parent.set_generation = hal_backend_set_generation;
	backend->parent.set_color = hal_backend_set_color;
	backend->parent.set_factory_id = hal_backend_set_factory_id;
	backend->parent.set_production_year = hal_backend_set_production_year;
	backend->parent.set_production_week = hal_backend_set_production_week;
	backend->parent.set_production_index = hal_backend_set_production_index;
	backend->parent.set_control_path = hal_backend_set_control_path;
	backend->parent.set_name = hal_backend_set_name;
	backend->parent.set_artwork_formats = hal_backend_set_artwork_formats;

	return (ItdbBackend *)backend;
}

#ifdef HAVE_LIBUSB
static gboolean hal_get_ipod_usb_position (LibHalContext *ctx, const char *udi,
                                           int *usb_bus_number, int *usb_device_number)
{
	char *parent_udi;
	char *subsystem;
	gboolean found_ids;
	DBusError error;


	parent_udi = NULL;
	subsystem = NULL;
	found_ids = FALSE;
	dbus_error_init (&error);
	while (TRUE) {
		parent_udi = libhal_device_get_property_string (ctx, udi,
				"info.parent", &error);
		if (parent_udi == NULL || dbus_error_is_set (&error))
			goto end;
		udi = parent_udi;
		subsystem = libhal_device_get_property_string (ctx, udi,
							       "linux.subsystem",
							       &error);
		if (subsystem == NULL || dbus_error_is_set (&error)) {
			dbus_error_free (&error);
			dbus_error_init (&error);
			continue;
		}
		if (strcmp (subsystem, "usb") == 0) {
			*usb_bus_number = libhal_device_get_property_int (ctx, udi,
									  "usb.bus_number", &error);
			if (dbus_error_is_set (&error)) {
				goto end;
			}
			*usb_device_number = libhal_device_get_property_int (ctx, udi,
									     "usb.linux.device_number", &error);
			if (dbus_error_is_set (&error)) {
				goto end;
			}
			found_ids = TRUE;
			goto end;
		}
	}
end:
	libhal_free_string (parent_udi);
	libhal_free_string (subsystem);
	if (dbus_error_is_set (&error)) {
	    g_print ("Error: %s\n", error.message);
	    dbus_error_free (&error);
	}

	return found_ids;
}
#endif

int main (int argc, char **argv)
{
	ItdbBackend *backend;
	int result;
	const char *dev;
	const char *fstype;
        gint usb_bus_number = 0;
        gint usb_device_number = 0;
        HalBackend *hal_backend;

	g_type_init ();

	backend = hal_backend_new ();
        if (backend == NULL) {
                return -1;
        }

	dev = g_getenv ("HAL_PROP_BLOCK_DEVICE");
	if (dev == NULL) {
		return -1;
	}

        fstype = g_getenv ("HAL_PROP_VOLUME_FSTYPE");
        if (fstype == NULL) {
                return -1;
        }

        hal_backend = (HalBackend *)backend;
#ifdef HAVE_LIBUSB
        hal_get_ipod_usb_position (hal_backend->ctx, hal_backend->udi,
                                   &usb_bus_number, &usb_device_number);
#endif

	result = itdb_callout_set_ipod_properties (backend, dev,
                                                   usb_bus_number,
                                                   usb_device_number,
                                                   fstype);
	backend->destroy (backend);

	return result;
}