commit 5be58b42bd9c401324849d958d6beb6871bcb55d Author: erik Date: Wed Jun 6 16:23:41 2007 +0000 Added Songbird patches to libgpod. git-svn-id: http://publicsvn.songbirdnest.com/vendor/trunk/dependencies/vendor/libgpod@4910 37441250-4157-47a9-a2c9-f9fe3212d2d3 diff --git a/src/itdb.h b/src/itdb.h index 422dc95..e5e0c47 100644 --- a/src/itdb.h +++ b/src/itdb.h @@ -66,6 +66,7 @@ typedef struct _Itdb_Playlist Itdb_Playlist; typedef struct _Itdb_PhotoAlbum Itdb_PhotoAlbum; typedef struct _Itdb_Track Itdb_Track; typedef struct _Itdb_IpodInfo Itdb_IpodInfo; +typedef struct _Itdb_Prefs Itdb_Prefs; /* ------------------------------------------------------------ *\ @@ -799,6 +800,56 @@ struct _Itdb_Track /* (gtkpod note: don't forget to add fields read from the file to * copy_new_info() in file.c!) */ +/* default iPod preferences contents */ +const static gchar default_prefs[] = +{ + 0x66, 0x72, 0x70, 0x64, 0x01, 0x00, 0x03, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x39, 0x0e, 0x70, + 0x8f, 0xdc, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x39, 0x0e, 0x70, 0x8f, 0xdc, 0x6f, 0x76, + 0x02, 0x00, 0x00, 0x00, 0x6e, 0x39, 0x0e, 0x70, + 0x8f, 0xdc, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +struct _Itdb_Prefs +{ + gchar *contents; /* preferences file contents */ + gint length; /* contents length */ + gboolean valid_file; /* true if valid preferences file read */ + guint8 ipod_set_up; /* Offset 0x08: 0x00 iPod has not been set up + !0x00 iPod has been set up */ + guint8 music_mgmt_type; /* Offset 0x0A: 0x00 manual management + !0x00 auto update */ + guint8 music_update_type; /* Offset 0x0B: 0x01 update all + 0x02 update playlists */ + guint64 music_lib_link_id; /* Offset 0x0C: ID of music library linked to + iPod */ +}; + /* ------------------------------------------------------------ *\ * @@ -1003,6 +1057,17 @@ gboolean itdb_init_ipod (const gchar *mountpoint, const gchar *ipod_name, GError **error); +/* prefs functions */ +Itdb_Prefs *itdb_prefs_new (void); +void itdb_prefs_free (Itdb_Prefs *prefs); +Itdb_Prefs *itdb_prefs_parse(Itdb_Device *device, GError **error); +gboolean itdb_prefs_write(Itdb_Device *device, Itdb_Prefs *prefs, + GError **error); +gboolean itdb_update_playlists_read(Itdb_Device *device, guint64 **playlists, + gint *num_playlists, GError **error); +gboolean itdb_update_playlists_write(Itdb_Device *device, guint64 *playlists, + gint num_playlists, GError **error); + G_END_DECLS #endif diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c index f95d4ef..d7f3ea7 100644 --- a/src/itdb_itunesdb.c +++ b/src/itdb_itunesdb.c @@ -5927,3 +5951,307 @@ static gboolean itdb_create_directories (Itdb_Device *device, GError **error) g_free (podpath); return result; } + +/*zzz should put in itdb_prefs.c */ + +/** + * itdb_prefs_new: + * + * Creates a new Itdb_Prefs. + * + * Return value: a newly created Itdb_Prefs to be freed with itdb_prefs_free() + * when it's no longer needed + **/ +Itdb_Prefs *itdb_prefs_new (void) +{ + Itdb_Prefs *prefs = g_new0 (Itdb_Prefs, 1); + prefs->contents = NULL; + prefs->valid_file = FALSE; + + return prefs; +} + +/** + * itdb_prefs_free: + * @prefs: an #Itdb_Prefs + * + * Free the memory taken by @prefs. + **/ +void itdb_prefs_free (Itdb_Prefs *prefs) +{ + if (prefs) + { + if (prefs->contents) + g_free(prefs->contents); + g_free (prefs); + } +} + +/** + * itdb_prefs_parse: + * @device: an #Itdb_Device + * @error: return location for a #GError or NULL + * + * Parse the Itdb_Prefs of the iPod device @device + * + * Return value: a newly allocated #Itdb_Prefs struct holding the preference + * settings of the iPod @device, NULL if the preferences file could not be read. + * If non-NULL, the #Itdb_Prefs is to be freed with itdb_prefs_free() when it's + * no longer needed + **/ +Itdb_Prefs *itdb_prefs_parse(Itdb_Device *device, GError **error) +{ + gchar *prefs_filename; + gchar *itunes_dir; + Itdb_Prefs *prefs = NULL; + const gchar *p_prefspath[] = {"iTunesPrefs", NULL}; + gchar *contents = NULL; + gsize length = 0; + + itunes_dir = itdb_get_itunes_dir (device->mountpoint); + + if (!itunes_dir) + { + error_no_itunes_dir (device->mountpoint, error); + return NULL; + } + + prefs = itdb_prefs_new (); + + prefs_filename = itdb_resolve_path(itunes_dir, p_prefspath); + if (prefs_filename) + { + if (g_file_get_contents (prefs_filename, &contents, &length, error)) + prefs->valid_file = TRUE; + g_free (prefs_filename); + } + + /* if a complete, valid preferences file is not available, + * fill preferences contents in with default values */ + if (length < sizeof (default_prefs)) + { + prefs->contents = g_malloc (sizeof (default_prefs)); + prefs->length = sizeof (default_prefs); + bcopy (default_prefs, prefs->contents, sizeof (default_prefs)); + bcopy (contents, prefs->contents, length); + g_free (contents); + contents = prefs->contents; + } + else + { + prefs->contents = contents; + prefs->length = length; + } + + prefs->ipod_set_up = contents[0x08]; + prefs->music_mgmt_type = contents[0x0A]; + prefs->music_update_type = contents[0x0B]; + bcopy (&(contents[0x0C]), &(prefs->music_lib_link_id), 8); + + g_free (itunes_dir); + return prefs; +} + +/** + * itdb_prefs_write: + * @device: an #Itdb_Device + * @prefs: the #Itdb_Prefs to write to the iPod + * @error: return location for a #GError or NULL + * + * Write out an iPod preferences file. + * + * Return value: TRUE on success, FALSE on error, in which case @error is + * set accordingly. + *zzz should be able to create file if it doesn't exist. + *zzz endianess? + **/ +gboolean itdb_prefs_write(Itdb_Device *device, Itdb_Prefs *prefs, + GError **error) +{ + gchar *prefs_filename = NULL, *itunes_path = NULL; + FILE *fd; + gint length; + gchar *contents = NULL; + gboolean result = TRUE; + + g_return_val_if_fail (device, FALSE); + g_return_val_if_fail (device->mountpoint, FALSE); + g_return_val_if_fail (prefs, FALSE); + + itunes_path = itdb_get_itunes_dir (device->mountpoint); + + if(!itunes_path) + { + error_no_itunes_dir (device->mountpoint, error); + return FALSE; + } + + prefs_filename = g_build_filename (itunes_path, "iTunesPrefs", NULL); + + /* get the preferences contents */ + contents = prefs->contents; + length = prefs->length; + + /* update the known preferences */ + contents[0x08] = prefs->ipod_set_up; + contents[0x0A] = prefs->music_mgmt_type; + contents[0x0B] = prefs->music_update_type; + bcopy (&(prefs->music_lib_link_id), &(contents[0x0C]), 8); + + /* open the preferences file for writing */ + fd = fopen(prefs_filename, "wb"); + if (fd == NULL) + { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Error opening '%s' for writing (%s)."), + prefs_filename, g_strerror (errno)); + return FALSE; + } + + /* write the preferences file */ + fwrite(contents, 1, length, fd); + fclose(fd); + + if (prefs_filename) + g_free (prefs_filename); + if (itunes_path) + g_free (itunes_path); + + /* make sure all buffers are flushed as some people tend to + disconnect as soon as gtkpod returns */ + sync (); + + return result; +} + +/** + * itdb_update_playlists_read: + * @device: an #Itdb_Device + * @playlists: returned list of update playlist IDs + * @num_playlists: returned number of update playlists + * @error: return location for a #GError or NULL + * + * Read an iPod update playlists file. + * + * Return value: TRUE on success, FALSE on error, in which case @error is + * set accordingly. + *zzz endianess? + **/ +gboolean itdb_update_playlists_read(Itdb_Device *device, guint64 **playlists, + gint *num_playlists, GError **error) +{ + gchar *playlists_filename = NULL, *itunes_path = NULL; + gchar *itunes_dir; + const gchar *p_playlistspath[] = {"iTunesPlaylists", NULL}; + gsize length; + + itunes_dir = itdb_get_itunes_dir (device->mountpoint); + + if (!itunes_dir) + { + error_no_itunes_dir (device->mountpoint, error); + return FALSE; + } + + playlists_filename = itdb_resolve_path(itunes_dir, p_playlistspath); + if (playlists_filename) + { + if (g_file_get_contents (playlists_filename, + (gchar **) playlists, + &length, + error)) + { + *num_playlists = length / sizeof (guint64); + } + else + { + gchar *str = g_build_filename (device->mountpoint, + p_playlistspath[0], + NULL); + g_set_error (error, + ITDB_FILE_ERROR, + ITDB_FILE_ERROR_NOTFOUND, + _("Error reading file: '%s'."), + str); + g_free (str); + } + + g_free (playlists_filename); + } + else + { + *num_playlists = 0; + *playlists = NULL; + } + + g_free (itunes_dir); + return TRUE; +} + +/** + * itdb_update_playlists_write: + * @device: an #Itdb_Device + * @playlists: the list of update playlists to write to the iPod + * @num_playlists: the number of playlists + * @error: return location for a #GError or NULL + * + * Write out an iPod update playlists file. + * + * Return value: TRUE on success, FALSE on error, in which case @error is + * set accordingly. + *zzz endianess? + **/ +gboolean itdb_update_playlists_write(Itdb_Device *device, guint64 *playlists, + gint num_playlists, GError **error) +{ + gchar *playlists_filename = NULL, *itunes_path = NULL; + FILE *fd; + int length; + gboolean result = TRUE; + + g_return_val_if_fail (device, FALSE); + g_return_val_if_fail (device->mountpoint, FALSE); + g_return_val_if_fail (playlists, FALSE); + + itunes_path = itdb_get_itunes_dir (device->mountpoint); + + if(!itunes_path) + { + error_no_itunes_dir (device->mountpoint, error); + return FALSE; + } + + playlists_filename = g_build_filename (itunes_path, + "iTunesPlaylists", + NULL); + + /* open the playlists file for writing */ + fd = fopen(playlists_filename, "wb"); + if (fd == NULL) + { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Error opening '%s' for writing (%s)."), + playlists_filename, g_strerror (errno)); + return FALSE; + } + + /* write the playlists file */ + fwrite(playlists, 1, num_playlists * sizeof (guint64), fd); + fclose(fd); + + if (playlists_filename) + g_free (playlists_filename); + if (itunes_path) + g_free (itunes_path); + + /* make sure all buffers are flushed as some people tend to + disconnect as soon as gtkpod returns */ + sync (); + + return result; +} +