No issues found
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 |
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 }