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