hythmbox-2.98/metadata/rb-metadata-dbus-service.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found rb-metadata-dbus-service.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  *  Copyright (C) 2006 Jonathan Matthew <jonathan@kaolin.hn.org>
  3  *
  4  *  This program is free software; you can redistribute it and/or modify
  5  *  it under the terms of the GNU General Public License as published by
  6  *  the Free Software Foundation; either version 2 of the License, or
  7  *  (at your option) any later version.
  8  *
  9  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 10  *  GStreamer plugins to be used and distributed together with GStreamer
 11  *  and Rhythmbox. This permission is above and beyond the permissions granted
 12  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 13  *  you may extend this exception to your version of the code, but you are not
 14  *  obligated to do so. If you do not wish to do so, delete this exception
 15  *  statement from your version.
 16  *
 17  *  This program is distributed in the hope that it will be useful,
 18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20  *  GNU General Public License for more details.
 21  *
 22  *  You should have received a copy of the GNU General Public License
 23  *  along with this program; if not, write to the Free Software
 24  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 25  *
 26  */
 27 
 28 /*
 29  * Rhythmbox out-of-process metadata reader.
 30  */
 31 
 32 #include <config.h>
 33 #include <time.h>
 34 #include <string.h>
 35 #include <unistd.h>
 36 
 37 #include <glib/gi18n.h>
 38 #include <gst/gst.h>
 39 #include <gio/gio.h>
 40 
 41 #include "rb-metadata.h"
 42 #include "rb-metadata-dbus.h"
 43 #include "rb-debug.h"
 44 #include "rb-util.h"
 45 
 46 /* number of seconds to hang around doing nothing */
 47 #define ATTENTION_SPAN		30
 48 
 49 typedef struct {
 50 	GDBusServer *server;
 51 	GDBusConnection *connection;
 52 	GDBusNodeInfo *node_info;
 53 	GMainLoop *loop;
 54 	time_t last_active;
 55 	RBMetaData *metadata;
 56 	gboolean external;
 57 } ServiceData;
 58 
 59 static void
 60 rb_metadata_dbus_load (GVariant *parameters,
 61 		       GDBusMethodInvocation *invocation,
 62 		       ServiceData *svc)
 63 {
 64 	const char *uri;
 65 	GError *error = NULL;
 66 	GVariant *response;
 67 	const char *nothing[] = { NULL };
 68 	char **missing_plugins = NULL;
 69 	char **plugin_descriptions = NULL;
 70 	const char *mediatype;
 71 
 72 	g_variant_get (parameters, "(&s)", &uri);
 73 
 74 	rb_debug ("loading metadata from %s", uri);
 75 	rb_metadata_load (svc->metadata, uri, &error);
 76 	mediatype = rb_metadata_get_media_type (svc->metadata);
 77 	rb_debug ("metadata load finished (type %s)", mediatype);
 78 
 79 	rb_metadata_get_missing_plugins (svc->metadata, &missing_plugins, &plugin_descriptions);
 80 
 81 	response = g_variant_new ("(^as^asbbbsbisa{iv})",
 82 				  missing_plugins ? missing_plugins : (char **)nothing,
 83 				  plugin_descriptions ? plugin_descriptions : (char **)nothing,
 84 				  rb_metadata_has_audio (svc->metadata),
 85 				  rb_metadata_has_video (svc->metadata),
 86 				  rb_metadata_has_other_data (svc->metadata),
 87 				  mediatype ? mediatype : "",
 88 				  (error == NULL),
 89 				  (error != NULL ? error->code : 0),
 90 				  (error != NULL ? error->message : ""),
 91 				  rb_metadata_dbus_get_variant_builder (svc->metadata));
 92 	g_strfreev (missing_plugins);
 93 	g_strfreev (plugin_descriptions);
 94 
 95 	g_dbus_method_invocation_return_value (invocation, response);
 96 }
 97 
 98 static void
 99 rb_metadata_dbus_get_saveable_types (GVariant *parameters,
100 				     GDBusMethodInvocation *invocation,
101 				     ServiceData *svc)
102 {
103 	char **saveable_types;
104 
105 	saveable_types = rb_metadata_get_saveable_types (svc->metadata);
106 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(^as)", saveable_types));
107 	g_strfreev (saveable_types);
108 }
109 
110 static void
111 rb_metadata_dbus_save (GVariant *parameters,
112 		       GDBusMethodInvocation *invocation,
113 		       ServiceData *svc)
114 {
115 	const char *uri;
116 	GError *error = NULL;
117 	GVariantIter *metadata;
118 	RBMetaDataField key;
119 	GVariant *value;
120 
121 	g_variant_get (parameters, "(&sa{iv})", &uri, &metadata);
122 
123 	/* pass metadata to real metadata instance */
124 	rb_metadata_reset (svc->metadata);
125 	while (g_variant_iter_next (metadata, "{iv}", &key, &value)) {
126 		GValue val = {0,};
127 
128 		switch (rb_metadata_get_field_type (key)) {
129 		case G_TYPE_STRING:
130 			g_value_init (&val, G_TYPE_STRING);
131 			g_value_set_string (&val, g_variant_get_string (value, NULL));
132 			break;
133 		case G_TYPE_ULONG:
134 			g_value_init (&val, G_TYPE_ULONG);
135 			g_value_set_ulong (&val, g_variant_get_uint32 (value));
136 			break;
137 		case G_TYPE_DOUBLE:
138 			g_value_init (&val, G_TYPE_DOUBLE);
139 			g_value_set_double (&val, g_variant_get_double (value));
140 			break;
141 		default:
142 			g_assert_not_reached ();
143 			break;
144 		}
145 		rb_metadata_set (svc->metadata, key, &val);
146 		g_variant_unref (value);
147 		g_value_unset (&val);
148 	}
149 
150 	rb_metadata_save (svc->metadata, uri, &error);
151 	g_dbus_method_invocation_return_value (invocation,
152 					       g_variant_new ("(bis)",
153 							      (error == NULL),
154 							      (error != NULL ? error->code : 0),
155 							      (error != NULL ? error->message : "")));
156 }
157 
158 static void
159 rb_metadata_dbus_ping (GVariant *parameters,
160 		       GDBusMethodInvocation *invocation,
161 		       ServiceData *svc)
162 {
163 	rb_debug ("ping");
164 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
165 }
166 
167 static gboolean
168 electromagnetic_shotgun (gpointer data)
169 {
170 	ServiceData *c = (ServiceData *)data;
171 	GTime now = time(NULL);
172 	int idle = now - c->last_active;
173 
174 	/* quit if we haven't done anything for a while */
175 	if (idle > ATTENTION_SPAN) {
176 		rb_debug ("shutting down (%ds idle)", idle);
177 		g_main_loop_quit (c->loop);
178 	}
179 
180 	return TRUE;
181 }
182 
183 static void
184 handle_method_call (GDBusConnection *connection,
185 		    const char *sender,
186 		    const char *object_path,
187 		    const char *interface_name,
188 		    const char *method_name,
189 		    GVariant *parameters,
190 		    GDBusMethodInvocation *invocation,
191 		    ServiceData *svc)
192 {
193 	rb_debug ("handling metadata service message: %s.%s", interface_name, method_name);
194 	if (g_strcmp0 (method_name, "ping") == 0) {
195 		rb_metadata_dbus_ping (parameters, invocation, svc);
196 	} else if (g_strcmp0 (method_name, "load") == 0) {
197 		rb_metadata_dbus_load (parameters, invocation, svc);
198 	} else if (g_strcmp0 (method_name, "getSaveableTypes") == 0) {
199 		rb_metadata_dbus_get_saveable_types (parameters, invocation, svc);
200 	} else if (g_strcmp0 (method_name, "save") == 0) {
201 		rb_metadata_dbus_save (parameters, invocation, svc);
202 	}
203 	svc->last_active = time (NULL);
204 }
205 
206 static const GDBusInterfaceVTable metadata_vtable = {
207 	(GDBusInterfaceMethodCallFunc) handle_method_call,
208 	NULL,
209 	NULL
210 };
211 
212 static void
213 connection_closed_cb (GDBusConnection *connection,
214 		      gboolean remote_peer_vanished,
215 		      GError *error,
216 		      ServiceData *svc)
217 {
218 	rb_debug ("client connection closed");
219 	g_assert (connection == svc->connection);
220 	svc->connection = NULL;
221 }
222 
223 static void
224 new_connection_cb (GDBusServer *server,
225 		   GDBusConnection *connection,
226 		   ServiceData *svc)
227 {
228 	GError *error = NULL;
229 	rb_debug ("new connection to metadata service");
230 
231 	/* don't allow more than one connection at a time */
232 	if (svc->connection) {
233 		rb_debug ("metadata service already has a client.  go away.");
234 		return;
235 	}
236 	g_dbus_connection_register_object (connection,
237 					   RB_METADATA_DBUS_OBJECT_PATH,
238 					   g_dbus_node_info_lookup_interface (svc->node_info, RB_METADATA_DBUS_INTERFACE),
239 					   &metadata_vtable,
240 					   svc,
241 					   NULL,
242 					   &error);
243 	if (error != NULL) {
244 		rb_debug ("unable to register metadata object: %s", error->message);
245 		g_clear_error (&error);
246 	} else {
247 		svc->connection = g_object_ref (connection);
248 		g_signal_connect (connection, "closed", G_CALLBACK (connection_closed_cb), svc);
249 
250 		g_dbus_connection_set_exit_on_close (connection, (svc->external == FALSE));
251 	}
252 }
253 
254 static int
255 test_saveable_types ()
256 {
257 	RBMetaData *md;
258 	char **saveable;
259 	int i;
260 
261 	md = rb_metadata_new ();
262 	saveable = rb_metadata_get_saveable_types (md);
263 	g_object_unref (md);
264 
265 	for (i = 0; saveable[i] != NULL; i++) {
266 		g_print ("%s\n", saveable[i]);
267 	}
268 	g_strfreev (saveable);
269 
270 	return 0;
271 }
272 
273 static int
274 test_load (const char *uri)
275 {
276 	RBMetaData *md;
277 	GError *error = NULL;
278 	int rv = 0;
279 	char **missing_plugins;
280 	char **plugin_descriptions;
281 
282 	md = rb_metadata_new ();
283 	rb_metadata_load (md, uri, &error);
284 	if (error) {
285 		g_print ("Error loading metadata from %s: %s\n", uri, error->message);
286 		g_clear_error (&error);
287 		g_print ("media type: %s\n", rb_metadata_get_media_type (md));
288 		rv = -1;
289 	} else {
290 		int i;
291 		g_print ("media type: %s\n", rb_metadata_get_media_type (md));
292 		for (i=0; i<RB_METADATA_FIELD_LAST; i++) {
293 			GValue v = {0,};
294 			GValue sv = {0,};
295 			if (rb_metadata_get (md, i, &v)) {
296 				g_value_init (&sv, G_TYPE_STRING);
297 				g_value_transform (&v, &sv);
298 
299 				g_print ("%s: %s\n", rb_metadata_get_field_name (i), g_value_get_string (&sv));
300 
301 				g_value_unset (&v);
302 				g_value_unset (&sv);
303 			}
304 		}
305 	}
306 
307 	g_print ("has audio: %d\n", rb_metadata_has_audio (md));
308 	g_print ("has video: %d\n", rb_metadata_has_video (md));
309 	g_print ("has other: %d\n", rb_metadata_has_other_data (md));
310 
311 	if (rb_metadata_get_missing_plugins (md, &missing_plugins, &plugin_descriptions)) {
312 		int i = 0;
313 		g_print ("missing plugins:\n");
314 		while (missing_plugins[i] != NULL) {
315 			g_print ("\t%s (%s)\n", missing_plugins[i], plugin_descriptions[i]);
316 			i++;
317 		}
318 		g_strfreev (missing_plugins);
319 	}
320 
321 	g_object_unref (G_OBJECT (md));
322 	return rv;
323 }
324 
325 int
326 main (int argc, char **argv)
327 {
328 	ServiceData svc = {0,};
329 	GError *error = NULL;
330 	const char *address = NULL;
331 	char *guid;
332 
333 #ifdef ENABLE_NLS
334 	/* initialize i18n */
335 	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
336 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
337 	textdomain (GETTEXT_PACKAGE);
338 #endif
339 	g_type_init ();
340 	gst_init (NULL, NULL);
341 	g_set_prgname ("rhythmbox-metadata");
342 
343 	if (argv[1] != NULL && strcmp(argv[1], "--debug") == 0) {
344 		argv++;
345 		rb_debug_init (TRUE);
346 	} else if (argv[1] != NULL && strcmp (argv[1], "--debug-match") == 0) {
347 		rb_debug_init_match (argv[2]);
348 		argv += 2;
349 	} else {
350 		rb_debug_init (FALSE);
351 	}
352 
353 	/* bug report modes */
354 	if (argv[1] != NULL && strcmp(argv[1], "--load") == 0) {
355 		return test_load (argv[2]);
356 	}
357 	if (argv[1] != NULL && strcmp(argv[1], "--saveable-types") == 0) {
358 		return test_saveable_types ();
359 	}
360 
361 	if (argv[1] != NULL && strcmp (argv[1], "--external") == 0) {
362 		argv++;
363 		svc.external = TRUE;
364 	}
365 	if (argv[1] == NULL) {
366 		address = "unix:tmpdir=/tmp";
367 	} else {
368 		address = argv[1];
369 	}
370 
371 	rb_debug ("initializing metadata service; pid = %d; address = %s", getpid (), address);
372 	svc.metadata = rb_metadata_new ();
373 	svc.loop = g_main_loop_new (NULL, TRUE);
374 
375 	/* create the server */
376 	guid = g_dbus_generate_guid ();
377 	svc.server = g_dbus_server_new_sync (address,
378 					     G_DBUS_SERVER_FLAGS_NONE,
379 					     guid,
380 					     NULL,
381 					     NULL,
382 					     &error);
383 	g_free (guid);
384 	if (error != NULL) {
385 		g_warning ("D-Bus server init failed: %s", error->message);
386 		return -1;
387 	}
388 
389 	/* set up interface info */
390 	svc.node_info = g_dbus_node_info_new_for_xml (rb_metadata_iface_xml, &error);
391 	if (error != NULL) {
392 		g_warning ("D-Bus server init failed: %s", error->message);
393 		return -1;
394 	}
395 
396 	g_signal_connect (svc.server, "new-connection", G_CALLBACK (new_connection_cb), &svc);
397 	g_dbus_server_start (svc.server);
398 
399 	/* write the server address back to the parent process */
400 	{
401 		const char *addr;
402 		addr = g_dbus_server_get_client_address (svc.server);
403 		rb_debug ("D-BUS server listening on address %s", addr);
404 		printf ("%s\n", addr);
405 		fflush (stdout);
406 	}
407 
408 	/* run main loop until we get bored */
409 	if (!svc.external)
410 		g_timeout_add_seconds (ATTENTION_SPAN / 2, (GSourceFunc) electromagnetic_shotgun, &svc);
411 
412 	g_main_loop_run (svc.loop);
413 
414 	if (svc.connection) {
415 		g_dbus_connection_close_sync (svc.connection, NULL, NULL);
416 		g_object_unref (svc.connection);
417 	}
418 
419 	g_object_unref (svc.metadata);
420 	g_main_loop_unref (svc.loop);
421 
422 	g_dbus_server_stop (svc.server);
423 	g_object_unref (svc.server);
424 	gst_deinit ();
425 
426 	return 0;
427 }