summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJorg Schuler <jcsjcs@users.sourceforge.net>2005-10-09 16:27:46 +0000
committerJorg Schuler <jcsjcs@users.sourceforge.net>2005-10-09 16:27:46 +0000
commit5b02248eb39cb1cdd1ca6f7daf0ce34585c4225c (patch)
tree380208d30975c2562189c0f518c48f1db55b3584
parent1e6147b63567fd2c0f424dda4a05323b21991f03 (diff)
downloadlibgpod-tmz-5b02248eb39cb1cdd1ca6f7daf0ce34585c4225c.tar.gz
libgpod-tmz-5b02248eb39cb1cdd1ca6f7daf0ce34585c4225c.tar.xz
libgpod-tmz-5b02248eb39cb1cdd1ca6f7daf0ce34585c4225c.zip
* bindings/python/gpod.i: applied Kelvin Lawson's patch to query
integers. * src/ipod-device.[ch],hal-common.[ch],Makefile.am: code ported from libipoddevice to retrieve information about the iPod without libhal dependence. * tests/test-ipod-device.c: small script to show how to to query the iPod for information. * tests/Makefile.am: initialize <LIBS> with better default * configure.ac: add dependency for libgobject git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1113 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r--ChangeLog16
-rw-r--r--README56
-rw-r--r--bindings/python/gpod.i2
-rw-r--r--configure.ac8
-rw-r--r--src/Makefile.am10
-rw-r--r--src/hal-common.c120
-rw-r--r--src/hal-common.h97
-rw-r--r--src/ipod-device.c1748
-rw-r--r--src/ipod-device.h182
-rw-r--r--src/itdb_itunesdb.c4
-rw-r--r--tests/Makefile.am10
-rw-r--r--tests/test-ipod-device.c65
12 files changed, 2307 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 567f22b..8fdd285 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2005-10-09 Jorg Schuler <jcsjcs at users.sourceforge.net>
+
+ * bindings/python/gpod.i: applied Kelvin Lawson's patch to query
+ integers.
+
+ * src/ipod-device.[ch],hal-common.[ch],Makefile.am: code ported
+ from libipoddevice to retrieve information about the iPod
+ without libhal dependence.
+
+ * tests/test-ipod-device.c: small script to show how to to query
+ the iPod for information.
+
+ * tests/Makefile.am: initialize <LIBS> with better default
+
+ * configure.ac: add dependency for libgobject
+
2005-10-02 Jorg Schuler <jcsjcs at users.sourceforge.net>
* Makefile.am: added bindings/... to EXTRA_DIST
diff --git a/README b/README
index 52dae19..822ce21 100644
--- a/README
+++ b/README
@@ -19,3 +19,59 @@ access the CVS server. The module to download is called 'libgpod'. The
package released on sourceforge is simply there to raise awareness and
hopefully have some package maintainers pick up the library.
----------------------------------------------------------------------
+
+Note about photo databases:
+
+First thing, there are 2 different artwork databases on the iPod
+Photo/Color, the ArtworkDB file which stores information about cover art
+(thumbnails) for the songs stored on the iPod, and the Photo Database
+which is used to store random photos not associated with songs on the
+iPod.
+
+The main target I had in mind when writing artwork support was cover art
+thumbnails for songs. The parsing code should be reusable for generic
+Photo Database support, but there are probably some tweaks to do, and
+some stuff isn't handled, for example Photo Albums (roughtly equivalent
+to a playlist) which aren't used in the ArtworkDB (they are only
+useful/meaningful in the Photo Database)
+
+Even though the cover art data is stored in a separate file (ArtworkDB),
+it's intrisically linked with a song in the iTunesDB files through the
+'dbid' 64 bit field in the mhit iTunesDB records (it's meant to be
+displayed along when the song is being played, so it makes sense to
+associate them).
+
+What ipod_parse_photo_db is to parse this ArtworkDB file to gather info
+about the song thumbnails. It then fills the 'thumbnails' field in
+Itdb_Track which is a list of Itdb_Image. The Itdb_Image structure
+contains a few basic information about the image (I'll let you check its
+definition in itdb.h for more details), but it doesn't store the pixel
+data since this is stored separately, and I feared loading all the cover
+thumbnails automatically would be too memory hungry. So an
+itdb_image_get_rgb_data function is provided to trigger the load of the
+pixel data when it's useful.
+
+The 2 test programs I added are meant to be small samples of how this
+stuff works, one of them parses the ArtworkDB and outputs all the
+thumbnails it finds in /tmp as .png files, the other one is used to
+randomly associate images as thumbnails to all songs in the database,
+it's meant to show how to write thumbnails. If you add support for that
+to gtkpod, be aware that currently adding cover thumbnails to a few
+songs on an iPod which already has cover thumbnails assigned to some
+other songs is not something that is tranparently handled, ie you'll
+need to add code either to libgpod or to gtkpod to make that work
+properly.
+
+As for Photo Database handling (which is not dealt with currently), I
+agree it doesn't make sense to associate its parsing with an
+Itdb_ItunesDB object, and that a 'parallel' api mimicking somewhat the
+Track/Playlist stuff with Photo/Album entities would need to be
+designed, but I didn't work on that since, and I probably won't short
+term.
+
+People wanting more info can find lots of details on
+http://ipodlinux.org/ITunesDB#Artwork_Database
+
+I hope that's helpful,
+
+Christophe
diff --git a/bindings/python/gpod.i b/bindings/python/gpod.i
index 7bfab55..610a288 100644
--- a/bindings/python/gpod.i
+++ b/bindings/python/gpod.i
@@ -34,6 +34,8 @@ PyObject* sw_get_playlists(Itdb_iTunesDB *itdb) {
typedef char gchar;
typedef int gboolean;
+typedef int gint32;
+typedef unsigned int guint32;
PyObject* sw_get_tracks(Itdb_iTunesDB *itdb);
PyObject* sw_get_playlists(Itdb_iTunesDB *itdb);
diff --git a/configure.ac b/configure.ac
index 8670f7c..6242295 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,7 +52,7 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_INTLTOOL([0.21])
-PKG_CHECK_MODULES(LIBGPOD, glib-2.0)
+PKG_CHECK_MODULES(LIBGPOD, glib-2.0 gobject-2.0)
LIBGPOD_CFLAGS="$LIBGPOD_CFLAGS -Wall"
AC_SUBST(LIBGPOD_CFLAGS)
AC_SUBST(LIBGPOD_LIBS)
@@ -70,6 +70,12 @@ AC_SUBST(GDKPIXBUF_CFLAGS)
AC_SUBST(GDKPIXBUF_LIBS)
dnl **************************************************
+dnl * hal is optional
+dnl **************************************************
+
+AC_CHECK_LIB([hal], [libhal_device_get_property_uint64])
+
+dnl **************************************************
dnl * internationalization support
dnl **************************************************
ALL_LINGUAS="de fr he it ja sv"
diff --git a/src/Makefile.am b/src/Makefile.am
index dff33d4..4b67317 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,11 +15,15 @@ libgpod_la_SOURCES = \
db-image-parser.c \
db-image-parser.h \
db-artwork-writer.c \
- ithumb-writer.c
+ ithumb-writer.c \
+ ipod-device.c \
+ ipod-device.h \
+ hal-common.c \
+ hal-common.h
-libgpod_la_headers = itdb.h
-libgpod_la_noinst_headers = itdb_private.h
+libgpod_la_headers = itdb.h ipod-device.h
+libgpod_la_noinst_headers = itdb_private.h hal-common.h
libgpod_la_LDFLAGS = -version-info $(LIBGPOD_CURRENT):$(LIBGPOD_REVISION):$(LIBGPOD_AGE) \
-no-undefined
diff --git a/src/hal-common.c b/src/hal-common.c
new file mode 100644
index 0000000..23dca80
--- /dev/null
+++ b/src/hal-common.c
@@ -0,0 +1,120 @@
+/* Time-stamp: <2005-10-10 01:23:29 jcs>
+|
+| Copyright (C) 2005 Jorg Schuler <jcsjcs at users sourceforge net>
+| Part of the gtkpod project.
+|
+| URL: http://www.gtkpod.org/
+| URL: http://gtkpod.sourceforge.net/
+|
+|
+| The source is taken from libipoddevice, CVS version October 8 2005
+| (http://64.14.94.162/index.php/Libipoddevice).
+|
+| I decided not to make libgpod dependent on libipoddevice because
+| the latter depends on libraries not widely available yet (libhal >=
+| 0.5.2, glib >= 2.8). It is planned to replace these files with a
+| libipoddevice dependence at some later time.
+|
+| The following changes were done:
+|
+| - libhal becomes optional (see #if HAVE_LIBHAL sections)
+| - provide some dummy libhal functions to make libhal-independence
+| of ipod-device.c easier.
+|
+| Because of these changes only a limited amount of functionality is
+| available. See ipod-device.h for summary.
+|
+|
+|
+|
+| $Id$
+*/
+/* ex: set ts=4: */
+/***************************************************************************
+* hal-common.c
+* Copyright (C) 2005 Novell
+* Written by Aaron Bockover <aaron@aaronbock.net>
+****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "hal-common.h"
+
+#if HAVE_LIBHAL
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+dbus_bool_t
+hal_mainloop_integration(LibHalContext *ctx, DBusError *error)
+{
+ DBusConnection *dbus_connection;
+
+ dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, error);
+
+ if(dbus_error_is_set(error))
+ return FALSE;
+
+ dbus_connection_setup_with_g_main(dbus_connection,
+ ipod_device_global_main_context);
+ libhal_ctx_set_dbus_connection(ctx, dbus_connection);
+
+ return TRUE;
+}
+
+void ipod_device_set_global_main_context(GMainContext *ctx)
+{
+ ipod_device_global_main_context = ctx;
+}
+#else
+gchar **libhal_manager_find_device_string_match (LibHalContext *hal_ctx,
+ const gchar *type,
+ const gchar *str,
+ gint *vol_count,
+ void *error)
+{
+/* gchar **volumes = g_new0 (gchar *, 2);
+ volumes[0] = g_strdup (type);*/
+ gchar **volumes = NULL;
+ *vol_count = 0;
+ return volumes;
+}
+void libhal_free_string_array (gchar **volumes)
+{
+/* g_strfreev (volumes);*/
+}
+gboolean libhal_device_property_exists (LibHalContext *hal_ctx,
+ const gchar *vol,
+ const gchar *prop,
+ void *error)
+{
+ return FALSE;
+}
+gboolean libhal_device_get_property_bool (LibHalContext *hal_ctx,
+ const gchar *vol,
+ const gchar *prop,
+ void *error)
+{
+ return FALSE;
+}
+void libhal_ctx_shutdown (LibHalContext *hal_ctx, void *error) {}
+void libhal_ctx_free (LibHalContext *hal_ctx) {}
+#endif
diff --git a/src/hal-common.h b/src/hal-common.h
new file mode 100644
index 0000000..a4e8909
--- /dev/null
+++ b/src/hal-common.h
@@ -0,0 +1,97 @@
+/* Time-stamp: <2005-10-10 01:23:30 jcs>
+|
+| Copyright (C) 2005 Jorg Schuler <jcsjcs at users sourceforge net>
+| Part of the gtkpod project.
+|
+| URL: http://www.gtkpod.org/
+| URL: http://gtkpod.sourceforge.net/
+|
+|
+| The source is taken from libipoddevice, CVS version October 8 2005
+| (http://64.14.94.162/index.php/Libipoddevice).
+|
+| I decided not to make libgpod dependent on libipoddevice because
+| the latter depends on libraries not widely available yet (libhal >=
+| 0.5.2, glib >= 2.8). It is planned to replace these files with a
+| libipoddevice dependence at some later time.
+|
+| The following changes were done:
+|
+| - libhal becomes optional (see #if HAVE_LIBHAL sections)
+| - provide some dummy libhal functions to make libhal-independence
+| of ipod-device.c easier.
+|
+| Because of these changes only a limited amount of functionality is
+| available. See ipod-device.h for summary.
+|
+|
+|
+|
+| $Id$
+*/
+/* ex: set ts=4: */
+/***************************************************************************
+* hal-common.h
+* Copyright (C) 2005 Novell
+* Written by Aaron Bockover <aaron@aaronbock.net>
+****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#ifndef HAL_COMMON_H
+#define HAL_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#if HAVE_LIBHAL
+
+#include <libhal.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+static GMainContext *ipod_device_global_main_context = NULL;
+
+dbus_bool_t hal_mainloop_integration(LibHalContext *ctx, DBusError *error);
+void ipod_device_set_global_main_context(GMainContext *ctx);
+
+#else
+typedef void LibHalContext;
+gchar **libhal_manager_find_device_string_match (LibHalContext *hal_ctx,
+ const gchar *dev,
+ const gchar *str,
+ gint *vol_count,
+ void *error);
+void libhal_free_string_array (gchar **volumes);
+gboolean libhal_device_property_exists (LibHalContext *hal_ctx,
+ const gchar *vol,
+ const gchar *prop,
+ void *error);
+gboolean libhal_device_get_property_bool (LibHalContext *hal_ctx,
+ const gchar *vol,
+ const gchar *prop,
+ void *error);
+void libhal_ctx_shutdown (LibHalContext *hal_ctx, void *error);
+void libhal_ctx_free (LibHalContext *hal_ctx);
+#endif
+
+
+#endif /* HAL_COMMON_H */
diff --git a/src/ipod-device.c b/src/ipod-device.c
new file mode 100644
index 0000000..4731c70
--- /dev/null
+++ b/src/ipod-device.c
@@ -0,0 +1,1748 @@
+/* Time-stamp: <2005-10-10 01:23:29 jcs>
+|
+| Copyright (C) 2005 Jorg Schuler <jcsjcs at users sourceforge net>
+| Part of the gtkpod project.
+|
+| URL: http://www.gtkpod.org/
+| URL: http://gtkpod.sourceforge.net/
+|
+|
+| The source is taken from libipoddevice, CVS version October 8 2005
+| (http://64.14.94.162/index.php/Libipoddevice).
+|
+| I decided not to make libgpod dependent on libipoddevice because
+| the latter depends on libraries not widely available yet (libhal >=
+| 0.5.2, glib >= 2.8). It is planned to replace these files with a
+| libipoddevice dependence at some later time.
+|
+| The following changes were done:
+|
+| - libhal becomes optional (see #if HAVE_LIBHAL sections)
+| - g_mkdir_with_parents() is provided if not available (glib < 2.8)
+| - publicly available functions were renamed from ipod_device_...()
+| to itdb_device_...()
+|
+| Because of these changes only a limited amount of functionality is
+| available. See ipod-device.h for summary.
+|
+|
+|
+|
+| $Id$
+*/
+/* ex: set ts=4: */
+/***************************************************************************
+* ipod-device.c
+* Copyright (C) 2005 Novell
+* Written by Aaron Bockover <aaron@aaronbock.net>
+****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+
+/* JCS: Change from ipod_device... to itdb_device for public functions */
+#define ipod_device_get_type itdb_device_get_type
+#define ipod_device_new itdb_device_new
+#define ipod_device_rescan_disk itdb_device_rescan_disk
+#define ipod_device_eject itdb_device_eject
+#define ipod_device_reboot itdb_device_reboot
+#define ipod_device_debug itdb_device_debug
+#define ipod_device_save itdb_device_save
+#define ipod_device_list_devices itdb_device_list_devices
+#define ipod_device_list_device_udis itdb_device_list_device_udis
+
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <glib/gstdio.h>
+
+#include "hal-common.h"
+#include "ipod-device.h"
+
+#define GB 1024
+
+typedef struct _IpodModel {
+ const gchar *model_number;
+ const guint64 capacity;
+ guint model_type;
+ guint generation;
+} IpodModel;
+
+static const IpodModel ipod_model_table [] = {
+ /* Handle idiots who hose their iPod file system, or
+ lucky people with iPods we don't yet know about*/
+ {"Invalid", 0, MODEL_TYPE_INVALID, UNKNOWN_GENERATION},
+ {"Unknown", 0, MODEL_TYPE_UNKNOWN, UNKNOWN_GENERATION},
+
+ /* First Generation */
+ {"8513", 5 * GB, MODEL_TYPE_REGULAR, FIRST_GENERATION},
+ {"8541", 5 * GB, MODEL_TYPE_REGULAR, FIRST_GENERATION},
+ {"8697", 5 * GB, MODEL_TYPE_REGULAR, FIRST_GENERATION},
+ {"8709", 10 * GB, MODEL_TYPE_REGULAR, FIRST_GENERATION},
+
+ /* Second Generation */
+ {"8737", 10 * GB, MODEL_TYPE_REGULAR, SECOND_GENERATION},
+ {"8740", 10 * GB, MODEL_TYPE_REGULAR, SECOND_GENERATION},
+ {"8738", 20 * GB, MODEL_TYPE_REGULAR, SECOND_GENERATION},
+ {"8741", 20 * GB, MODEL_TYPE_REGULAR, SECOND_GENERATION},
+
+ /* Third Generation */
+ {"8976", 10 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+ {"8946", 15 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+ {"9460", 15 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+ {"9244", 20 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+ {"8948", 30 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+ {"9245", 40 * GB, MODEL_TYPE_REGULAR, THIRD_GENERATION},
+
+
+ /* Fourth Generation */
+ {"9282", 20 * GB, MODEL_TYPE_REGULAR, FOURTH_GENERATION},
+ {"9787", 25 * GB, MODEL_TYPE_REGULAR_U2, FOURTH_GENERATION},
+ {"9268", 40 * GB, MODEL_TYPE_REGULAR, FOURTH_GENERATION},
+ {"A079", 20 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+ {"A127", 20 * GB, MODEL_TYPE_COLOR_U2, FOURTH_GENERATION},
+ {"9830", 60 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+
+ /* First Generation Mini */
+ {"9160", 4 * GB, MODEL_TYPE_MINI, FIRST_GENERATION},
+ {"9436", 4 * GB, MODEL_TYPE_MINI_BLUE, FIRST_GENERATION},
+ {"9435", 4 * GB, MODEL_TYPE_MINI_PINK, FIRST_GENERATION},
+ {"9434", 4 * GB, MODEL_TYPE_MINI_GREEN, FIRST_GENERATION},
+ {"9437", 4 * GB, MODEL_TYPE_MINI_GOLD, FIRST_GENERATION},
+
+ /* Second Generation Mini */
+ {"9800", 4 * GB, MODEL_TYPE_MINI, SECOND_GENERATION},
+ {"9802", 4 * GB, MODEL_TYPE_MINI_BLUE, SECOND_GENERATION},
+ {"9804", 4 * GB, MODEL_TYPE_MINI_PINK, SECOND_GENERATION},
+ {"9806", 4 * GB, MODEL_TYPE_MINI_GREEN, SECOND_GENERATION},
+ {"9801", 6 * GB, MODEL_TYPE_MINI, SECOND_GENERATION},
+ {"9803", 6 * GB, MODEL_TYPE_MINI_BLUE, SECOND_GENERATION},
+ {"9805", 6 * GB, MODEL_TYPE_MINI_PINK, SECOND_GENERATION},
+ {"9807", 6 * GB, MODEL_TYPE_MINI_GREEN, SECOND_GENERATION},
+
+ /* Photo / Fourth Generation */
+ {"9829", 30 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+ {"9585", 40 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+ {"9586", 60 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+ {"9830", 60 * GB, MODEL_TYPE_COLOR, FOURTH_GENERATION},
+
+ /* Shuffle / Fourth Generation */
+ {"9724", GB / 2, MODEL_TYPE_SHUFFLE, FOURTH_GENERATION},
+ {"9725", GB, MODEL_TYPE_SHUFFLE, FOURTH_GENERATION},
+
+ /* Nano / Fourth Generation */
+ {"A004", GB * 2, MODEL_TYPE_NANO_WHITE, FOURTH_GENERATION},
+ {"A099", GB * 2, MODEL_TYPE_NANO_BLACK, FOURTH_GENERATION},
+ {"A005", GB * 4, MODEL_TYPE_NANO_WHITE, FOURTH_GENERATION},
+ {"A107", GB * 4, MODEL_TYPE_NANO_BLACK, FOURTH_GENERATION},
+
+ /* HP iPods, need contributions for this table */
+ {"E436", 40 * GB, MODEL_TYPE_REGULAR, FOURTH_GENERATION},
+
+ {NULL, 0, 0, 0}
+};
+
+static const gchar *ipod_model_name_table [] = {
+ "Invalid",
+ "Unknown",
+ "Color",
+ "Color U2",
+ "Grayscale",
+ "Grayscale U2",
+ "Mini (Silver)",
+ "Mini (Blue)",
+ "Mini (Pink)",
+ "Mini (Green)",
+ "Mini (Gold)",
+ "Shuffle",
+ "Nano (White)",
+ "Nano (Black)",
+ NULL
+};
+
+#define g_free_if_not_null(o) \
+ if(o != NULL) { \
+ g_free(o); \
+ o = NULL; \
+ }
+
+static const gchar *sysinfo_field_names [] = {
+ "pszSerialNumber",
+ "ModelNumStr",
+ "visibleBuildID",
+ NULL
+};
+
+static gchar *sysinfo_arr_get_dup(gchar *arr[], const gchar *key)
+{
+ gint i = 0;
+
+ for(i = 0; sysinfo_field_names[i] != NULL; i++) {
+ if(g_strcasecmp(sysinfo_field_names[i], key) == 0)
+ return g_strdup(arr[i]);
+ }
+
+ return NULL;
+}
+
+
+#if ((GTK_MAJOR_VERSION <= 2) && (GTK_MINOR_VERSION < 8))
+/**
+ * g_mkdir_with_parents:
+ * @pathname: a pathname in the GLib file name encoding
+ * @mode: permissions to use for newly created directories
+ *
+ * Create a directory if it doesn't already exist. Create intermediate
+ * parent directories as needed, too.
+ *
+ * Returns: 0 if the directory already exists, or was successfully
+ * created. Returns -1 if an error occurred, with errno set.
+ *
+ * Since: 2.8 (copied from GLIB version 2.8 - JCS)
+ */
+int
+g_mkdir_with_parents (const gchar *pathname,
+ int mode);
+int
+g_mkdir_with_parents (const gchar *pathname,
+ int mode)
+{
+ gchar *fn, *p;
+
+ if (pathname == NULL || *pathname == '\0')
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fn = g_strdup (pathname);
+
+ if (g_path_is_absolute (fn))
+ p = (gchar *) g_path_skip_root (fn);
+ else
+ p = fn;
+
+ do
+ {
+ while (*p && !G_IS_DIR_SEPARATOR (*p))
+ p++;
+
+ if (!*p)
+ p = NULL;
+ else
+ *p = '\0';
+
+ if (!g_file_test (fn, G_FILE_TEST_EXISTS))
+ {
+ if (g_mkdir (fn, mode) == -1)
+ {
+ int errno_save = errno;
+ g_free (fn);
+ errno = errno_save;
+ return -1;
+ }
+ }
+ else if (!g_file_test (fn, G_FILE_TEST_IS_DIR))
+ {
+ g_free (fn);
+ errno = ENOTDIR;
+ return -1;
+ }
+ if (p)
+ {
+ *p++ = G_DIR_SEPARATOR;
+ while (*p && G_IS_DIR_SEPARATOR (*p))
+ p++;
+ }
+ }
+ while (p);
+
+ g_free (fn);
+
+ return 0;
+}
+#endif
+
+
+static void ipod_device_class_init(IpodDeviceClass *klass);
+static void ipod_device_init(IpodDevice *sp);
+static void ipod_device_finalize(GObject *object);
+
+gchar *ipod_device_read_device_info_string(FILE *fd);
+void ipod_device_write_device_info_string(gchar *str, FILE *fd);
+
+gboolean ipod_device_reload(IpodDevice *device);
+void ipod_device_construct_paths(IpodDevice *device);
+gboolean ipod_device_info_load(IpodDevice *device);
+guint ipod_device_detect_model(IpodDevice *device);
+gboolean ipod_device_detect_volume_info(IpodDevice *device);
+LibHalContext *ipod_device_hal_initialize(void);
+void ipod_device_detect_volume_used(IpodDevice *device);
+guint64 ipod_device_dir_size(const gchar *path);
+gboolean ipod_device_has_open_fd(IpodDevice *device);
+gboolean ipod_device_read_sysinfo(IpodDevice *device);
+gboolean ipod_device_detect_writeable(IpodDevice *device);
+void ipod_device_restore_reboot_preferences(IpodDevice *device);
+
+struct IpodDevicePrivate {
+ LibHalContext *hal_context;
+
+ /* Paths */
+ gchar *device_path;
+ gchar *mount_point;
+ gchar *control_path;
+ gchar *hal_volume_id;
+
+ gchar *adv_capacity;
+ guint model_index;
+
+ /* DeviceInfo Fields (All Devices) */
+ gchar *device_name;
+ gchar *user_name;
+ gchar *host_name;
+
+ /* Volume Size/Usage */
+ guint64 volume_size;
+ guint64 volume_available;
+ guint64 volume_used;
+
+ /* System Info */
+ gchar *serial_number;
+ gchar *model_number;
+ gchar *firmware_version;
+
+ gchar *volume_uuid;
+ gchar *volume_label;
+
+ /* Fresh from the factory/restore? */
+ gboolean is_new;
+
+ /* Safety */
+ gboolean is_ipod;
+ gboolean can_write;
+};
+
+static GObjectClass *parent_class = NULL;
+
+/* GObject Class Specific Methods */
+
+GType
+ipod_device_get_type()
+{
+ static GType type = 0;
+
+ if(type == 0) {
+ static const GTypeInfo our_info = {
+ sizeof (IpodDeviceClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)ipod_device_class_init,
+ NULL,
+ NULL,
+ sizeof (IpodDevice),
+ 0,
+ (GInstanceInitFunc)ipod_device_init,
+ };
+
+ type = g_type_register_static(G_TYPE_OBJECT,
+ "IpodDevice", &our_info, 0);
+ }
+
+ return type;
+}
+
+static void
+ipod_device_get_property(GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ IpodDevice *device = IPOD_DEVICE(object);
+
+ switch(prop_id) {
+ case PROP_HAL_CONTEXT:
+ g_value_set_pointer(value, device->priv->hal_context);
+ break;
+ case PROP_HAL_VOLUME_ID:
+ g_value_set_string(value, device->priv->hal_volume_id);
+ break;
+ case PROP_MOUNT_POINT:
+ g_value_set_string(value, device->priv->mount_point);
+ break;
+ case PROP_DEVICE_PATH:
+ g_value_set_string(value, device->priv->device_path);
+ break;
+ case PROP_CONTROL_PATH:
+ g_value_set_string(value, device->priv->control_path);
+ break;
+ case PROP_DEVICE_MODEL:
+ g_value_set_uint(value,
+ ipod_model_table[device->priv->model_index].model_type);
+ break;
+ case PROP_DEVICE_MODEL_STRING:
+ g_value_set_string(value,
+ ipod_model_name_table[ipod_model_table[
+ device->priv->model_index].model_type]);
+ break;
+ case PROP_DEVICE_GENERATION:
+ g_value_set_uint(value,
+ ipod_model_table[device->priv->model_index].generation);
+ break;
+ case PROP_ADVERTISED_CAPACITY:
+ g_value_set_string(value, device->priv->adv_capacity);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_set_string(value, device->priv->device_name);
+ break;
+ case PROP_USER_NAME:
+ g_value_set_string(value, device->priv->user_name);
+ break;
+ case PROP_HOST_NAME:
+ g_value_set_string(value, device->priv->host_name);
+ break;
+ case PROP_VOLUME_SIZE:
+ g_value_set_uint64(value, device->priv->volume_size);
+ break;
+ case PROP_VOLUME_AVAILABLE:
+ g_value_set_uint64(value, device->priv->volume_available);
+ break;
+ case PROP_VOLUME_USED:
+ g_value_set_uint64(value, device->priv->volume_used);
+ break;
+ case PROP_IS_IPOD:
+ g_value_set_boolean(value, device->priv->is_ipod);
+ break;
+ case PROP_IS_NEW:
+ g_value_set_boolean(value, device->priv->is_new);
+ break;
+ case PROP_SERIAL_NUMBER:
+ g_value_set_string(value, device->priv->serial_number);
+ break;
+ case PROP_MODEL_NUMBER:
+ g_value_set_string(value, device->priv->model_number);
+ break;
+ case PROP_FIRMWARE_VERSION:
+ g_value_set_string(value, device->priv->firmware_version);
+ break;
+ case PROP_VOLUME_UUID:
+ g_value_set_string(value, device->priv->volume_uuid);
+ break;
+ case PROP_VOLUME_LABEL:
+ g_value_set_string(value, device->priv->volume_label);
+ break;
+ case PROP_CAN_WRITE:
+ g_value_set_boolean(value, device->priv->can_write);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ipod_device_set_property(GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ IpodDevice *device = IPOD_DEVICE(object);
+ const gchar *str;
+ gchar **volumes;
+ gint volume_count;
+
+ switch(prop_id) {
+ case PROP_MOUNT_POINT:
+ case PROP_DEVICE_PATH:
+ case PROP_HAL_VOLUME_ID:
+ str = g_value_get_string(value);
+ volumes = libhal_manager_find_device_string_match(
+ device->priv->hal_context, "block.device", str,
+ &volume_count, NULL);
+
+ if(volume_count == 0) {
+ libhal_free_string_array(volumes);
+ volumes = libhal_manager_find_device_string_match(
+ device->priv->hal_context, "volume.mount_point",
+ str, &volume_count, NULL);
+
+ if(volume_count >= 1)
+ str = volumes[0];
+ } else {
+ str = volumes[0];
+ }
+#if HAVE_LIBHAL
+ g_free_if_not_null(device->priv->hal_volume_id);
+ device->priv->hal_volume_id = g_strdup(str);
+#else
+/* JCS for libgpod */
+ g_free (device->priv->mount_point);
+ device->priv->mount_point = g_strdup (str);
+/* end JCS for libgpod */
+#endif
+ device->priv->is_ipod = ipod_device_reload(device);
+ libhal_free_string_array(volumes);
+ break;
+ case PROP_DEVICE_NAME:
+ str = g_value_get_string(value);
+ g_free_if_not_null(device->priv->device_name);
+ device->priv->device_name = g_strdup(str);
+ break;
+ case PROP_USER_NAME:
+ str = g_value_get_string(value);
+ g_free_if_not_null(device->priv->user_name);
+ device->priv->user_name = g_strdup(str);
+ break;
+ case PROP_HOST_NAME:
+ str = g_value_get_string(value);
+ g_free_if_not_null(device->priv->host_name);
+ device->priv->host_name = g_strdup(str);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ipod_device_class_init(IpodDeviceClass *klass)
+{
+ GParamSpec *hal_context_param;
+ GParamSpec *hal_volume_id_param;
+ GParamSpec *mount_point_param;
+ GParamSpec *device_path_param;
+ GParamSpec *control_path_param;
+ GParamSpec *device_model_param;
+ GParamSpec *device_model_string_param;
+ GParamSpec *device_name_param;
+ GParamSpec *user_name_param;
+ GParamSpec *host_name_param;
+ GParamSpec *volume_size_param;
+ GParamSpec *volume_available_param;
+ GParamSpec *volume_used_param;
+ GParamSpec *is_ipod_param;
+ GParamSpec *is_new_param;
+ GParamSpec *serial_number_param;
+ GParamSpec *model_number_param;
+ GParamSpec *firmware_version_param;
+ GParamSpec *volume_uuid_param;
+ GParamSpec *volume_label_param;
+ GParamSpec *can_write_param;
+ GParamSpec *device_generation_param;
+ GParamSpec *advertised_capacity_param;
+
+ GObjectClass *class = G_OBJECT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+ class->finalize = ipod_device_finalize;
+
+ hal_context_param = g_param_spec_pointer("hal-context", "HAL Context",
+ "LibHalContext handle", G_PARAM_READABLE);
+
+ hal_volume_id_param = g_param_spec_string("hal-volume-id", "HAL Volume ID",
+ "Volume ID of a device in HAL",
+ NULL, G_PARAM_READWRITE);
+
+ mount_point_param = g_param_spec_string("mount-point", "Mount Point",
+ "Where iPod is mounted (parent of an iPod_Control directory)",
+ NULL, G_PARAM_READWRITE);
+
+ device_path_param = g_param_spec_string("device-path", "Device Path",
+ "Path to raw iPod Device (/dev/sda2, for example)",
+ NULL, G_PARAM_READWRITE);
+
+ control_path_param = g_param_spec_string("control-path",
+ "iPod_Control Path","Full path to iPod_Control",
+ NULL, G_PARAM_READABLE);
+
+ device_model_param = g_param_spec_uint("device-model", "Device Model",
+ "Type of iPod (Regular, Photo, Shuffle)", 0, 2, 0, G_PARAM_READABLE);
+
+ device_model_string_param = g_param_spec_string("device-model-string",
+ "Device Model String", "String type of iPod (Regular, Shuffle)",
+ NULL, G_PARAM_READABLE);
+
+ device_name_param = g_param_spec_string("device-name", "Device Name",
+ "The user-assigned name of their iPod", NULL, G_PARAM_READWRITE);
+
+ user_name_param = g_param_spec_string("user-name", "User Name",
+ "On Windows, Maybe Mac, the user account owning the iPod",
+ NULL, G_PARAM_READWRITE);
+
+ host_name_param = g_param_spec_string("host-name", "Host Name",
+ "On Windows, Maybe Mac, the host/computer name owning the iPod",
+ NULL, G_PARAM_READWRITE);
+
+ volume_size_param = g_param_spec_uint64("volume-size", "Volume Size",
+ "Total size of the iPod's hard drive", 0, G_MAXLONG, 0,
+ G_PARAM_READABLE);
+
+ volume_available_param = g_param_spec_uint64("volume-available",
+ "Volume Available", "Available space on the iPod",
+ 0, G_MAXLONG, 0, G_PARAM_READABLE);
+
+ volume_used_param = g_param_spec_uint64("volume-used", "Volume Used",
+ "How much space has been used", 0, G_MAXLONG, 0, G_PARAM_READABLE);
+
+ is_ipod_param = g_param_spec_boolean("is-ipod", "Is iPod",
+ "If all device checks are okay, then this is true",
+ FALSE, G_PARAM_READABLE);
+
+ is_new_param = g_param_spec_boolean("is-new", "Is iPod",
+ "If device is fresh from factory/restore, this is true",
+ FALSE, G_PARAM_READABLE);
+
+ serial_number_param = g_param_spec_string("serial-number", "Serial Number",
+ "Serial Number of the iPod",
+ NULL, G_PARAM_READABLE);
+
+ model_number_param = g_param_spec_string("model-number", "Model Number",
+ "Model Number of the iPod",
+ NULL, G_PARAM_READABLE);
+
+ firmware_version_param = g_param_spec_string("firmware-version",
+ "Firmware Version", "iPod Firmware Version",
+ NULL, G_PARAM_READABLE);
+
+ volume_uuid_param = g_param_spec_string("volume-uuid", "Volume UUID",
+ "Volume UUID of the iPod",
+ NULL, G_PARAM_READABLE);
+
+ volume_label_param = g_param_spec_string("volume-label", "Volume Label",
+ "Volume Label of the iPod",
+ NULL, G_PARAM_READABLE);
+
+ can_write_param = g_param_spec_boolean("can-write", "Can Write",
+ "True if device can be written to (mounted read/write)",
+ FALSE, G_PARAM_READABLE);
+
+ advertised_capacity_param = g_param_spec_string("advertised-capacity",
+ "Advertised Capacity", "Apple Marketed/Advertised Capacity String",
+ NULL, G_PARAM_READABLE);
+
+ device_generation_param = g_param_spec_uint("device-generation",
+ "Generation", "Generation of the iPod",
+ 0, G_MAXUINT, 0, G_PARAM_READABLE);
+
+ class->set_property = ipod_device_set_property;
+ class->get_property = ipod_device_get_property;
+ g_object_class_install_property(class, PROP_HAL_CONTEXT,
+ hal_context_param);
+
+ g_object_class_install_property(class, PROP_HAL_VOLUME_ID,
+ hal_volume_id_param);
+
+ g_object_class_install_property(class, PROP_MOUNT_POINT,
+ mount_point_param);
+
+ g_object_class_install_property(class, PROP_DEVICE_PATH,
+ device_path_param);
+
+ g_object_class_install_property(class, PROP_CONTROL_PATH,
+ control_path_param);
+
+ g_object_class_install_property(class, PROP_DEVICE_MODEL,
+ device_model_param);
+
+ g_object_class_install_property(class, PROP_DEVICE_MODEL_STRING,
+ device_model_string_param);
+
+ g_object_class_install_property(class, PROP_DEVICE_NAME,
+ device_name_param);
+
+ g_object_class_install_property(class, PROP_USER_NAME,
+ user_name_param);
+
+ g_object_class_install_property(class, PROP_HOST_NAME,
+ host_name_param);
+
+ g_object_class_install_property(class, PROP_VOLUME_SIZE,
+ volume_size_param);
+
+ g_object_class_install_property(class, PROP_VOLUME_AVAILABLE,
+ volume_available_param);
+
+ g_object_class_install_property(class, PROP_VOLUME_USED,
+ volume_used_param);
+
+ g_object_class_install_property(class, PROP_IS_IPOD, is_ipod_param);
+
+ g_object_class_install_property(class, PROP_IS_NEW, is_new_param);
+
+ g_object_class_install_property(class, PROP_SERIAL_NUMBER,
+ serial_number_param);
+
+ g_object_class_install_property(class, PROP_MODEL_NUMBER,
+ model_number_param);
+
+ g_object_class_install_property(class, PROP_FIRMWARE_VERSION,
+ firmware_version_param);
+
+ g_object_class_install_property(class, PROP_VOLUME_UUID,
+ volume_uuid_param);
+
+ g_object_class_install_property(class, PROP_VOLUME_LABEL,
+ volume_label_param);
+
+ g_object_class_install_property(class, PROP_CAN_WRITE,
+ can_write_param);
+
+ g_object_class_install_property(class, PROP_DEVICE_GENERATION,
+ device_generation_param);
+
+ g_object_class_install_property(class, PROP_ADVERTISED_CAPACITY,
+ advertised_capacity_param);
+}
+
+static void
+ipod_device_init(IpodDevice *device)
+{
+ device->priv = g_new0(IpodDevicePrivate, 1);
+
+ device->priv->hal_context = ipod_device_hal_initialize();
+
+ device->priv->hal_volume_id = NULL;
+ device->priv->mount_point = NULL;
+ device->priv->device_path = NULL;
+ device->priv->control_path = NULL;
+ device->priv->device_name = NULL;
+ device->priv->user_name = NULL;
+ device->priv->host_name = NULL;
+ device->priv->adv_capacity = NULL;
+ device->priv->serial_number = NULL;
+ device->priv->model_number = NULL;
+ device->priv->firmware_version = NULL;
+ device->priv->volume_uuid = NULL;
+ device->priv->volume_label = NULL;
+
+ device->priv->volume_size = 0;
+ device->priv->volume_available = 0;
+ device->priv->volume_used = 0;
+
+ device->priv->is_new = FALSE;
+ device->priv->can_write = FALSE;
+}
+
+static void
+ipod_device_finalize(GObject *object)
+{
+ IpodDevice *device = IPOD_DEVICE(object);
+
+ /* Free private members, etc. */
+ g_free_if_not_null(device->priv->hal_volume_id);
+ g_free_if_not_null(device->priv->device_path);
+ g_free_if_not_null(device->priv->mount_point);
+ g_free_if_not_null(device->priv->control_path);
+ g_free_if_not_null(device->priv->device_name);
+ g_free_if_not_null(device->priv->user_name);
+ g_free_if_not_null(device->priv->host_name);
+ g_free_if_not_null(device->priv->adv_capacity);
+ g_free_if_not_null(device->priv->serial_number);
+ g_free_if_not_null(device->priv->model_number);
+ g_free_if_not_null(device->priv->firmware_version);
+ g_free_if_not_null(device->priv->volume_uuid);
+ g_free_if_not_null(device->priv->volume_label);
+
+ if(device->priv->hal_context != NULL) {
+ libhal_ctx_shutdown(device->priv->hal_context, NULL);
+ libhal_ctx_free(device->priv->hal_context);
+ }
+ g_free(device->priv);
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+/* PRIVATE METHODS */
+
+LibHalContext *
+ipod_device_hal_initialize()
+{
+#if HAVE_LIBHAL
+ LibHalContext *hal_context;
+ DBusError error;
+ DBusConnection *dbus_connection;
+ char **devices;
+ gint device_count;
+
+ 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)) {
+ libhal_ctx_free(hal_context);
+ return NULL;
+ }
+
+ devices = libhal_get_all_devices(hal_context, &device_count, NULL);
+ if(devices == NULL) {
+ libhal_ctx_shutdown(hal_context, NULL);
+ libhal_ctx_free(hal_context);
+ hal_context = NULL;
+ return NULL;
+ }
+
+ libhal_free_string_array(devices);
+
+ return hal_context;
+#else
+ return NULL;
+#endif
+}
+
+gboolean
+ipod_device_reload(IpodDevice *device)
+{
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ device->priv->model_index = 0;
+
+ if(!ipod_device_detect_volume_info(device))
+ return FALSE;
+
+ ipod_device_construct_paths(device);
+
+ device->priv->is_new = !ipod_device_info_load(device);
+
+ ipod_device_detect_volume_used(device);
+ ipod_device_detect_writeable(device);
+ ipod_device_read_sysinfo(device);
+ ipod_device_detect_model(device);
+ ipod_device_restore_reboot_preferences(device);
+
+ return device->priv->model_index != 0;
+}
+
+void
+ipod_device_construct_paths(IpodDevice *device)
+{
+ int len;
+
+ g_return_if_fail(IS_IPOD_DEVICE(device));
+ g_return_if_fail(device->priv->mount_point != NULL);
+
+ len = strlen(device->priv->mount_point);
+ if(device->priv->mount_point[len - 1] == '/')
+ device->priv->mount_point[len - 1] = '\0';
+
+ if(strlen(device->priv->mount_point) == 0)
+ return;
+
+ device->priv->control_path = g_strdup_printf("%s/%s",
+ device->priv->mount_point, "iPod_Control/");
+}
+
+gchar *
+ipod_device_read_device_info_string(FILE *fd)
+{
+ gshort length;
+ gunichar2 *utf16;
+ gchar *utf8;
+
+ fread(&length, 1, sizeof(gshort), fd);
+
+ if(length <= 0)
+ return NULL;
+
+ utf16 = (gunichar2 *)g_malloc(length * sizeof(gunichar2));
+ fread(utf16, sizeof(gunichar2), length, fd);
+
+ if(utf16 == NULL)
+ return NULL;
+
+ utf8 = g_utf16_to_utf8(utf16, length, NULL, NULL, NULL);
+
+ g_free(utf16);
+ utf16 = NULL;
+
+ return utf8;
+}
+
+void
+ipod_device_write_device_info_string(gchar *str, FILE *fd)
+{
+ gunichar2 *unistr;
+ gshort length;
+
+ if(str == NULL)
+ return;
+
+ length = strlen(str);
+ unistr = g_utf8_to_utf16(str, length, NULL, NULL, NULL);
+
+ length = length > 0x198 ? 0x198 : length;
+
+ fwrite(&length, 2, 1, fd);
+ fwrite(unistr, 2, length, fd);
+
+ g_free(unistr);
+}
+
+gboolean
+ipod_device_read_sysinfo(IpodDevice *device)
+{
+ gchar *field_values[sizeof(sysinfo_field_names) + 1];
+ gchar *tmp, *path, buf[512];
+ gint i, name_len;
+ FILE *fd;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ path = g_strdup_printf("%sDevice/SysInfo",
+ device->priv->control_path);
+
+ fd = fopen(path, "r");
+ if(fd == NULL) {
+ g_free(path);
+ return FALSE;
+ }
+
+ while(fgets(buf, sizeof(buf), fd)) {
+ buf[strlen(buf) - 1] = '\0';
+
+ for(i = 0; sysinfo_field_names[i] != NULL; i++) {
+ name_len = strlen(sysinfo_field_names[i]);
+ if(strncasecmp(buf, sysinfo_field_names[i], name_len) == 0) {
+ field_values[i] = strdup(buf + name_len + 2);
+ if(strncasecmp(field_values[i], "0x", 2) == 0) {
+ if((tmp = strstr(field_values[i], "(")) != NULL) {
+ field_values[i] = tmp + 1;
+ field_values[i][strlen(field_values[i]) - 1] = '\0';
+ }
+ }
+
+ field_values[i] = g_strdup(field_values[i]);
+ }
+ }
+ }
+
+ fclose(fd);
+
+ device->priv->serial_number = sysinfo_arr_get_dup(field_values,
+ "pszSerialNumber");
+ device->priv->model_number = sysinfo_arr_get_dup(field_values,
+ "ModelNumStr");
+ device->priv->firmware_version = sysinfo_arr_get_dup(field_values,
+ "visibleBuildID");
+
+ g_free(path);
+
+ return TRUE;
+}
+
+gboolean
+ipod_device_info_load(IpodDevice *device)
+{
+ gchar *path;
+ FILE *fd;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ path = g_strdup_printf("%siTunes/DeviceInfo",
+ device->priv->control_path);
+
+ fd = fopen(path, "r");
+ if(fd == NULL) {
+ g_free(path);
+ return FALSE;
+ }
+
+ device->priv->device_name = ipod_device_read_device_info_string(fd);
+ if(device->priv->device_name == NULL)
+ device->priv->device_name = g_strdup("iPod");
+
+ fseek(fd, 0x200, SEEK_SET);
+ device->priv->user_name = ipod_device_read_device_info_string(fd);
+
+ fseek(fd, 0x400, SEEK_SET);
+ device->priv->host_name = ipod_device_read_device_info_string(fd);
+
+ fclose(fd);
+ g_free(path);
+
+ return TRUE;
+}
+
+gboolean
+ipod_device_detect_writeable(IpodDevice *device)
+{
+ FILE *fp;
+ gchar *itunes_dir, *music_dir, *itunesdb_path;
+ struct stat finfo;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ device->priv->can_write = FALSE;
+
+ itunes_dir = g_strdup_printf("%siTunes", device->priv->control_path);
+
+ if(!g_file_test(itunes_dir, G_FILE_TEST_IS_DIR)) {
+ if(g_mkdir_with_parents(itunes_dir, 0755) != 0) {
+ g_free(itunes_dir);
+ return FALSE;
+ }
+ }
+
+ itunesdb_path = g_strdup_printf("%s/iTunesDB", itunes_dir);
+
+ if((fp = fopen(itunesdb_path, "a+")) != NULL) {
+ device->priv->can_write = TRUE;
+ fclose(fp);
+
+ memset(&finfo, 0, sizeof(finfo));
+ if(stat(itunesdb_path, &finfo) == 0) {
+ if(finfo.st_size == 0) {
+ unlink(itunesdb_path);
+ }
+ }
+ } else {
+ g_free(itunes_dir);
+ g_free(itunesdb_path);
+ return FALSE;
+ }
+
+ music_dir = g_strdup_printf("%sMusic", device->priv->control_path);
+
+ if(!g_file_test(music_dir, G_FILE_TEST_IS_DIR)) {
+ device->priv->can_write = g_mkdir_with_parents(music_dir, 0755) == 0;
+ }
+
+ g_free(itunes_dir);
+ g_free(itunesdb_path);
+ g_free(music_dir);
+
+ return device->priv->can_write;
+}
+
+gint
+ipod_device_get_model_index_from_table(const gchar *_model_num);
+gint
+ipod_device_get_model_index_from_table(const gchar *_model_num)
+{
+ gint i;
+ gchar *model_num = g_strdup(_model_num);
+ gchar *p = model_num;
+
+ if(isalpha(model_num[0]))
+ *p++;
+
+ for(i = 2; ipod_model_table[i].model_number != NULL; i++) {
+ if(g_strncasecmp(p, ipod_model_table[i].model_number, 4) == 0) {
+ g_free(model_num);
+ return i;
+ }
+ }
+
+ g_free(model_num);
+ return 1;
+}
+
+guint
+ipod_device_detect_model(IpodDevice *device)
+{
+ gint i;
+ guint64 adv, act;
+ gint cap;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), 0);
+
+ device->priv->model_index = 0;
+
+ /* Shuffle! */
+ if(device->priv->model_number == NULL) {
+ for(i = 2; ipod_model_table[i].model_number != NULL; i++) {
+ if(ipod_model_table[i].model_type != MODEL_TYPE_SHUFFLE)
+ continue;
+
+ cap = ipod_model_table[i].capacity;
+ adv = cap * 1048576;
+ act = device->priv->volume_size;
+
+ if((adv - act) / 1048576 < 50) {
+ device->priv->model_index = i;
+ device->priv->model_number = g_strdup_printf("M%s",
+ ipod_model_table[i].model_number);
+
+ device->priv->adv_capacity = g_strdup_printf("%d %s",
+ cap < 1024 ? cap : cap / 1024,
+ cap < 1024 ? "MB" : "GB");
+ break;
+ }
+ }
+ } else {
+ /* Anything Else */
+ device->priv->model_index =
+ ipod_device_get_model_index_from_table(device->priv->model_number);
+
+ cap = ipod_model_table[device->priv->model_index].capacity;
+
+ device->priv->adv_capacity = g_strdup_printf("%d %s",
+ cap < 1024 ? cap : cap / 1024,
+ cap < 1024 ? "MB" : "GB");
+ }
+
+ return device->priv->model_index;
+}
+
+void
+ipod_device_restore_reboot_preferences(IpodDevice *device)
+{
+ gchar *backup_prefs, *prefs;
+
+ backup_prefs = g_strdup_printf("%s/.Reboot_Preferences",
+ device->priv->control_path);
+ prefs = g_strdup_printf("%s/Device/Preferences",
+ device->priv->control_path);
+
+ g_return_if_fail(IS_IPOD_DEVICE(device));
+
+ if(g_file_test(backup_prefs, G_FILE_TEST_EXISTS)) {
+ unlink(prefs);
+ g_rename(backup_prefs, prefs);
+ }
+}
+
+gboolean
+ipod_device_detect_volume_info(IpodDevice *device)
+{
+#if HAVE_LIBHAL
+ LibHalContext *hal_context;
+ gchar **volumes;
+ gchar *hd_mount_point, *hd_device_path;
+ gchar *hd_hal_id = NULL, *maybe_hd_hal_id = NULL;
+ gint volume_count, i;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+ hal_context = device->priv->hal_context;
+
+ g_free_if_not_null(device->priv->device_path);
+ g_free_if_not_null(device->priv->mount_point);
+ device->priv->volume_size = 0;
+
+ if(!libhal_device_exists(hal_context, device->priv->hal_volume_id, NULL)) {
+ /* For testing/debugging... we don't have a real device, but
+ the location may be a directory containing an iPod image */
+ if(g_strncasecmp(device->priv->hal_volume_id, "/dev/", 5) == 0 ||
+ device->priv->hal_volume_id[0] != '/')
+ return FALSE;
+
+ g_free_if_not_null(device->priv->mount_point);
+ device->priv->mount_point = g_strdup(device->priv->hal_volume_id);
+
+ g_free_if_not_null(device->priv->hal_volume_id);
+ g_free_if_not_null(device->priv->device_path);
+
+ /* Let's find out about the disk drive containing our image */
+
+ volumes = libhal_manager_find_device_string_match(hal_context,
+ "info.category", "volume", &volume_count, NULL);
+
+ for(i = 0; i < volume_count; i++) {
+ if(!libhal_device_property_exists(hal_context,
+ volumes[i], "volume.is_mounted", NULL) ||
+ !libhal_device_get_property_bool(hal_context,
+ volumes[i], "volume.is_mounted", NULL)) {
+ continue;
+ }
+
+ hd_mount_point = libhal_device_get_property_string(hal_context,
+ volumes[i], "volume.mount_point", NULL);
+
+ if(g_strncasecmp(hd_mount_point, device->priv->mount_point,
+ strlen(hd_mount_point)) != 0)
+ continue;
+
+ if(g_strcasecmp(hd_mount_point, "/") == 0)
+ maybe_hd_hal_id = volumes[i];
+ else
+ hd_hal_id = volumes[i];
+ }
+
+ if(hd_hal_id == NULL && maybe_hd_hal_id != NULL)
+ hd_hal_id = maybe_hd_hal_id;
+
+ if(hd_hal_id == NULL) {
+ libhal_free_string_array(volumes);
+ return FALSE;
+ }
+
+ if(!libhal_device_exists(hal_context, hd_hal_id, NULL)) {
+ libhal_free_string_array(volumes);
+ return FALSE;
+ }
+
+ hd_device_path = libhal_device_get_property_string(hal_context,
+ hd_hal_id, "block.device", NULL);
+
+ device->priv->hal_volume_id = g_strdup(hd_hal_id);
+ device->priv->device_path = g_strdup(hd_device_path);
+ device->priv->volume_size = libhal_device_get_property_uint64(
+ hal_context, hd_hal_id, "volume.size", NULL);
+
+ libhal_free_string_array(volumes);
+
+ return TRUE;
+ }
+
+ if(!libhal_device_property_exists(hal_context,
+ device->priv->hal_volume_id, "volume.is_mounted", NULL)
+ || !libhal_device_get_property_bool(hal_context,
+ device->priv->hal_volume_id, "volume.is_mounted", NULL)) {
+ return FALSE;
+ }
+
+ if(libhal_device_property_exists(hal_context, device->priv->hal_volume_id,
+ "block.device", NULL))
+ device->priv->device_path = libhal_device_get_property_string(
+ hal_context, device->priv->hal_volume_id, "block.device", NULL);
+
+ if(libhal_device_property_exists(hal_context, device->priv->hal_volume_id,
+ "volume.mount_point", NULL))
+ device->priv->mount_point = libhal_device_get_property_string(
+ hal_context, device->priv->hal_volume_id,
+ "volume.mount_point", NULL);
+
+ if(libhal_device_property_exists(hal_context, device->priv->hal_volume_id,
+ "volume.size", NULL))
+ device->priv->volume_size = libhal_device_get_property_uint64(
+ hal_context, device->priv->hal_volume_id, "volume.size", NULL);
+
+ if(libhal_device_property_exists(hal_context, device->priv->hal_volume_id,
+ "volume.uuid", NULL)) {
+ device->priv->volume_uuid = libhal_device_get_property_string(
+ hal_context, device->priv->hal_volume_id,
+ "volume.uuid", NULL);
+
+ if(strlen(device->priv->volume_uuid) == 0) {
+ g_free(device->priv->volume_uuid);
+ device->priv->volume_uuid = NULL;
+ }
+ }
+
+ if(libhal_device_property_exists(hal_context, device->priv->hal_volume_id,
+ "volume.label", NULL))
+ device->priv->volume_label = libhal_device_get_property_string(
+ hal_context, device->priv->hal_volume_id,
+ "volume.label", NULL);
+#endif
+ return TRUE;
+}
+
+void
+ipod_device_detect_volume_used(IpodDevice *device)
+{
+ device->priv->volume_used =
+ ipod_device_dir_size(device->priv->mount_point);
+ device->priv->volume_available = device->priv->volume_size -
+ device->priv->volume_used;
+}
+
+void
+_ipod_device_dir_size(const gchar *path, guint64 *total_size);
+void
+_ipod_device_dir_size(const gchar *path, guint64 *total_size)
+{
+ GDir *dir;
+ const gchar *next_path;
+ gchar *fullpath;
+ struct stat finfo;
+
+ if((dir = g_dir_open(path, 0, NULL)) == NULL)
+ return;
+
+ while((next_path = g_dir_read_name(dir)) != NULL) {
+ fullpath = g_strdup_printf("%s/%s", path, next_path);
+
+ if(g_file_test(fullpath, G_FILE_TEST_IS_DIR))
+ _ipod_device_dir_size(fullpath, total_size);
+ else
+ *total_size += stat(fullpath, &finfo) == 0 ? finfo.st_size : 0;
+
+ g_free(fullpath);
+ fullpath = NULL;
+ }
+
+ g_dir_close(dir);
+}
+
+guint64
+ipod_device_dir_size(const gchar *path)
+{
+ guint64 retsize, *size = g_new(guint64, 1);
+ *size = 0;
+ _ipod_device_dir_size(path, size);
+ retsize = *size;
+ g_free(size);
+ return retsize;
+}
+
+gboolean
+ipod_device_has_open_fd(IpodDevice *device)
+{
+ GDir *dir, *fddir;
+ gchar *fdpath, *fdidpath, *realpath;
+ const gchar *procpath, *fdid;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ if((dir = g_dir_open("/proc", 0, NULL)) == NULL)
+ return FALSE;
+
+ while((procpath = g_dir_read_name(dir)) != NULL) {
+ if(atoi(procpath) <= 0)
+ continue;
+
+ fdpath = g_strdup_printf("/proc/%s/fd", procpath);
+
+ if(!g_file_test(fdpath, G_FILE_TEST_IS_DIR)) {
+ g_free(fdpath);
+ continue;
+ }
+
+ if((fddir = g_dir_open(fdpath, 0, NULL)) == NULL) {
+ g_free(fdpath);
+ continue;
+ }
+
+ while((fdid = g_dir_read_name(fddir)) != NULL) {
+ fdidpath = g_strdup_printf("%s/%s", fdpath, fdid);
+ realpath = g_file_read_link(fdidpath, NULL);
+
+ if(realpath == NULL) {
+ g_free(fdidpath);
+ continue;
+ }
+
+ if(g_strncasecmp(realpath, device->priv->mount_point,
+ strlen(device->priv->mount_point)) == 0) {
+ g_dir_close(fddir);
+ g_dir_close(dir);
+ g_free(realpath);
+ g_free(fdidpath);
+ return TRUE;
+ }
+
+ g_free(realpath);
+ g_free(fdidpath);
+ }
+
+ g_dir_close(fddir);
+ }
+
+ g_dir_close(dir);
+
+ return FALSE;
+}
+
+#if HAVE_LIBHAL
+/* modded from g-v-m */
+static int
+ipod_device_run_command(IpodDevice *device, const char *command,
+ GError **error_out)
+{
+ char *path;
+ const char *inptr, *start;
+ GError *error = NULL;
+ GString *exec;
+ char *argv[4];
+ int status = 0;
+
+ exec = g_string_new(NULL);
+
+ /* perform s/%d/device/, s/%m/mount_point/ and s/%h/udi/ */
+ start = inptr = command;
+ while((inptr = strchr (inptr, '%')) != NULL) {
+ g_string_append_len(exec, start, inptr - start);
+ inptr++;
+ switch (*inptr) {
+ case 'd':
+ g_string_append(exec, device->priv->device_path ?
+ device->priv->device_path : "");
+ break;
+ case 'm':
+ if(device->priv->mount_point) {
+ path = g_shell_quote(device->priv->mount_point);
+ g_string_append(exec, path);
+ g_free(path);
+ } else {
+ g_string_append(exec, "\"\"");
+ }
+ break;
+ case 'h':
+ g_string_append(exec, device->priv->hal_volume_id);
+ break;
+ case '%':
+ g_string_append_c(exec, '%');
+ break;
+ default:
+ g_string_append_c(exec, '%');
+ if(*inptr)
+ g_string_append_c(exec, *inptr);
+ break;
+ }
+
+ if(*inptr)
+ inptr++;
+ start = inptr;
+ }
+
+ g_string_append(exec, start);
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = exec->str;
+ argv[3] = NULL;
+
+ g_spawn_sync(g_get_home_dir(), argv, NULL, 0, NULL,
+ NULL, NULL, NULL, &status, &error);
+
+ if(error != NULL)
+ g_propagate_error(error_out, error);
+
+ g_string_free(exec, TRUE);
+
+ return status;
+}
+#endif
+
+/* PUBLIC METHODS */
+
+IpodDevice *
+ipod_device_new(gchar *hal_volume_id)
+{
+ IpodDevice *device = g_object_new(TYPE_IPOD_DEVICE,
+ "hal-volume-id", hal_volume_id, NULL);
+
+ if(!device->priv->is_ipod) {
+ g_object_unref(device);
+ return NULL;
+ }
+
+ return device;
+}
+
+gboolean
+ipod_device_rescan_disk(IpodDevice *device)
+{
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+ ipod_device_detect_volume_used(device);
+ return TRUE;
+}
+
+guint
+ipod_device_eject(IpodDevice *device, GError **error_out)
+{
+#if HAVE_LIBHAL
+ gint exit_status;
+ GError *error = NULL;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), EJECT_ERROR);
+ g_return_val_if_fail(device->priv->is_ipod, EJECT_ERROR);
+
+ if(ipod_device_has_open_fd(device))
+ return EJECT_BUSY;
+
+#ifdef ASSUME_SUBMOUNT
+ sync();
+
+ exit_status = ipod_device_run_command(device, EJECT_COMMAND, &error);
+ if(error) {
+ g_propagate_error(error_out, error);
+ return EJECT_ERROR;
+ }
+
+ return exit_status == 0 ? EJECT_OK : EJECT_ERROR;
+#endif
+
+ exit_status = ipod_device_run_command(device, UNMOUNT_COMMAND, &error);
+
+ if(!error && exit_status == 0) {
+ exit_status = ipod_device_run_command(device, EJECT_COMMAND, &error);
+ if(error) {
+ g_propagate_error(error_out, error);
+ return EJECT_ERROR;
+ }
+
+ return exit_status == 0 ? EJECT_OK : EJECT_ERROR;
+ }
+
+ if(error)
+ g_propagate_error(error_out, error);
+
+ return EJECT_ERROR;
+}
+
+guint
+ipod_device_reboot(IpodDevice *device, GError **error_out)
+{
+ gchar *sysinfo, *prefs, *backup_prefs, *devpath;
+ gboolean can_eject = TRUE;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), EJECT_ERROR);
+ g_return_val_if_fail(device->priv->is_ipod, EJECT_ERROR);
+
+ devpath = g_strdup_printf("%s/Device/", device->priv->control_path);
+ sysinfo = g_strdup_printf("%sSysInfo", devpath);
+ prefs = g_strdup_printf("%sPreferences", devpath);
+ backup_prefs = g_strdup_printf("%s/.Reboot_Preferences",
+ device->priv->control_path);
+
+ if(g_file_test(sysinfo, G_FILE_TEST_EXISTS))
+ can_eject = unlink(sysinfo) == 0;
+
+ if(g_file_test(prefs, G_FILE_TEST_EXISTS) && can_eject) {
+ if(g_file_test(backup_prefs, G_FILE_TEST_EXISTS))
+ unlink(backup_prefs);
+
+ g_rename(prefs, backup_prefs);
+ unlink(prefs);
+
+ can_eject = TRUE;
+ }
+
+ if(can_eject)
+ can_eject = rmdir(devpath) == 0;
+
+ g_free(devpath);
+ g_free(sysinfo);
+ g_free(prefs);
+ g_free(backup_prefs);
+
+ if(can_eject)
+ return ipod_device_eject(device, error_out);
+
+ g_propagate_error(error_out, g_error_new(g_quark_from_string("UNLINK"),
+ errno, "Could not remove file to initiate iPod reboot"));
+#endif
+ return EJECT_ERROR;
+}
+
+GList *
+_ipod_device_list_devices(gboolean create_device);
+GList *
+_ipod_device_list_devices(gboolean create_device)
+{
+ LibHalContext *hal_context;
+ GList *finalDevices = NULL;
+ gchar **ipods, **volumes;
+ gint ipod_count, volume_count, i, j;
+ IpodDevice *ipod;
+ gboolean validIpod = FALSE;
+
+ hal_context = ipod_device_hal_initialize();
+ if(hal_context == NULL)
+ return NULL;
+
+ ipods = libhal_manager_find_device_string_match(hal_context,
+ "info.product", "iPod", &ipod_count, NULL);
+
+ for(i = 0; i < ipod_count; i++) {
+ volumes = libhal_manager_find_device_string_match(hal_context,
+ "info.parent", ipods[i], &volume_count, NULL);
+
+ for(j = 0; j < volume_count; j++) {
+ if(!libhal_device_property_exists(hal_context,
+ volumes[j], "volume.is_mounted", NULL)
+ || !libhal_device_get_property_bool(hal_context,
+ volumes[j], "volume.is_mounted", NULL))
+ continue;
+
+ if(!create_device) {
+ finalDevices = g_list_append(finalDevices,
+ g_strdup(volumes[j]));
+ continue;
+ }
+
+ if((ipod = ipod_device_new(volumes[j])) == NULL)
+ continue;
+
+ g_object_get(ipod, "is-ipod", &validIpod, NULL);
+ if(validIpod)
+ finalDevices = g_list_append(finalDevices, ipod);
+ }
+ }
+
+ libhal_ctx_shutdown(hal_context, NULL);
+ libhal_ctx_free(hal_context);
+
+ return finalDevices;
+}
+
+GList *
+ipod_device_list_devices()
+{
+ return _ipod_device_list_devices(TRUE);
+}
+
+GList *
+ipod_device_list_device_udis()
+{
+ return _ipod_device_list_devices(FALSE);
+}
+
+gboolean
+ipod_device_save(IpodDevice *device, GError **error_out)
+{
+ FILE *fd;
+ gchar *path, *itunes_dir;
+ gchar bs = 0;
+ GError *error = NULL;
+
+ g_return_val_if_fail(IS_IPOD_DEVICE(device), FALSE);
+
+ itunes_dir = g_strdup_printf("%siTunes", device->priv->control_path);
+ path = g_strdup_printf("%s/DeviceInfo", itunes_dir);
+
+ if(!g_file_test(itunes_dir, G_FILE_TEST_IS_DIR)) {
+ if(g_mkdir_with_parents(itunes_dir, 0744) != 0) {
+ if(error_out != NULL) {
+ error = g_error_new(g_quark_from_static_string("IPOD_DEVICE"),
+ ERROR_SAVE, "Could not create iTunes Directory: %s",
+ itunes_dir);
+ g_propagate_error(error_out, error);
+ }
+
+ g_free(path);
+ g_free(itunes_dir);
+
+ return FALSE;
+ }
+ }
+
+ fd = fopen(path, "w+");
+ if(fd == NULL) {
+ if(error_out != NULL) {
+ error = g_error_new(g_quark_from_static_string("IPOD_DEVICE"),
+ ERROR_SAVE, "Could not save DeviceInfo file: %s", path);
+ g_propagate_error(error_out, error);
+ }
+
+ g_free(path);
+ g_free(itunes_dir);
+
+ return FALSE;
+ }
+
+ ipod_device_write_device_info_string(device->priv->device_name, fd);
+
+ fseek(fd, 0x200, SEEK_SET);
+ ipod_device_write_device_info_string(device->priv->user_name, fd);
+
+ fseek(fd, 0x400, SEEK_SET);
+ ipod_device_write_device_info_string(device->priv->host_name, fd);
+
+ fseek(fd, 0X5FF, SEEK_SET);
+ fwrite(&bs, 1, 1, fd);
+
+ fclose(fd);
+
+ g_free(path);
+ g_free(itunes_dir);
+
+ return TRUE;
+}
+
+void
+ipod_device_debug(IpodDevice *device)
+{
+ static const gchar *generation_names [] = {
+ "Unknown",
+ "First",
+ "Second",
+ "Third",
+ "Fourth"
+ };
+
+ gchar *device_path, *mount_point, *control_path, *hal_id;
+ gchar *model_number, *adv_capacity, *model_string;
+ guint model, generation;
+ gboolean is_new, can_write;
+ gchar *serial_number, *firmware_version;
+ guint64 volume_size, volume_used, volume_available;
+ gchar *volume_uuid, *volume_label;
+ gchar *device_name, *user_name, *host_name;
+
+ g_return_if_fail(IS_IPOD_DEVICE(device));
+
+ g_object_get(device,
+ "device-path", &device_path,
+ "mount-point", &mount_point,
+ "control-path", &control_path,
+ "hal-volume-id", &hal_id,
+ "model-number", &model_number,
+ "device-model", &model,
+ "device-model-string", &model_string,
+ "device-generation", &generation,
+ "advertised-capacity", &adv_capacity,
+ "is-new", &is_new,
+ "can-write", &can_write,
+ "serial-number", &serial_number,
+ "firmware-version", &firmware_version,
+ "volume-size", &volume_size,
+ "volume-used", &volume_used,
+ "volume-available", &volume_available,
+ "volume_uuid", &volume_uuid,
+ "volume-label", &volume_label,
+ "device-name", &device_name,
+ "user-name", &user_name,
+ "host-name", &host_name,
+ NULL);
+
+ g_printf("Path Info\n");
+ g_printf(" Device Path: %s\n", device_path);
+ g_printf(" Mount Point: %s\n", mount_point);
+ g_printf(" Control Path: %s\n", control_path);
+ g_printf(" HAL ID: %s\n", hal_id);
+
+ g_printf("Device Info\n");
+ g_printf(" Model Number: %s\n", model_number);
+ g_printf(" Device Model: %s\n", model_string);
+ g_printf(" iPod Generation: %s\n", generation_names[generation]);
+ g_printf(" Adv. Capacity: %s\n", adv_capacity);
+ g_printf(" Is New: %s\n", is_new ? "YES" : "NO");
+ g_printf(" Writeable: %s\n", can_write ? "YES" : "NO");
+ g_printf(" Serial Number: %s\n", serial_number);
+ g_printf(" Firmware Version: %s\n", firmware_version);
+ g_printf("Volume Info\n");
+ g_printf(" Volume Size: %lld\n", volume_size);
+ g_printf(" Volume Used: %lld\n", volume_used);
+ g_printf(" Available %lld\n", volume_available);
+ g_printf(" UUID: %s\n", volume_uuid);
+ g_printf(" Label %s\n", volume_label);
+ g_printf("User-Provided Info\n");
+ g_printf(" Device Name: %s\n", device_name);
+ g_printf(" User Name: %s\n", user_name);
+ g_printf(" Host Name: %s\n", host_name);
+
+ g_printf("\n");
+ fflush(stdout);
+}
diff --git a/src/ipod-device.h b/src/ipod-device.h
new file mode 100644
index 0000000..68b3f2a
--- /dev/null
+++ b/src/ipod-device.h
@@ -0,0 +1,182 @@
+/* Time-stamp: <2005-10-10 01:23:28 jcs>
+|
+| Copyright (C) 2005 Jorg Schuler <jcsjcs at users sourceforge net>
+| Part of the gtkpod project.
+|
+| URL: http://www.gtkpod.org/
+| URL: http://gtkpod.sourceforge.net/
+|
+|
+| The source is taken from libipoddevice, CVS version October 8 2005
+| (http://64.14.94.162/index.php/Libipoddevice).
+|
+| I decided not to make libgpod dependent on libipoddevice because
+| the latter depends on libraries not widely available yet (libhal >=
+| 0.5.2, glib >= 2.8). It is planned to replace these files with a
+| libipoddevice dependence at some later time.
+|
+| The following changes were done:
+|
+| - libhal becomes optional (see #if HAVE_LIBHAL sections)
+| - publicly available functions were renamed from ipod_device_...()
+| to itdb_device_...()
+|
+| Because of these changes only a limited amount of functionality is
+| available if libhal is not present. In particular the following
+| functions are non-functional:
+|
+| GList *ipod_device_list_devices(void);
+| GList *ipod_device_list_device_udis(void);
+| guint ipod_device_eject(IpodDevice *device, GError **error);
+| guint ipod_device_reboot(IpodDevice *device, GError **error_out);
+|
+| Only the following properties are available:
+|
+|
+| device-model
+| device-model-string
+| device-generation
+| advertised-capacity
+| is-new
+| can-write
+| serial-number
+| firmware-version
+| device-name
+| user-name
+| host-name
+|
+|
+| $Id$
+*/
+/* ex: set ts=4: */
+/***************************************************************************
+* ipod-device.h
+* Copyright (C) 2005 Novell
+* Written by Aaron Bockover <aaron@aaronbock.net>
+****************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#ifndef IPOD_DEVICE_H
+#define IPOD_DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if HAVE_LIBHAL
+# include <libhal.h>
+# include <dbus/dbus.h>
+# include <dbus/dbus-glib.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define TYPE_IPOD_DEVICE (ipod_device_get_type ())
+#define IPOD_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_IPOD_DEVICE, IpodDevice))
+#define IPOD_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TYPE_IPOD_DEVICE, IpodDeviceClass))
+#define IS_IPOD_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_IPOD_DEVICE))
+#define IS_IPOD_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TYPE_IPOD_DEVICE))
+#define IPOD_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_IPOD_DEVICE, IpodDeviceClass))
+
+typedef struct IpodDevicePrivate IpodDevicePrivate;
+
+typedef struct {
+ GObject parent;
+ IpodDevicePrivate *priv;
+} IpodDevice;
+
+typedef struct {
+ GObjectClass parent_class;
+} IpodDeviceClass;
+
+enum {
+ UNKNOWN_GENERATION,
+ FIRST_GENERATION,
+ SECOND_GENERATION,
+ THIRD_GENERATION,
+ FOURTH_GENERATION
+};
+
+enum {
+ MODEL_TYPE_INVALID,
+ MODEL_TYPE_UNKNOWN,
+ MODEL_TYPE_COLOR,
+ MODEL_TYPE_COLOR_U2,
+ MODEL_TYPE_REGULAR,
+ MODEL_TYPE_REGULAR_U2,
+ MODEL_TYPE_MINI,
+ MODEL_TYPE_MINI_BLUE,
+ MODEL_TYPE_MINI_PINK,
+ MODEL_TYPE_MINI_GREEN,
+ MODEL_TYPE_MINI_GOLD,
+ MODEL_TYPE_SHUFFLE,
+ MODEL_TYPE_NANO_WHITE,
+ MODEL_TYPE_NANO_BLACK
+};
+
+enum {
+ EJECT_OK,
+ EJECT_ERROR,
+ EJECT_BUSY
+};
+
+enum {
+ PROP_IPOD_0,
+ PROP_HAL_VOLUME_ID,
+ PROP_HAL_CONTEXT,
+ PROP_MOUNT_POINT,
+ PROP_DEVICE_PATH,
+ PROP_CONTROL_PATH,
+ PROP_DEVICE_MODEL,
+ PROP_DEVICE_MODEL_STRING,
+ PROP_DEVICE_GENERATION,
+ PROP_ADVERTISED_CAPACITY,
+ PROP_DEVICE_NAME,
+ PROP_USER_NAME,
+ PROP_HOST_NAME,
+ PROP_VOLUME_SIZE,
+ PROP_VOLUME_AVAILABLE,
+ PROP_VOLUME_USED,
+ PROP_IS_IPOD,
+ PROP_IS_NEW,
+ PROP_SERIAL_NUMBER,
+ PROP_MODEL_NUMBER,
+ PROP_FIRMWARE_VERSION,
+ PROP_VOLUME_UUID,
+ PROP_VOLUME_LABEL,
+ PROP_CAN_WRITE
+};
+
+enum {
+ ERROR_SAVE
+};
+
+GType itdb_device_get_type(void);
+IpodDevice *itdb_device_new(gchar *mount_point);
+gboolean itdb_device_rescan_disk(IpodDevice *device);
+guint itdb_device_eject(IpodDevice *device, GError **error);
+guint itdb_device_reboot(IpodDevice *device, GError **error_out);
+void itdb_device_debug(IpodDevice *device);
+gboolean itdb_device_save(IpodDevice *device, GError **error);
+GList *itdb_device_list_devices(void);
+GList *itdb_device_list_device_udis(void);
+
+#endif /* IPOD_DEVICE_H */
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index f5f1bd6..1ec1b8d 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -1,4 +1,4 @@
-/* Time-stamp: <2005-10-02 20:14:55 jcs>
+/* Time-stamp: <2005-10-09 22:09:01 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -8,7 +8,7 @@
|
| Much of the code in this file has originally been ported from the
| perl script "mktunes.pl" (part of the gnupod-tools collection)
-| written by Adrian Ulrich <pab at blinkenlights.ch>.
+| written by Adrian Ulrich <pab at blinkenlights.ch>:
|
| gnupod-tools: http://www.blinkenlights.ch/cgi-bin/fm.pl?get=ipod
|
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 16d9214..0b7bfe6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,20 +4,20 @@ else
TESTTHUMBS=
endif
-noinst_PROGRAMS=test-itdb $(TESTTHUMBS)
+noinst_PROGRAMS=test-ipod-device test-itdb $(TESTTHUMBS)
INCLUDES=$(LIBGPOD_CFLAGS) -I$(top_srcdir)/src -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
-LIBS=$(LIBGPOD_LIBS)
+LIBS=$(LIBGPOD_LIBS) $(top_builddir)/src/libgpod.la
test_itdb_SOURCES = itdb_main.c
-test_itdb_LDADD = $(top_builddir)/src/libgpod.la
+test_itdb_LDADD =
if HAVE_GDKPIXBUF
test_thumbnails_SOURCES = test-covers.c
test_thumbnails_CFLAGS = $(GDKPIXBUF_CFLAGS) $(AM_CFLAGS)
-test_thumbnails_LDADD = $(top_builddir)/src/libgpod.la $(GDKPIXBUF_LIBS)
+test_thumbnails_LDADD = $(GDKPIXBUF_LIBS)
test_write_thumbnails_SOURCES = test-write-covers.c
test_write_thumbnails_CFLAGS = $(GDKPIXBUF_CFLAGS) $(AM_CFLAGS)
-test_write_thumbnails_LDADD = $(top_builddir)/src/libgpod.la $(GDKPIXBUF_LIBS)
+test_write_thumbnails_LDADD = $(GDKPIXBUF_LIBS)
endif
diff --git a/tests/test-ipod-device.c b/tests/test-ipod-device.c
new file mode 100644
index 0000000..0ffefac
--- /dev/null
+++ b/tests/test-ipod-device.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2005, Jorg Schuler <jcsjcs at users.sourceforge.net>
+ * All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the <ORGANIZATION> nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ipod-device.h"
+#include <locale.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ IpodDevice *device=NULL;
+
+
+ if (argc < 2) {
+ g_print ("Usage: %s mountpoint\n", argv[0]);
+ return 1;
+ }
+ setlocale (LC_ALL, "");
+ g_type_init ();
+
+ device = itdb_device_new (argv[1]);
+
+ if (!device)
+ {
+ g_print ("Error accessing iPod at '%s'\n", argv[1]);
+ return 0;
+ }
+
+ /* Have a look at itdb_device_debug() in ipod-device.c to see how
+ the information is retrieved */
+ itdb_device_debug (device);
+
+ /* This is how to free the memory */
+ g_object_unref (device);
+
+ return 0;
+}