Branch data Line data Source code
1 : : /* GDBus - GLib D-Bus Library
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: David Zeuthen <davidz@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <stdlib.h>
26 : : #include <string.h>
27 : : #include <stdio.h>
28 : : #include <locale.h>
29 : :
30 : : #include <gio/gio.h>
31 : :
32 : : #ifdef G_OS_UNIX
33 : : #include <gio/gunixfdlist.h>
34 : : #endif
35 : :
36 : : #include <gi18n.h>
37 : :
38 : : #ifdef G_OS_WIN32
39 : : #include "glib/glib-private.h"
40 : : #include "gdbusprivate.h"
41 : : #endif
42 : :
43 : : /* ---------------------------------------------------------------------------------------------------- */
44 : :
45 : : /* Escape values for console colors */
46 : : #define UNDERLINE "\033[4m"
47 : : #define BLUE "\033[34m"
48 : : #define CYAN "\033[36m"
49 : : #define GREEN "\033[32m"
50 : : #define MAGENTA "\033[35m"
51 : : #define RED "\033[31m"
52 : : #define YELLOW "\033[33m"
53 : :
54 : : /* ---------------------------------------------------------------------------------------------------- */
55 : :
56 : : G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
57 : :
58 : : /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
59 : : * to not have it interfere with stdout/stderr)
60 : : */
61 : : #if 0
62 : : G_GNUC_UNUSED static void
63 : : completion_debug (const gchar *format, ...)
64 : : {
65 : : va_list var_args;
66 : : gchar *s;
67 : : static FILE *f = NULL;
68 : :
69 : : va_start (var_args, format);
70 : : s = g_strdup_vprintf (format, var_args);
71 : : if (f == NULL)
72 : : {
73 : : f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
74 : : }
75 : : fprintf (f, "%s\n", s);
76 : : g_free (s);
77 : : }
78 : : #else
79 : : static void
80 : 0 : completion_debug (const gchar *format, ...)
81 : : {
82 : 0 : }
83 : : #endif
84 : :
85 : : /* ---------------------------------------------------------------------------------------------------- */
86 : :
87 : :
88 : : static void
89 : 0 : remove_arg (gint num, gint *argc, gchar **argv[])
90 : : {
91 : : gint n;
92 : :
93 : 0 : g_assert (num <= (*argc));
94 : :
95 [ # # ]: 0 : for (n = num; (*argv)[n] != NULL; n++)
96 : 0 : (*argv)[n] = (*argv)[n+1];
97 : 0 : (*argv)[n] = NULL;
98 : 0 : (*argc) = (*argc) - 1;
99 : 0 : }
100 : :
101 : : static void
102 : 0 : usage (gint *argc, gchar **argv[], gboolean use_stdout)
103 : : {
104 : : GOptionContext *o;
105 : : gchar *s;
106 : : gchar *program_name;
107 : :
108 : 0 : o = g_option_context_new (_("COMMAND"));
109 : 0 : g_option_context_set_help_enabled (o, FALSE);
110 : : /* Ignore parsing result */
111 : 0 : g_option_context_parse (o, argc, argv, NULL);
112 [ # # ]: 0 : program_name = (*argc > 0) ? g_path_get_basename ((*argv)[0]) : g_strdup ("gdbus-tool");
113 : 0 : s = g_strdup_printf (_("Commands:\n"
114 : : " help Shows this information\n"
115 : : " introspect Introspect a remote object\n"
116 : : " monitor Monitor a remote object\n"
117 : : " call Invoke a method on a remote object\n"
118 : : " emit Emit a signal\n"
119 : : " wait Wait for a bus name to appear\n"
120 : : "\n"
121 : : "Use “%s COMMAND --help” to get help on each command.\n"),
122 : : program_name);
123 : 0 : g_free (program_name);
124 : 0 : g_option_context_set_description (o, s);
125 : 0 : g_free (s);
126 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
127 [ # # ]: 0 : if (use_stdout)
128 : 0 : g_print ("%s", s);
129 : : else
130 : 0 : g_printerr ("%s", s);
131 : 0 : g_free (s);
132 : 0 : g_option_context_free (o);
133 : 0 : }
134 : :
135 : : static void
136 : 0 : modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
137 : : {
138 : : gchar *s;
139 : : gchar *program_name;
140 : :
141 : : /* TODO:
142 : : * 1. get a g_set_prgname() ?; or
143 : : * 2. save old argv[0] and restore later
144 : : */
145 : :
146 : 0 : g_assert (*argc > 1);
147 : 0 : g_assert (g_strcmp0 ((*argv)[1], command) == 0);
148 : 0 : remove_arg (1, argc, argv);
149 : :
150 : 0 : program_name = g_path_get_basename ((*argv)[0]);
151 : 0 : s = g_strdup_printf ("%s %s", program_name, command);
152 : 0 : (*argv)[0] = s;
153 : 0 : g_free (program_name);
154 : 0 : }
155 : :
156 : : static GOptionContext *
157 : 0 : command_option_context_new (const gchar *parameter_string,
158 : : const gchar *summary,
159 : : const GOptionEntry *entries,
160 : : gboolean request_completion)
161 : : {
162 : 0 : GOptionContext *o = NULL;
163 : :
164 : 0 : o = g_option_context_new (parameter_string);
165 [ # # ]: 0 : if (request_completion)
166 : 0 : g_option_context_set_ignore_unknown_options (o, TRUE);
167 : 0 : g_option_context_set_help_enabled (o, FALSE);
168 : 0 : g_option_context_set_summary (o, summary);
169 : 0 : g_option_context_add_main_entries (o, entries, GETTEXT_PACKAGE);
170 : :
171 : 0 : return g_steal_pointer (&o);
172 : : }
173 : :
174 : : /* ---------------------------------------------------------------------------------------------------- */
175 : :
176 : : static void
177 : 0 : print_methods_and_signals (GDBusConnection *c,
178 : : const gchar *name,
179 : : const gchar *path,
180 : : gboolean print_methods,
181 : : gboolean print_signals)
182 : : {
183 : : GVariant *result;
184 : : GError *error;
185 : : const gchar *xml_data;
186 : : GDBusNodeInfo *node;
187 : : guint n;
188 : : guint m;
189 : :
190 : 0 : error = NULL;
191 : 0 : result = g_dbus_connection_call_sync (c,
192 : : name,
193 : : path,
194 : : "org.freedesktop.DBus.Introspectable",
195 : : "Introspect",
196 : : NULL,
197 : : G_VARIANT_TYPE ("(s)"),
198 : : G_DBUS_CALL_FLAGS_NONE,
199 : : 3000, /* 3 secs */
200 : : NULL,
201 : : &error);
202 [ # # ]: 0 : if (result == NULL)
203 : : {
204 : 0 : g_printerr (_("Error: %s\n"), error->message);
205 : 0 : g_error_free (error);
206 : 0 : goto out;
207 : : }
208 : 0 : g_variant_get (result, "(&s)", &xml_data);
209 : :
210 : 0 : error = NULL;
211 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
212 : 0 : g_variant_unref (result);
213 [ # # ]: 0 : if (node == NULL)
214 : : {
215 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
216 : 0 : g_error_free (error);
217 : 0 : goto out;
218 : : }
219 : :
220 [ # # # # ]: 0 : for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
221 : : {
222 : 0 : const GDBusInterfaceInfo *iface = node->interfaces[n];
223 [ # # # # : 0 : for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++)
# # ]
224 : : {
225 : 0 : const GDBusMethodInfo *method = iface->methods[m];
226 : 0 : g_print ("%s.%s \n", iface->name, method->name);
227 : : }
228 [ # # # # : 0 : for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++)
# # ]
229 : : {
230 : 0 : const GDBusSignalInfo *signal = iface->signals[m];
231 : 0 : g_print ("%s.%s \n", iface->name, signal->name);
232 : : }
233 : : }
234 : 0 : g_dbus_node_info_unref (node);
235 : :
236 : 0 : out:
237 : : ;
238 : 0 : }
239 : :
240 : : static void
241 : 0 : print_paths (GDBusConnection *c,
242 : : const gchar *name,
243 : : const gchar *path)
244 : : {
245 : : GVariant *result;
246 : : GError *error;
247 : : const gchar *xml_data;
248 : : GDBusNodeInfo *node;
249 : : guint n;
250 : :
251 [ # # ]: 0 : if (!g_dbus_is_name (name))
252 : : {
253 : 0 : g_printerr (_("Error: %s is not a valid name\n"), name);
254 : 0 : goto out;
255 : : }
256 [ # # ]: 0 : if (!g_variant_is_object_path (path))
257 : : {
258 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), path);
259 : 0 : goto out;
260 : : }
261 : :
262 : 0 : error = NULL;
263 : 0 : result = g_dbus_connection_call_sync (c,
264 : : name,
265 : : path,
266 : : "org.freedesktop.DBus.Introspectable",
267 : : "Introspect",
268 : : NULL,
269 : : G_VARIANT_TYPE ("(s)"),
270 : : G_DBUS_CALL_FLAGS_NONE,
271 : : 3000, /* 3 secs */
272 : : NULL,
273 : : &error);
274 [ # # ]: 0 : if (result == NULL)
275 : : {
276 : 0 : g_printerr (_("Error: %s\n"), error->message);
277 : 0 : g_error_free (error);
278 : 0 : goto out;
279 : : }
280 : 0 : g_variant_get (result, "(&s)", &xml_data);
281 : :
282 : : //g_printerr ("xml='%s'", xml_data);
283 : :
284 : 0 : error = NULL;
285 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
286 : 0 : g_variant_unref (result);
287 [ # # ]: 0 : if (node == NULL)
288 : : {
289 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
290 : 0 : g_error_free (error);
291 : 0 : goto out;
292 : : }
293 : :
294 : : //g_printerr ("bar '%s'\n", path);
295 : :
296 [ # # ]: 0 : if (node->interfaces != NULL)
297 : 0 : g_print ("%s \n", path);
298 : :
299 [ # # # # ]: 0 : for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
300 : : {
301 : : gchar *s;
302 : :
303 : : //g_printerr ("foo '%s'\n", node->nodes[n].path);
304 : :
305 [ # # ]: 0 : if (g_strcmp0 (path, "/") == 0)
306 : 0 : s = g_strdup_printf ("/%s", node->nodes[n]->path);
307 : : else
308 : 0 : s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
309 : :
310 : 0 : print_paths (c, name, s);
311 : :
312 : 0 : g_free (s);
313 : : }
314 : 0 : g_dbus_node_info_unref (node);
315 : :
316 : 0 : out:
317 : : ;
318 : 0 : }
319 : :
320 : : static void
321 : 0 : print_names (GDBusConnection *c,
322 : : gboolean include_unique_names)
323 : : {
324 : : GVariant *result;
325 : : GError *error;
326 : : GVariantIter *iter;
327 : : gchar *str;
328 : : GHashTable *name_set;
329 : : GPtrArray *keys;
330 : :
331 : 0 : name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
332 : :
333 : 0 : error = NULL;
334 : 0 : result = g_dbus_connection_call_sync (c,
335 : : "org.freedesktop.DBus",
336 : : "/org/freedesktop/DBus",
337 : : "org.freedesktop.DBus",
338 : : "ListNames",
339 : : NULL,
340 : : G_VARIANT_TYPE ("(as)"),
341 : : G_DBUS_CALL_FLAGS_NONE,
342 : : 3000, /* 3 secs */
343 : : NULL,
344 : : &error);
345 [ # # ]: 0 : if (result == NULL)
346 : : {
347 : 0 : g_printerr (_("Error: %s\n"), error->message);
348 : 0 : g_error_free (error);
349 : 0 : goto out;
350 : : }
351 : 0 : g_variant_get (result, "(as)", &iter);
352 [ # # ]: 0 : while (g_variant_iter_loop (iter, "s", &str))
353 : 0 : g_hash_table_add (name_set, g_strdup (str));
354 : 0 : g_variant_iter_free (iter);
355 : 0 : g_variant_unref (result);
356 : :
357 : 0 : error = NULL;
358 : 0 : result = g_dbus_connection_call_sync (c,
359 : : "org.freedesktop.DBus",
360 : : "/org/freedesktop/DBus",
361 : : "org.freedesktop.DBus",
362 : : "ListActivatableNames",
363 : : NULL,
364 : : G_VARIANT_TYPE ("(as)"),
365 : : G_DBUS_CALL_FLAGS_NONE,
366 : : 3000, /* 3 secs */
367 : : NULL,
368 : : &error);
369 [ # # ]: 0 : if (result == NULL)
370 : : {
371 : 0 : g_printerr (_("Error: %s\n"), error->message);
372 : 0 : g_error_free (error);
373 : 0 : goto out;
374 : : }
375 : 0 : g_variant_get (result, "(as)", &iter);
376 [ # # ]: 0 : while (g_variant_iter_loop (iter, "s", &str))
377 : 0 : g_hash_table_add (name_set, g_strdup (str));
378 : 0 : g_variant_iter_free (iter);
379 : 0 : g_variant_unref (result);
380 : :
381 : 0 : keys = g_hash_table_steal_all_keys (name_set);
382 : 0 : g_ptr_array_sort_values (keys, (GCompareFunc) g_strcmp0);
383 [ # # ]: 0 : for (guint i = 0; i < keys->len; ++i)
384 : : {
385 : 0 : const gchar *name = g_ptr_array_index (keys, i);
386 [ # # # # : 0 : if (!include_unique_names && g_str_has_prefix (name, ":"))
# # # # #
# ]
387 : 0 : continue;
388 : :
389 : 0 : g_print ("%s \n", name);
390 : : }
391 : 0 : g_clear_pointer (&keys, g_ptr_array_unref);
392 : :
393 : 0 : out:
394 : 0 : g_hash_table_unref (name_set);
395 : 0 : }
396 : :
397 : : /* ---------------------------------------------------------------------------------------------------- */
398 : :
399 : : static gboolean opt_connection_system = FALSE;
400 : : static gboolean opt_connection_session = FALSE;
401 : : static gchar *opt_connection_address = NULL;
402 : :
403 : : static const GOptionEntry connection_entries[] =
404 : : {
405 : : { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
406 : : { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
407 : : { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), N_("ADDRESS") },
408 : : G_OPTION_ENTRY_NULL
409 : : };
410 : :
411 : : static GOptionGroup *
412 : 0 : connection_get_group (void)
413 : : {
414 : : static GOptionGroup *g;
415 : :
416 : 0 : g = g_option_group_new ("connection",
417 : : N_("Connection Endpoint Options:"),
418 : : N_("Options specifying the connection endpoint"),
419 : : NULL,
420 : : NULL);
421 : 0 : g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
422 : 0 : g_option_group_add_entries (g, connection_entries);
423 : :
424 : 0 : return g;
425 : : }
426 : :
427 : : static GDBusConnection *
428 : 0 : connection_get_dbus_connection (gboolean require_message_bus,
429 : : GError **error)
430 : : {
431 : : GDBusConnection *c;
432 : :
433 : 0 : c = NULL;
434 : :
435 : : /* First, ensure we have exactly one connect */
436 [ # # # # : 0 : if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
# # ]
437 : : {
438 : 0 : g_set_error (error,
439 : : G_IO_ERROR,
440 : : G_IO_ERROR_FAILED,
441 : 0 : _("No connection endpoint specified"));
442 : 0 : goto out;
443 : : }
444 [ # # # # : 0 : else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
# # ]
445 [ # # # # : 0 : (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
# # ]
446 [ # # # # : 0 : (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
# # ]
447 : : {
448 : 0 : g_set_error (error,
449 : : G_IO_ERROR,
450 : : G_IO_ERROR_FAILED,
451 : 0 : _("Multiple connection endpoints specified"));
452 : 0 : goto out;
453 : : }
454 : :
455 [ # # ]: 0 : if (opt_connection_system)
456 : : {
457 : 0 : c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
458 : : }
459 [ # # ]: 0 : else if (opt_connection_session)
460 : : {
461 : 0 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
462 : : }
463 [ # # ]: 0 : else if (opt_connection_address != NULL)
464 : : {
465 : 0 : GDBusConnectionFlags flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT;
466 [ # # ]: 0 : if (require_message_bus)
467 : 0 : flags |= G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION;
468 : 0 : c = g_dbus_connection_new_for_address_sync (opt_connection_address,
469 : : flags,
470 : : NULL, /* GDBusAuthObserver */
471 : : NULL, /* GCancellable */
472 : : error);
473 : : }
474 : :
475 : 0 : out:
476 : 0 : return c;
477 : : }
478 : :
479 : : /* ---------------------------------------------------------------------------------------------------- */
480 : :
481 : : static GPtrArray *
482 : 0 : call_helper_get_method_in_signature (GDBusConnection *c,
483 : : const gchar *dest,
484 : : const gchar *path,
485 : : const gchar *interface_name,
486 : : const gchar *method_name,
487 : : GError **error)
488 : : {
489 : : GPtrArray *ret;
490 : : GVariant *result;
491 : : GDBusNodeInfo *node_info;
492 : : const gchar *xml_data;
493 : : GDBusInterfaceInfo *interface_info;
494 : : GDBusMethodInfo *method_info;
495 : : guint n;
496 : :
497 : 0 : ret = NULL;
498 : 0 : result = NULL;
499 : 0 : node_info = NULL;
500 : :
501 : 0 : result = g_dbus_connection_call_sync (c,
502 : : dest,
503 : : path,
504 : : "org.freedesktop.DBus.Introspectable",
505 : : "Introspect",
506 : : NULL,
507 : : G_VARIANT_TYPE ("(s)"),
508 : : G_DBUS_CALL_FLAGS_NONE,
509 : : 3000, /* 3 secs */
510 : : NULL,
511 : : error);
512 [ # # ]: 0 : if (result == NULL)
513 : 0 : goto out;
514 : :
515 : 0 : g_variant_get (result, "(&s)", &xml_data);
516 : 0 : node_info = g_dbus_node_info_new_for_xml (xml_data, error);
517 [ # # ]: 0 : if (node_info == NULL)
518 : 0 : goto out;
519 : :
520 : 0 : interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
521 [ # # ]: 0 : if (interface_info == NULL)
522 : : {
523 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
524 : 0 : _("Warning: According to introspection data, interface “%s” does not exist\n"),
525 : : interface_name);
526 : 0 : goto out;
527 : : }
528 : :
529 : 0 : method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
530 [ # # ]: 0 : if (method_info == NULL)
531 : : {
532 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
533 : 0 : _("Warning: According to introspection data, method “%s” does not exist on interface “%s”\n"),
534 : : method_name,
535 : : interface_name);
536 : 0 : goto out;
537 : : }
538 : :
539 : 0 : ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
540 [ # # # # ]: 0 : for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
541 : : {
542 : 0 : g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
543 : : }
544 : :
545 : 0 : out:
546 [ # # ]: 0 : if (node_info != NULL)
547 : 0 : g_dbus_node_info_unref (node_info);
548 [ # # ]: 0 : if (result != NULL)
549 : 0 : g_variant_unref (result);
550 : :
551 : 0 : return ret;
552 : : }
553 : :
554 : : /* ---------------------------------------------------------------------------------------------------- */
555 : :
556 : : static GVariant *
557 : 0 : _g_variant_parse_me_harder (GVariantType *type,
558 : : const gchar *given_str,
559 : : GError **error)
560 : : {
561 : : GVariant *value;
562 : : gchar *s;
563 : : guint n;
564 : : GString *str;
565 : :
566 : 0 : str = g_string_new ("\"");
567 [ # # ]: 0 : for (n = 0; given_str[n] != '\0'; n++)
568 : : {
569 [ # # ]: 0 : if (G_UNLIKELY (given_str[n] == '\"'))
570 [ # # ]: 0 : g_string_append (str, "\\\"");
571 : : else
572 [ # # ]: 0 : g_string_append_c (str, given_str[n]);
573 : : }
574 : : g_string_append_c (str, '"');
575 : 0 : s = g_string_free (str, FALSE);
576 : :
577 : 0 : value = g_variant_parse (type,
578 : : s,
579 : : NULL,
580 : : NULL,
581 : : error);
582 : 0 : g_free (s);
583 : :
584 : 0 : return value;
585 : : }
586 : :
587 : : /* ---------------------------------------------------------------------------------------------------- */
588 : :
589 : : static gchar *opt_emit_dest = NULL;
590 : : static gchar *opt_emit_object_path = NULL;
591 : : static gchar *opt_emit_signal = NULL;
592 : :
593 : : static const GOptionEntry emit_entries[] =
594 : : {
595 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
596 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
597 : : { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
598 : : G_OPTION_ENTRY_NULL
599 : : };
600 : :
601 : : static gboolean
602 : 0 : handle_emit (gint *argc,
603 : : gchar **argv[],
604 : : gboolean request_completion,
605 : : const gchar *completion_cur,
606 : : const gchar *completion_prev)
607 : : {
608 : : gint ret;
609 : : GOptionContext *o;
610 : : gchar *s;
611 : : GError *error;
612 : : GDBusConnection *c;
613 : : GVariant *parameters;
614 : : gchar *interface_name;
615 : : gchar *signal_name;
616 : : GVariantBuilder builder;
617 : : gboolean skip_dashes;
618 : : guint parm;
619 : : guint n;
620 : : gboolean complete_names, complete_paths, complete_signals;
621 : :
622 : 0 : ret = FALSE;
623 : 0 : c = NULL;
624 : 0 : parameters = NULL;
625 : 0 : interface_name = NULL;
626 : 0 : signal_name = NULL;
627 : :
628 : 0 : modify_argv0_for_command (argc, argv, "emit");
629 : :
630 : 0 : o = command_option_context_new (NULL, _("Emit a signal."),
631 : : emit_entries, request_completion);
632 : 0 : g_option_context_add_group (o, connection_get_group ());
633 : :
634 : 0 : complete_names = FALSE;
635 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
# # ]
636 : : {
637 : 0 : complete_names = TRUE;
638 : 0 : remove_arg ((*argc) - 1, argc, argv);
639 : : }
640 : :
641 : 0 : complete_paths = FALSE;
642 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
# # ]
643 : : {
644 : 0 : complete_paths = TRUE;
645 : 0 : remove_arg ((*argc) - 1, argc, argv);
646 : : }
647 : :
648 : 0 : complete_signals = FALSE;
649 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
# # ]
650 : : {
651 : 0 : complete_signals = TRUE;
652 : 0 : remove_arg ((*argc) - 1, argc, argv);
653 : : }
654 : :
655 [ # # ]: 0 : if (!g_option_context_parse (o, argc, argv, NULL))
656 : : {
657 [ # # ]: 0 : if (!request_completion)
658 : : {
659 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
660 : 0 : g_printerr ("%s", s);
661 : 0 : g_free (s);
662 : 0 : goto out;
663 : : }
664 : : }
665 : :
666 : 0 : error = NULL;
667 : 0 : c = connection_get_dbus_connection ((opt_emit_dest != NULL), &error);
668 [ # # ]: 0 : if (c == NULL)
669 : : {
670 [ # # ]: 0 : if (request_completion)
671 : : {
672 [ # # ]: 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
673 : : {
674 : 0 : g_print ("unix:\n"
675 : : "tcp:\n"
676 : : "nonce-tcp:\n");
677 : : }
678 : : else
679 : : {
680 : 0 : g_print ("--system \n--session \n--address \n");
681 : : }
682 : : }
683 : : else
684 : : {
685 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
686 : : }
687 : 0 : g_error_free (error);
688 : 0 : goto out;
689 : : }
690 : :
691 : : /* validate and complete destination (bus name) */
692 [ # # ]: 0 : if (complete_names)
693 : : {
694 : 0 : print_names (c, FALSE);
695 : 0 : goto out;
696 : : }
697 [ # # # # : 0 : if (request_completion && opt_emit_dest != NULL && g_strcmp0 ("--dest", completion_prev) == 0)
# # ]
698 : : {
699 [ # # # # : 0 : print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
# # ]
700 : 0 : goto out;
701 : : }
702 : :
703 [ # # # # : 0 : if (!request_completion && opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
# # ]
704 : : {
705 : 0 : g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
706 : 0 : goto out;
707 : : }
708 : :
709 [ # # # # : 0 : if (opt_emit_dest == NULL && opt_emit_object_path == NULL && request_completion)
# # ]
710 : : {
711 : 0 : g_print ("--dest \n");
712 : : }
713 : : /* validate and complete object path */
714 [ # # # # ]: 0 : if (opt_emit_dest != NULL && complete_paths)
715 : : {
716 : 0 : print_paths (c, opt_emit_dest, "/");
717 : 0 : goto out;
718 : : }
719 [ # # ]: 0 : if (opt_emit_object_path == NULL)
720 : : {
721 [ # # ]: 0 : if (request_completion)
722 : 0 : g_print ("--object-path \n");
723 : : else
724 : 0 : g_printerr (_("Error: Object path is not specified\n"));
725 : 0 : goto out;
726 : : }
727 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
728 : : {
729 [ # # ]: 0 : if (opt_emit_dest != NULL)
730 : : {
731 : : gchar *p;
732 : 0 : s = g_strdup (opt_emit_object_path);
733 : 0 : p = strrchr (s, '/');
734 [ # # ]: 0 : if (p != NULL)
735 : : {
736 [ # # ]: 0 : if (p == s)
737 : 0 : p++;
738 : 0 : *p = '\0';
739 : : }
740 : 0 : print_paths (c, opt_emit_dest, s);
741 : 0 : g_free (s);
742 : : }
743 : 0 : goto out;
744 : : }
745 [ # # # # ]: 0 : if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
746 : : {
747 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
748 : 0 : goto out;
749 : : }
750 : :
751 : : /* validate and complete signal (interface + signal name) */
752 [ # # # # : 0 : if (opt_emit_dest != NULL && opt_emit_object_path != NULL && complete_signals)
# # ]
753 : : {
754 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
755 : 0 : goto out;
756 : : }
757 [ # # ]: 0 : if (opt_emit_signal == NULL)
758 : : {
759 : : /* don't keep repeatedly completing --signal */
760 [ # # ]: 0 : if (request_completion)
761 : : {
762 [ # # ]: 0 : if (g_strcmp0 ("--signal", completion_prev) != 0)
763 : 0 : g_print ("--signal \n");
764 : : }
765 : : else
766 : : {
767 : 0 : g_printerr (_("Error: Signal name is not specified\n"));
768 : : }
769 : :
770 : 0 : goto out;
771 : : }
772 [ # # # # : 0 : if (request_completion && opt_emit_dest != NULL && opt_emit_object_path != NULL &&
# # # # ]
773 : 0 : g_strcmp0 ("--signal", completion_prev) == 0)
774 : : {
775 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
776 : 0 : goto out;
777 : : }
778 : 0 : s = strrchr (opt_emit_signal, '.');
779 [ # # # # ]: 0 : if (!request_completion && s == NULL)
780 : : {
781 : 0 : g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
782 : 0 : goto out;
783 : : }
784 : 0 : signal_name = g_strdup (s + 1);
785 : 0 : interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
786 : :
787 : : /* All done with completion now */
788 [ # # ]: 0 : if (request_completion)
789 : 0 : goto out;
790 : :
791 [ # # ]: 0 : if (!g_dbus_is_interface_name (interface_name))
792 : : {
793 : 0 : g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
794 : 0 : goto out;
795 : : }
796 : :
797 [ # # ]: 0 : if (!g_dbus_is_member_name (signal_name))
798 : : {
799 : 0 : g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
800 : 0 : goto out;
801 : : }
802 : :
803 : : /* Read parameters */
804 : 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
805 : 0 : skip_dashes = TRUE;
806 : 0 : parm = 0;
807 [ # # ]: 0 : for (n = 1; n < (guint) *argc; n++)
808 : : {
809 : : GVariant *value;
810 : :
811 : : /* Under certain conditions, g_option_context_parse returns the "--"
812 : : itself (setting off unparsed arguments), too: */
813 [ # # # # ]: 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
814 : : {
815 : 0 : skip_dashes = FALSE;
816 : 0 : continue;
817 : : }
818 : :
819 : 0 : error = NULL;
820 : 0 : value = g_variant_parse (NULL,
821 : 0 : (*argv)[n],
822 : : NULL,
823 : : NULL,
824 : : &error);
825 [ # # ]: 0 : if (value == NULL)
826 : : {
827 : : gchar *context;
828 : :
829 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
830 : 0 : g_error_free (error);
831 : 0 : error = NULL;
832 : 0 : value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
833 [ # # ]: 0 : if (value == NULL)
834 : : {
835 : : /* Use the original non-"parse-me-harder" error */
836 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
837 : : parm + 1,
838 : : context);
839 : 0 : g_error_free (error);
840 : 0 : g_free (context);
841 : 0 : g_variant_builder_clear (&builder);
842 : 0 : goto out;
843 : : }
844 : 0 : g_free (context);
845 : : }
846 : 0 : g_variant_builder_add_value (&builder, value);
847 : 0 : ++parm;
848 : : }
849 : 0 : parameters = g_variant_builder_end (&builder);
850 : :
851 [ # # ]: 0 : if (parameters != NULL)
852 : 0 : parameters = g_variant_ref_sink (parameters);
853 [ # # ]: 0 : if (!g_dbus_connection_emit_signal (c,
854 : : opt_emit_dest,
855 : : opt_emit_object_path,
856 : : interface_name,
857 : : signal_name,
858 : : parameters,
859 : : &error))
860 : : {
861 : 0 : g_printerr (_("Error: %s\n"), error->message);
862 : 0 : g_error_free (error);
863 : 0 : goto out;
864 : : }
865 : :
866 [ # # ]: 0 : if (!g_dbus_connection_flush_sync (c, NULL, &error))
867 : : {
868 : 0 : g_printerr (_("Error flushing connection: %s\n"), error->message);
869 : 0 : g_error_free (error);
870 : 0 : goto out;
871 : : }
872 : :
873 : 0 : ret = TRUE;
874 : :
875 : 0 : out:
876 [ # # ]: 0 : if (c != NULL)
877 : 0 : g_object_unref (c);
878 [ # # ]: 0 : if (parameters != NULL)
879 : 0 : g_variant_unref (parameters);
880 : 0 : g_free (interface_name);
881 : 0 : g_free (signal_name);
882 : 0 : g_option_context_free (o);
883 : 0 : return ret;
884 : : }
885 : :
886 : : /* ---------------------------------------------------------------------------------------------------- */
887 : :
888 : : static gchar *opt_call_dest = NULL;
889 : : static gchar *opt_call_object_path = NULL;
890 : : static gchar *opt_call_method = NULL;
891 : : static gint opt_call_timeout = -1;
892 : : static gboolean opt_call_interactive = FALSE;
893 : :
894 : : static const GOptionEntry call_entries[] =
895 : : {
896 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
897 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
898 : : { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
899 : : { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
900 : : { "interactive", 'i', 0, G_OPTION_ARG_NONE, &opt_call_interactive, N_("Allow interactive authorization"), NULL},
901 : : G_OPTION_ENTRY_NULL
902 : : };
903 : :
904 : : static gboolean
905 : 0 : handle_call (gint *argc,
906 : : gchar **argv[],
907 : : gboolean request_completion,
908 : : const gchar *completion_cur,
909 : : const gchar *completion_prev)
910 : : {
911 : : gint ret;
912 : : GOptionContext *o;
913 : : gchar *s;
914 : : GError *error;
915 : : GDBusConnection *c;
916 : : GVariant *parameters;
917 : : gchar *interface_name;
918 : : gchar *method_name;
919 : : GVariant *result;
920 : : GPtrArray *in_signature_types;
921 : : #ifdef G_OS_UNIX
922 : : GUnixFDList *fd_list;
923 : : gint fd_id;
924 : : #endif
925 : : gboolean complete_names;
926 : : gboolean complete_paths;
927 : : gboolean complete_methods;
928 : : GVariantBuilder builder;
929 : : gboolean skip_dashes;
930 : : guint parm;
931 : : guint n;
932 : : GDBusCallFlags flags;
933 : :
934 : 0 : ret = FALSE;
935 : 0 : c = NULL;
936 : 0 : parameters = NULL;
937 : 0 : interface_name = NULL;
938 : 0 : method_name = NULL;
939 : 0 : result = NULL;
940 : 0 : in_signature_types = NULL;
941 : : #ifdef G_OS_UNIX
942 : 0 : fd_list = NULL;
943 : : #endif
944 : :
945 : 0 : modify_argv0_for_command (argc, argv, "call");
946 : :
947 : 0 : o = command_option_context_new (NULL, _("Invoke a method on a remote object."),
948 : : call_entries, request_completion);
949 : 0 : g_option_context_add_group (o, connection_get_group ());
950 : :
951 : 0 : complete_names = FALSE;
952 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
# # ]
953 : : {
954 : 0 : complete_names = TRUE;
955 : 0 : remove_arg ((*argc) - 1, argc, argv);
956 : : }
957 : :
958 : 0 : complete_paths = FALSE;
959 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
# # ]
960 : : {
961 : 0 : complete_paths = TRUE;
962 : 0 : remove_arg ((*argc) - 1, argc, argv);
963 : : }
964 : :
965 : 0 : complete_methods = FALSE;
966 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
# # ]
967 : : {
968 : 0 : complete_methods = TRUE;
969 : 0 : remove_arg ((*argc) - 1, argc, argv);
970 : : }
971 : :
972 [ # # ]: 0 : if (!g_option_context_parse (o, argc, argv, NULL))
973 : : {
974 [ # # ]: 0 : if (!request_completion)
975 : : {
976 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
977 : 0 : g_printerr ("%s", s);
978 : 0 : g_free (s);
979 : 0 : goto out;
980 : : }
981 : : }
982 : :
983 : 0 : error = NULL;
984 : 0 : c = connection_get_dbus_connection (TRUE, &error);
985 [ # # ]: 0 : if (c == NULL)
986 : : {
987 [ # # ]: 0 : if (request_completion)
988 : : {
989 [ # # ]: 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
990 : : {
991 : 0 : g_print ("unix:\n"
992 : : "tcp:\n"
993 : : "nonce-tcp:\n");
994 : : }
995 : : else
996 : : {
997 : 0 : g_print ("--system \n--session \n--address \n");
998 : : }
999 : : }
1000 : : else
1001 : : {
1002 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1003 : : }
1004 : 0 : g_error_free (error);
1005 : 0 : goto out;
1006 : : }
1007 : :
1008 : : /* validate and complete destination (bus name) */
1009 [ # # ]: 0 : if (complete_names)
1010 : : {
1011 : 0 : print_names (c, FALSE);
1012 : 0 : goto out;
1013 : : }
1014 [ # # ]: 0 : if (opt_call_dest == NULL)
1015 : : {
1016 [ # # ]: 0 : if (request_completion)
1017 : 0 : g_print ("--dest \n");
1018 : : else
1019 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1020 : 0 : goto out;
1021 : : }
1022 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1023 : : {
1024 [ # # # # : 0 : print_names (c, g_str_has_prefix (opt_call_dest, ":"));
# # ]
1025 : 0 : goto out;
1026 : : }
1027 : :
1028 [ # # # # ]: 0 : if (!request_completion && !g_dbus_is_name (opt_call_dest))
1029 : : {
1030 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
1031 : 0 : goto out;
1032 : : }
1033 : :
1034 : : /* validate and complete object path */
1035 [ # # ]: 0 : if (complete_paths)
1036 : : {
1037 : 0 : print_paths (c, opt_call_dest, "/");
1038 : 0 : goto out;
1039 : : }
1040 [ # # ]: 0 : if (opt_call_object_path == NULL)
1041 : : {
1042 [ # # ]: 0 : if (request_completion)
1043 : 0 : g_print ("--object-path \n");
1044 : : else
1045 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1046 : 0 : goto out;
1047 : : }
1048 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1049 : : {
1050 : : gchar *p;
1051 : 0 : s = g_strdup (opt_call_object_path);
1052 : 0 : p = strrchr (s, '/');
1053 [ # # ]: 0 : if (p != NULL)
1054 : : {
1055 [ # # ]: 0 : if (p == s)
1056 : 0 : p++;
1057 : 0 : *p = '\0';
1058 : : }
1059 : 0 : print_paths (c, opt_call_dest, s);
1060 : 0 : g_free (s);
1061 : 0 : goto out;
1062 : : }
1063 [ # # # # ]: 0 : if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
1064 : : {
1065 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
1066 : 0 : goto out;
1067 : : }
1068 : :
1069 : : /* validate and complete method (interface + method name) */
1070 [ # # ]: 0 : if (complete_methods)
1071 : : {
1072 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1073 : 0 : goto out;
1074 : : }
1075 [ # # ]: 0 : if (opt_call_method == NULL)
1076 : : {
1077 [ # # ]: 0 : if (request_completion)
1078 : 0 : g_print ("--method \n");
1079 : : else
1080 : 0 : g_printerr (_("Error: Method name is not specified\n"));
1081 : 0 : goto out;
1082 : : }
1083 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
1084 : : {
1085 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1086 : 0 : goto out;
1087 : : }
1088 : 0 : s = strrchr (opt_call_method, '.');
1089 [ # # # # ]: 0 : if (!request_completion && s == NULL)
1090 : : {
1091 : 0 : g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
1092 : 0 : goto out;
1093 : : }
1094 : 0 : method_name = g_strdup (s + 1);
1095 : 0 : interface_name = g_strndup (opt_call_method, s - opt_call_method);
1096 : :
1097 : : /* All done with completion now */
1098 [ # # ]: 0 : if (request_completion)
1099 : 0 : goto out;
1100 : :
1101 : : /* Introspect, for easy conversion - it's not fatal if we can't do this */
1102 : 0 : in_signature_types = call_helper_get_method_in_signature (c,
1103 : : opt_call_dest,
1104 : : opt_call_object_path,
1105 : : interface_name,
1106 : : method_name,
1107 : : &error);
1108 [ # # ]: 0 : if (in_signature_types == NULL)
1109 : : {
1110 : : //g_printerr ("Error getting introspection data: %s\n", error->message);
1111 : 0 : g_error_free (error);
1112 : 0 : error = NULL;
1113 : : }
1114 : :
1115 : : /* Read parameters */
1116 : 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1117 : 0 : skip_dashes = TRUE;
1118 : 0 : parm = 0;
1119 [ # # ]: 0 : for (n = 1; n < (guint) *argc; n++)
1120 : : {
1121 : : GVariant *value;
1122 : : GVariantType *type;
1123 : :
1124 : : /* Under certain conditions, g_option_context_parse returns the "--"
1125 : : itself (setting off unparsed arguments), too: */
1126 [ # # # # ]: 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
1127 : : {
1128 : 0 : skip_dashes = FALSE;
1129 : 0 : continue;
1130 : : }
1131 : :
1132 : 0 : type = NULL;
1133 [ # # ]: 0 : if (in_signature_types != NULL)
1134 : : {
1135 [ # # ]: 0 : if (parm >= in_signature_types->len)
1136 : : {
1137 : : /* Only warn for the first param */
1138 [ # # ]: 0 : if (parm == in_signature_types->len)
1139 : : {
1140 : 0 : g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
1141 : : in_signature_types->len);
1142 : : }
1143 : : }
1144 : : else
1145 : : {
1146 : 0 : type = in_signature_types->pdata[parm];
1147 : : }
1148 : : }
1149 : :
1150 : 0 : error = NULL;
1151 : 0 : value = g_variant_parse (type,
1152 : 0 : (*argv)[n],
1153 : : NULL,
1154 : : NULL,
1155 : : &error);
1156 [ # # ]: 0 : if (value == NULL)
1157 : : {
1158 : : gchar *context;
1159 : :
1160 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
1161 : 0 : g_error_free (error);
1162 : 0 : error = NULL;
1163 : 0 : value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
1164 [ # # ]: 0 : if (value == NULL)
1165 : : {
1166 [ # # ]: 0 : if (type != NULL)
1167 : : {
1168 : 0 : s = g_variant_type_dup_string (type);
1169 : 0 : g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
1170 : : parm + 1,
1171 : : s,
1172 : : context);
1173 : 0 : g_free (s);
1174 : : }
1175 : : else
1176 : : {
1177 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
1178 : : parm + 1,
1179 : : context);
1180 : : }
1181 : 0 : g_error_free (error);
1182 : 0 : g_variant_builder_clear (&builder);
1183 : 0 : g_free (context);
1184 : 0 : goto out;
1185 : : }
1186 : 0 : g_free (context);
1187 : : }
1188 : : #ifdef G_OS_UNIX
1189 [ # # ]: 0 : if (g_variant_is_of_type (value, G_VARIANT_TYPE_HANDLE))
1190 : : {
1191 [ # # ]: 0 : if (!fd_list)
1192 : 0 : fd_list = g_unix_fd_list_new ();
1193 [ # # ]: 0 : if ((fd_id = g_unix_fd_list_append (fd_list, g_variant_get_handle (value), &error)) == -1)
1194 : : {
1195 : 0 : g_printerr (_("Error adding handle %d: %s\n"),
1196 : 0 : g_variant_get_handle (value), error->message);
1197 : 0 : g_variant_builder_clear (&builder);
1198 : 0 : g_error_free (error);
1199 : 0 : goto out;
1200 : : }
1201 : 0 : g_variant_unref (value);
1202 : 0 : value = g_variant_new_handle (fd_id);
1203 : : }
1204 : : #endif
1205 : 0 : g_variant_builder_add_value (&builder, value);
1206 : 0 : ++parm;
1207 : : }
1208 : 0 : parameters = g_variant_builder_end (&builder);
1209 : :
1210 [ # # ]: 0 : if (parameters != NULL)
1211 : 0 : parameters = g_variant_ref_sink (parameters);
1212 : :
1213 : 0 : flags = G_DBUS_CALL_FLAGS_NONE;
1214 [ # # ]: 0 : if (opt_call_interactive)
1215 : 0 : flags |= G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
1216 : :
1217 : : #ifdef G_OS_UNIX
1218 : 0 : result = g_dbus_connection_call_with_unix_fd_list_sync (c,
1219 : : opt_call_dest,
1220 : : opt_call_object_path,
1221 : : interface_name,
1222 : : method_name,
1223 : : parameters,
1224 : : NULL,
1225 : : flags,
1226 [ # # ]: 0 : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1227 : : fd_list,
1228 : : NULL,
1229 : : NULL,
1230 : : &error);
1231 : : #else
1232 : : result = g_dbus_connection_call_sync (c,
1233 : : opt_call_dest,
1234 : : opt_call_object_path,
1235 : : interface_name,
1236 : : method_name,
1237 : : parameters,
1238 : : NULL,
1239 : : flags,
1240 : : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1241 : : NULL,
1242 : : &error);
1243 : : #endif
1244 [ # # ]: 0 : if (result == NULL)
1245 : : {
1246 : 0 : g_printerr (_("Error: %s\n"), error->message);
1247 : :
1248 [ # # # # ]: 0 : if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
1249 : : {
1250 [ # # ]: 0 : if (in_signature_types->len > 0)
1251 : : {
1252 : : GString *str;
1253 : 0 : str = g_string_new (NULL);
1254 : :
1255 [ # # ]: 0 : for (n = 0; n < in_signature_types->len; n++)
1256 : : {
1257 : 0 : GVariantType *type = in_signature_types->pdata[n];
1258 : 0 : g_string_append_len (str,
1259 : : g_variant_type_peek_string (type),
1260 : : g_variant_type_get_string_length (type));
1261 : : }
1262 : :
1263 : 0 : g_printerr ("(According to introspection data, you need to pass '%s')\n", str->str);
1264 : 0 : g_string_free (str, TRUE);
1265 : : }
1266 : : else
1267 : 0 : g_printerr ("(According to introspection data, you need to pass no arguments)\n");
1268 : : }
1269 : :
1270 : 0 : g_error_free (error);
1271 : 0 : goto out;
1272 : : }
1273 : :
1274 : 0 : s = g_variant_print (result, TRUE);
1275 : 0 : g_print ("%s\n", s);
1276 : 0 : g_free (s);
1277 : :
1278 : 0 : ret = TRUE;
1279 : :
1280 : 0 : out:
1281 [ # # ]: 0 : if (in_signature_types != NULL)
1282 : 0 : g_ptr_array_unref (in_signature_types);
1283 [ # # ]: 0 : if (result != NULL)
1284 : 0 : g_variant_unref (result);
1285 [ # # ]: 0 : if (c != NULL)
1286 : 0 : g_object_unref (c);
1287 [ # # ]: 0 : if (parameters != NULL)
1288 : 0 : g_variant_unref (parameters);
1289 : 0 : g_free (interface_name);
1290 : 0 : g_free (method_name);
1291 : 0 : g_option_context_free (o);
1292 : : #ifdef G_OS_UNIX
1293 : 0 : g_clear_object (&fd_list);
1294 : : #endif
1295 : 0 : return ret;
1296 : : }
1297 : :
1298 : : /* ---------------------------------------------------------------------------------------------------- */
1299 : :
1300 : : static gchar *opt_introspect_dest = NULL;
1301 : : static gchar *opt_introspect_object_path = NULL;
1302 : : static gboolean opt_introspect_xml = FALSE;
1303 : : static gboolean opt_introspect_recurse = FALSE;
1304 : : static gboolean opt_introspect_only_properties = FALSE;
1305 : :
1306 : : /* Introspect colors */
1307 : : #define RESET_COLOR (use_colors? "\033[0m": "")
1308 : : #define INTROSPECT_TITLE_COLOR (use_colors? UNDERLINE: "")
1309 : : #define INTROSPECT_NODE_COLOR (use_colors? RESET_COLOR: "")
1310 : : #define INTROSPECT_INTERFACE_COLOR (use_colors? YELLOW: "")
1311 : : #define INTROSPECT_METHOD_COLOR (use_colors? BLUE: "")
1312 : : #define INTROSPECT_SIGNAL_COLOR (use_colors? BLUE: "")
1313 : : #define INTROSPECT_PROPERTY_COLOR (use_colors? MAGENTA: "")
1314 : : #define INTROSPECT_INOUT_COLOR (use_colors? RESET_COLOR: "")
1315 : : #define INTROSPECT_TYPE_COLOR (use_colors? GREEN: "")
1316 : : #define INTROSPECT_ANNOTATION_COLOR (use_colors? RESET_COLOR: "")
1317 : :
1318 : : static void
1319 : 0 : dump_annotation (const GDBusAnnotationInfo *o,
1320 : : guint indent,
1321 : : gboolean ignore_indent,
1322 : : gboolean use_colors)
1323 : : {
1324 : : guint n;
1325 [ # # # # ]: 0 : g_print ("%*s%s@%s(\"%s\")%s\n",
1326 : : ignore_indent ? 0 : indent, "",
1327 [ # # ]: 0 : INTROSPECT_ANNOTATION_COLOR, o->key, o->value, RESET_COLOR);
1328 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1329 : 0 : dump_annotation (o->annotations[n], indent + 2, FALSE, use_colors);
1330 : 0 : }
1331 : :
1332 : : static void
1333 : 0 : dump_arg (const GDBusArgInfo *o,
1334 : : guint indent,
1335 : : const gchar *direction,
1336 : : gboolean ignore_indent,
1337 : : gboolean include_newline,
1338 : : gboolean use_colors)
1339 : : {
1340 : : guint n;
1341 : :
1342 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1343 : : {
1344 : 0 : dump_annotation (o->annotations[n], indent, ignore_indent, use_colors);
1345 : 0 : ignore_indent = FALSE;
1346 : : }
1347 : :
1348 [ # # # # : 0 : g_print ("%*s%s%s%s%s%s%s %s%s",
# # # # ]
1349 : : ignore_indent ? 0 : indent, "",
1350 : : INTROSPECT_INOUT_COLOR, direction, RESET_COLOR,
1351 [ # # ]: 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1352 [ # # ]: 0 : o->name,
1353 : : include_newline ? ",\n" : "");
1354 : 0 : }
1355 : :
1356 : : static guint
1357 : 0 : count_args (GDBusArgInfo **args)
1358 : : {
1359 : : guint n;
1360 : 0 : n = 0;
1361 [ # # ]: 0 : if (args == NULL)
1362 : 0 : goto out;
1363 [ # # ]: 0 : while (args[n] != NULL)
1364 : 0 : n++;
1365 : 0 : out:
1366 : 0 : return n;
1367 : : }
1368 : :
1369 : : static void
1370 : 0 : dump_method (const GDBusMethodInfo *o,
1371 : : guint indent,
1372 : : gboolean use_colors)
1373 : : {
1374 : : guint n;
1375 : : guint m;
1376 : : guint name_len;
1377 : : guint total_num_args;
1378 : :
1379 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1380 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1381 : :
1382 [ # # ]: 0 : g_print ("%*s%s%s%s(",
1383 : : indent, "",
1384 [ # # ]: 0 : INTROSPECT_METHOD_COLOR, o->name, RESET_COLOR);
1385 : 0 : name_len = strlen (o->name);
1386 : 0 : total_num_args = count_args (o->in_args) + count_args (o->out_args);
1387 [ # # # # ]: 0 : for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1388 : : {
1389 : 0 : gboolean ignore_indent = (m == 0);
1390 : 0 : gboolean include_newline = (m != total_num_args - 1);
1391 : :
1392 : 0 : dump_arg (o->in_args[n],
1393 : 0 : indent + name_len + 1,
1394 : : "in ",
1395 : : ignore_indent,
1396 : : include_newline,
1397 : : use_colors);
1398 : : }
1399 [ # # # # ]: 0 : for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1400 : : {
1401 : 0 : gboolean ignore_indent = (m == 0);
1402 : 0 : gboolean include_newline = (m != total_num_args - 1);
1403 : 0 : dump_arg (o->out_args[n],
1404 : 0 : indent + name_len + 1,
1405 : : "out ",
1406 : : ignore_indent,
1407 : : include_newline,
1408 : : use_colors);
1409 : : }
1410 : 0 : g_print (");\n");
1411 : 0 : }
1412 : :
1413 : : static void
1414 : 0 : dump_signal (const GDBusSignalInfo *o,
1415 : : guint indent,
1416 : : gboolean use_colors)
1417 : : {
1418 : : guint n;
1419 : : guint name_len;
1420 : : guint total_num_args;
1421 : :
1422 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1423 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1424 : :
1425 [ # # ]: 0 : g_print ("%*s%s%s%s(",
1426 : : indent, "",
1427 [ # # ]: 0 : INTROSPECT_SIGNAL_COLOR, o->name, RESET_COLOR);
1428 : 0 : name_len = strlen (o->name);
1429 : 0 : total_num_args = count_args (o->args);
1430 [ # # # # ]: 0 : for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1431 : : {
1432 : 0 : gboolean ignore_indent = (n == 0);
1433 : 0 : gboolean include_newline = (n != total_num_args - 1);
1434 : 0 : dump_arg (o->args[n],
1435 : 0 : indent + name_len + 1,
1436 : : "",
1437 : : ignore_indent,
1438 : : include_newline,
1439 : : use_colors);
1440 : : }
1441 : 0 : g_print (");\n");
1442 : 0 : }
1443 : :
1444 : : static void
1445 : 0 : dump_property (const GDBusPropertyInfo *o,
1446 : : guint indent,
1447 : : gboolean use_colors,
1448 : : GVariant *value)
1449 : : {
1450 : : const gchar *access;
1451 : : guint n;
1452 : :
1453 [ # # ]: 0 : if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1454 : 0 : access = "readonly";
1455 [ # # ]: 0 : else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1456 : 0 : access = "writeonly";
1457 [ # # ]: 0 : else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1458 : 0 : access = "readwrite";
1459 : : else
1460 : : g_assert_not_reached ();
1461 : :
1462 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1463 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1464 : :
1465 [ # # ]: 0 : if (value != NULL)
1466 : : {
1467 : 0 : gchar *s = g_variant_print (value, FALSE);
1468 [ # # # # ]: 0 : g_print ("%*s%s %s%s%s %s%s%s = %s;\n", indent, "", access,
1469 [ # # ]: 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1470 [ # # ]: 0 : INTROSPECT_PROPERTY_COLOR, o->name, RESET_COLOR,
1471 : : s);
1472 : 0 : g_free (s);
1473 : : }
1474 : : else
1475 : : {
1476 : 0 : g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1477 : : }
1478 : 0 : }
1479 : :
1480 : : static void
1481 : 0 : dump_interface (GDBusConnection *c,
1482 : : const gchar *name,
1483 : : const GDBusInterfaceInfo *o,
1484 : : guint indent,
1485 : : gboolean use_colors,
1486 : : const gchar *object_path)
1487 : : {
1488 : : guint n;
1489 : : GHashTable *properties;
1490 : :
1491 : 0 : properties = g_hash_table_new_full (g_str_hash,
1492 : : g_str_equal,
1493 : : g_free,
1494 : : (GDestroyNotify) g_variant_unref);
1495 : :
1496 : : /* Try to get properties */
1497 [ # # # # : 0 : if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
# # # # ]
1498 : : {
1499 : : GVariant *result;
1500 : 0 : result = g_dbus_connection_call_sync (c,
1501 : : name,
1502 : : object_path,
1503 : : "org.freedesktop.DBus.Properties",
1504 : : "GetAll",
1505 : 0 : g_variant_new ("(s)", o->name),
1506 : : NULL,
1507 : : G_DBUS_CALL_FLAGS_NONE,
1508 : : 3000,
1509 : : NULL,
1510 : : NULL);
1511 [ # # ]: 0 : if (result != NULL)
1512 : : {
1513 [ # # ]: 0 : if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1514 : : {
1515 : : GVariantIter *iter;
1516 : : GVariant *item;
1517 : 0 : g_variant_get (result,
1518 : : "(a{sv})",
1519 : : &iter);
1520 [ # # ]: 0 : while ((item = g_variant_iter_next_value (iter)))
1521 : : {
1522 : : gchar *key;
1523 : : GVariant *value;
1524 : 0 : g_variant_get (item,
1525 : : "{sv}",
1526 : : &key,
1527 : : &value);
1528 : :
1529 : 0 : g_hash_table_insert (properties, key, g_variant_ref (value));
1530 : : }
1531 : : }
1532 : 0 : g_variant_unref (result);
1533 : : }
1534 : : else
1535 : : {
1536 [ # # # # ]: 0 : for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1537 : : {
1538 : 0 : result = g_dbus_connection_call_sync (c,
1539 : : name,
1540 : : object_path,
1541 : : "org.freedesktop.DBus.Properties",
1542 : : "Get",
1543 : 0 : g_variant_new ("(ss)", o->name, o->properties[n]->name),
1544 : : G_VARIANT_TYPE ("(v)"),
1545 : : G_DBUS_CALL_FLAGS_NONE,
1546 : : 3000,
1547 : : NULL,
1548 : : NULL);
1549 [ # # ]: 0 : if (result != NULL)
1550 : : {
1551 : : GVariant *property_value;
1552 : 0 : g_variant_get (result,
1553 : : "(v)",
1554 : : &property_value);
1555 : 0 : g_hash_table_insert (properties,
1556 : 0 : g_strdup (o->properties[n]->name),
1557 : 0 : g_variant_ref (property_value));
1558 : 0 : g_variant_unref (result);
1559 : : }
1560 : : }
1561 : : }
1562 : : }
1563 : :
1564 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1565 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1566 : :
1567 [ # # ]: 0 : g_print ("%*s%sinterface %s%s {\n",
1568 : : indent, "",
1569 [ # # ]: 0 : INTROSPECT_INTERFACE_COLOR, o->name, RESET_COLOR);
1570 [ # # # # ]: 0 : if (o->methods != NULL && !opt_introspect_only_properties)
1571 : : {
1572 [ # # # # ]: 0 : g_print ("%*s %smethods%s:\n",
1573 : : indent, "",
1574 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1575 [ # # ]: 0 : for (n = 0; o->methods[n] != NULL; n++)
1576 : 0 : dump_method (o->methods[n], indent + 4, use_colors);
1577 : : }
1578 [ # # # # ]: 0 : if (o->signals != NULL && !opt_introspect_only_properties)
1579 : : {
1580 [ # # # # ]: 0 : g_print ("%*s %ssignals%s:\n",
1581 : : indent, "",
1582 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1583 [ # # ]: 0 : for (n = 0; o->signals[n] != NULL; n++)
1584 : 0 : dump_signal (o->signals[n], indent + 4, use_colors);
1585 : : }
1586 [ # # ]: 0 : if (o->properties != NULL)
1587 : : {
1588 [ # # # # ]: 0 : g_print ("%*s %sproperties%s:\n",
1589 : : indent, "",
1590 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1591 [ # # ]: 0 : for (n = 0; o->properties[n] != NULL; n++)
1592 : : {
1593 : 0 : dump_property (o->properties[n],
1594 : : indent + 4,
1595 : : use_colors,
1596 : 0 : g_hash_table_lookup (properties, (o->properties[n])->name));
1597 : : }
1598 : : }
1599 : 0 : g_print ("%*s};\n",
1600 : : indent, "");
1601 : :
1602 : 0 : g_hash_table_unref (properties);
1603 : 0 : }
1604 : :
1605 : : static gboolean
1606 : : introspect_do (GDBusConnection *c,
1607 : : const gchar *object_path,
1608 : : guint indent,
1609 : : gboolean use_colors);
1610 : :
1611 : : static void
1612 : 0 : dump_node (GDBusConnection *c,
1613 : : const gchar *name,
1614 : : const GDBusNodeInfo *o,
1615 : : guint indent,
1616 : : gboolean use_colors,
1617 : : const gchar *object_path,
1618 : : gboolean recurse)
1619 : : {
1620 : : guint n;
1621 : : const gchar *object_path_to_print;
1622 : :
1623 : 0 : object_path_to_print = object_path;
1624 [ # # ]: 0 : if (o->path != NULL)
1625 : 0 : object_path_to_print = o->path;
1626 : :
1627 [ # # # # ]: 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1628 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1629 : :
1630 [ # # # # : 0 : g_print ("%*s%snode %s%s",
# # ]
1631 : : indent, "",
1632 : : INTROSPECT_NODE_COLOR,
1633 : : object_path_to_print != NULL ? object_path_to_print : "(not set)",
1634 : : RESET_COLOR);
1635 [ # # # # ]: 0 : if (o->interfaces != NULL || o->nodes != NULL)
1636 : : {
1637 : 0 : g_print (" {\n");
1638 [ # # # # ]: 0 : for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1639 : : {
1640 [ # # ]: 0 : if (opt_introspect_only_properties)
1641 : : {
1642 [ # # # # ]: 0 : if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1643 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1644 : : }
1645 : : else
1646 : : {
1647 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1648 : : }
1649 : : }
1650 [ # # # # ]: 0 : for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1651 : : {
1652 [ # # ]: 0 : if (recurse)
1653 : : {
1654 : : gchar *child_path;
1655 [ # # ]: 0 : if (g_variant_is_object_path (o->nodes[n]->path))
1656 : : {
1657 : 0 : child_path = g_strdup (o->nodes[n]->path);
1658 : : /* avoid infinite loops */
1659 [ # # ]: 0 : if (g_str_has_prefix (child_path, object_path))
1660 : : {
1661 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1662 : : }
1663 : : else
1664 : : {
1665 : 0 : g_print ("Skipping path %s that is not enclosed by parent %s\n",
1666 : : child_path, object_path);
1667 : : }
1668 : : }
1669 : : else
1670 : : {
1671 [ # # ]: 0 : if (g_strcmp0 (object_path, "/") == 0)
1672 : 0 : child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1673 : : else
1674 : 0 : child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1675 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1676 : : }
1677 : 0 : g_free (child_path);
1678 : : }
1679 : : else
1680 : : {
1681 : 0 : dump_node (NULL, NULL, o->nodes[n], indent + 2, use_colors, NULL, recurse);
1682 : : }
1683 : : }
1684 : 0 : g_print ("%*s};\n",
1685 : : indent, "");
1686 : : }
1687 : : else
1688 : : {
1689 : 0 : g_print ("\n");
1690 : : }
1691 : 0 : }
1692 : :
1693 : : static const GOptionEntry introspect_entries[] =
1694 : : {
1695 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1696 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1697 : : { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1698 : : { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1699 : : { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1700 : : G_OPTION_ENTRY_NULL
1701 : : };
1702 : :
1703 : : static gboolean
1704 : 0 : introspect_do (GDBusConnection *c,
1705 : : const gchar *object_path,
1706 : : guint indent,
1707 : : gboolean use_colors)
1708 : : {
1709 : : GError *error;
1710 : : GVariant *result;
1711 : : GDBusNodeInfo *node;
1712 : : gboolean ret;
1713 : : const gchar *xml_data;
1714 : :
1715 : 0 : ret = FALSE;
1716 : 0 : node = NULL;
1717 : 0 : result = NULL;
1718 : :
1719 : 0 : error = NULL;
1720 : 0 : result = g_dbus_connection_call_sync (c,
1721 : : opt_introspect_dest,
1722 : : object_path,
1723 : : "org.freedesktop.DBus.Introspectable",
1724 : : "Introspect",
1725 : : NULL,
1726 : : G_VARIANT_TYPE ("(s)"),
1727 : : G_DBUS_CALL_FLAGS_NONE,
1728 : : 3000, /* 3 sec */
1729 : : NULL,
1730 : : &error);
1731 [ # # ]: 0 : if (result == NULL)
1732 : : {
1733 : 0 : g_printerr (_("Error: %s\n"), error->message);
1734 : 0 : g_error_free (error);
1735 : 0 : goto out;
1736 : : }
1737 : 0 : g_variant_get (result, "(&s)", &xml_data);
1738 : :
1739 [ # # ]: 0 : if (opt_introspect_xml)
1740 : : {
1741 : 0 : g_print ("%s", xml_data);
1742 : : }
1743 : : else
1744 : : {
1745 : 0 : error = NULL;
1746 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
1747 [ # # ]: 0 : if (node == NULL)
1748 : : {
1749 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1750 : 0 : g_error_free (error);
1751 : 0 : goto out;
1752 : : }
1753 : :
1754 : 0 : dump_node (c, opt_introspect_dest, node, indent, use_colors, object_path, opt_introspect_recurse);
1755 : : }
1756 : :
1757 : 0 : ret = TRUE;
1758 : :
1759 : 0 : out:
1760 [ # # ]: 0 : if (node != NULL)
1761 : 0 : g_dbus_node_info_unref (node);
1762 [ # # ]: 0 : if (result != NULL)
1763 : 0 : g_variant_unref (result);
1764 : 0 : return ret;
1765 : : }
1766 : :
1767 : : static gboolean
1768 : 0 : handle_introspect (gint *argc,
1769 : : gchar **argv[],
1770 : : gboolean request_completion,
1771 : : const gchar *completion_cur,
1772 : : const gchar *completion_prev)
1773 : : {
1774 : : gint ret;
1775 : : GOptionContext *o;
1776 : : gchar *s;
1777 : : GError *error;
1778 : : GDBusConnection *c;
1779 : : gboolean complete_names;
1780 : : gboolean complete_paths;
1781 : : gboolean color_support;
1782 : :
1783 : 0 : ret = FALSE;
1784 : 0 : c = NULL;
1785 : :
1786 : 0 : modify_argv0_for_command (argc, argv, "introspect");
1787 : :
1788 : 0 : o = command_option_context_new (NULL, _("Introspect a remote object."),
1789 : : introspect_entries, request_completion);
1790 : 0 : g_option_context_add_group (o, connection_get_group ());
1791 : :
1792 : 0 : complete_names = FALSE;
1793 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
# # ]
1794 : : {
1795 : 0 : complete_names = TRUE;
1796 : 0 : remove_arg ((*argc) - 1, argc, argv);
1797 : : }
1798 : :
1799 : 0 : complete_paths = FALSE;
1800 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
# # ]
1801 : : {
1802 : 0 : complete_paths = TRUE;
1803 : 0 : remove_arg ((*argc) - 1, argc, argv);
1804 : : }
1805 : :
1806 [ # # ]: 0 : if (!g_option_context_parse (o, argc, argv, NULL))
1807 : : {
1808 [ # # ]: 0 : if (!request_completion)
1809 : : {
1810 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
1811 : 0 : g_printerr ("%s", s);
1812 : 0 : g_free (s);
1813 : 0 : goto out;
1814 : : }
1815 : : }
1816 : :
1817 : 0 : error = NULL;
1818 : 0 : c = connection_get_dbus_connection (TRUE, &error);
1819 [ # # ]: 0 : if (c == NULL)
1820 : : {
1821 [ # # ]: 0 : if (request_completion)
1822 : : {
1823 [ # # ]: 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
1824 : : {
1825 : 0 : g_print ("unix:\n"
1826 : : "tcp:\n"
1827 : : "nonce-tcp:\n");
1828 : : }
1829 : : else
1830 : : {
1831 : 0 : g_print ("--system \n--session \n--address \n");
1832 : : }
1833 : : }
1834 : : else
1835 : : {
1836 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1837 : : }
1838 : 0 : g_error_free (error);
1839 : 0 : goto out;
1840 : : }
1841 : :
1842 [ # # ]: 0 : if (complete_names)
1843 : : {
1844 : 0 : print_names (c, FALSE);
1845 : 0 : goto out;
1846 : : }
1847 : : /* this only makes sense on message bus connections */
1848 [ # # ]: 0 : if (opt_introspect_dest == NULL)
1849 : : {
1850 [ # # ]: 0 : if (request_completion)
1851 : 0 : g_print ("--dest \n");
1852 : : else
1853 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1854 : 0 : goto out;
1855 : : }
1856 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1857 : : {
1858 [ # # # # : 0 : print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
# # ]
1859 : 0 : goto out;
1860 : : }
1861 : :
1862 [ # # ]: 0 : if (complete_paths)
1863 : : {
1864 : 0 : print_paths (c, opt_introspect_dest, "/");
1865 : 0 : goto out;
1866 : : }
1867 : :
1868 [ # # # # ]: 0 : if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
1869 : : {
1870 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
1871 : 0 : goto out;
1872 : : }
1873 : :
1874 [ # # ]: 0 : if (opt_introspect_object_path == NULL)
1875 : : {
1876 [ # # ]: 0 : if (request_completion)
1877 : 0 : g_print ("--object-path \n");
1878 : : else
1879 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1880 : 0 : goto out;
1881 : : }
1882 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1883 : : {
1884 : : gchar *p;
1885 : 0 : s = g_strdup (opt_introspect_object_path);
1886 : 0 : p = strrchr (s, '/');
1887 [ # # ]: 0 : if (p != NULL)
1888 : : {
1889 [ # # ]: 0 : if (p == s)
1890 : 0 : p++;
1891 : 0 : *p = '\0';
1892 : : }
1893 : 0 : print_paths (c, opt_introspect_dest, s);
1894 : 0 : g_free (s);
1895 : 0 : goto out;
1896 : : }
1897 [ # # # # ]: 0 : if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1898 : : {
1899 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1900 : 0 : goto out;
1901 : : }
1902 : :
1903 [ # # # # : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
# # ]
1904 : : {
1905 : 0 : g_print ("--recurse \n");
1906 : : }
1907 : :
1908 [ # # # # : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
# # ]
1909 : : {
1910 : 0 : g_print ("--only-properties \n");
1911 : : }
1912 : :
1913 : : /* All done with completion now */
1914 [ # # ]: 0 : if (request_completion)
1915 : 0 : goto out;
1916 : :
1917 : : /* Before we start printing the actual info, check if we can do colors*/
1918 : 0 : color_support = g_log_writer_supports_color (fileno (stdout));
1919 : :
1920 [ # # ]: 0 : if (!introspect_do (c, opt_introspect_object_path, 0, color_support))
1921 : 0 : goto out;
1922 : :
1923 : 0 : ret = TRUE;
1924 : :
1925 : 0 : out:
1926 [ # # ]: 0 : if (c != NULL)
1927 : 0 : g_object_unref (c);
1928 : 0 : g_option_context_free (o);
1929 : 0 : return ret;
1930 : : }
1931 : :
1932 : : /* ---------------------------------------------------------------------------------------------------- */
1933 : :
1934 : : static gchar *opt_monitor_dest = NULL;
1935 : : static gchar *opt_monitor_object_path = NULL;
1936 : :
1937 : : static guint monitor_filter_id = 0;
1938 : :
1939 : : static void
1940 : 0 : monitor_signal_cb (GDBusConnection *connection,
1941 : : const gchar *sender_name,
1942 : : const gchar *object_path,
1943 : : const gchar *interface_name,
1944 : : const gchar *signal_name,
1945 : : GVariant *parameters,
1946 : : gpointer user_data)
1947 : : {
1948 : : gchar *s;
1949 : 0 : s = g_variant_print (parameters, TRUE);
1950 : 0 : g_print ("%s: %s.%s %s\n",
1951 : : object_path,
1952 : : interface_name,
1953 : : signal_name,
1954 : : s);
1955 : 0 : g_free (s);
1956 : 0 : }
1957 : :
1958 : : static void
1959 : 0 : monitor_on_name_appeared (GDBusConnection *connection,
1960 : : const gchar *name,
1961 : : const gchar *name_owner,
1962 : : gpointer user_data)
1963 : : {
1964 : 0 : g_print ("The name %s is owned by %s\n", name, name_owner);
1965 : 0 : g_assert (monitor_filter_id == 0);
1966 : 0 : monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1967 : : name_owner,
1968 : : NULL, /* any interface */
1969 : : NULL, /* any member */
1970 : : opt_monitor_object_path,
1971 : : NULL, /* arg0 */
1972 : : G_DBUS_SIGNAL_FLAGS_NONE,
1973 : : monitor_signal_cb,
1974 : : NULL, /* user_data */
1975 : : NULL); /* user_data destroy notify */
1976 : 0 : }
1977 : :
1978 : : static void
1979 : 0 : monitor_on_name_vanished (GDBusConnection *connection,
1980 : : const gchar *name,
1981 : : gpointer user_data)
1982 : : {
1983 : 0 : g_print ("The name %s does not have an owner\n", name);
1984 : :
1985 [ # # ]: 0 : if (monitor_filter_id != 0)
1986 : : {
1987 : 0 : g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
1988 : 0 : monitor_filter_id = 0;
1989 : : }
1990 : 0 : }
1991 : :
1992 : : static const GOptionEntry monitor_entries[] =
1993 : : {
1994 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1995 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1996 : : G_OPTION_ENTRY_NULL
1997 : : };
1998 : :
1999 : : static gboolean
2000 : 0 : handle_monitor (gint *argc,
2001 : : gchar **argv[],
2002 : : gboolean request_completion,
2003 : : const gchar *completion_cur,
2004 : : const gchar *completion_prev)
2005 : : {
2006 : : gint ret;
2007 : : GOptionContext *o;
2008 : : gchar *s;
2009 : : GError *error;
2010 : : GDBusConnection *c;
2011 : : gboolean complete_names;
2012 : : gboolean complete_paths;
2013 : : GMainLoop *loop;
2014 : :
2015 : 0 : ret = FALSE;
2016 : 0 : c = NULL;
2017 : :
2018 : 0 : modify_argv0_for_command (argc, argv, "monitor");
2019 : :
2020 : 0 : o = command_option_context_new (NULL, _("Monitor a remote object."),
2021 : : monitor_entries, request_completion);
2022 : 0 : g_option_context_add_group (o, connection_get_group ());
2023 : :
2024 : 0 : complete_names = FALSE;
2025 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
# # ]
2026 : : {
2027 : 0 : complete_names = TRUE;
2028 : 0 : remove_arg ((*argc) - 1, argc, argv);
2029 : : }
2030 : :
2031 : 0 : complete_paths = FALSE;
2032 [ # # # # : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
# # ]
2033 : : {
2034 : 0 : complete_paths = TRUE;
2035 : 0 : remove_arg ((*argc) - 1, argc, argv);
2036 : : }
2037 : :
2038 [ # # ]: 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2039 : : {
2040 [ # # ]: 0 : if (!request_completion)
2041 : : {
2042 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2043 : 0 : g_printerr ("%s", s);
2044 : 0 : g_free (s);
2045 : 0 : goto out;
2046 : : }
2047 : : }
2048 : :
2049 : 0 : error = NULL;
2050 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2051 [ # # ]: 0 : if (c == NULL)
2052 : : {
2053 [ # # ]: 0 : if (request_completion)
2054 : : {
2055 [ # # ]: 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2056 : : {
2057 : 0 : g_print ("unix:\n"
2058 : : "tcp:\n"
2059 : : "nonce-tcp:\n");
2060 : : }
2061 : : else
2062 : : {
2063 : 0 : g_print ("--system \n--session \n--address \n");
2064 : : }
2065 : : }
2066 : : else
2067 : : {
2068 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2069 : : }
2070 : 0 : g_error_free (error);
2071 : 0 : goto out;
2072 : : }
2073 : :
2074 : : /* Monitoring doesn’t make sense on a non-message-bus connection. */
2075 [ # # ]: 0 : if (g_dbus_connection_get_unique_name (c) == NULL)
2076 : : {
2077 [ # # ]: 0 : if (!request_completion)
2078 : 0 : g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
2079 : 0 : goto out;
2080 : : }
2081 : :
2082 [ # # ]: 0 : if (complete_names)
2083 : : {
2084 : 0 : print_names (c, FALSE);
2085 : 0 : goto out;
2086 : : }
2087 : : /* this only makes sense on message bus connections */
2088 [ # # ]: 0 : if (opt_monitor_dest == NULL)
2089 : : {
2090 [ # # ]: 0 : if (request_completion)
2091 : 0 : g_print ("--dest \n");
2092 : : else
2093 : 0 : g_printerr (_("Error: Destination is not specified\n"));
2094 : 0 : goto out;
2095 : : }
2096 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
2097 : : {
2098 [ # # # # : 0 : print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
# # ]
2099 : 0 : goto out;
2100 : : }
2101 : :
2102 [ # # # # ]: 0 : if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
2103 : : {
2104 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
2105 : 0 : goto out;
2106 : : }
2107 : :
2108 [ # # ]: 0 : if (complete_paths)
2109 : : {
2110 : 0 : print_paths (c, opt_monitor_dest, "/");
2111 : 0 : goto out;
2112 : : }
2113 [ # # ]: 0 : if (opt_monitor_object_path == NULL)
2114 : : {
2115 [ # # ]: 0 : if (request_completion)
2116 : : {
2117 : 0 : g_print ("--object-path \n");
2118 : 0 : goto out;
2119 : : }
2120 : : /* it's fine to not have an object path */
2121 : : }
2122 [ # # # # ]: 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
2123 : : {
2124 : : gchar *p;
2125 : 0 : s = g_strdup (opt_monitor_object_path);
2126 : 0 : p = strrchr (s, '/');
2127 [ # # ]: 0 : if (p != NULL)
2128 : : {
2129 [ # # ]: 0 : if (p == s)
2130 : 0 : p++;
2131 : 0 : *p = '\0';
2132 : : }
2133 : 0 : print_paths (c, opt_monitor_dest, s);
2134 : 0 : g_free (s);
2135 : 0 : goto out;
2136 : : }
2137 [ # # # # : 0 : if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
# # ]
2138 : : {
2139 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
2140 : 0 : goto out;
2141 : : }
2142 : :
2143 : : /* All done with completion now */
2144 [ # # ]: 0 : if (request_completion)
2145 : 0 : goto out;
2146 : :
2147 [ # # ]: 0 : if (opt_monitor_object_path != NULL)
2148 : 0 : g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
2149 : : else
2150 : 0 : g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
2151 : :
2152 : 0 : loop = g_main_loop_new (NULL, FALSE);
2153 : 0 : g_bus_watch_name_on_connection (c,
2154 : : opt_monitor_dest,
2155 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2156 : : monitor_on_name_appeared,
2157 : : monitor_on_name_vanished,
2158 : : NULL,
2159 : : NULL);
2160 : :
2161 : 0 : g_main_loop_run (loop);
2162 : 0 : g_main_loop_unref (loop);
2163 : :
2164 : 0 : ret = TRUE;
2165 : :
2166 : 0 : out:
2167 [ # # ]: 0 : if (c != NULL)
2168 : 0 : g_object_unref (c);
2169 : 0 : g_option_context_free (o);
2170 : 0 : return ret;
2171 : : }
2172 : :
2173 : : /* ---------------------------------------------------------------------------------------------------- */
2174 : :
2175 : : static gboolean opt_wait_activate_set = FALSE;
2176 : : static gchar *opt_wait_activate_name = NULL;
2177 : : static gint64 opt_wait_timeout_secs = 0; /* no timeout */
2178 : :
2179 : : typedef enum {
2180 : : WAIT_STATE_RUNNING, /* waiting to see the service */
2181 : : WAIT_STATE_SUCCESS, /* seen it successfully */
2182 : : WAIT_STATE_TIMEOUT, /* timed out before seeing it */
2183 : : } WaitState;
2184 : :
2185 : : static gboolean
2186 : 0 : opt_wait_activate_cb (const gchar *option_name,
2187 : : const gchar *value,
2188 : : gpointer data,
2189 : : GError **error)
2190 : : {
2191 : : /* @value may be NULL */
2192 : 0 : opt_wait_activate_set = TRUE;
2193 : 0 : opt_wait_activate_name = g_strdup (value);
2194 : :
2195 : 0 : return TRUE;
2196 : : }
2197 : :
2198 : : static const GOptionEntry wait_entries[] =
2199 : : {
2200 : : { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
2201 : : opt_wait_activate_cb,
2202 : : N_("Service to activate before waiting for the other one (well-known name)"),
2203 : : "[NAME]" },
2204 : : { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout_secs,
2205 : : N_("Timeout to wait for before exiting with an error (seconds); 0 for "
2206 : : "no timeout (default)"), "SECS" },
2207 : : G_OPTION_ENTRY_NULL
2208 : : };
2209 : :
2210 : : static void
2211 : 0 : wait_name_appeared_cb (GDBusConnection *connection,
2212 : : const gchar *name,
2213 : : const gchar *name_owner,
2214 : : gpointer user_data)
2215 : : {
2216 : 0 : WaitState *wait_state = user_data;
2217 : :
2218 : 0 : *wait_state = WAIT_STATE_SUCCESS;
2219 : 0 : }
2220 : :
2221 : : static gboolean
2222 : 0 : wait_timeout_cb (gpointer user_data)
2223 : : {
2224 : 0 : WaitState *wait_state = user_data;
2225 : :
2226 : 0 : *wait_state = WAIT_STATE_TIMEOUT;
2227 : :
2228 : : /* Removed in handle_wait(). */
2229 : 0 : return G_SOURCE_CONTINUE;
2230 : : }
2231 : :
2232 : : static gboolean
2233 : 0 : handle_wait (gint *argc,
2234 : : gchar **argv[],
2235 : : gboolean request_completion,
2236 : : const gchar *completion_cur,
2237 : : const gchar *completion_prev)
2238 : : {
2239 : : gint ret;
2240 : : GOptionContext *o;
2241 : : gchar *s;
2242 : : GError *error;
2243 : : GDBusConnection *c;
2244 : 0 : guint watch_id, timer_id = 0, activate_watch_id;
2245 : : const gchar *activate_service, *wait_service;
2246 : 0 : WaitState wait_state = WAIT_STATE_RUNNING;
2247 : :
2248 : 0 : ret = FALSE;
2249 : 0 : c = NULL;
2250 : :
2251 : 0 : modify_argv0_for_command (argc, argv, "wait");
2252 : :
2253 : 0 : o = command_option_context_new (_("[OPTION…] BUS-NAME"),
2254 : 0 : _("Wait for a bus name to appear."),
2255 : : wait_entries, request_completion);
2256 : 0 : g_option_context_add_group (o, connection_get_group ());
2257 : :
2258 [ # # ]: 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2259 : : {
2260 [ # # ]: 0 : if (!request_completion)
2261 : : {
2262 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2263 : 0 : g_printerr ("%s", s);
2264 : 0 : g_free (s);
2265 : 0 : goto out;
2266 : : }
2267 : : }
2268 : :
2269 : 0 : error = NULL;
2270 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2271 [ # # ]: 0 : if (c == NULL)
2272 : : {
2273 [ # # ]: 0 : if (request_completion)
2274 : : {
2275 [ # # ]: 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2276 : : {
2277 : 0 : g_print ("unix:\n"
2278 : : "tcp:\n"
2279 : : "nonce-tcp:\n");
2280 : : }
2281 : : else
2282 : : {
2283 : 0 : g_print ("--system \n--session \n--address \n");
2284 : : }
2285 : : }
2286 : : else
2287 : : {
2288 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2289 : : }
2290 : 0 : g_error_free (error);
2291 : 0 : goto out;
2292 : : }
2293 : :
2294 : : /* All done with completion now */
2295 [ # # ]: 0 : if (request_completion)
2296 : 0 : goto out;
2297 : :
2298 : : /*
2299 : : * Try and disentangle the command line arguments, with the aim of supporting:
2300 : : * gdbus wait --session --activate ActivateName WaitName
2301 : : * gdbus wait --session --activate ActivateAndWaitName
2302 : : * gdbus wait --activate --session ActivateAndWaitName
2303 : : * gdbus wait --session WaitName
2304 : : */
2305 [ # # # # : 0 : if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
# # ]
2306 : : {
2307 : 0 : activate_service = opt_wait_activate_name;
2308 : 0 : wait_service = (*argv)[1];
2309 : : }
2310 [ # # # # ]: 0 : else if (*argc == 2 &&
2311 [ # # ]: 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2312 : : {
2313 : 0 : activate_service = (*argv)[1];
2314 : 0 : wait_service = (*argv)[1];
2315 : : }
2316 [ # # # # ]: 0 : else if (*argc == 2 && !opt_wait_activate_set)
2317 : : {
2318 : 0 : activate_service = NULL; /* disabled */
2319 : 0 : wait_service = (*argv)[1];
2320 : : }
2321 [ # # # # ]: 0 : else if (*argc == 1 &&
2322 [ # # ]: 0 : opt_wait_activate_set && opt_wait_activate_name != NULL)
2323 : : {
2324 : 0 : activate_service = opt_wait_activate_name;
2325 : 0 : wait_service = opt_wait_activate_name;
2326 : : }
2327 [ # # # # ]: 0 : else if (*argc == 1 &&
2328 [ # # ]: 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2329 : : {
2330 : 0 : g_printerr (_("Error: A service to activate for must be specified.\n"));
2331 : 0 : goto out;
2332 : : }
2333 [ # # # # ]: 0 : else if (*argc == 1 && !opt_wait_activate_set)
2334 : : {
2335 : 0 : g_printerr (_("Error: A service to wait for must be specified.\n"));
2336 : 0 : goto out;
2337 : : }
2338 : : else /* if (*argc > 2) */
2339 : : {
2340 : 0 : g_printerr (_("Error: Too many arguments.\n"));
2341 : 0 : goto out;
2342 : : }
2343 : :
2344 [ # # # # ]: 0 : if (activate_service != NULL &&
2345 [ # # ]: 0 : (!g_dbus_is_name (activate_service) ||
2346 : 0 : g_dbus_is_unique_name (activate_service)))
2347 : : {
2348 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2349 : : activate_service);
2350 : 0 : goto out;
2351 : : }
2352 : :
2353 [ # # # # ]: 0 : if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
2354 : : {
2355 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2356 : : wait_service);
2357 : 0 : goto out;
2358 : : }
2359 : :
2360 : : /* Start the prerequisite service if needed. */
2361 [ # # ]: 0 : if (activate_service != NULL)
2362 : : {
2363 : 0 : activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
2364 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2365 : : NULL, NULL,
2366 : : NULL, NULL);
2367 : : }
2368 : : else
2369 : : {
2370 : 0 : activate_watch_id = 0;
2371 : : }
2372 : :
2373 : : /* Wait for the expected name to appear. */
2374 : 0 : watch_id = g_bus_watch_name_on_connection (c,
2375 : : wait_service,
2376 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
2377 : : wait_name_appeared_cb,
2378 : : NULL, &wait_state, NULL);
2379 : :
2380 : : /* Safety timeout. */
2381 [ # # ]: 0 : if (opt_wait_timeout_secs > 0)
2382 : 0 : timer_id = g_timeout_add_seconds (opt_wait_timeout_secs, wait_timeout_cb, &wait_state);
2383 : :
2384 [ # # ]: 0 : while (wait_state == WAIT_STATE_RUNNING)
2385 : 0 : g_main_context_iteration (NULL, TRUE);
2386 : :
2387 : 0 : g_bus_unwatch_name (watch_id);
2388 [ # # ]: 0 : if (timer_id != 0)
2389 : 0 : g_source_remove (timer_id);
2390 [ # # ]: 0 : if (activate_watch_id != 0)
2391 : 0 : g_bus_unwatch_name (activate_watch_id);
2392 : :
2393 : 0 : ret = (wait_state == WAIT_STATE_SUCCESS);
2394 : :
2395 : 0 : out:
2396 : 0 : g_clear_object (&c);
2397 : 0 : g_option_context_free (o);
2398 : 0 : g_free (opt_wait_activate_name);
2399 : 0 : opt_wait_activate_name = NULL;
2400 : :
2401 : 0 : return ret;
2402 : : }
2403 : :
2404 : : /* ---------------------------------------------------------------------------------------------------- */
2405 : :
2406 : : static gchar *
2407 : 0 : pick_word_at (const gchar *s,
2408 : : gint cursor,
2409 : : gint *out_word_begins_at)
2410 : : {
2411 : : gint begin;
2412 : : gint end;
2413 : :
2414 [ # # ]: 0 : if (s[0] == '\0')
2415 : : {
2416 [ # # ]: 0 : if (out_word_begins_at != NULL)
2417 : 0 : *out_word_begins_at = -1;
2418 : 0 : return NULL;
2419 : : }
2420 : :
2421 [ # # # # : 0 : if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
# # # # ]
2422 : : {
2423 [ # # ]: 0 : if (out_word_begins_at != NULL)
2424 : 0 : *out_word_begins_at = cursor;
2425 : 0 : return g_strdup ("");
2426 : : }
2427 : :
2428 [ # # # # ]: 0 : while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
2429 : 0 : cursor--;
2430 : 0 : begin = cursor;
2431 : :
2432 : 0 : end = begin;
2433 [ # # # # ]: 0 : while (!g_ascii_isspace (s[end]) && s[end] != '\0')
2434 : 0 : end++;
2435 : :
2436 [ # # ]: 0 : if (out_word_begins_at != NULL)
2437 : 0 : *out_word_begins_at = begin;
2438 : :
2439 : 0 : return g_strndup (s + begin, end - begin);
2440 : : }
2441 : :
2442 : : gint
2443 : 0 : main (gint argc, gchar *argv[])
2444 : : {
2445 : : gint ret;
2446 : : const gchar *command;
2447 : : gboolean request_completion;
2448 : : gchar *completion_cur;
2449 : : gchar *completion_prev;
2450 : : #ifdef G_OS_WIN32
2451 : : gchar *tmp;
2452 : : #endif
2453 : :
2454 : 0 : setlocale (LC_ALL, "");
2455 : 0 : textdomain (GETTEXT_PACKAGE);
2456 : :
2457 : : #ifdef G_OS_WIN32
2458 : : tmp = _glib_get_locale_dir ();
2459 : : bindtextdomain (GETTEXT_PACKAGE, tmp);
2460 : : g_free (tmp);
2461 : : #else
2462 : 0 : bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
2463 : : #endif
2464 : :
2465 : : #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2466 : 0 : bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2467 : : #endif
2468 : :
2469 : 0 : ret = 1;
2470 : 0 : completion_cur = NULL;
2471 : 0 : completion_prev = NULL;
2472 : :
2473 [ # # ]: 0 : if (argc < 2)
2474 : : {
2475 : 0 : usage (&argc, &argv, FALSE);
2476 : 0 : goto out;
2477 : : }
2478 : :
2479 : 0 : request_completion = FALSE;
2480 : :
2481 : : //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
2482 : :
2483 : 0 : again:
2484 : 0 : command = argv[1];
2485 [ # # ]: 0 : if (g_strcmp0 (command, "help") == 0)
2486 : : {
2487 [ # # ]: 0 : if (request_completion)
2488 : : {
2489 : : /* do nothing */
2490 : : }
2491 : : else
2492 : : {
2493 : 0 : usage (&argc, &argv, TRUE);
2494 : 0 : ret = 0;
2495 : : }
2496 : 0 : goto out;
2497 : : }
2498 [ # # ]: 0 : else if (g_strcmp0 (command, "emit") == 0)
2499 : : {
2500 [ # # ]: 0 : if (handle_emit (&argc,
2501 : : &argv,
2502 : : request_completion,
2503 : : completion_cur,
2504 : : completion_prev))
2505 : 0 : ret = 0;
2506 : 0 : goto out;
2507 : : }
2508 [ # # ]: 0 : else if (g_strcmp0 (command, "call") == 0)
2509 : : {
2510 [ # # ]: 0 : if (handle_call (&argc,
2511 : : &argv,
2512 : : request_completion,
2513 : : completion_cur,
2514 : : completion_prev))
2515 : 0 : ret = 0;
2516 : 0 : goto out;
2517 : : }
2518 [ # # ]: 0 : else if (g_strcmp0 (command, "introspect") == 0)
2519 : : {
2520 [ # # ]: 0 : if (handle_introspect (&argc,
2521 : : &argv,
2522 : : request_completion,
2523 : : completion_cur,
2524 : : completion_prev))
2525 : 0 : ret = 0;
2526 : 0 : goto out;
2527 : : }
2528 [ # # ]: 0 : else if (g_strcmp0 (command, "monitor") == 0)
2529 : : {
2530 [ # # ]: 0 : if (handle_monitor (&argc,
2531 : : &argv,
2532 : : request_completion,
2533 : : completion_cur,
2534 : : completion_prev))
2535 : 0 : ret = 0;
2536 : 0 : goto out;
2537 : : }
2538 [ # # ]: 0 : else if (g_strcmp0 (command, "wait") == 0)
2539 : : {
2540 [ # # ]: 0 : if (handle_wait (&argc,
2541 : : &argv,
2542 : : request_completion,
2543 : : completion_cur,
2544 : : completion_prev))
2545 : 0 : ret = 0;
2546 : 0 : goto out;
2547 : : }
2548 : : #ifdef G_OS_WIN32
2549 : : else if (g_strcmp0 (command, _GDBUS_ARG_WIN32_RUN_SESSION_BUS) == 0)
2550 : : {
2551 : : g_win32_run_session_bus (NULL, NULL, NULL, 0);
2552 : : ret = 0;
2553 : : goto out;
2554 : : }
2555 : : #endif
2556 [ # # # # : 0 : else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
# # ]
2557 : : {
2558 : : const gchar *completion_line;
2559 : : gchar **completion_argv;
2560 : : gint completion_argc;
2561 : : gint completion_point;
2562 : : gchar *endp;
2563 : : gint cur_begin;
2564 : :
2565 : 0 : request_completion = TRUE;
2566 : :
2567 : 0 : completion_line = argv[2];
2568 : 0 : completion_point = strtol (argv[3], &endp, 10);
2569 [ # # # # ]: 0 : if (endp == argv[3] || *endp != '\0')
2570 : 0 : goto out;
2571 : :
2572 : : #if 0
2573 : : completion_debug ("completion_point=%d", completion_point);
2574 : : completion_debug ("----");
2575 : : completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2576 : : completion_debug ("'%s'", completion_line);
2577 : : completion_debug (" %*s^",
2578 : : completion_point, "");
2579 : : completion_debug ("----");
2580 : : #endif
2581 : :
2582 [ # # ]: 0 : if (!g_shell_parse_argv (completion_line,
2583 : : &completion_argc,
2584 : : &completion_argv,
2585 : : NULL))
2586 : : {
2587 : : /* it's very possible the command line can't be parsed (for
2588 : : * example, missing quotes etc) - in that case, we just
2589 : : * don't autocomplete at all
2590 : : */
2591 : 0 : goto out;
2592 : : }
2593 : :
2594 : : /* compute cur and prev */
2595 : 0 : completion_prev = NULL;
2596 : 0 : completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2597 [ # # ]: 0 : if (cur_begin > 0)
2598 : : {
2599 : : gint prev_end;
2600 [ # # ]: 0 : for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2601 : : {
2602 [ # # ]: 0 : if (!g_ascii_isspace (completion_line[prev_end]))
2603 : : {
2604 : 0 : completion_prev = pick_word_at (completion_line, prev_end, NULL);
2605 : 0 : break;
2606 : : }
2607 : : }
2608 : : }
2609 : : #if 0
2610 : : completion_debug (" cur='%s'", completion_cur);
2611 : : completion_debug ("prev='%s'", completion_prev);
2612 : : #endif
2613 : :
2614 : 0 : argc = completion_argc;
2615 : 0 : argv = completion_argv;
2616 : :
2617 : 0 : ret = 0;
2618 : :
2619 : 0 : goto again;
2620 : : }
2621 : : else
2622 : : {
2623 [ # # ]: 0 : if (request_completion)
2624 : : {
2625 : 0 : g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
2626 : 0 : ret = 0;
2627 : 0 : goto out;
2628 : : }
2629 : : else
2630 : : {
2631 : 0 : g_printerr ("Unknown command '%s'\n", command);
2632 : 0 : usage (&argc, &argv, FALSE);
2633 : 0 : goto out;
2634 : : }
2635 : : }
2636 : :
2637 : 0 : out:
2638 : 0 : g_free (completion_cur);
2639 : 0 : g_free (completion_prev);
2640 : 0 : return ret;
2641 : : }
|