/* | Copyright (C) 2007 Jorg Schuler | Part of the gtkpod project. | | URL: http://gtkpod.sourceforge.net/ | URL: http://www.gtkpod.org | | 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., 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! | | $Id: autodetection.c 1565 2007-06-20 04:46:34Z tmzullinger $ */ #include "autodetection.h" #include "config.h" #include "misc.h" #include "prefs.h" #include #include #ifdef HAVE_GNOME_VFS #include #endif #ifdef HAVE_HAL #include #include #endif #undef DEBUG_AUTO #ifdef DEBUG_AUTO # define _TO_STR(x) #x # define TO_STR(x) _TO_STR(x) # define debug(...) do { fprintf(stderr, __FILE__ ":" TO_STR(__LINE__) ":" __VA_ARGS__); } while(0) #else # define debug(...) #endif /* Find out if an itdb uses the mountpoint @mountpoint and return that itdb */ static iTunesDB *ad_find_repository_with_mountpoint (const gchar *mountpoint) { GList *gl; gchar *mp; gint lenmp; iTunesDB *result = NULL; struct itdbs_head *itdbs; g_return_val_if_fail (mountpoint, NULL); itdbs = gp_get_itdbs_head (gtkpod_window); g_return_val_if_fail (itdbs, NULL); /* eliminate trailing dir separators ('/') */ mp = g_strdup (mountpoint); lenmp = strlen (mountpoint); if ((lenmp > 0) && (mp[lenmp-1] == G_DIR_SEPARATOR)) { mp[lenmp-1] = 0; } for (gl=itdbs->itdbs; gl; gl=gl->next) { iTunesDB *itdb = gl->data; g_return_val_if_fail (itdb, NULL); if (itdb->usertype & GP_ITDB_TYPE_IPOD) { gchar *imp = get_itdb_prefs_string (itdb, KEY_MOUNTPOINT); if (imp) { gint comp; gint lenimp = strlen (imp); /* eliminate trailing dir separators ('/') */ if ((lenimp > 0) && (imp[lenimp-1] == G_DIR_SEPARATOR)) { imp[lenmp-1] = 0; } comp = strcmp (mp, imp); g_free (imp); if (comp == 0) { result = itdb; break; } } } } g_free (mp); return result; } #ifdef HAVE_GNOME_VFS typedef struct _AutoDetect AutoDetect; static gboolean ad_timeout_cb (gpointer data); struct _AutoDetect { GMutex *mutex; /* shared lock */ GList *new_ipod_uris; /* list of new mounts */ guint timeout_id; }; static AutoDetect *autodetect; #ifdef HAVE_HAL /* from rb-ipod-source.c (rhythmbox ipod plugin) */ static gboolean hal_udi_is_ipod (const char *udi) { LibHalContext *ctx; DBusConnection *conn; char *parent_udi; char *parent_name; gboolean result; DBusError error; gboolean inited = FALSE; result = FALSE; dbus_error_init (&error); conn = NULL; parent_udi = NULL; parent_name = NULL; ctx = libhal_ctx_new (); if (ctx == NULL) { /* FIXME: should we return an error somehow so that we can * fall back to a check for iTunesDB presence instead ? */ debug ("cannot connect to HAL"); goto end; } conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error); if (conn == NULL || dbus_error_is_set (&error)) goto end; libhal_ctx_set_dbus_connection (ctx, conn); if (!libhal_ctx_init (ctx, &error) || dbus_error_is_set (&error)) goto end; inited = TRUE; parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", &error); if (parent_udi == NULL || dbus_error_is_set (&error)) goto end; parent_name = libhal_device_get_property_string (ctx, parent_udi, "storage.model", &error); if (parent_name == NULL || dbus_error_is_set (&error)) goto end; if (strcmp (parent_name, "iPod") == 0) result = TRUE; end: g_free (parent_udi); g_free (parent_name); if (dbus_error_is_set (&error)) { debug ("Error: %s\n", error.message); dbus_error_free (&error); dbus_error_init (&error); } if (ctx) { if (inited) libhal_ctx_shutdown (ctx, &error); libhal_ctx_free(ctx); } dbus_error_free (&error); return result; } #endif /* adapted from rb-ipod-source.c (rhythmbox ipod plugin) */ static gchar *ad_get_itunes_dir (GnomeVFSVolume *volume) { gchar *mount_point_uri; gchar *result = NULL; mount_point_uri = gnome_vfs_volume_get_activation_uri (volume); if (mount_point_uri) { gchar *mount_point; mount_point = g_filename_from_uri (mount_point_uri, NULL, NULL); if (mount_point) { result = itdb_get_itunes_dir (mount_point); g_free (mount_point); } g_free (mount_point_uri); } return result; } /* adapted from rb-ipod-source.c (rhythmbox ipod plugin) */ static gboolean ad_volume_has_ipod_dir (GnomeVFSVolume *volume) { gchar *itunes_dir; gboolean result = FALSE; itunes_dir = ad_get_itunes_dir (volume); if (itunes_dir) { result = g_file_test (itunes_dir, G_FILE_TEST_EXISTS); } g_free (itunes_dir); return result; } /* adapted from rb-ipod-source.c (rhythmbox ipod plugin) */ static gboolean ad_volume_is_ipod (GnomeVFSVolume *volume) { #ifdef HAVE_HAL gchar *udi; #endif if (gnome_vfs_volume_get_volume_type (volume) != GNOME_VFS_VOLUME_TYPE_MOUNTPOINT) { return FALSE; } #ifdef HAVE_HAL udi = gnome_vfs_volume_get_hal_udi (volume); if (udi != NULL) { gboolean result; result = hal_udi_is_ipod (udi); g_free (udi); if (result == FALSE) { return FALSE; } } #endif return ad_volume_has_ipod_dir (volume); } static void ad_volume_mounted_cb (GnomeVFSVolumeMonitor *vfsvolumemonitor, GnomeVFSVolume *volume, AutoDetect *ad) { g_return_if_fail (volume && ad); if (ad_volume_is_ipod (volume)) { gchar *uri; uri = gnome_vfs_volume_get_activation_uri (volume); debug ("mounted iPod: '%s'\n", uri); g_mutex_lock (ad->mutex); ad->new_ipod_uris = g_list_prepend (ad->new_ipod_uris, uri); g_mutex_unlock (ad->mutex); } } void autodetection_init () { if (autodetect == NULL) { GList *volumes, *gl; if (!gnome_vfs_init ()) { gtkpod_warning (_("Could not initialize GnomeVFS\n")); g_return_if_reached (); } autodetect = g_new0 (AutoDetect, 1); autodetect->mutex = g_mutex_new (); /* Check if an iPod is already mounted and add it to the list */ volumes = gnome_vfs_volume_monitor_get_mounted_volumes ( gnome_vfs_get_volume_monitor ()); for (gl=volumes; gl; gl=gl->next) { GnomeVFSVolume *volume = gl->data; g_return_if_fail (volume); ad_volume_mounted_cb (NULL, volume, autodetect); gnome_vfs_volume_unref (volume); } g_list_free (volumes); g_signal_connect (G_OBJECT (gnome_vfs_get_volume_monitor ()), "volume-mounted", G_CALLBACK (ad_volume_mounted_cb), autodetect); /* start timeout function for the monitor */ autodetect->timeout_id = g_timeout_add (100, /* every 100 ms */ ad_timeout_cb, autodetect); } } static gboolean ad_timeout_cb (gpointer data) { AutoDetect *ad = data; g_return_val_if_fail (ad, FALSE); /* Don't interfere with a blocked display -- try again later */ if (!widgets_blocked) { gdk_threads_enter (); g_mutex_lock (ad->mutex); while (ad->new_ipod_uris) { iTunesDB *itdb, *loaded_itdb = NULL; gchar *mountpoint; struct itdbs_head *itdbs; GList *gl = ad->new_ipod_uris; gchar *mount_uri = gl->data; ad->new_ipod_uris = g_list_delete_link (ad->new_ipod_uris, gl); g_mutex_unlock (ad->mutex); g_return_val_if_fail (mount_uri, (gdk_threads_leave(), release_widgets(), TRUE)); mountpoint = g_filename_from_uri (mount_uri, NULL, NULL); g_free (mount_uri); debug ("Mounted iPod at '%s'\n", mountpoint); itdb = ad_find_repository_with_mountpoint (mountpoint); itdbs = gp_get_itdbs_head (gtkpod_window); g_return_val_if_fail (itdbs, (gdk_threads_leave(), release_widgets(), TRUE)); block_widgets (); if (itdb) { ExtraiTunesDBData *eitdb = itdb->userdata; g_return_val_if_fail (eitdb,(gdk_threads_leave(), release_widgets(), TRUE)); debug ("...used by itdb %p\n", itdb); if (!eitdb->itdb_imported) { loaded_itdb = gp_load_ipod (itdb); loaded_itdb->usertype |= GP_ITDB_TYPE_AUTOMATIC; set_itdb_prefs_int (loaded_itdb, "type", loaded_itdb->usertype); } else { gtkpod_warning (_("Newly mounted iPod at '%s' appearss to be already loaded!\n\n")); } debug ("...OK (used)\n"); } else { /* Set up new itdb (which we'll add to the end of the list) */ iTunesDB *new_itdb; gint index = g_list_length (itdbs->itdbs); debug ("...not used by any itdb.\n"); set_itdb_index_prefs_string (index, KEY_MOUNTPOINT, mountpoint); set_itdb_index_prefs_string (index, "name", _("New iPod")); set_itdb_index_prefs_int (index, "type", GP_ITDB_TYPE_IPOD | GP_ITDB_TYPE_AUTOMATIC); new_itdb = setup_itdb_n (index); g_return_val_if_fail (new_itdb, (gdk_threads_leave(), release_widgets(), TRUE)); /* add to display */ gp_itdb_add (new_itdb, -1); /* load prefs from iPod */ loaded_itdb = gp_load_ipod (new_itdb); if (!loaded_itdb) { /* remove itdb and all associated keys again */ remove_itdb_prefs (itdb); gp_itdb_remove (new_itdb); gp_itdb_free (new_itdb); } debug ("...OK (new)\n"); } release_widgets (); g_free (mountpoint); g_mutex_lock (ad->mutex); } g_mutex_unlock (ad->mutex); gdk_threads_leave(); } return TRUE; } #else /* No GNOME_VFS support */ void autodetection_init () { } #endif