hythmbox-2.98/plugins/ipod/rb-ipod-helpers.c

No issues found

  1 /*
  2  * rb-ipod-helpers.c
  3  *
  4  * Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
  5  * Copyright (C) 2006 James "Doc" Livingston
  6  * Copyright (C) 2008 Christophe Fergeau <teuf@gnome.org>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2, or (at your option)
 11  * any later version.
 12  *
 13  * The Rhythmbox authors hereby grant permission for non-GPL compatible
 14  * GStreamer plugins to be used and distributed together with GStreamer
 15  * and Rhythmbox. This permission is above and beyond the permissions granted
 16  * by the GPL license by which Rhythmbox is covered. If you modify this code
 17  * you may extend this exception to your version of the code, but you are not
 18  * obligated to do so. If you do not wish to do so, delete this exception
 19  * statement from your version.
 20  *
 21  * This program is distributed in the hope that it will be useful,
 22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 24  * GNU General Public License for more details.
 25  *
 26  * You should have received a copy of the GNU General Public License
 27  * along with this program; if not, write to the Free Software
 28  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 29  */
 30 
 31 #ifdef HAVE_CONFIG_H
 32 #include <config.h>
 33 #endif
 34 
 35 #include <string.h>
 36 
 37 #include <glib/gi18n.h>
 38 #include <gtk/gtk.h>
 39 #include <gpod/itdb.h>
 40 
 41 #include "rb-ipod-helpers.h"
 42 #include "rb-util.h"
 43 #include "rb-builder-helpers.h"
 44 
 45 #include "rb-debug.h"
 46 #include "rb-dialog.h"
 47 
 48 
 49 enum {
 50       COL_INFO = 0,
 51 };
 52 
 53 static gchar *ipod_info_to_string (const Itdb_IpodInfo *info)
 54 {
 55 	if (info->capacity >= 1) {   /* size in GB */
 56 		return g_strdup_printf ("%2.0f GB %s", info->capacity,
 57 					itdb_info_get_ipod_model_name_string (info->ipod_model));
 58 	} else if (info->capacity > 0) {   /* size in MB */
 59 		return g_strdup_printf ("%3.0f MB %s", info->capacity * 1024,
 60 					itdb_info_get_ipod_model_name_string (info->ipod_model));
 61 	} else {   /* no capacity information available */
 62 		return g_strdup_printf ("%s",
 63 					itdb_info_get_ipod_model_name_string (info->ipod_model));
 64 	}
 65 }
 66 
 67 static double 
 68 get_rounded_ipod_capacity (const char *mountpoint)
 69 {
 70         guint64 capacity;
 71 
 72         capacity = rb_ipod_helpers_get_capacity (mountpoint);
 73         capacity += (1000*1000*500 - 1);
 74         capacity -= (capacity % (1000*1000*500));
 75         return (double)capacity/(1000.0*1000*1000);
 76 }
 77 
 78 static void
 79 set_cell (GtkCellLayout   *cell_layout,
 80 	  GtkCellRenderer *cell,
 81 	  GtkTreeModel    *tree_model,
 82 	  GtkTreeIter     *iter,
 83 	  gpointer         data)
 84 {
 85 	gboolean header;
 86 	gchar *text;
 87 	Itdb_IpodInfo *info;
 88 
 89 	gtk_tree_model_get (tree_model, iter, COL_INFO, &info, -1);
 90 	g_return_if_fail (info);
 91 
 92 	header = gtk_tree_model_iter_has_child (tree_model, iter);
 93 
 94 	if (header) {
 95 		text = g_strdup (
 96 				 itdb_info_get_ipod_generation_string (info->ipod_generation));
 97 	} else {
 98 		text = ipod_info_to_string (info);
 99 	}
100 
101 	g_object_set (cell,
102 		      "sensitive", !header,
103 		      "text", text,
104 		      NULL);
105 	g_free (text);
106 }
107 
108 static gboolean
109 model_equals (gconstpointer a, gconstpointer b)
110 {
111 	const Itdb_IpodInfo *lhs = (const Itdb_IpodInfo *)a;
112 	const Itdb_IpodInfo *rhs = (const Itdb_IpodInfo *)b;
113 
114 	return !((lhs->capacity == rhs->capacity) 
115 		 && (lhs->ipod_model == rhs->ipod_model) 
116 		 && (lhs->ipod_generation == rhs->ipod_generation));
117 }
118 
119 static GHashTable *
120 build_model_table (const char *mount_path)
121 {
122 	const Itdb_IpodInfo *table;
123 	const Itdb_IpodInfo *model_info;
124 	GHashTable *models;
125 	gdouble ipod_capacity;
126 
127 	ipod_capacity = get_rounded_ipod_capacity (mount_path);
128 	models = g_hash_table_new_full (g_int_hash, g_int_equal,
129 					NULL, (GDestroyNotify)g_list_free);
130 	table = itdb_info_get_ipod_info_table ();
131 	for (model_info = table;
132 	     model_info->model_number != NULL;
133 	     model_info++) {
134 		GList *infos;
135 
136 		infos = g_hash_table_lookup (models,
137 					     &model_info->ipod_generation);
138 		if (g_list_find_custom (infos, model_info, model_equals)) {
139 			continue;
140 		}
141 		if (model_info->capacity == ipod_capacity) {
142 			/* Steal the key from the hash table since we don't 
143 			 * want 'infos' to be g_list_freed by the hash
144 			 * table destroy notify function
145 			 */
146 			g_hash_table_steal (models,
147 					    &model_info->ipod_generation);
148 			infos = g_list_prepend (infos, (gpointer)model_info);
149 
150 			g_hash_table_insert (models, 
151 					     (gpointer)&model_info->ipod_generation, 
152 					     infos);
153 		}
154 	}
155 
156 	return models;
157 }
158 
159 struct FillModelContext {
160 	GtkWidget *combo;
161 	GtkTreeStore *store;
162 	const Itdb_IpodInfo *ipod_info;
163 };
164 
165 static void 
166 fill_one_generation (gpointer key, gpointer value, gpointer data)
167 {
168 	GList *infos;
169 	GList *it;
170 	Itdb_IpodGeneration generation;
171 	gboolean first;
172 	GtkTreeIter iter;
173 	struct FillModelContext *ctx;
174 
175 	ctx = (struct FillModelContext *)data;
176 	infos = (GList *)value;
177 	generation = *(Itdb_IpodGeneration*)key;
178 
179 	first = TRUE;
180 	for (it = infos; it != NULL; it = it->next) {
181 		const Itdb_IpodInfo *info;
182 		GtkTreeIter iter_child;
183 
184 		info = (const Itdb_IpodInfo *)it->data;
185 		g_assert (info->ipod_generation == generation);
186 
187 		if (first) {
188 			gtk_tree_store_append (ctx->store, &iter, NULL);
189 			gtk_tree_store_set (ctx->store, &iter, 
190 					    COL_INFO, info, -1);
191 			first = FALSE;
192 		}
193 		gtk_tree_store_append (ctx->store, &iter_child, &iter);
194 		gtk_tree_store_set (ctx->store, &iter_child, 
195 				    COL_INFO, info, -1);
196 		if (info == ctx->ipod_info) {
197 			gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ctx->combo), 
198 						       &iter_child);
199 		}
200 	}
201 }
202 
203 void
204 rb_ipod_helpers_fill_model_combo (GtkWidget *combo, const char *mount_path)
205 {
206 	GHashTable *models;
207 	Itdb_Device *device;
208 	GtkTreeStore *store;
209 	const Itdb_IpodInfo *ipod_info;
210 	GtkCellRenderer *renderer;
211 	struct FillModelContext ctx;
212 
213 	device = itdb_device_new ();
214 	itdb_device_set_mountpoint (device, mount_path);
215 	itdb_device_read_sysinfo (device);
216 	ipod_info = itdb_device_get_ipod_info (device);
217 	itdb_device_free (device);
218 
219 	store = gtk_tree_store_new (1, G_TYPE_POINTER);
220 	gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
221 
222 	ctx.combo = combo;
223 	ctx.store = store;
224 	ctx.ipod_info = ipod_info;
225 	models = build_model_table (mount_path);
226 	g_hash_table_foreach (models, fill_one_generation, &ctx);
227 	g_hash_table_destroy (models);
228 	g_object_unref (store);
229 
230 	gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
231 
232 	renderer = gtk_cell_renderer_text_new ();
233 	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
234 	gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
235 					    renderer,
236 					    set_cell,
237 					    NULL, NULL);
238 }
239 
240 static gchar *
241 rb_ipod_helpers_get_itunesdb_path (GMount *mount)
242 {
243         GFile *root;
244         gchar *mount_point;
245         gchar *result = NULL;
246 
247         root = g_mount_get_root (mount);
248         if (root != NULL) {
249                 mount_point = g_file_get_path (root);
250                 if (mount_point != NULL) {
251                         result = itdb_get_itunesdb_path (mount_point);
252                 }
253 
254                 g_free (mount_point);
255                 g_object_unref (root);
256         }
257 
258         return result;
259 }
260 
261 static guint64 get_fs_property (const char *mountpoint, const char *attr)
262 {
263         GFile *root;
264         GFileInfo *info;
265         guint64 value;
266 
267         root = g_file_new_for_path (mountpoint);
268         info = g_file_query_filesystem_info (root, attr, NULL, NULL);
269         g_object_unref (G_OBJECT (root));
270         if (info == NULL) {
271                 return 0;
272         }
273         if (!g_file_info_has_attribute (info, attr)) {
274                 g_object_unref (G_OBJECT (info));
275                 return 0;
276         }
277         value = g_file_info_get_attribute_uint64 (info, attr);
278         g_object_unref (G_OBJECT (info));
279 
280         return value;
281 }
282 
283 guint64
284 rb_ipod_helpers_get_capacity (const char *mountpoint)
285 {
286         return  get_fs_property (mountpoint, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
287 }
288 
289 guint64
290 rb_ipod_helpers_get_free_space (const char *mountpoint)
291 {
292         return get_fs_property (mountpoint, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
293 }
294 
295 char *
296 rb_ipod_helpers_get_device (RBSource *source)
297 {
298         GMount *mount;
299         GVolume *volume;
300         char *device;
301 
302         g_object_get (RB_SOURCE (source), "mount", &mount, NULL);
303         volume = g_mount_get_volume (mount);
304         device = g_volume_get_identifier (volume,
305                                           G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
306         g_object_unref (G_OBJECT (volume));
307         g_object_unref (G_OBJECT (mount));
308 
309         return device;
310 }
311 
312 static gboolean
313 rb_ipod_helpers_mount_has_ipod_db (GMount *mount)
314 {
315         char *itunesdb_path;
316         gboolean result;
317 
318         itunesdb_path = rb_ipod_helpers_get_itunesdb_path (mount);
319 
320         if (itunesdb_path != NULL) {
321                 result = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
322         } else {
323                 result = FALSE;
324         }
325         g_free (itunesdb_path);
326 
327         return result;
328 }
329 
330 gboolean
331 rb_ipod_helpers_is_ipod (GMount *mount, MPIDDevice *device_info)
332 {
333 	GFile *root;
334 	gboolean result = FALSE;
335 	char **protocols;
336 
337 	/* if we have specific information about the device, use it.
338 	 * otherwise, check if the device has an ipod device directory on it.
339 	 */
340 	g_object_get (device_info, "access-protocols", &protocols, NULL);
341 	if (protocols != NULL && g_strv_length (protocols) > 0) {
342 		int i;
343 
344 		for (i = 0; protocols[i] != NULL; i++) {
345 			if (g_str_equal (protocols[i], "ipod")) {
346 				result = TRUE;
347 				break;
348 			}
349 		}
350 	} else {
351 		root = g_mount_get_root (mount);
352 		if (root != NULL) {
353 			gchar *device_dir;
354 
355 			if (g_file_has_uri_scheme (root, "afc") != FALSE) {
356 				gchar *uri;
357 				uri = g_file_get_uri (root);
358 				/* afc://<40 chars>:stuff */
359 				g_assert (strlen (uri) >= 46);
360 				if (uri[6 + 40] == ':' &&
361 				    uri[6 + 40 + 1] != '1') {
362 					result = FALSE;
363 				} else {
364 					result = TRUE;
365 				}
366 				g_free (uri);
367 			} else {
368 				gchar *mount_point;
369 				mount_point = g_file_get_path (root);
370 				if (mount_point != NULL) {
371 					device_dir = itdb_get_device_dir (mount_point);
372 					if (device_dir != NULL)  {
373 						result = g_file_test (device_dir,
374 								      G_FILE_TEST_IS_DIR);
375 						g_free (device_dir);
376 					}
377 				}
378 
379 				g_free (mount_point);
380 			}
381 			g_object_unref (root);
382 		}
383 	}
384 
385 	g_strfreev (protocols);
386 	return result;
387 }
388 
389 gboolean
390 rb_ipod_helpers_needs_init (GMount *mount)
391 {
392 	/* This function is a useless one-liner for now, but it should check
393 	 * for the existence of the firsttime file on the ipod to tell if
394 	 * the ipod is new or not
395 	 */
396 	return (!rb_ipod_helpers_mount_has_ipod_db (mount));
397 }