hythmbox-2.98/plugins/mtpdevice/rb-mtp-plugin.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found rb-mtp-plugin.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /*
  2  * rb-mtp-plugin.c
  3  *
  4  * Copyright (C) 2006 Peter Grundstrรถm <pete@openfestis.org>
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation; either version 2, or (at your option)
  9  * any later version.
 10  *
 11  * The Rhythmbox authors hereby grant permission for non-GPL compatible
 12  * GStreamer plugins to be used and distributed together with GStreamer
 13  * and Rhythmbox. This permission is above and beyond the permissions granted
 14  * by the GPL license by which Rhythmbox is covered. If you modify this code
 15  * you may extend this exception to your version of the code, but you are not
 16  * obligated to do so. If you do not wish to do so, delete this exception
 17  * statement from your version.
 18  *
 19  * This program is distributed in the hope that it will be useful,
 20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22  * GNU General Public License for more details.
 23  *
 24  * You should have received a copy of the GNU General Public License
 25  * along with this program; if not, write to the Free Software
 26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 27  */
 28 
 29 #ifdef HAVE_CONFIG_H
 30 #include <config.h>
 31 #endif
 32 
 33 #include <string.h>
 34 #include <glib/gi18n-lib.h>
 35 #include <gmodule.h>
 36 #include <gtk/gtk.h>
 37 #include <glib.h>
 38 #include <glib-object.h>
 39 #include <libmtp.h>
 40 
 41 #if defined(HAVE_GUDEV)
 42 #define G_UDEV_API_IS_SUBJECT_TO_CHANGE
 43 #include <gudev/gudev.h>
 44 #else
 45 #include <hal/libhal.h>
 46 #include <dbus/dbus.h>
 47 #include <dbus/dbus-glib.h>
 48 #include <dbus/dbus-glib-lowlevel.h>
 49 #endif
 50 
 51 #include "rb-plugin-macros.h"
 52 #include "rb-source.h"
 53 #include "rb-display-page-group.h"
 54 #include "rb-display-page-tree.h"
 55 #include "rb-mtp-source.h"
 56 #include "rb-mtp-thread.h"
 57 #include "rb-debug.h"
 58 #include "rb-file-helpers.h"
 59 #include "rb-util.h"
 60 #include "rb-shell.h"
 61 #include "rb-stock-icons.h"
 62 #include "rb-removable-media-manager.h"
 63 
 64 
 65 #define RB_TYPE_MTP_PLUGIN		(rb_mtp_plugin_get_type ())
 66 #define RB_MTP_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_MTP_PLUGIN, RBMtpPlugin))
 67 #define RB_MTP_PLUGIN_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_IPOD_PLUGIN, RBMtpPluginClass))
 68 #define RB_IS_MTP_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_MTP_PLUGIN))
 69 #define RB_IS_MTP_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_MTP_PLUGIN))
 70 #define RB_MTP_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_MTP_PLUGIN, RBMtpPluginClass))
 71 
 72 
 73 typedef struct
 74 {
 75 	PeasExtensionBase parent;
 76 
 77 	GtkActionGroup *action_group;
 78 	guint ui_merge_id;
 79 
 80 	guint create_device_source_id;
 81 
 82 	GList *mtp_sources;
 83 
 84 #if !defined(HAVE_GUDEV)
 85 	LibHalContext *hal_context;
 86 	DBusConnection *dbus_connection;
 87 #endif
 88 } RBMtpPlugin;
 89 
 90 typedef struct
 91 {
 92 	PeasExtensionBaseClass parent_class;
 93 } RBMtpPluginClass;
 94 
 95 
 96 G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
 97 
 98 static void rb_mtp_plugin_init (RBMtpPlugin *plugin);
 99 
