ci: collect test coverage and deploy a html report through gitlab pages
[glib.git] / gio / gdbus-tool.c
blob8d06f191bc891ac014e7d5a07bfb4cb7c67f11eb
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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.
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.
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/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <locale.h>
28 #include <gio/gio.h>
30 #include <gi18n.h>
32 #ifdef G_OS_WIN32
33 #include "glib/glib-private.h"
34 #endif
36 /* ---------------------------------------------------------------------------------------------------- */
38 G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
40 /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
41 * to not have it interfere with stdout/stderr)
43 #if 0
44 G_GNUC_UNUSED static void
45 completion_debug (const gchar *format, ...)
47 va_list var_args;
48 gchar *s;
49 static FILE *f = NULL;
51 va_start (var_args, format);
52 s = g_strdup_vprintf (format, var_args);
53 if (f == NULL)
55 f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
57 fprintf (f, "%s\n", s);
58 g_free (s);
60 #else
61 static void
62 completion_debug (const gchar *format, ...)
65 #endif
67 /* ---------------------------------------------------------------------------------------------------- */
70 static void
71 remove_arg (gint num, gint *argc, gchar **argv[])
73 gint n;
75 g_assert (num <= (*argc));
77 for (n = num; (*argv)[n] != NULL; n++)
78 (*argv)[n] = (*argv)[n+1];
79 (*argv)[n] = NULL;
80 (*argc) = (*argc) - 1;
83 static void
84 usage (gint *argc, gchar **argv[], gboolean use_stdout)
86 GOptionContext *o;
87 gchar *s;
88 gchar *program_name;
90 o = g_option_context_new (_("COMMAND"));
91 g_option_context_set_help_enabled (o, FALSE);
92 /* Ignore parsing result */
93 g_option_context_parse (o, argc, argv, NULL);
94 program_name = g_path_get_basename ((*argv)[0]);
95 s = g_strdup_printf (_("Commands:\n"
96 " help Shows this information\n"
97 " introspect Introspect a remote object\n"
98 " monitor Monitor a remote object\n"
99 " call Invoke a method on a remote object\n"
100 " emit Emit a signal\n"
101 " wait Wait for a bus name to appear\n"
102 "\n"
103 "Use “%s COMMAND --help” to get help on each command.\n"),
104 program_name);
105 g_free (program_name);
106 g_option_context_set_description (o, s);
107 g_free (s);
108 s = g_option_context_get_help (o, FALSE, NULL);
109 if (use_stdout)
110 g_print ("%s", s);
111 else
112 g_printerr ("%s", s);
113 g_free (s);
114 g_option_context_free (o);
117 static void
118 modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
120 gchar *s;
121 gchar *program_name;
123 /* TODO:
124 * 1. get a g_set_prgname() ?; or
125 * 2. save old argv[0] and restore later
128 g_assert (g_strcmp0 ((*argv)[1], command) == 0);
129 remove_arg (1, argc, argv);
131 program_name = g_path_get_basename ((*argv)[0]);
132 s = g_strdup_printf ("%s %s", (*argv)[0], command);
133 (*argv)[0] = s;
134 g_free (program_name);
137 static GOptionContext *
138 command_option_context_new (const gchar *parameter_string,
139 const gchar *summary,
140 const GOptionEntry *entries,
141 gboolean request_completion)
143 GOptionContext *o = NULL;
145 o = g_option_context_new (parameter_string);
146 if (request_completion)
147 g_option_context_set_ignore_unknown_options (o, TRUE);
148 g_option_context_set_help_enabled (o, FALSE);
149 g_option_context_set_summary (o, summary);
150 g_option_context_add_main_entries (o, entries, GETTEXT_PACKAGE);
152 return g_steal_pointer (&o);
155 /* ---------------------------------------------------------------------------------------------------- */
157 static void
158 print_methods_and_signals (GDBusConnection *c,
159 const gchar *name,
160 const gchar *path,
161 gboolean print_methods,
162 gboolean print_signals)
164 GVariant *result;
165 GError *error;
166 const gchar *xml_data;
167 GDBusNodeInfo *node;
168 guint n;
169 guint m;
171 error = NULL;
172 result = g_dbus_connection_call_sync (c,
173 name,
174 path,
175 "org.freedesktop.DBus.Introspectable",
176 "Introspect",
177 NULL,
178 G_VARIANT_TYPE ("(s)"),
179 G_DBUS_CALL_FLAGS_NONE,
180 3000, /* 3 secs */
181 NULL,
182 &error);
183 if (result == NULL)
185 g_printerr (_("Error: %s\n"), error->message);
186 g_error_free (error);
187 goto out;
189 g_variant_get (result, "(&s)", &xml_data);
191 error = NULL;
192 node = g_dbus_node_info_new_for_xml (xml_data, &error);
193 g_variant_unref (result);
194 if (node == NULL)
196 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
197 g_error_free (error);
198 goto out;
201 for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
203 const GDBusInterfaceInfo *iface = node->interfaces[n];
204 for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++)
206 const GDBusMethodInfo *method = iface->methods[m];
207 g_print ("%s.%s \n", iface->name, method->name);
209 for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++)
211 const GDBusSignalInfo *signal = iface->signals[m];
212 g_print ("%s.%s \n", iface->name, signal->name);
215 g_dbus_node_info_unref (node);
217 out:
221 static void
222 print_paths (GDBusConnection *c,
223 const gchar *name,
224 const gchar *path)
226 GVariant *result;
227 GError *error;
228 const gchar *xml_data;
229 GDBusNodeInfo *node;
230 guint n;
232 if (!g_dbus_is_name (name))
234 g_printerr (_("Error: %s is not a valid name\n"), name);
235 goto out;
238 error = NULL;
239 result = g_dbus_connection_call_sync (c,
240 name,
241 path,
242 "org.freedesktop.DBus.Introspectable",
243 "Introspect",
244 NULL,
245 G_VARIANT_TYPE ("(s)"),
246 G_DBUS_CALL_FLAGS_NONE,
247 3000, /* 3 secs */
248 NULL,
249 &error);
250 if (result == NULL)
252 g_printerr (_("Error: %s\n"), error->message);
253 g_error_free (error);
254 goto out;
256 g_variant_get (result, "(&s)", &xml_data);
258 //g_printerr ("xml='%s'", xml_data);
260 error = NULL;
261 node = g_dbus_node_info_new_for_xml (xml_data, &error);
262 g_variant_unref (result);
263 if (node == NULL)
265 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
266 g_error_free (error);
267 goto out;
270 //g_printerr ("bar '%s'\n", path);
272 if (node->interfaces != NULL)
273 g_print ("%s \n", path);
275 for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
277 gchar *s;
279 //g_printerr ("foo '%s'\n", node->nodes[n].path);
281 if (g_strcmp0 (path, "/") == 0)
282 s = g_strdup_printf ("/%s", node->nodes[n]->path);
283 else
284 s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
286 print_paths (c, name, s);
288 g_free (s);
290 g_dbus_node_info_unref (node);
292 out:
296 static void
297 print_names (GDBusConnection *c,
298 gboolean include_unique_names)
300 GVariant *result;
301 GError *error;
302 GVariantIter *iter;
303 gchar *str;
304 GHashTable *name_set;
305 GList *keys;
306 GList *l;
308 name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
310 error = NULL;
311 result = g_dbus_connection_call_sync (c,
312 "org.freedesktop.DBus",
313 "/org/freedesktop/DBus",
314 "org.freedesktop.DBus",
315 "ListNames",
316 NULL,
317 G_VARIANT_TYPE ("(as)"),
318 G_DBUS_CALL_FLAGS_NONE,
319 3000, /* 3 secs */
320 NULL,
321 &error);
322 if (result == NULL)
324 g_printerr (_("Error: %s\n"), error->message);
325 g_error_free (error);
326 goto out;
328 g_variant_get (result, "(as)", &iter);
329 while (g_variant_iter_loop (iter, "s", &str))
330 g_hash_table_add (name_set, g_strdup (str));
331 g_variant_iter_free (iter);
332 g_variant_unref (result);
334 error = NULL;
335 result = g_dbus_connection_call_sync (c,
336 "org.freedesktop.DBus",
337 "/org/freedesktop/DBus",
338 "org.freedesktop.DBus",
339 "ListActivatableNames",
340 NULL,
341 G_VARIANT_TYPE ("(as)"),
342 G_DBUS_CALL_FLAGS_NONE,
343 3000, /* 3 secs */
344 NULL,
345 &error);
346 if (result == NULL)
348 g_printerr (_("Error: %s\n"), error->message);
349 g_error_free (error);
350 goto out;
352 g_variant_get (result, "(as)", &iter);
353 while (g_variant_iter_loop (iter, "s", &str))
354 g_hash_table_add (name_set, g_strdup (str));
355 g_variant_iter_free (iter);
356 g_variant_unref (result);
358 keys = g_hash_table_get_keys (name_set);
359 keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
360 for (l = keys; l != NULL; l = l->next)
362 const gchar *name = l->data;
363 if (!include_unique_names && g_str_has_prefix (name, ":"))
364 continue;
366 g_print ("%s \n", name);
368 g_list_free (keys);
370 out:
371 g_hash_table_unref (name_set);
374 /* ---------------------------------------------------------------------------------------------------- */
376 static gboolean opt_connection_system = FALSE;
377 static gboolean opt_connection_session = FALSE;
378 static gchar *opt_connection_address = NULL;
380 static const GOptionEntry connection_entries[] =
382 { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
383 { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
384 { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), NULL},
385 { NULL }
388 static GOptionGroup *
389 connection_get_group (void)
391 static GOptionGroup *g;
393 g = g_option_group_new ("connection",
394 N_("Connection Endpoint Options:"),
395 N_("Options specifying the connection endpoint"),
396 NULL,
397 NULL);
398 g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
399 g_option_group_add_entries (g, connection_entries);
401 return g;
404 static GDBusConnection *
405 connection_get_dbus_connection (GError **error)
407 GDBusConnection *c;
409 c = NULL;
411 /* First, ensure we have exactly one connect */
412 if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
414 g_set_error (error,
415 G_IO_ERROR,
416 G_IO_ERROR_FAILED,
417 _("No connection endpoint specified"));
418 goto out;
420 else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
421 (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
422 (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
424 g_set_error (error,
425 G_IO_ERROR,
426 G_IO_ERROR_FAILED,
427 _("Multiple connection endpoints specified"));
428 goto out;
431 if (opt_connection_system)
433 c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
435 else if (opt_connection_session)
437 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
439 else if (opt_connection_address != NULL)
441 c = g_dbus_connection_new_for_address_sync (opt_connection_address,
442 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
443 NULL, /* GDBusAuthObserver */
444 NULL, /* GCancellable */
445 error);
448 out:
449 return c;
452 /* ---------------------------------------------------------------------------------------------------- */
454 static GPtrArray *
455 call_helper_get_method_in_signature (GDBusConnection *c,
456 const gchar *dest,
457 const gchar *path,
458 const gchar *interface_name,
459 const gchar *method_name,
460 GError **error)
462 GPtrArray *ret;
463 GVariant *result;
464 GDBusNodeInfo *node_info;
465 const gchar *xml_data;
466 GDBusInterfaceInfo *interface_info;
467 GDBusMethodInfo *method_info;
468 guint n;
470 ret = NULL;
471 result = NULL;
472 node_info = NULL;
474 result = g_dbus_connection_call_sync (c,
475 dest,
476 path,
477 "org.freedesktop.DBus.Introspectable",
478 "Introspect",
479 NULL,
480 G_VARIANT_TYPE ("(s)"),
481 G_DBUS_CALL_FLAGS_NONE,
482 3000, /* 3 secs */
483 NULL,
484 error);
485 if (result == NULL)
486 goto out;
488 g_variant_get (result, "(&s)", &xml_data);
489 node_info = g_dbus_node_info_new_for_xml (xml_data, error);
490 if (node_info == NULL)
491 goto out;
493 interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
494 if (interface_info == NULL)
496 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
497 _("Warning: According to introspection data, interface “%s” does not exist\n"),
498 interface_name);
499 goto out;
502 method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
503 if (method_info == NULL)
505 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
506 _("Warning: According to introspection data, method “%s” does not exist on interface “%s”\n"),
507 method_name,
508 interface_name);
509 goto out;
512 ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
513 for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
515 g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
518 out:
519 if (node_info != NULL)
520 g_dbus_node_info_unref (node_info);
521 if (result != NULL)
522 g_variant_unref (result);
524 return ret;
527 /* ---------------------------------------------------------------------------------------------------- */
529 static GVariant *
530 _g_variant_parse_me_harder (GVariantType *type,
531 const gchar *given_str,
532 GError **error)
534 GVariant *value;
535 gchar *s;
536 guint n;
537 GString *str;
539 str = g_string_new ("\"");
540 for (n = 0; given_str[n] != '\0'; n++)
542 if (G_UNLIKELY (given_str[n] == '\"'))
543 g_string_append (str, "\\\"");
544 else
545 g_string_append_c (str, given_str[n]);
547 g_string_append_c (str, '"');
548 s = g_string_free (str, FALSE);
550 value = g_variant_parse (type,
552 NULL,
553 NULL,
554 error);
555 g_free (s);
557 return value;
560 /* ---------------------------------------------------------------------------------------------------- */
562 static gchar *opt_emit_dest = NULL;
563 static gchar *opt_emit_object_path = NULL;
564 static gchar *opt_emit_signal = NULL;
566 static const GOptionEntry emit_entries[] =
568 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
569 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
570 { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
571 { NULL }
574 static gboolean
575 handle_emit (gint *argc,
576 gchar **argv[],
577 gboolean request_completion,
578 const gchar *completion_cur,
579 const gchar *completion_prev)
581 gint ret;
582 GOptionContext *o;
583 gchar *s;
584 GError *error;
585 GDBusConnection *c;
586 GVariant *parameters;
587 gchar *interface_name;
588 gchar *signal_name;
589 GVariantBuilder builder;
590 gboolean skip_dashes;
591 guint parm;
592 guint n;
593 gboolean complete_names, complete_paths, complete_signals;
595 ret = FALSE;
596 c = NULL;
597 parameters = NULL;
598 interface_name = NULL;
599 signal_name = NULL;
601 modify_argv0_for_command (argc, argv, "emit");
603 o = command_option_context_new (NULL, _("Emit a signal."),
604 emit_entries, request_completion);
605 g_option_context_add_group (o, connection_get_group ());
607 complete_names = FALSE;
608 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
610 complete_names = TRUE;
611 remove_arg ((*argc) - 1, argc, argv);
614 complete_paths = FALSE;
615 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
617 complete_paths = TRUE;
618 remove_arg ((*argc) - 1, argc, argv);
621 complete_signals = FALSE;
622 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
624 complete_signals = TRUE;
625 remove_arg ((*argc) - 1, argc, argv);
628 if (!g_option_context_parse (o, argc, argv, NULL))
630 if (!request_completion)
632 s = g_option_context_get_help (o, FALSE, NULL);
633 g_printerr ("%s", s);
634 g_free (s);
635 goto out;
639 error = NULL;
640 c = connection_get_dbus_connection (&error);
641 if (c == NULL)
643 if (request_completion)
645 if (g_strcmp0 (completion_prev, "--address") == 0)
647 g_print ("unix:\n"
648 "tcp:\n"
649 "nonce-tcp:\n");
651 else
653 g_print ("--system \n--session \n--address \n");
656 else
658 g_printerr (_("Error connecting: %s\n"), error->message);
659 g_error_free (error);
661 goto out;
664 /* validate and complete destination (bus name) */
665 if (complete_names)
667 print_names (c, FALSE);
668 goto out;
670 if (request_completion && opt_emit_dest != NULL && g_strcmp0 ("--dest", completion_prev) == 0)
672 print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
673 goto out;
676 if (!request_completion && opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
678 g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
679 goto out;
682 if (opt_emit_dest == NULL && opt_emit_object_path == NULL && request_completion)
684 g_print ("--dest \n");
686 /* validate and complete object path */
687 if (opt_emit_dest != NULL && complete_paths)
689 print_paths (c, opt_emit_dest, "/");
690 goto out;
692 if (opt_emit_object_path == NULL)
694 if (request_completion)
695 g_print ("--object-path \n");
696 else
697 g_printerr (_("Error: Object path is not specified\n"));
698 goto out;
700 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
702 if (opt_emit_dest != NULL)
704 gchar *p;
705 s = g_strdup (opt_emit_object_path);
706 p = strrchr (s, '/');
707 if (p != NULL)
709 if (p == s)
710 p++;
711 *p = '\0';
713 print_paths (c, opt_emit_dest, s);
714 g_free (s);
716 goto out;
718 if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
720 g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
721 goto out;
724 /* validate and complete signal (interface + signal name) */
725 if (opt_emit_dest != NULL && opt_emit_object_path != NULL && complete_signals)
727 print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
728 goto out;
730 if (opt_emit_signal == NULL)
732 /* don't keep repeatedly completing --signal */
733 if (request_completion)
735 if (g_strcmp0 ("--signal", completion_prev) != 0)
736 g_print ("--signal \n");
738 else
740 g_printerr (_("Error: Signal name is not specified\n"));
743 goto out;
745 if (request_completion && opt_emit_dest != NULL && opt_emit_object_path != NULL &&
746 g_strcmp0 ("--signal", completion_prev) == 0)
748 print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
749 goto out;
751 s = strrchr (opt_emit_signal, '.');
752 if (!request_completion && s == NULL)
754 g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
755 goto out;
757 signal_name = g_strdup (s + 1);
758 interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
760 /* All done with completion now */
761 if (request_completion)
762 goto out;
764 if (!g_dbus_is_interface_name (interface_name))
766 g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
767 goto out;
770 if (!g_dbus_is_member_name (signal_name))
772 g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
773 goto out;
776 /* Read parameters */
777 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
778 skip_dashes = TRUE;
779 parm = 0;
780 for (n = 1; n < (guint) *argc; n++)
782 GVariant *value;
784 /* Under certain conditions, g_option_context_parse returns the "--"
785 itself (setting off unparsed arguments), too: */
786 if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
788 skip_dashes = FALSE;
789 continue;
792 error = NULL;
793 value = g_variant_parse (NULL,
794 (*argv)[n],
795 NULL,
796 NULL,
797 &error);
798 if (value == NULL)
800 gchar *context;
802 context = g_variant_parse_error_print_context (error, (*argv)[n]);
803 g_error_free (error);
804 error = NULL;
805 value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
806 if (value == NULL)
808 /* Use the original non-"parse-me-harder" error */
809 g_printerr (_("Error parsing parameter %d: %s\n"),
810 parm + 1,
811 context);
812 g_error_free (error);
813 g_free (context);
814 g_variant_builder_clear (&builder);
815 goto out;
817 g_free (context);
819 g_variant_builder_add_value (&builder, value);
820 ++parm;
822 parameters = g_variant_builder_end (&builder);
824 if (parameters != NULL)
825 parameters = g_variant_ref_sink (parameters);
826 if (!g_dbus_connection_emit_signal (c,
827 opt_emit_dest,
828 opt_emit_object_path,
829 interface_name,
830 signal_name,
831 parameters,
832 &error))
834 g_printerr (_("Error: %s\n"), error->message);
835 g_error_free (error);
836 goto out;
839 if (!g_dbus_connection_flush_sync (c, NULL, &error))
841 g_printerr (_("Error flushing connection: %s\n"), error->message);
842 g_error_free (error);
843 goto out;
846 ret = TRUE;
848 out:
849 if (c != NULL)
850 g_object_unref (c);
851 if (parameters != NULL)
852 g_variant_unref (parameters);
853 g_free (interface_name);
854 g_free (signal_name);
855 g_option_context_free (o);
856 return ret;
859 /* ---------------------------------------------------------------------------------------------------- */
861 static gchar *opt_call_dest = NULL;
862 static gchar *opt_call_object_path = NULL;
863 static gchar *opt_call_method = NULL;
864 static gint opt_call_timeout = -1;
866 static const GOptionEntry call_entries[] =
868 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
869 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
870 { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
871 { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
872 { NULL }
875 static gboolean
876 handle_call (gint *argc,
877 gchar **argv[],
878 gboolean request_completion,
879 const gchar *completion_cur,
880 const gchar *completion_prev)
882 gint ret;
883 GOptionContext *o;
884 gchar *s;
885 GError *error;
886 GDBusConnection *c;
887 GVariant *parameters;
888 gchar *interface_name;
889 gchar *method_name;
890 GVariant *result;
891 GPtrArray *in_signature_types;
892 gboolean complete_names;
893 gboolean complete_paths;
894 gboolean complete_methods;
895 GVariantBuilder builder;
896 gboolean skip_dashes;
897 guint parm;
898 guint n;
900 ret = FALSE;
901 c = NULL;
902 parameters = NULL;
903 interface_name = NULL;
904 method_name = NULL;
905 result = NULL;
906 in_signature_types = NULL;
908 modify_argv0_for_command (argc, argv, "call");
910 o = command_option_context_new (NULL, _("Invoke a method on a remote object."),
911 call_entries, request_completion);
912 g_option_context_add_group (o, connection_get_group ());
914 complete_names = FALSE;
915 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
917 complete_names = TRUE;
918 remove_arg ((*argc) - 1, argc, argv);
921 complete_paths = FALSE;
922 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
924 complete_paths = TRUE;
925 remove_arg ((*argc) - 1, argc, argv);
928 complete_methods = FALSE;
929 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
931 complete_methods = TRUE;
932 remove_arg ((*argc) - 1, argc, argv);
935 if (!g_option_context_parse (o, argc, argv, NULL))
937 if (!request_completion)
939 s = g_option_context_get_help (o, FALSE, NULL);
940 g_printerr ("%s", s);
941 g_free (s);
942 goto out;
946 error = NULL;
947 c = connection_get_dbus_connection (&error);
948 if (c == NULL)
950 if (request_completion)
952 if (g_strcmp0 (completion_prev, "--address") == 0)
954 g_print ("unix:\n"
955 "tcp:\n"
956 "nonce-tcp:\n");
958 else
960 g_print ("--system \n--session \n--address \n");
963 else
965 g_printerr (_("Error connecting: %s\n"), error->message);
966 g_error_free (error);
968 goto out;
971 /* validate and complete destination (bus name) */
972 if (complete_names)
974 print_names (c, FALSE);
975 goto out;
977 if (opt_call_dest == NULL)
979 if (request_completion)
980 g_print ("--dest \n");
981 else
982 g_printerr (_("Error: Destination is not specified\n"));
983 goto out;
985 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
987 print_names (c, g_str_has_prefix (opt_call_dest, ":"));
988 goto out;
991 if (!request_completion && !g_dbus_is_name (opt_call_dest))
993 g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
994 goto out;
997 /* validate and complete object path */
998 if (complete_paths)
1000 print_paths (c, opt_call_dest, "/");
1001 goto out;
1003 if (opt_call_object_path == NULL)
1005 if (request_completion)
1006 g_print ("--object-path \n");
1007 else
1008 g_printerr (_("Error: Object path is not specified\n"));
1009 goto out;
1011 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1013 gchar *p;
1014 s = g_strdup (opt_call_object_path);
1015 p = strrchr (s, '/');
1016 if (p != NULL)
1018 if (p == s)
1019 p++;
1020 *p = '\0';
1022 print_paths (c, opt_call_dest, s);
1023 g_free (s);
1024 goto out;
1026 if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
1028 g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
1029 goto out;
1032 /* validate and complete method (interface + method name) */
1033 if (complete_methods)
1035 print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1036 goto out;
1038 if (opt_call_method == NULL)
1040 if (request_completion)
1041 g_print ("--method \n");
1042 else
1043 g_printerr (_("Error: Method name is not specified\n"));
1044 goto out;
1046 if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
1048 print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1049 goto out;
1051 s = strrchr (opt_call_method, '.');
1052 if (!request_completion && s == NULL)
1054 g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
1055 goto out;
1057 method_name = g_strdup (s + 1);
1058 interface_name = g_strndup (opt_call_method, s - opt_call_method);
1060 /* All done with completion now */
1061 if (request_completion)
1062 goto out;
1064 /* Introspect, for easy conversion - it's not fatal if we can't do this */
1065 in_signature_types = call_helper_get_method_in_signature (c,
1066 opt_call_dest,
1067 opt_call_object_path,
1068 interface_name,
1069 method_name,
1070 &error);
1071 if (in_signature_types == NULL)
1073 //g_printerr ("Error getting introspection data: %s\n", error->message);
1074 g_error_free (error);
1075 error = NULL;
1078 /* Read parameters */
1079 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1080 skip_dashes = TRUE;
1081 parm = 0;
1082 for (n = 1; n < (guint) *argc; n++)
1084 GVariant *value;
1085 GVariantType *type;
1087 /* Under certain conditions, g_option_context_parse returns the "--"
1088 itself (setting off unparsed arguments), too: */
1089 if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
1091 skip_dashes = FALSE;
1092 continue;
1095 type = NULL;
1096 if (in_signature_types != NULL)
1098 if (parm >= in_signature_types->len)
1100 /* Only warn for the first param */
1101 if (parm == in_signature_types->len)
1103 g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
1104 in_signature_types->len);
1107 else
1109 type = in_signature_types->pdata[parm];
1113 error = NULL;
1114 value = g_variant_parse (type,
1115 (*argv)[n],
1116 NULL,
1117 NULL,
1118 &error);
1119 if (value == NULL)
1121 gchar *context;
1123 context = g_variant_parse_error_print_context (error, (*argv)[n]);
1124 g_error_free (error);
1125 error = NULL;
1126 value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
1127 if (value == NULL)
1129 if (type != NULL)
1131 s = g_variant_type_dup_string (type);
1132 g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
1133 parm + 1,
1135 context);
1136 g_free (s);
1138 else
1140 g_printerr (_("Error parsing parameter %d: %s\n"),
1141 parm + 1,
1142 context);
1144 g_error_free (error);
1145 g_variant_builder_clear (&builder);
1146 g_free (context);
1147 goto out;
1149 g_free (context);
1151 g_variant_builder_add_value (&builder, value);
1152 ++parm;
1154 parameters = g_variant_builder_end (&builder);
1156 if (parameters != NULL)
1157 parameters = g_variant_ref_sink (parameters);
1158 result = g_dbus_connection_call_sync (c,
1159 opt_call_dest,
1160 opt_call_object_path,
1161 interface_name,
1162 method_name,
1163 parameters,
1164 NULL,
1165 G_DBUS_CALL_FLAGS_NONE,
1166 opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1167 NULL,
1168 &error);
1169 if (result == NULL)
1171 g_printerr (_("Error: %s\n"), error->message);
1173 if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
1175 if (in_signature_types->len > 0)
1177 GString *s;
1178 s = g_string_new (NULL);
1180 for (n = 0; n < in_signature_types->len; n++)
1182 GVariantType *type = in_signature_types->pdata[n];
1183 g_string_append_len (s,
1184 g_variant_type_peek_string (type),
1185 g_variant_type_get_string_length (type));
1188 g_printerr ("(According to introspection data, you need to pass '%s')\n", s->str);
1189 g_string_free (s, TRUE);
1191 else
1192 g_printerr ("(According to introspection data, you need to pass no arguments)\n");
1195 g_error_free (error);
1196 goto out;
1199 s = g_variant_print (result, TRUE);
1200 g_print ("%s\n", s);
1201 g_free (s);
1203 ret = TRUE;
1205 out:
1206 if (in_signature_types != NULL)
1207 g_ptr_array_unref (in_signature_types);
1208 if (result != NULL)
1209 g_variant_unref (result);
1210 if (c != NULL)
1211 g_object_unref (c);
1212 if (parameters != NULL)
1213 g_variant_unref (parameters);
1214 g_free (interface_name);
1215 g_free (method_name);
1216 g_option_context_free (o);
1217 return ret;
1220 /* ---------------------------------------------------------------------------------------------------- */
1222 static gchar *opt_introspect_dest = NULL;
1223 static gchar *opt_introspect_object_path = NULL;
1224 static gboolean opt_introspect_xml = FALSE;
1225 static gboolean opt_introspect_recurse = FALSE;
1226 static gboolean opt_introspect_only_properties = FALSE;
1228 static void
1229 dump_annotation (const GDBusAnnotationInfo *o,
1230 guint indent,
1231 gboolean ignore_indent)
1233 guint n;
1234 g_print ("%*s@%s(\"%s\")\n",
1235 ignore_indent ? 0 : indent, "",
1236 o->key,
1237 o->value);
1238 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1239 dump_annotation (o->annotations[n], indent + 2, FALSE);
1242 static void
1243 dump_arg (const GDBusArgInfo *o,
1244 guint indent,
1245 const gchar *direction,
1246 gboolean ignore_indent,
1247 gboolean include_newline)
1249 guint n;
1251 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1253 dump_annotation (o->annotations[n], indent, ignore_indent);
1254 ignore_indent = FALSE;
1257 g_print ("%*s%s%s %s%s",
1258 ignore_indent ? 0 : indent, "",
1259 direction,
1260 o->signature,
1261 o->name,
1262 include_newline ? ",\n" : "");
1265 static guint
1266 count_args (GDBusArgInfo **args)
1268 guint n;
1269 n = 0;
1270 if (args == NULL)
1271 goto out;
1272 while (args[n] != NULL)
1273 n++;
1274 out:
1275 return n;
1278 static void
1279 dump_method (const GDBusMethodInfo *o,
1280 guint indent)
1282 guint n;
1283 guint m;
1284 guint name_len;
1285 guint total_num_args;
1287 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1288 dump_annotation (o->annotations[n], indent, FALSE);
1290 g_print ("%*s%s(", indent, "", o->name);
1291 name_len = strlen (o->name);
1292 total_num_args = count_args (o->in_args) + count_args (o->out_args);
1293 for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1295 gboolean ignore_indent = (m == 0);
1296 gboolean include_newline = (m != total_num_args - 1);
1298 dump_arg (o->in_args[n],
1299 indent + name_len + 1,
1300 "in ",
1301 ignore_indent,
1302 include_newline);
1304 for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1306 gboolean ignore_indent = (m == 0);
1307 gboolean include_newline = (m != total_num_args - 1);
1308 dump_arg (o->out_args[n],
1309 indent + name_len + 1,
1310 "out ",
1311 ignore_indent,
1312 include_newline);
1314 g_print (");\n");
1317 static void
1318 dump_signal (const GDBusSignalInfo *o,
1319 guint indent)
1321 guint n;
1322 guint name_len;
1323 guint total_num_args;
1325 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1326 dump_annotation (o->annotations[n], indent, FALSE);
1328 g_print ("%*s%s(", indent, "", o->name);
1329 name_len = strlen (o->name);
1330 total_num_args = count_args (o->args);
1331 for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1333 gboolean ignore_indent = (n == 0);
1334 gboolean include_newline = (n != total_num_args - 1);
1335 dump_arg (o->args[n],
1336 indent + name_len + 1,
1338 ignore_indent,
1339 include_newline);
1341 g_print (");\n");
1344 static void
1345 dump_property (const GDBusPropertyInfo *o,
1346 guint indent,
1347 GVariant *value)
1349 const gchar *access;
1350 guint n;
1352 if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1353 access = "readonly";
1354 else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1355 access = "writeonly";
1356 else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1357 access = "readwrite";
1358 else
1359 g_assert_not_reached ();
1361 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1362 dump_annotation (o->annotations[n], indent, FALSE);
1364 if (value != NULL)
1366 gchar *s = g_variant_print (value, FALSE);
1367 g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
1368 g_free (s);
1370 else
1372 g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1376 static void
1377 dump_interface (GDBusConnection *c,
1378 const gchar *name,
1379 const GDBusInterfaceInfo *o,
1380 guint indent,
1381 const gchar *object_path)
1383 guint n;
1384 GHashTable *properties;
1386 properties = g_hash_table_new_full (g_str_hash,
1387 g_str_equal,
1388 g_free,
1389 (GDestroyNotify) g_variant_unref);
1391 /* Try to get properties */
1392 if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1394 GVariant *result;
1395 result = g_dbus_connection_call_sync (c,
1396 name,
1397 object_path,
1398 "org.freedesktop.DBus.Properties",
1399 "GetAll",
1400 g_variant_new ("(s)", o->name),
1401 NULL,
1402 G_DBUS_CALL_FLAGS_NONE,
1403 3000,
1404 NULL,
1405 NULL);
1406 if (result != NULL)
1408 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1410 GVariantIter *iter;
1411 GVariant *item;
1412 g_variant_get (result,
1413 "(a{sv})",
1414 &iter);
1415 while ((item = g_variant_iter_next_value (iter)))
1417 gchar *key;
1418 GVariant *value;
1419 g_variant_get (item,
1420 "{sv}",
1421 &key,
1422 &value);
1424 g_hash_table_insert (properties, key, g_variant_ref (value));
1427 g_variant_unref (result);
1429 else
1431 guint n;
1432 for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1434 result = g_dbus_connection_call_sync (c,
1435 name,
1436 object_path,
1437 "org.freedesktop.DBus.Properties",
1438 "Get",
1439 g_variant_new ("(ss)", o->name, o->properties[n]->name),
1440 G_VARIANT_TYPE ("(v)"),
1441 G_DBUS_CALL_FLAGS_NONE,
1442 3000,
1443 NULL,
1444 NULL);
1445 if (result != NULL)
1447 GVariant *property_value;
1448 g_variant_get (result,
1449 "(v)",
1450 &property_value);
1451 g_hash_table_insert (properties,
1452 g_strdup (o->properties[n]->name),
1453 g_variant_ref (property_value));
1454 g_variant_unref (result);
1460 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1461 dump_annotation (o->annotations[n], indent, FALSE);
1463 g_print ("%*sinterface %s {\n", indent, "", o->name);
1464 if (o->methods != NULL && !opt_introspect_only_properties)
1466 g_print ("%*s methods:\n", indent, "");
1467 for (n = 0; o->methods[n] != NULL; n++)
1468 dump_method (o->methods[n], indent + 4);
1470 if (o->signals != NULL && !opt_introspect_only_properties)
1472 g_print ("%*s signals:\n", indent, "");
1473 for (n = 0; o->signals[n] != NULL; n++)
1474 dump_signal (o->signals[n], indent + 4);
1476 if (o->properties != NULL)
1478 g_print ("%*s properties:\n", indent, "");
1479 for (n = 0; o->properties[n] != NULL; n++)
1481 dump_property (o->properties[n],
1482 indent + 4,
1483 g_hash_table_lookup (properties, (o->properties[n])->name));
1486 g_print ("%*s};\n",
1487 indent, "");
1489 g_hash_table_unref (properties);
1492 static gboolean
1493 introspect_do (GDBusConnection *c,
1494 const gchar *object_path,
1495 guint indent);
1497 static void
1498 dump_node (GDBusConnection *c,
1499 const gchar *name,
1500 const GDBusNodeInfo *o,
1501 guint indent,
1502 const gchar *object_path,
1503 gboolean recurse)
1505 guint n;
1506 const gchar *object_path_to_print;
1508 object_path_to_print = object_path;
1509 if (o->path != NULL)
1510 object_path_to_print = o->path;
1512 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1513 dump_annotation (o->annotations[n], indent, FALSE);
1515 g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
1516 if (o->interfaces != NULL || o->nodes != NULL)
1518 g_print (" {\n");
1519 for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1521 if (opt_introspect_only_properties)
1523 if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1524 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1526 else
1528 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1531 for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1533 if (recurse)
1535 gchar *child_path;
1536 if (g_variant_is_object_path (o->nodes[n]->path))
1538 child_path = g_strdup (o->nodes[n]->path);
1539 /* avoid infinite loops */
1540 if (g_str_has_prefix (child_path, object_path))
1542 introspect_do (c, child_path, indent + 2);
1544 else
1546 g_print ("Skipping path %s that is not enclosed by parent %s\n",
1547 child_path, object_path);
1550 else
1552 if (g_strcmp0 (object_path, "/") == 0)
1553 child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1554 else
1555 child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1556 introspect_do (c, child_path, indent + 2);
1558 g_free (child_path);
1560 else
1562 dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
1565 g_print ("%*s};\n",
1566 indent, "");
1568 else
1570 g_print ("\n");
1574 static const GOptionEntry introspect_entries[] =
1576 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1577 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1578 { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1579 { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1580 { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1581 { NULL }
1584 static gboolean
1585 introspect_do (GDBusConnection *c,
1586 const gchar *object_path,
1587 guint indent)
1589 GError *error;
1590 GVariant *result;
1591 GDBusNodeInfo *node;
1592 gboolean ret;
1593 const gchar *xml_data;
1595 ret = FALSE;
1596 node = NULL;
1597 result = NULL;
1599 error = NULL;
1600 result = g_dbus_connection_call_sync (c,
1601 opt_introspect_dest,
1602 object_path,
1603 "org.freedesktop.DBus.Introspectable",
1604 "Introspect",
1605 NULL,
1606 G_VARIANT_TYPE ("(s)"),
1607 G_DBUS_CALL_FLAGS_NONE,
1608 3000, /* 3 sec */
1609 NULL,
1610 &error);
1611 if (result == NULL)
1613 g_printerr (_("Error: %s\n"), error->message);
1614 g_error_free (error);
1615 goto out;
1617 g_variant_get (result, "(&s)", &xml_data);
1619 if (opt_introspect_xml)
1621 g_print ("%s", xml_data);
1623 else
1625 error = NULL;
1626 node = g_dbus_node_info_new_for_xml (xml_data, &error);
1627 if (node == NULL)
1629 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1630 g_error_free (error);
1631 goto out;
1634 dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
1637 ret = TRUE;
1639 out:
1640 if (node != NULL)
1641 g_dbus_node_info_unref (node);
1642 if (result != NULL)
1643 g_variant_unref (result);
1644 return ret;
1647 static gboolean
1648 handle_introspect (gint *argc,
1649 gchar **argv[],
1650 gboolean request_completion,
1651 const gchar *completion_cur,
1652 const gchar *completion_prev)
1654 gint ret;
1655 GOptionContext *o;
1656 gchar *s;
1657 GError *error;
1658 GDBusConnection *c;
1659 gboolean complete_names;
1660 gboolean complete_paths;
1662 ret = FALSE;
1663 c = NULL;
1665 modify_argv0_for_command (argc, argv, "introspect");
1667 o = command_option_context_new (NULL, _("Introspect a remote object."),
1668 introspect_entries, request_completion);
1669 g_option_context_add_group (o, connection_get_group ());
1671 complete_names = FALSE;
1672 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1674 complete_names = TRUE;
1675 remove_arg ((*argc) - 1, argc, argv);
1678 complete_paths = FALSE;
1679 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1681 complete_paths = TRUE;
1682 remove_arg ((*argc) - 1, argc, argv);
1685 if (!g_option_context_parse (o, argc, argv, NULL))
1687 if (!request_completion)
1689 s = g_option_context_get_help (o, FALSE, NULL);
1690 g_printerr ("%s", s);
1691 g_free (s);
1692 goto out;
1696 error = NULL;
1697 c = connection_get_dbus_connection (&error);
1698 if (c == NULL)
1700 if (request_completion)
1702 if (g_strcmp0 (completion_prev, "--address") == 0)
1704 g_print ("unix:\n"
1705 "tcp:\n"
1706 "nonce-tcp:\n");
1708 else
1710 g_print ("--system \n--session \n--address \n");
1713 else
1715 g_printerr (_("Error connecting: %s\n"), error->message);
1716 g_error_free (error);
1718 goto out;
1721 if (complete_names)
1723 print_names (c, FALSE);
1724 goto out;
1726 /* this only makes sense on message bus connections */
1727 if (opt_introspect_dest == NULL)
1729 if (request_completion)
1730 g_print ("--dest \n");
1731 else
1732 g_printerr (_("Error: Destination is not specified\n"));
1733 goto out;
1735 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1737 print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1738 goto out;
1741 if (complete_paths)
1743 print_paths (c, opt_introspect_dest, "/");
1744 goto out;
1747 if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
1749 g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
1750 goto out;
1753 if (opt_introspect_object_path == NULL)
1755 if (request_completion)
1756 g_print ("--object-path \n");
1757 else
1758 g_printerr (_("Error: Object path is not specified\n"));
1759 goto out;
1761 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1763 gchar *p;
1764 s = g_strdup (opt_introspect_object_path);
1765 p = strrchr (s, '/');
1766 if (p != NULL)
1768 if (p == s)
1769 p++;
1770 *p = '\0';
1772 print_paths (c, opt_introspect_dest, s);
1773 g_free (s);
1774 goto out;
1776 if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1778 g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1779 goto out;
1782 if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1784 g_print ("--recurse \n");
1787 if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1789 g_print ("--only-properties \n");
1792 /* All done with completion now */
1793 if (request_completion)
1794 goto out;
1796 if (!introspect_do (c, opt_introspect_object_path, 0))
1797 goto out;
1799 ret = TRUE;
1801 out:
1802 if (c != NULL)
1803 g_object_unref (c);
1804 g_option_context_free (o);
1805 return ret;
1808 /* ---------------------------------------------------------------------------------------------------- */
1810 static gchar *opt_monitor_dest = NULL;
1811 static gchar *opt_monitor_object_path = NULL;
1813 static guint monitor_filter_id = 0;
1815 static void
1816 monitor_signal_cb (GDBusConnection *connection,
1817 const gchar *sender_name,
1818 const gchar *object_path,
1819 const gchar *interface_name,
1820 const gchar *signal_name,
1821 GVariant *parameters,
1822 gpointer user_data)
1824 gchar *s;
1825 s = g_variant_print (parameters, TRUE);
1826 g_print ("%s: %s.%s %s\n",
1827 object_path,
1828 interface_name,
1829 signal_name,
1831 g_free (s);
1834 static void
1835 monitor_on_name_appeared (GDBusConnection *connection,
1836 const gchar *name,
1837 const gchar *name_owner,
1838 gpointer user_data)
1840 g_print ("The name %s is owned by %s\n", name, name_owner);
1841 g_assert (monitor_filter_id == 0);
1842 monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1843 name_owner,
1844 NULL, /* any interface */
1845 NULL, /* any member */
1846 opt_monitor_object_path,
1847 NULL, /* arg0 */
1848 G_DBUS_SIGNAL_FLAGS_NONE,
1849 monitor_signal_cb,
1850 NULL, /* user_data */
1851 NULL); /* user_data destroy notify */
1854 static void
1855 monitor_on_name_vanished (GDBusConnection *connection,
1856 const gchar *name,
1857 gpointer user_data)
1859 g_print ("The name %s does not have an owner\n", name);
1861 if (monitor_filter_id != 0)
1863 g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
1864 monitor_filter_id = 0;
1868 static const GOptionEntry monitor_entries[] =
1870 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1871 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1872 { NULL }
1875 static gboolean
1876 handle_monitor (gint *argc,
1877 gchar **argv[],
1878 gboolean request_completion,
1879 const gchar *completion_cur,
1880 const gchar *completion_prev)
1882 gint ret;
1883 GOptionContext *o;
1884 gchar *s;
1885 GError *error;
1886 GDBusConnection *c;
1887 gboolean complete_names;
1888 gboolean complete_paths;
1889 GMainLoop *loop;
1891 ret = FALSE;
1892 c = NULL;
1894 modify_argv0_for_command (argc, argv, "monitor");
1896 o = command_option_context_new (NULL, _("Monitor a remote object."),
1897 monitor_entries, request_completion);
1898 g_option_context_add_group (o, connection_get_group ());
1900 complete_names = FALSE;
1901 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1903 complete_names = TRUE;
1904 remove_arg ((*argc) - 1, argc, argv);
1907 complete_paths = FALSE;
1908 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1910 complete_paths = TRUE;
1911 remove_arg ((*argc) - 1, argc, argv);
1914 if (!g_option_context_parse (o, argc, argv, NULL))
1916 if (!request_completion)
1918 s = g_option_context_get_help (o, FALSE, NULL);
1919 g_printerr ("%s", s);
1920 g_free (s);
1921 goto out;
1925 error = NULL;
1926 c = connection_get_dbus_connection (&error);
1927 if (c == NULL)
1929 if (request_completion)
1931 if (g_strcmp0 (completion_prev, "--address") == 0)
1933 g_print ("unix:\n"
1934 "tcp:\n"
1935 "nonce-tcp:\n");
1937 else
1939 g_print ("--system \n--session \n--address \n");
1942 else
1944 g_printerr (_("Error connecting: %s\n"), error->message);
1945 g_error_free (error);
1947 goto out;
1950 /* Monitoring doesn’t make sense on a non-message-bus connection. */
1951 if (g_dbus_connection_get_unique_name (c) == NULL)
1953 if (!request_completion)
1954 g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
1955 goto out;
1958 if (complete_names)
1960 print_names (c, FALSE);
1961 goto out;
1963 /* this only makes sense on message bus connections */
1964 if (opt_monitor_dest == NULL)
1966 if (request_completion)
1967 g_print ("--dest \n");
1968 else
1969 g_printerr (_("Error: Destination is not specified\n"));
1970 goto out;
1972 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1974 print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
1975 goto out;
1978 if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
1980 g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
1981 goto out;
1984 if (complete_paths)
1986 print_paths (c, opt_monitor_dest, "/");
1987 goto out;
1989 if (opt_monitor_object_path == NULL)
1991 if (request_completion)
1993 g_print ("--object-path \n");
1994 goto out;
1996 /* it's fine to not have an object path */
1998 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
2000 gchar *p;
2001 s = g_strdup (opt_monitor_object_path);
2002 p = strrchr (s, '/');
2003 if (p != NULL)
2005 if (p == s)
2006 p++;
2007 *p = '\0';
2009 print_paths (c, opt_monitor_dest, s);
2010 g_free (s);
2011 goto out;
2013 if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
2015 g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
2016 goto out;
2019 /* All done with completion now */
2020 if (request_completion)
2021 goto out;
2023 if (opt_monitor_object_path != NULL)
2024 g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
2025 else
2026 g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
2028 loop = g_main_loop_new (NULL, FALSE);
2029 g_bus_watch_name_on_connection (c,
2030 opt_monitor_dest,
2031 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2032 monitor_on_name_appeared,
2033 monitor_on_name_vanished,
2034 NULL,
2035 NULL);
2037 g_main_loop_run (loop);
2038 g_main_loop_unref (loop);
2040 ret = TRUE;
2042 out:
2043 if (c != NULL)
2044 g_object_unref (c);
2045 g_option_context_free (o);
2046 return ret;
2049 /* ---------------------------------------------------------------------------------------------------- */
2051 static gboolean opt_wait_activate_set = FALSE;
2052 static gchar *opt_wait_activate_name = NULL;
2053 static gint64 opt_wait_timeout = 0; /* no timeout */
2055 typedef enum {
2056 WAIT_STATE_RUNNING, /* waiting to see the service */
2057 WAIT_STATE_SUCCESS, /* seen it successfully */
2058 WAIT_STATE_TIMEOUT, /* timed out before seeing it */
2059 } WaitState;
2061 static gboolean
2062 opt_wait_activate_cb (const gchar *option_name,
2063 const gchar *value,
2064 gpointer data,
2065 GError **error)
2067 /* @value may be NULL */
2068 opt_wait_activate_set = TRUE;
2069 opt_wait_activate_name = g_strdup (value);
2071 return TRUE;
2074 static const GOptionEntry wait_entries[] =
2076 { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
2077 opt_wait_activate_cb,
2078 N_("Service to activate before waiting for the other one (well-known name)"),
2079 "[NAME]" },
2080 { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout,
2081 N_("Timeout to wait for before exiting with an error (seconds); 0 for "
2082 "no timeout (default)"), "SECS" },
2083 { NULL }
2086 static void
2087 wait_name_appeared_cb (GDBusConnection *connection,
2088 const gchar *name,
2089 const gchar *name_owner,
2090 gpointer user_data)
2092 WaitState *wait_state = user_data;
2094 *wait_state = WAIT_STATE_SUCCESS;
2097 static gboolean
2098 wait_timeout_cb (gpointer user_data)
2100 WaitState *wait_state = user_data;
2102 *wait_state = WAIT_STATE_TIMEOUT;
2104 /* Removed in handle_wait(). */
2105 return G_SOURCE_CONTINUE;
2108 static gboolean
2109 handle_wait (gint *argc,
2110 gchar **argv[],
2111 gboolean request_completion,
2112 const gchar *completion_cur,
2113 const gchar *completion_prev)
2115 gint ret;
2116 GOptionContext *o;
2117 gchar *s;
2118 GError *error;
2119 GDBusConnection *c;
2120 guint watch_id, timer_id = 0, activate_watch_id;
2121 const gchar *activate_service, *wait_service;
2122 WaitState wait_state = WAIT_STATE_RUNNING;
2124 ret = FALSE;
2125 c = NULL;
2127 modify_argv0_for_command (argc, argv, "wait");
2129 o = command_option_context_new (_("[OPTION…] BUS-NAME"),
2130 _("Wait for a bus name to appear."),
2131 wait_entries, request_completion);
2132 g_option_context_add_group (o, connection_get_group ());
2134 if (!g_option_context_parse (o, argc, argv, NULL))
2136 if (!request_completion)
2138 s = g_option_context_get_help (o, FALSE, NULL);
2139 g_printerr ("%s", s);
2140 g_free (s);
2141 goto out;
2145 error = NULL;
2146 c = connection_get_dbus_connection (&error);
2147 if (c == NULL)
2149 if (request_completion)
2151 if (g_strcmp0 (completion_prev, "--address") == 0)
2153 g_print ("unix:\n"
2154 "tcp:\n"
2155 "nonce-tcp:\n");
2157 else
2159 g_print ("--system \n--session \n--address \n");
2162 else
2164 g_printerr (_("Error connecting: %s\n"), error->message);
2165 g_error_free (error);
2167 goto out;
2170 /* All done with completion now */
2171 if (request_completion)
2172 goto out;
2175 * Try and disentangle the command line arguments, with the aim of supporting:
2176 * gdbus wait --session --activate ActivateName WaitName
2177 * gdbus wait --session --activate ActivateAndWaitName
2178 * gdbus wait --activate --session ActivateAndWaitName
2179 * gdbus wait --session WaitName
2181 if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
2183 activate_service = opt_wait_activate_name;
2184 wait_service = (*argv)[1];
2186 else if (*argc == 2 &&
2187 opt_wait_activate_set && opt_wait_activate_name == NULL)
2189 activate_service = (*argv)[1];
2190 wait_service = (*argv)[1];
2192 else if (*argc == 2 && !opt_wait_activate_set)
2194 activate_service = NULL; /* disabled */
2195 wait_service = (*argv)[1];
2197 else if (*argc == 1 &&
2198 opt_wait_activate_set && opt_wait_activate_name != NULL)
2200 activate_service = opt_wait_activate_name;
2201 wait_service = opt_wait_activate_name;
2203 else if (*argc == 1 &&
2204 opt_wait_activate_set && opt_wait_activate_name == NULL)
2206 g_printerr (_("Error: A service to activate for must be specified.\n"));
2207 goto out;
2209 else if (*argc == 1 && !opt_wait_activate_set)
2211 g_printerr (_("Error: A service to wait for must be specified.\n"));
2212 goto out;
2214 else /* if (*argc > 2) */
2216 g_printerr (_("Error: Too many arguments.\n"));
2217 goto out;
2220 if (activate_service != NULL &&
2221 (!g_dbus_is_name (activate_service) ||
2222 g_dbus_is_unique_name (activate_service)))
2224 g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2225 activate_service);
2226 goto out;
2229 if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
2231 g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2232 wait_service);
2233 goto out;
2236 /* Start the prerequisite service if needed. */
2237 if (activate_service != NULL)
2239 activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
2240 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2241 NULL, NULL,
2242 NULL, NULL);
2244 else
2246 activate_watch_id = 0;
2249 /* Wait for the expected name to appear. */
2250 watch_id = g_bus_watch_name_on_connection (c,
2251 wait_service,
2252 G_BUS_NAME_WATCHER_FLAGS_NONE,
2253 wait_name_appeared_cb,
2254 NULL, &wait_state, NULL);
2256 /* Safety timeout. */
2257 if (opt_wait_timeout > 0)
2258 timer_id = g_timeout_add (opt_wait_timeout, wait_timeout_cb, &wait_state);
2260 while (wait_state == WAIT_STATE_RUNNING)
2261 g_main_context_iteration (NULL, TRUE);
2263 g_bus_unwatch_name (watch_id);
2264 if (timer_id != 0)
2265 g_source_remove (timer_id);
2266 if (activate_watch_id != 0)
2267 g_bus_unwatch_name (activate_watch_id);
2269 ret = (wait_state == WAIT_STATE_SUCCESS);
2271 out:
2272 g_clear_object (&c);
2273 g_option_context_free (o);
2274 g_free (opt_wait_activate_name);
2275 opt_wait_activate_name = NULL;
2277 return ret;
2280 /* ---------------------------------------------------------------------------------------------------- */
2282 static gchar *
2283 pick_word_at (const gchar *s,
2284 gint cursor,
2285 gint *out_word_begins_at)
2287 gint begin;
2288 gint end;
2290 if (s[0] == '\0')
2292 if (out_word_begins_at != NULL)
2293 *out_word_begins_at = -1;
2294 return NULL;
2297 if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
2299 if (out_word_begins_at != NULL)
2300 *out_word_begins_at = cursor;
2301 return g_strdup ("");
2304 while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
2305 cursor--;
2306 begin = cursor;
2308 end = begin;
2309 while (!g_ascii_isspace (s[end]) && s[end] != '\0')
2310 end++;
2312 if (out_word_begins_at != NULL)
2313 *out_word_begins_at = begin;
2315 return g_strndup (s + begin, end - begin);
2318 gint
2319 main (gint argc, gchar *argv[])
2321 gint ret;
2322 const gchar *command;
2323 gboolean request_completion;
2324 gchar *completion_cur;
2325 gchar *completion_prev;
2326 #ifdef G_OS_WIN32
2327 gchar *tmp;
2328 #endif
2330 setlocale (LC_ALL, "");
2331 textdomain (GETTEXT_PACKAGE);
2333 #ifdef G_OS_WIN32
2334 tmp = _glib_get_locale_dir ();
2335 bindtextdomain (GETTEXT_PACKAGE, tmp);
2336 g_free (tmp);
2337 #else
2338 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
2339 #endif
2341 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2342 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2343 #endif
2345 ret = 1;
2346 completion_cur = NULL;
2347 completion_prev = NULL;
2349 if (argc < 2)
2351 usage (&argc, &argv, FALSE);
2352 goto out;
2355 request_completion = FALSE;
2357 //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
2359 again:
2360 command = argv[1];
2361 if (g_strcmp0 (command, "help") == 0)
2363 if (request_completion)
2365 /* do nothing */
2367 else
2369 usage (&argc, &argv, TRUE);
2370 ret = 0;
2372 goto out;
2374 else if (g_strcmp0 (command, "emit") == 0)
2376 if (handle_emit (&argc,
2377 &argv,
2378 request_completion,
2379 completion_cur,
2380 completion_prev))
2381 ret = 0;
2382 goto out;
2384 else if (g_strcmp0 (command, "call") == 0)
2386 if (handle_call (&argc,
2387 &argv,
2388 request_completion,
2389 completion_cur,
2390 completion_prev))
2391 ret = 0;
2392 goto out;
2394 else if (g_strcmp0 (command, "introspect") == 0)
2396 if (handle_introspect (&argc,
2397 &argv,
2398 request_completion,
2399 completion_cur,
2400 completion_prev))
2401 ret = 0;
2402 goto out;
2404 else if (g_strcmp0 (command, "monitor") == 0)
2406 if (handle_monitor (&argc,
2407 &argv,
2408 request_completion,
2409 completion_cur,
2410 completion_prev))
2411 ret = 0;
2412 goto out;
2414 else if (g_strcmp0 (command, "wait") == 0)
2416 if (handle_wait (&argc,
2417 &argv,
2418 request_completion,
2419 completion_cur,
2420 completion_prev))
2421 ret = 0;
2422 goto out;
2424 else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2426 const gchar *completion_line;
2427 gchar **completion_argv;
2428 gint completion_argc;
2429 gint completion_point;
2430 gchar *endp;
2431 gint cur_begin;
2433 request_completion = TRUE;
2435 completion_line = argv[2];
2436 completion_point = strtol (argv[3], &endp, 10);
2437 if (endp == argv[3] || *endp != '\0')
2438 goto out;
2440 #if 0
2441 completion_debug ("completion_point=%d", completion_point);
2442 completion_debug ("----");
2443 completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2444 completion_debug ("'%s'", completion_line);
2445 completion_debug (" %*s^",
2446 completion_point, "");
2447 completion_debug ("----");
2448 #endif
2450 if (!g_shell_parse_argv (completion_line,
2451 &completion_argc,
2452 &completion_argv,
2453 NULL))
2455 /* it's very possible the command line can't be parsed (for
2456 * example, missing quotes etc) - in that case, we just
2457 * don't autocomplete at all
2459 goto out;
2462 /* compute cur and prev */
2463 completion_prev = NULL;
2464 completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2465 if (cur_begin > 0)
2467 gint prev_end;
2468 for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2470 if (!g_ascii_isspace (completion_line[prev_end]))
2472 completion_prev = pick_word_at (completion_line, prev_end, NULL);
2473 break;
2477 #if 0
2478 completion_debug (" cur='%s'", completion_cur);
2479 completion_debug ("prev='%s'", completion_prev);
2480 #endif
2482 argc = completion_argc;
2483 argv = completion_argv;
2485 ret = 0;
2487 goto again;
2489 else
2491 if (request_completion)
2493 g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
2494 ret = 0;
2495 goto out;
2497 else
2499 g_printerr ("Unknown command '%s'\n", command);
2500 usage (&argc, &argv, FALSE);
2501 goto out;
2505 out:
2506 g_free (completion_cur);
2507 g_free (completion_prev);
2508 return ret;