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 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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
33 /* ---------------------------------------------------------------------------------------------------- */
35 G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
37 /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
38 * to not have it interfere with stdout/stderr)
41 G_GNUC_UNUSED static void
42 completion_debug (const gchar *format, ...)
46 static FILE *f = NULL;
48 va_start (var_args, format);
49 s = g_strdup_vprintf (format, var_args);
52 f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
54 fprintf (f, "%s\n", s);
59 completion_debug (const gchar *format, ...)
64 /* ---------------------------------------------------------------------------------------------------- */
68 remove_arg (gint num, gint *argc, gchar **argv[])
72 g_assert (num <= (*argc));
74 for (n = num; (*argv)[n] != NULL; n++)
75 (*argv)[n] = (*argv)[n+1];
77 (*argc) = (*argc) - 1;
81 usage (gint *argc, gchar **argv[], gboolean use_stdout)
87 o = g_option_context_new (_("COMMAND"));
88 g_option_context_set_help_enabled (o, FALSE);
89 /* Ignore parsing result */
90 g_option_context_parse (o, argc, argv, NULL);
91 program_name = g_path_get_basename ((*argv)[0]);
92 s = g_strdup_printf (_("Commands:\n"
93 " help Shows this information\n"
94 " introspect Introspect a remote object\n"
95 " call Invoke a method on a remote object\n"
97 "Use \"%s COMMAND --help\" to get help on each command.\n"),
99 g_free (program_name);
100 g_option_context_set_description (o, s);
102 s = g_option_context_get_help (o, FALSE, NULL);
106 g_printerr ("%s", s);
108 g_option_context_free (o);
112 modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
118 * 1. get a g_set_prgname() ?; or
119 * 2. save old argv[0] and restore later
122 g_assert (g_strcmp0 ((*argv)[1], command) == 0);
123 remove_arg (1, argc, argv);
125 program_name = g_path_get_basename ((*argv)[0]);
126 s = g_strdup_printf ("%s %s", (*argv)[0], command);
128 g_free (program_name);
131 /* ---------------------------------------------------------------------------------------------------- */
134 print_methods (GDBusConnection *c,
140 const gchar *xml_data;
146 result = g_dbus_connection_call_sync (c,
149 "org.freedesktop.DBus.Introspectable",
152 G_DBUS_CALL_FLAGS_NONE,
158 g_printerr (_("Error: %s\n"), error->message);
159 g_error_free (error);
162 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
164 g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
165 g_variant_get_type_string (result));
166 g_variant_unref (result);
169 g_variant_get (result, "(s)", &xml_data);
172 node = g_dbus_node_info_new_for_xml (xml_data, &error);
173 g_variant_unref (result);
176 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
177 g_error_free (error);
181 for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
183 const GDBusInterfaceInfo *iface = node->interfaces[n];
184 for (m = 0; iface->methods != NULL && iface->methods[m] != NULL; m++)
186 const GDBusMethodInfo *method = iface->methods[m];
187 g_print ("%s.%s \n", iface->name, method->name);
190 g_dbus_node_info_unref (node);
197 print_paths (GDBusConnection *c,
203 const gchar *xml_data;
208 result = g_dbus_connection_call_sync (c,
211 "org.freedesktop.DBus.Introspectable",
214 G_DBUS_CALL_FLAGS_NONE,
220 g_printerr (_("Error: %s\n"), error->message);
221 g_error_free (error);
224 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
226 g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
227 g_variant_get_type_string (result));
228 g_variant_unref (result);
231 g_variant_get (result, "(s)", &xml_data);
234 node = g_dbus_node_info_new_for_xml (xml_data, &error);
235 g_variant_unref (result);
238 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
239 g_error_free (error);
243 //g_printerr ("xml=`%s'", xml_data);
245 //g_printerr ("bar `%s'\n", path);
247 if (node->interfaces != NULL)
248 g_print ("%s \n", path);
250 for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
254 //g_printerr ("foo `%s'\n", node->nodes[n].path);
256 if (g_strcmp0 (path, "/") == 0)
257 s = g_strdup_printf ("/%s", node->nodes[n]->path);
259 s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
261 print_paths (c, name, s);
265 g_dbus_node_info_unref (node);
272 print_names (GDBusConnection *c,
273 gboolean include_unique_names)
279 GHashTable *name_set;
283 name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
286 result = g_dbus_connection_call_sync (c,
287 "org.freedesktop.DBus",
288 "/org/freedesktop/DBus",
289 "org.freedesktop.DBus",
292 G_DBUS_CALL_FLAGS_NONE,
298 g_printerr (_("Error: %s\n"), error->message);
299 g_error_free (error);
302 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
304 g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
305 g_variant_unref (result);
308 g_variant_get (result, "(as)", &iter);
309 while (g_variant_iter_loop (iter, "s", &str))
310 g_hash_table_insert (name_set, g_strdup (str), NULL);
311 g_variant_iter_free (iter);
312 g_variant_unref (result);
315 result = g_dbus_connection_call_sync (c,
316 "org.freedesktop.DBus",
317 "/org/freedesktop/DBus",
318 "org.freedesktop.DBus",
319 "ListActivatableNames",
321 G_DBUS_CALL_FLAGS_NONE,
327 g_printerr (_("Error: %s\n"), error->message);
328 g_error_free (error);
331 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
333 g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
334 g_variant_unref (result);
337 g_variant_get (result, "(as)", &iter);
338 while (g_variant_iter_loop (iter, "s", &str))
339 g_hash_table_insert (name_set, g_strdup (str), NULL);
340 g_variant_iter_free (iter);
341 g_variant_unref (result);
343 keys = g_hash_table_get_keys (name_set);
344 keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
345 for (l = keys; l != NULL; l = l->next)
347 const gchar *name = l->data;
348 if (!include_unique_names && g_str_has_prefix (name, ":"))
351 g_print ("%s \n", name);
356 g_hash_table_unref (name_set);
359 /* ---------------------------------------------------------------------------------------------------- */
361 static gboolean opt_connection_system = FALSE;
362 static gboolean opt_connection_session = FALSE;
363 static gchar *opt_connection_address = NULL;
365 static const GOptionEntry connection_entries[] =
367 { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
368 { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
369 { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), NULL},
373 static GOptionGroup *
374 connection_get_group (void)
376 static GOptionGroup *g;
378 g = g_option_group_new ("connection",
379 N_("Connection Endpoint Options:"),
380 N_("Options specifying the connection endpoint"),
383 g_option_group_add_entries (g, connection_entries);
387 static GDBusConnection *
388 connection_get_dbus_connection (GError **error)
394 /* First, ensure we have exactly one connect */
395 if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
400 _("No connection endpoint specified"));
403 else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
404 (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
405 (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
410 _("Multiple connection endpoints specified"));
414 if (opt_connection_system)
416 c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
418 else if (opt_connection_session)
420 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
422 else if (opt_connection_address != NULL)
424 c = g_dbus_connection_new_for_address_sync (opt_connection_address,
425 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
426 NULL, /* GCancellable */
434 /* ---------------------------------------------------------------------------------------------------- */
437 call_helper_get_method_in_signature (GDBusConnection *c,
440 const gchar *interface_name,
441 const gchar *method_name,
446 GDBusNodeInfo *node_info;
447 const gchar *xml_data;
448 const GDBusInterfaceInfo *interface_info;
449 const GDBusMethodInfo *method_info;
456 result = g_dbus_connection_call_sync (c,
459 "org.freedesktop.DBus.Introspectable",
462 G_DBUS_CALL_FLAGS_NONE,
469 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
471 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
472 _("Error: Result is type `%s', expected `(s)'\n"),
473 g_variant_get_type_string (result));
477 g_variant_get (result, "(s)", &xml_data);
478 node_info = g_dbus_node_info_new_for_xml (xml_data, error);
479 if (node_info == NULL)
482 interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
483 if (interface_info == NULL)
485 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
486 _("Warning: According to introspection data, interface `%s' does not exist\n"),
491 method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
492 if (method_info == NULL)
494 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
495 _("Warning: According to introspection data, method `%s' does not exist on interface `%s'\n"),
501 ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
502 for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
504 g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
508 if (node_info != NULL)
509 g_dbus_node_info_unref (node_info);
511 g_variant_unref (result);
516 /* ---------------------------------------------------------------------------------------------------- */
519 _g_variant_parse_me_harder (GVariantType *type,
520 const gchar *given_str,
528 str = g_string_new ("\"");
529 for (n = 0; given_str[n] != '\0'; n++)
531 if (G_UNLIKELY (given_str[n] == '\"'))
532 g_string_append (str, "\\\"");
534 g_string_append_c (str, given_str[n]);
536 g_string_append_c (str, '"');
537 s = g_string_free (str, FALSE);
539 value = g_variant_parse (type,
549 /* ---------------------------------------------------------------------------------------------------- */
551 static gchar *opt_call_dest = NULL;
552 static gchar *opt_call_object_path = NULL;
553 static gchar *opt_call_method = NULL;
555 static const GOptionEntry call_entries[] =
557 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
558 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
559 { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
564 handle_call (gint *argc,
566 gboolean request_completion,
567 const gchar *completion_cur,
568 const gchar *completion_prev)
575 GVariant *parameters;
576 gchar *interface_name;
579 GPtrArray *in_signature_types;
580 gboolean complete_names;
581 gboolean complete_paths;
582 gboolean complete_methods;
583 GVariantBuilder builder;
589 interface_name = NULL;
592 in_signature_types = NULL;
594 modify_argv0_for_command (argc, argv, "call");
596 o = g_option_context_new (NULL);
597 g_option_context_set_help_enabled (o, FALSE);
598 g_option_context_set_summary (o, _("Invoke a method on a remote object."));
599 g_option_context_add_main_entries (o, call_entries, NULL /* GETTEXT_PACKAGE*/);
600 g_option_context_add_group (o, connection_get_group ());
602 complete_names = FALSE;
603 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
605 complete_names = TRUE;
606 remove_arg ((*argc) - 1, argc, argv);
609 complete_paths = FALSE;
610 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
612 complete_paths = TRUE;
613 remove_arg ((*argc) - 1, argc, argv);
616 complete_methods = FALSE;
617 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
619 complete_methods = TRUE;
620 remove_arg ((*argc) - 1, argc, argv);
623 if (!g_option_context_parse (o, argc, argv, NULL))
625 if (!request_completion)
627 s = g_option_context_get_help (o, FALSE, NULL);
628 g_printerr ("%s", s);
635 c = connection_get_dbus_connection (&error);
638 if (request_completion)
640 if (g_strcmp0 (completion_prev, "--address") == 0)
648 g_print ("--system \n--session \n--address \n");
653 g_printerr (_("Error connecting: %s\n"), error->message);
654 g_error_free (error);
659 /* validate and complete destination (bus name) */
660 if (g_dbus_connection_get_unique_name (c) != NULL)
662 /* this only makes sense on message bus connections */
665 print_names (c, FALSE);
668 if (opt_call_dest == NULL)
670 if (request_completion)
671 g_print ("--dest \n");
673 g_printerr (_("Error: Destination is not specified\n"));
676 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
678 print_names (c, g_str_has_prefix (opt_call_dest, ":"));
683 /* validate and complete object path */
686 print_paths (c, opt_call_dest, "/");
689 if (opt_call_object_path == NULL)
691 if (request_completion)
692 g_print ("--object-path \n");
694 g_printerr (_("Error: Object path is not specified\n"));
697 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
700 s = g_strdup (opt_call_object_path);
701 p = strrchr (s, '/');
708 print_paths (c, opt_call_dest, s);
712 if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
714 g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
718 /* validate and complete method (interface + method name) */
719 if (complete_methods)
721 print_methods (c, opt_call_dest, opt_call_object_path);
724 if (opt_call_method == NULL)
726 if (request_completion)
727 g_print ("--method \n");
729 g_printerr (_("Error: Method name is not specified\n"));
732 if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
734 print_methods (c, opt_call_dest, opt_call_object_path);
737 s = strrchr (opt_call_method, '.');
738 if (!request_completion && s == NULL)
740 g_printerr (_("Error: Method name `%s' is invalid\n"), opt_call_method);
743 method_name = g_strdup (s + 1);
744 interface_name = g_strndup (opt_call_method, s - opt_call_method);
746 /* All done with completion now */
747 if (request_completion)
750 /* Introspect, for easy conversion - it's not fatal if we can't do this */
751 in_signature_types = call_helper_get_method_in_signature (c,
753 opt_call_object_path,
757 if (in_signature_types == NULL)
759 //g_printerr ("Error getting introspection data: %s\n", error->message);
760 g_error_free (error);
764 /* Read parameters */
765 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
766 for (n = 1; n < (guint) *argc; n++)
772 if (in_signature_types != NULL)
774 if (n - 1 >= in_signature_types->len)
776 /* Only warn for the first param */
777 if (n - 1 == in_signature_types->len)
779 g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
780 in_signature_types->len);
785 type = in_signature_types->pdata[n - 1];
790 value = g_variant_parse (type,
797 g_error_free (error);
799 value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
804 s = g_variant_type_dup_string (type);
805 g_printerr (_("Error parsing parameter %d of type `%s': %s\n"),
813 g_printerr (_("Error parsing parameter %d: %s\n"),
817 g_error_free (error);
818 g_variant_builder_clear (&builder);
822 g_variant_builder_add_value (&builder, value);
824 parameters = g_variant_builder_end (&builder);
826 if (parameters != NULL)
827 parameters = g_variant_ref_sink (parameters);
828 result = g_dbus_connection_call_sync (c,
830 opt_call_object_path,
834 G_DBUS_CALL_FLAGS_NONE,
840 g_printerr (_("Error: %s\n"), error->message);
841 g_error_free (error);
842 if (in_signature_types != NULL)
845 s = g_string_new (NULL);
846 for (n = 0; n < in_signature_types->len; n++)
848 GVariantType *type = in_signature_types->pdata[n];
849 g_string_append_len (s,
850 g_variant_type_peek_string (type),
851 g_variant_type_get_string_length (type));
853 g_printerr ("(According to introspection data, you need to pass `%s')\n", s->str);
854 g_string_free (s, TRUE);
859 s = g_variant_print (result, TRUE);
866 if (in_signature_types != NULL)
867 g_ptr_array_unref (in_signature_types);
869 g_variant_unref (result);
872 if (parameters != NULL)
873 g_variant_unref (parameters);
874 g_free (interface_name);
875 g_free (method_name);
876 g_option_context_free (o);
880 /* ---------------------------------------------------------------------------------------------------- */
882 /* TODO: dump annotations */
885 dump_annotation (const GDBusAnnotationInfo *o,
887 gboolean ignore_indent)
890 g_print ("%*s@%s(\"%s\")\n",
891 ignore_indent ? 0 : indent, "",
894 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
895 dump_annotation (o->annotations[n], indent + 2, FALSE);
899 dump_arg (const GDBusArgInfo *o,
901 const gchar *direction,
902 gboolean ignore_indent,
903 gboolean include_newline)
907 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
909 dump_annotation (o->annotations[n], indent, ignore_indent);
910 ignore_indent = FALSE;
913 g_print ("%*s%s%s %s%s",
914 ignore_indent ? 0 : indent, "",
918 include_newline ? ",\n" : "");
922 count_args (GDBusArgInfo **args)
928 while (args[n] != NULL)
935 dump_method (const GDBusMethodInfo *o,
941 guint total_num_args;
943 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
944 dump_annotation (o->annotations[n], indent, FALSE);
946 g_print ("%*s%s(", indent, "", o->name);
947 name_len = strlen (o->name);
948 total_num_args = count_args (o->in_args) + count_args (o->out_args);
949 for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
951 gboolean ignore_indent = (m == 0);
952 gboolean include_newline = (m != total_num_args - 1);
954 dump_arg (o->in_args[n],
955 indent + name_len + 1,
960 for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
962 gboolean ignore_indent = (m == 0);
963 gboolean include_newline = (m != total_num_args - 1);
964 dump_arg (o->out_args[n],
965 indent + name_len + 1,
974 dump_signal (const GDBusSignalInfo *o,
979 guint total_num_args;
981 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
982 dump_annotation (o->annotations[n], indent, FALSE);
984 g_print ("%*s%s(", indent, "", o->name);
985 name_len = strlen (o->name);
986 total_num_args = count_args (o->args);
987 for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
989 gboolean ignore_indent = (n == 0);
990 gboolean include_newline = (n != total_num_args - 1);
991 dump_arg (o->args[n],
992 indent + name_len + 1,
1001 dump_property (const GDBusPropertyInfo *o,
1005 const gchar *access;
1008 if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1009 access = "readonly";
1010 else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1011 access = "writeonly";
1012 else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1013 access = "readwrite";
1015 g_assert_not_reached ();
1017 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1018 dump_annotation (o->annotations[n], indent, FALSE);
1022 gchar *s = g_variant_print (value, FALSE);
1023 g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
1028 g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1033 dump_interface (GDBusConnection *c,
1035 const GDBusInterfaceInfo *o,
1037 const gchar *object_path)
1040 GHashTable *properties;
1042 properties = g_hash_table_new_full (g_str_hash,
1045 (GDestroyNotify) g_variant_unref);
1047 /* Try to get properties */
1048 if (c != NULL && name != NULL && object_path != NULL)
1051 result = g_dbus_connection_call_sync (c,
1054 "org.freedesktop.DBus.Properties",
1056 g_variant_new ("(s)", o->name),
1057 G_DBUS_CALL_FLAGS_NONE,
1063 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1067 g_variant_get (result,
1070 while ((item = g_variant_iter_next_value (iter)))
1074 g_variant_get (item,
1079 g_hash_table_insert (properties, g_strdup (key), g_variant_ref (value));
1082 g_variant_unref (result);
1087 for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1089 result = g_dbus_connection_call_sync (c,
1092 "org.freedesktop.DBus.Properties",
1094 g_variant_new ("(ss)", o->name, o->properties[n]->name),
1095 G_DBUS_CALL_FLAGS_NONE,
1101 GVariant *property_value;
1102 g_variant_get (result,
1105 g_hash_table_insert (properties,
1106 g_strdup (o->properties[n]->name),
1107 g_variant_ref (property_value));
1108 g_variant_unref (result);
1114 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1115 dump_annotation (o->annotations[n], indent, FALSE);
1117 g_print ("%*sinterface %s {\n", indent, "", o->name);
1118 if (o->methods != NULL)
1120 g_print ("%*s methods:\n", indent, "");
1121 for (n = 0; o->methods[n] != NULL; n++)
1122 dump_method (o->methods[n], indent + 4);
1124 if (o->signals != NULL)
1126 g_print ("%*s signals:\n", indent, "");
1127 for (n = 0; o->signals[n] != NULL; n++)
1128 dump_signal (o->signals[n], indent + 4);
1130 if (o->properties != NULL)
1132 g_print ("%*s properties:\n", indent, "");
1133 for (n = 0; o->properties[n] != NULL; n++)
1135 dump_property (o->properties[n],
1137 g_hash_table_lookup (properties, (o->properties[n])->name));
1143 g_hash_table_unref (properties);
1147 dump_node (GDBusConnection *c,
1149 const GDBusNodeInfo *o,
1151 const gchar *object_path)
1154 const gchar *object_path_to_print;
1156 object_path_to_print = object_path;
1157 if (o->path != NULL)
1158 object_path_to_print = o->path;
1160 for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1161 dump_annotation (o->annotations[n], indent, FALSE);
1163 g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
1164 if (o->interfaces != NULL || o->nodes != NULL)
1167 for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1168 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1169 for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1170 dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL);
1180 static gchar *opt_introspect_dest = NULL;
1181 static gchar *opt_introspect_object_path = NULL;
1183 static const GOptionEntry introspect_entries[] =
1185 { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1186 { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1191 handle_introspect (gint *argc,
1193 gboolean request_completion,
1194 const gchar *completion_cur,
1195 const gchar *completion_prev)
1203 const gchar *xml_data;
1204 GDBusNodeInfo *node;
1205 gboolean complete_names;
1206 gboolean complete_paths;
1213 modify_argv0_for_command (argc, argv, "introspect");
1215 o = g_option_context_new (NULL);
1216 if (request_completion)
1217 g_option_context_set_ignore_unknown_options (o, TRUE);
1218 g_option_context_set_help_enabled (o, FALSE);
1219 g_option_context_set_summary (o, _("Introspect a remote object."));
1220 g_option_context_add_main_entries (o, introspect_entries, NULL /* GETTEXT_PACKAGE*/);
1221 g_option_context_add_group (o, connection_get_group ());
1223 complete_names = FALSE;
1224 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1226 complete_names = TRUE;
1227 remove_arg ((*argc) - 1, argc, argv);
1230 complete_paths = FALSE;
1231 if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1233 complete_paths = TRUE;
1234 remove_arg ((*argc) - 1, argc, argv);
1237 if (!g_option_context_parse (o, argc, argv, NULL))
1239 if (!request_completion)
1241 s = g_option_context_get_help (o, FALSE, NULL);
1242 g_printerr ("%s", s);
1249 c = connection_get_dbus_connection (&error);
1252 if (request_completion)
1254 if (g_strcmp0 (completion_prev, "--address") == 0)
1262 g_print ("--system \n--session \n--address \n");
1267 g_printerr (_("Error connecting: %s\n"), error->message);
1268 g_error_free (error);
1273 if (g_dbus_connection_get_unique_name (c) != NULL)
1277 print_names (c, FALSE);
1280 /* this only makes sense on message bus connections */
1281 if (opt_introspect_dest == NULL)
1283 if (request_completion)
1284 g_print ("--dest \n");
1286 g_printerr (_("Error: Destination is not specified\n"));
1289 if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1291 print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1297 print_paths (c, opt_introspect_dest, "/");
1300 if (opt_introspect_object_path == NULL)
1302 if (request_completion)
1303 g_print ("--object-path \n");
1305 g_printerr (_("Error: Object path is not specified\n"));
1308 if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1311 s = g_strdup (opt_introspect_object_path);
1312 p = strrchr (s, '/');
1319 print_paths (c, opt_introspect_dest, s);
1323 if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1325 g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1329 /* All done with completion now */
1330 if (request_completion)
1333 result = g_dbus_connection_call_sync (c,
1334 opt_introspect_dest,
1335 opt_introspect_object_path,
1336 "org.freedesktop.DBus.Introspectable",
1339 G_DBUS_CALL_FLAGS_NONE,
1345 g_printerr (_("Error: %s\n"), error->message);
1346 g_error_free (error);
1349 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
1351 g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
1352 g_variant_get_type_string (result));
1355 g_variant_get (result, "(s)", &xml_data);
1358 node = g_dbus_node_info_new_for_xml (xml_data, &error);
1361 g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1362 g_error_free (error);
1366 dump_node (c, opt_introspect_dest, node, 0, opt_introspect_object_path);
1372 g_dbus_node_info_unref (node);
1374 g_variant_unref (result);
1377 g_option_context_free (o);
1381 /* ---------------------------------------------------------------------------------------------------- */
1384 pick_word_at (const gchar *s,
1386 gint *out_word_begins_at)
1393 if (out_word_begins_at != NULL)
1394 *out_word_begins_at = -1;
1398 if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
1400 if (out_word_begins_at != NULL)
1401 *out_word_begins_at = cursor;
1402 return g_strdup ("");
1405 while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
1410 while (!g_ascii_isspace (s[end]) && s[end] != '\0')
1413 if (out_word_begins_at != NULL)
1414 *out_word_begins_at = begin;
1416 return g_strndup (s + begin, end - begin);
1420 main (gint argc, gchar *argv[])
1423 const gchar *command;
1424 gboolean request_completion;
1425 gchar *completion_cur;
1426 gchar *completion_prev;
1429 completion_cur = NULL;
1430 completion_prev = NULL;
1436 usage (&argc, &argv, FALSE);
1440 request_completion = FALSE;
1442 //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
1446 if (g_strcmp0 (command, "help") == 0)
1448 if (request_completion)
1454 usage (&argc, &argv, TRUE);
1459 else if (g_strcmp0 (command, "call") == 0)
1461 if (handle_call (&argc,
1469 else if (g_strcmp0 (command, "introspect") == 0)
1471 if (handle_introspect (&argc,
1479 else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
1481 const gchar *completion_line;
1482 gchar **completion_argv;
1483 gint completion_argc;
1484 gint completion_point;
1488 request_completion = TRUE;
1490 completion_line = argv[2];
1491 completion_point = strtol (argv[3], &endp, 10);
1492 if (endp == argv[3] || *endp != '\0')
1496 completion_debug ("completion_point=%d", completion_point);
1497 completion_debug ("----");
1498 completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
1499 completion_debug ("`%s'", completion_line);
1500 completion_debug (" %*s^",
1501 completion_point, "");
1502 completion_debug ("----");
1505 if (!g_shell_parse_argv (completion_line,
1510 /* it's very possible the command line can't be parsed (for
1511 * example, missing quotes etc) - in that case, we just
1512 * don't autocomplete at all
1517 /* compute cur and prev */
1518 completion_prev = NULL;
1519 completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
1523 for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
1525 if (!g_ascii_isspace (completion_line[prev_end]))
1527 completion_prev = pick_word_at (completion_line, prev_end, NULL);
1533 completion_debug (" cur=`%s'", completion_cur);
1534 completion_debug ("prev=`%s'", completion_prev);
1537 argc = completion_argc;
1538 argv = completion_argv;
1546 if (request_completion)
1548 g_print ("help \ncall \nintrospect \n");
1554 g_printerr ("Unknown command `%s'\n", command);
1555 usage (&argc, &argv, FALSE);
1561 g_free (completion_cur);
1562 g_free (completion_prev);