• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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