100 #if defined(HAVE_GUDEV)
101 static RBSource* create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device, RBMtpPlugin *plugin);
102 #else
103 static void rb_mtp_plugin_maybe_add_source (RBMtpPlugin *plugin, const char *udi, LIBMTP_raw_device_t *raw_devices, int num);
104 static void rb_mtp_plugin_device_added (LibHalContext *context, const char *udi);
105 static void rb_mtp_plugin_device_removed (LibHalContext *context, const char *udi);
106 static gboolean rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin);
107 #endif
108 
109 static void rb_mtp_plugin_rename (GtkAction *action, RBSource *source);
110 static void rb_mtp_plugin_properties (GtkAction *action, RBSource *source);
111 
112 GType rb_mtp_src_get_type (void);
113 GType rb_mtp_sink_get_type (void);
114 
115 RB_DEFINE_PLUGIN(RB_TYPE_MTP_PLUGIN, RBMtpPlugin, rb_mtp_plugin,)
116 
117 static GtkActionEntry rb_mtp_plugin_actions [] =
118 {
119 	{ "MTPSourceRename", NULL, N_("_Rename"), NULL,
120 	  N_("Rename MTP-device"),
121 	  G_CALLBACK (rb_mtp_plugin_rename) },
122 	{ "MTPSourceProperties", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL,
123 	  N_("Display device properties"),
124 	  G_CALLBACK (rb_mtp_plugin_properties) }
125 };
126 
127 static void
128 rb_mtp_plugin_init (RBMtpPlugin *plugin)
129 {
130 	rb_debug ("RBMtpPlugin initialising");
131 	LIBMTP_Init ();
132 }
133 
134 static void
135 impl_activate (PeasActivatable *bplugin)
136 {
137 	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
138 	GtkUIManager *uimanager = NULL;
139 	RBRemovableMediaManager *rmm;
140 	char *file = NULL;
141 	RBShell *shell;
142 #if defined(HAVE_GUDEV)
143 	gboolean rmm_scanned = FALSE;
144 #else
145 	int num_mtp_devices;
146 	LIBMTP_raw_device_t *mtp_devices;
147 #endif
148 
149 	g_object_get (plugin, "object", &shell, NULL);
150 
151 	g_object_get (shell,
152 		     "ui-manager", &uimanager,
153 		     "removable-media-manager", &rmm,
154 		     NULL);
155 
156 	/* ui */
157 	rb_media_player_source_init_actions (shell);
158 	plugin->action_group = gtk_action_group_new ("MTPActions");
159 	gtk_action_group_set_translation_domain (plugin->action_group,
160 						 GETTEXT_PACKAGE);
161 	_rb_action_group_add_display_page_actions (plugin->action_group,
162 						   G_OBJECT (shell),
163 						   rb_mtp_plugin_actions,
164 						   G_N_ELEMENTS (rb_mtp_plugin_actions));
165 	gtk_ui_manager_insert_action_group (uimanager, plugin->action_group, 0);
166 	file = rb_find_plugin_data_file (G_OBJECT (bplugin), "mtp-ui.xml");
167 	plugin->ui_merge_id = gtk_ui_manager_add_ui_from_file (uimanager, file, NULL);
168 	g_object_unref (uimanager);
169 	g_object_unref (shell);
170 
171 	/* device detection */
172 #if defined(HAVE_GUDEV)
173 	plugin->create_device_source_id =
174 		g_signal_connect_object (rmm,
175 					 "create-source-device",
176 					 G_CALLBACK (create_source_device_cb),
177 					 plugin,
178 					 0);
179 
180 	/* only scan if we're being loaded after the initial scan has been done */
181 	g_object_get (rmm, "scanned", &rmm_scanned, NULL);
182 	if (rmm_scanned)
183 		rb_removable_media_manager_scan (rmm);
184 #else
185 	if (rb_mtp_plugin_setup_dbus_hal_connection (plugin) == FALSE) {
186 		rb_debug ("not scanning for MTP devices because we couldn't get a HAL context");
187 		g_object_unref (rmm);
188 		return;
189 	}
190 
191 	rb_profile_start ("scanning for MTP devices");
192 	LIBMTP_Detect_Raw_Devices (&mtp_devices, &num_mtp_devices);
193 	if (num_mtp_devices > 0) {
194 		int num_hal_devices;
195 		char **hal_devices;
196 		int i;
197 
198 		rb_debug ("%d MTP devices found", num_mtp_devices);
199 
200 		hal_devices = libhal_get_all_devices (plugin->hal_context, &num_hal_devices, NULL);
201 		for (i = 0; i < num_hal_devices; i++) {
202 			/* should narrow this down a bit - usb only, for a start */
203 			rb_mtp_plugin_maybe_add_source (plugin, hal_devices[i], mtp_devices, num_mtp_devices);
204 		}
205 		libhal_free_string_array (hal_devices);
206 	}
207 	if (mtp_devices != NULL) {
208 		free (mtp_devices);
209 	}
210 	rb_profile_end ("scanning for MTP devices");
211 #endif
212 
213 	g_object_unref (rmm);
214 }
215 
216 static void
217 impl_deactivate (PeasActivatable *bplugin)
218 {
219 	RBMtpPlugin *plugin = RB_MTP_PLUGIN (bplugin);
220 	GtkUIManager *uimanager = NULL;
221 	RBRemovableMediaManager *rmm = NULL;
222 	RBShell *shell;
223 
224 	g_object_get (plugin, "object", &shell, NULL);
225 	g_object_get (shell,
226 		      "ui-manager", &uimanager,
227 		      "removable-media-manager", &rmm,
228 		      NULL);
229 
230 	gtk_ui_manager_remove_ui (uimanager, plugin->ui_merge_id);
231 	gtk_ui_manager_remove_action_group (uimanager, plugin->action_group);
232 
233 	g_list_foreach (plugin->mtp_sources, (GFunc)rb_display_page_delete_thyself, NULL);
234 	g_list_free (plugin->mtp_sources);
235 	plugin->mtp_sources = NULL;
236 
237 #if defined(HAVE_GUDEV)
238 	g_signal_handler_disconnect (rmm, plugin->create_device_source_id);
239 	plugin->create_device_source_id = 0;
240 #else
241 	if (plugin->hal_context != NULL) {
242 		DBusError error;
243 		dbus_error_init (&error);
244 		libhal_ctx_shutdown (plugin->hal_context, &error);
245 		libhal_ctx_free (plugin->hal_context);
246 		dbus_error_free (&error);
247 
248 		plugin->hal_context = NULL;
249 	}
250 
251 	if (plugin->dbus_connection != NULL) {
252 		dbus_connection_unref (plugin->dbus_connection);
253 		plugin->dbus_connection = NULL;
254 	}
255 #endif
256 
257 	g_object_unref (uimanager);
258 	g_object_unref (rmm);
259 	g_object_unref (shell);
260 }
261 
262 static void
263 rb_mtp_plugin_rename (GtkAction *action, RBSource *source)
264 {
265 	RBShell *shell;
266 	RBDisplayPageTree *page_tree;
267 
268 	g_return_if_fail (RB_IS_MTP_SOURCE (source));
269 
270 	g_object_get (source, "shell", &shell, NULL);
271 	g_object_get (shell, "display-page-tree", &page_tree, NULL);
272 
273 	rb_display_page_tree_edit_source_name (page_tree, source);
274 
275 	g_object_unref (page_tree);
276 	g_object_unref (shell);
277 }
278 
279 static void
280 rb_mtp_plugin_properties (GtkAction *action, RBSource *source)
281 {
282 	g_return_if_fail (RB_IS_MTP_SOURCE (source));
283 	rb_media_player_source_show_properties (RB_MEDIA_PLAYER_SOURCE (source));
284 }
285 
286 
287 #if defined(HAVE_GUDEV)
288 static void
289 source_deleted_cb (RBMtpSource *source, RBMtpPlugin *plugin)
290 {
291 	plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
292 }
293 
294 static void
295 set_properties_action_sensitive (RBMtpPlugin *plugin, RBMtpSource *source)
296 {
297 	gboolean selected;
298 	RBSourceLoadStatus load_status;
299 	GtkAction *action;
300 
301 	g_object_get (source,
302 		      "selected", &selected,
303 		      "load-status", &load_status,
304 		      NULL);
305 	if (selected) {
306 		action = gtk_action_group_get_action (plugin->action_group, "MTPSourceProperties");
307 		gtk_action_set_sensitive (action, (load_status == RB_SOURCE_LOAD_STATUS_LOADED));
308 	}
309 }
310 
311 static void
312 source_selected_cb (GObject *object, GParamSpec *pspec, RBMtpPlugin *plugin)
313 {
314 	set_properties_action_sensitive (plugin, RB_MTP_SOURCE (object));
315 }
316 
317 static void
318 source_load_status_cb (GObject *object, GParamSpec *pspec, RBMtpPlugin *plugin)
319 {
320 	set_properties_action_sensitive (plugin, RB_MTP_SOURCE (object));
321 }
322 
323 static int
324 get_property_as_int (GUdevDevice *device, const char *property, int base)
325 {
326 	const char *strvalue;
327 
328 	strvalue = g_udev_device_get_property (device, property);
329 	if (strvalue == NULL) {
330 		return 0;
331 	}
332 
333 	return strtol (strvalue, NULL, base);
334 }
335 
336 static RBSource *
337 create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device_obj, RBMtpPlugin *plugin)
338 {
339 	GUdevDevice *device = G_UDEV_DEVICE (device_obj);
340 	LIBMTP_device_entry_t *device_list;
341 	int numdevs;
342 	int vendor;
343 	int model;
344 	int busnum;
345 	int devnum;
346 	int i;
347 
348 	/* check subsystem == usb? */
349 	if (g_strcmp0 (g_udev_device_get_subsystem (device), "usb") != 0) {
350 		rb_debug ("device %s is not a USB device", g_udev_device_get_name (device));
351 		return NULL;
352 	}
353 
354 	/* check that it's not an iPhone or iPod Touch */
355 	if (g_udev_device_get_property_as_boolean (device, "USBMUX_SUPPORTED")) {
356 		rb_debug ("device %s is supported through AFC, ignore", g_udev_device_get_name (device));
357 		return NULL;
358 	}
359 
360 	/* get device info */
361 	vendor = get_property_as_int (device, "ID_VENDOR_ID", 16);
362 	model = get_property_as_int (device, "ID_MODEL_ID", 16);
363 	busnum = get_property_as_int (device, "BUSNUM", 10);
364 	devnum = get_property_as_int (device, "DEVNUM", 10);
365 	if (vendor == 0 || model == 0) {
366 		rb_debug ("couldn't get vendor or model ID for device (%x:%x)", vendor, model);
367 		return NULL;
368 	}
369 
370 	rb_debug ("matching device %x:%x against libmtp device list", vendor, model);
371 	LIBMTP_Get_Supported_Devices_List(&device_list, &numdevs);
372 	for (i = 0; i < numdevs; i++) {
373 		if (device_list[i].vendor_id == vendor &&
374 		    device_list[i].product_id == model) {
375 			LIBMTP_raw_device_t rawdevice;
376 			RBSource *source;
377 			RBShell *shell;
378 
379 			rb_debug ("found libmtp device list entry (model: %s, vendor: %s)",
380 				  device_list[i].vendor, device_list[i].product);
381 
382 			rawdevice.device_entry = device_list[i];
383 			rawdevice.bus_location = busnum;
384 			rawdevice.devnum = devnum;
385 
386 			g_object_get (plugin, "object", &shell, NULL);
387 			source = rb_mtp_source_new (shell, G_OBJECT (plugin), device, &rawdevice);
388 
389 			plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
390 			g_signal_connect_object (G_OBJECT (source),
391 						"deleted", G_CALLBACK (source_deleted_cb),
392 						plugin, 0);
393 			g_signal_connect_object (G_OBJECT (source),
394 						 "notify::selected", G_CALLBACK (source_selected_cb),
395 						 plugin, 0);
396 			g_signal_connect_object (G_OBJECT (source),
397 						 "notify::load-status", G_CALLBACK (source_load_status_cb),
398 						 plugin, 0);
399 			g_object_unref (shell);
400 			return source;
401 		}
402 	}
403 
404 	rb_debug ("device didn't match anything");
405 	return NULL;
406 }
407 
408 #else
409 
410 static void
411 source_deleted_cb (RBMtpSource *source, RBMtpPlugin *plugin)
412 {
413 	plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
414 }
415 
416 static void
417 rb_mtp_plugin_maybe_add_source (RBMtpPlugin *plugin, const char *udi, LIBMTP_raw_device_t *raw_devices, int num_raw_devices)
418 {
419 	int i;
420 	int device_num = 0;
421 	DBusError error;
422 
423 	rb_debug ("checking if UDI %s matches an MTP device", udi);
424 
425 	/* get device number */
426 	dbus_error_init (&error);
427 	device_num = libhal_device_get_property_int (plugin->hal_context, udi, "usb.linux.device_number", &error);
428 	if (dbus_error_is_set (&error)) {
429 		rb_debug ("unable to get USB device number: %s", error.message);
430 		dbus_error_free (&error);
431 		return;
432 	}
433 
434 	rb_debug ("USB device number: %d", device_num);
435 
436 	for (i = 0; i < num_raw_devices; i++) {
437 		rb_debug ("detected MTP device: device number %d (bus location %u)", raw_devices[i].devnum, raw_devices[i].bus_location);
438 		if (raw_devices[i].devnum == device_num) {
439 			RBSource *source;
440 			RBShell *shell;
441 
442 			rb_debug ("device matched, creating a source");
443 			g_object_get (plugin, "object", &shell, NULL);
444 			source = RB_SOURCE (rb_mtp_source_new (shell, G_OBJECT (plugin), udi, &raw_devices[i]));
445 
446 			rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (source), RB_DISPLAY_PAGE_GROUP_DEVICES);
447 			plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source);
448 			g_signal_connect_object (source,
449 						"deleted", G_CALLBACK (source_deleted_cb),
450 						plugin, 0);
451 			g_object_unref (shell);
452 		}
453 	}
454 }
455 
456 static void
457 rb_mtp_plugin_device_added (LibHalContext *context, const char *udi)
458 {
459 	RBMtpPlugin *plugin = (RBMtpPlugin *) libhal_ctx_get_user_data (context);
460 	LIBMTP_raw_device_t *mtp_devices;
461 	int num_mtp_devices;
462 
463 	LIBMTP_Detect_Raw_Devices (&mtp_devices, &num_mtp_devices);
464 	if (mtp_devices != NULL) {
465 		rb_mtp_plugin_maybe_add_source (plugin, udi, mtp_devices, num_mtp_devices);
466 		free (mtp_devices);
467 	}
468 }
469 
470 static void
471 rb_mtp_plugin_device_removed (LibHalContext *context, const char *udi)
472 {
473 	RBMtpPlugin *plugin = (RBMtpPlugin *) libhal_ctx_get_user_data (context);
474 	GList *list = plugin->mtp_sources;
475 	GList *tmp;
476 
477 	for (tmp = list; tmp != NULL; tmp = tmp->next) {
478 		RBSource *source = (RBSource *)tmp->data;
479 		char *source_udi;
480 
481 		g_object_get (source, "udi", &source_udi, NULL);
482 		if (strcmp (udi, source_udi) == 0) {
483 			rb_debug ("removing device %s, %p", udi, source);
484 			plugin->mtp_sources = g_list_remove (plugin->mtp_sources, source);
485 			rb_display_page_delete_thyself (RB_DISPLAY_PAGE (source));
486 		}
487 		g_free (source_udi);
488 	}
489 }
490 
491 static gboolean
492 rb_mtp_plugin_setup_dbus_hal_connection (RBMtpPlugin *plugin)
493 {
494 	DBusError error;
495 
496 	dbus_error_init (&error);
497 	plugin->dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
498 	if (plugin->dbus_connection == NULL) {
499 		rb_debug ("error: dbus_bus_get: %s: %s\n", error.name, error.message);
500 		dbus_error_free (&error);
501 		return FALSE;
502 	}
503 
504 	dbus_connection_setup_with_g_main (plugin->dbus_connection, NULL);
505 
506 	rb_debug ("connected to: %s", dbus_bus_get_unique_name (plugin->dbus_connection));
507 
508 	plugin->hal_context = libhal_ctx_new ();
509 	if (plugin->hal_context == NULL) {
510 		dbus_error_free (&error);
511 		return FALSE;
512 	}
513 	libhal_ctx_set_dbus_connection (plugin->hal_context, plugin->dbus_connection);
514 
515 	libhal_ctx_set_user_data (plugin->hal_context, (void *)plugin);
516 	libhal_ctx_set_device_added (plugin->hal_context, rb_mtp_plugin_device_added);
517 	libhal_ctx_set_device_removed (plugin->hal_context, rb_mtp_plugin_device_removed);
518 	libhal_device_property_watch_all (plugin->hal_context, &error);
519 
520 	if (!libhal_ctx_init (plugin->hal_context, &error)) {
521 		rb_debug ("error: libhal_ctx_init: %s: %s\n", error.name, error.message);
522 		dbus_error_free (&error);
523 		return FALSE;
524 	}
525 
526 	dbus_error_free (&error);
527 	return TRUE;
528 }
529 
530 #endif
531 
532 G_MODULE_EXPORT void
533 peas_register_types (PeasObjectModule *module)
534 {
535 	rb_mtp_plugin_register_type (G_TYPE_MODULE (module));
536 	_rb_mtp_source_register_type (G_TYPE_MODULE (module));
537 	_rb_mtp_thread_register_type (G_TYPE_MODULE (module));
538 
539 	/* ensure the gstreamer elements get linked in */
540 	rb_mtp_src_get_type ();
541 	rb_mtp_sink_get_type ();
542 
543 	peas_object_module_register_extension_type (module,
544 						    PEAS_TYPE_ACTIVATABLE,
545 						    RB_TYPE_MTP_PLUGIN);
546 }