gdbus-tool: simplify some logic
[platform/upstream/glib.git] / gio / gdbus-tool.c
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 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 #endif
35
36 /* ---------------------------------------------------------------------------------------------------- */
37
38 G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
39
40 /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
41  * to not have it interfere with stdout/stderr)
42  */
43 #if 0
44 G_GNUC_UNUSED static void
45 completion_debug (const gchar *format, ...)
46 {
47   va_list var_args;
48   gchar *s;
49   static FILE *f = NULL;
50
51   va_start (var_args, format);
52   s = g_strdup_vprintf (format, var_args);
53   if (f == NULL)
54     {
55       f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
56     }
57   fprintf (f, "%s\n", s);
58   g_free (s);
59 }
60 #else
61 static void
62 completion_debug (const gchar *format, ...)
63 {
64 }
65 #endif
66
67 /* ---------------------------------------------------------------------------------------------------- */
68
69
70 static void
71 remove_arg (gint num, gint *argc, gchar **argv[])
72 {
73   gint n;
74
75   g_assert (num <= (*argc));
76
77   for (n = num; (*argv)[n] != NULL; n++)
78     (*argv)[n] = (*argv)[n+1];
79   (*argv)[n] = NULL;
80   (*argc) = (*argc) - 1;
81 }
82
83 static void
84 usage (gint *argc, gchar **argv[], gboolean use_stdout)
85 {
86   GOptionContext *o;
87   gchar *s;
88   gchar *program_name;
89
90   o = g_option_context_new (_("COMMAND"));
91   g_option_context_set_help_enabled (o, FALSE);
92   /* Ignore parsing result */
93   g_option_context_parse (o, argc, argv, NULL);
94   program_name = g_path_get_basename ((*argv)[0]);
95   s = g_strdup_printf (_("Commands:\n"
96                          "  help         Shows this information\n"
97                          "  introspect   Introspect a remote object\n"
98                          "  monitor      Monitor a remote object\n"
99                          "  call         Invoke a method on a remote object\n"
100                          "  emit         Emit a signal\n"
101                          "\n"
102                          "Use \"%s COMMAND --help\" to get help on each command.\n"),
103                        program_name);
104   g_free (program_name);
105   g_option_context_set_description (o, s);
106   g_free (s);
107   s = g_option_context_get_help (o, FALSE, NULL);
108   if (use_stdout)
109     g_print ("%s", s);
110   else
111     g_printerr ("%s", s);
112   g_free (s);
113   g_option_context_free (o);
114 }
115
116 static void
117 modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
118 {
119   gchar *s;
120   gchar *program_name;
121
122   /* TODO:
123    *  1. get a g_set_prgname() ?; or
124    *  2. save old argv[0] and restore later
125    */
126
127   g_assert (g_strcmp0 ((*argv)[1], command) == 0);
128   remove_arg (1, argc, argv);
129
130   program_name = g_path_get_basename ((*argv)[0]);
131   s = g_strdup_printf ("%s %s", (*argv)[0], command);
132   (*argv)[0] = s;
133   g_free (program_name);
134 }
135
136 /* ---------------------------------------------------------------------------------------------------- */
137
138 static void
139 print_methods (GDBusConnection *c,
140                const gchar *name,
141                const gchar *path)
142 {
143   GVariant *result;
144   GError *error;
145   const gchar *xml_data;
146   GDBusNodeInfo *node;
147   guint n;
148   guint m;
149
150   error = NULL;
151   result = g_dbus_connection_call_sync (c,
152                                         name,
153                                         path,
154                                         "org.freedesktop.DBus.Introspectable",
155                                         "Introspect",
156                                         NULL,
157                                         G_VARIANT_TYPE ("(s)"),
158                                         G_DBUS_CALL_FLAGS_NONE,
159                                         3000, /* 3 secs */
160                                         NULL,
161                                         &error);
162   if (result == NULL)
163     {
164       g_printerr (_("Error: %s\n"), error->message);
165       g_error_free (error);
166       goto out;
167     }
168   g_variant_get (result, "(&s)", &xml_data);
169
170   error = NULL;
171   node = g_dbus_node_info_new_for_xml (xml_data, &error);
172   g_variant_unref (result);
173   if (node == NULL)
174     {
175       g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
176       g_error_free (error);
177       goto out;
178     }
179
180   for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
181     {
182       const GDBusInterfaceInfo *iface = node->interfaces[n];
183       for (m = 0; iface->methods != NULL && iface->methods[m] != NULL; m++)
184         {
185           const GDBusMethodInfo *method = iface->methods[m];
186           g_print ("%s.%s \n", iface->name, method->name);
187         }
188     }
189   g_dbus_node_info_unref (node);
190
191  out:
192   ;
193 }
194
195 static void
196 print_paths (GDBusConnection *c,
197              const gchar *name,
198              const gchar *path)
199 {
200   GVariant *result;
201   GError *error;
202   const gchar *xml_data;
203   GDBusNodeInfo *node;
204   guint n;
205
206   error = NULL;
207   result = g_dbus_connection_call_sync (c,
208                                         name,
209                                         path,
210                                         "org.freedesktop.DBus.Introspectable",
211                                         "Introspect",
212                                         NULL,
213                                         G_VARIANT_TYPE ("(s)"),
214                                         G_DBUS_CALL_FLAGS_NONE,
215                                         3000, /* 3 secs */
216                                         NULL,
217                                         &error);
218   if (result == NULL)
219     {
220       g_printerr (_("Error: %s\n"), error->message);
221       g_error_free (error);
222       goto out;
223     }
224   g_variant_get (result, "(&s)", &xml_data);
225
226   //g_printerr ("xml='%s'", xml_data);
227
228   error = NULL;
229   node = g_dbus_node_info_new_for_xml (xml_data, &error);
230   g_variant_unref (result);
231   if (node == NULL)
232     {
233       g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
234       g_error_free (error);
235       goto out;
236     }
237
238   //g_printerr ("bar '%s'\n", path);
239
240   if (node->interfaces != NULL)
241     g_print ("%s \n", path);
242
243   for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
244     {
245       gchar *s;
246
247       //g_printerr ("foo '%s'\n", node->nodes[n].path);
248
249       if (g_strcmp0 (path, "/") == 0)
250         s = g_strdup_printf ("/%s", node->nodes[n]->path);
251       else
252         s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
253
254       print_paths (c, name, s);
255
256       g_free (s);
257     }
258   g_dbus_node_info_unref (node);
259
260  out:
261   ;
262 }
263
264 static void
265 print_names (GDBusConnection *c,
266              gboolean         include_unique_names)
267 {
268   GVariant *result;
269   GError *error;
270   GVariantIter *iter;
271   gchar *str;
272   GHashTable *name_set;
273   GList *keys;
274   GList *l;
275
276   name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
277
278   error = NULL;
279   result = g_dbus_connection_call_sync (c,
280                                         "org.freedesktop.DBus",
281                                         "/org/freedesktop/DBus",
282                                         "org.freedesktop.DBus",
283                                         "ListNames",
284                                         NULL,
285                                         G_VARIANT_TYPE ("(as)"),
286                                         G_DBUS_CALL_FLAGS_NONE,
287                                         3000, /* 3 secs */
288                                         NULL,
289                                         &error);
290   if (result == NULL)
291     {
292       g_printerr (_("Error: %s\n"), error->message);
293       g_error_free (error);
294       goto out;
295     }
296   g_variant_get (result, "(as)", &iter);
297   while (g_variant_iter_loop (iter, "s", &str))
298     g_hash_table_insert (name_set, g_strdup (str), NULL);
299   g_variant_iter_free (iter);
300   g_variant_unref (result);
301
302   error = NULL;
303   result = g_dbus_connection_call_sync (c,
304                                         "org.freedesktop.DBus",
305                                         "/org/freedesktop/DBus",
306                                         "org.freedesktop.DBus",
307                                         "ListActivatableNames",
308                                         NULL,
309                                         G_VARIANT_TYPE ("(as)"),
310                                         G_DBUS_CALL_FLAGS_NONE,
311                                         3000, /* 3 secs */
312                                         NULL,
313                                         &error);
314   if (result == NULL)
315     {
316       g_printerr (_("Error: %s\n"), error->message);
317       g_error_free (error);
318       goto out;
319     }
320   g_variant_get (result, "(as)", &iter);
321   while (g_variant_iter_loop (iter, "s", &str))
322     g_hash_table_insert (name_set, g_strdup (str), NULL);
323   g_variant_iter_free (iter);
324   g_variant_unref (result);
325
326   keys = g_hash_table_get_keys (name_set);
327   keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
328   for (l = keys; l != NULL; l = l->next)
329     {
330       const gchar *name = l->data;
331       if (!include_unique_names && g_str_has_prefix (name, ":"))
332         continue;
333
334       g_print ("%s \n", name);
335     }
336   g_list_free (keys);
337
338  out:
339   g_hash_table_unref (name_set);
340 }
341
342 /* ---------------------------------------------------------------------------------------------------- */
343
344 static gboolean  opt_connection_system  = FALSE;
345 static gboolean  opt_connection_session = FALSE;
346 static gboolean  opt_connection_user    = FALSE;
347 static gboolean  opt_connection_machine = FALSE;
348 static gchar    *opt_connection_address = NULL;
349
350 static const GOptionEntry connection_entries[] =
351 {
352   { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
353   { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
354   { "user", 'u', 0, G_OPTION_ARG_NONE, &opt_connection_user, N_("Connect to the system bus"), NULL},
355   { "machine", 'm', 0, G_OPTION_ARG_NONE, &opt_connection_machine, N_("Connect to the session bus"), NULL},
356   { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), NULL},
357   { NULL }
358 };
359
360 static GOptionGroup *
361 connection_get_group (void)
362 {
363   static GOptionGroup *g;
364
365   g = g_option_group_new ("connection",
366                           N_("Connection Endpoint Options:"),
367                           N_("Options specifying the connection endpoint"),
368                           NULL,
369                           NULL);
370   g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
371   g_option_group_add_entries (g, connection_entries);
372
373   return g;
374 }
375
376 static GDBusConnection *
377 connection_get_dbus_connection (GError **error)
378 {
379   GDBusConnection *c;
380   guint count;
381
382   c = NULL;
383
384   count = !!opt_connection_system +
385           !!opt_connection_session +
386           !!opt_connection_address;
387
388   /* First, ensure we have exactly one connect */
389   if (count == 0)
390     {
391       g_set_error (error,
392                    G_IO_ERROR,
393                    G_IO_ERROR_FAILED,
394                    _("No connection endpoint specified"));
395       goto out;
396     }
397   else if (count > 1)
398     {
399       g_set_error (error,
400                    G_IO_ERROR,
401                    G_IO_ERROR_FAILED,
402                    _("Multiple connection endpoints specified"));
403       goto out;
404     }
405
406   if (opt_connection_system)
407     {
408       c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
409     }
410   else if (opt_connection_session)
411     {
412       c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
413     }
414   else if (opt_connection_address != NULL)
415     {
416       c = g_dbus_connection_new_for_address_sync (opt_connection_address,
417                                                   G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
418                                                   NULL, /* GDBusAuthObserver */
419                                                   NULL, /* GCancellable */
420                                                   error);
421     }
422
423  out:
424   return c;
425 }
426
427 /* ---------------------------------------------------------------------------------------------------- */
428
429 static GPtrArray *
430 call_helper_get_method_in_signature (GDBusConnection  *c,
431                                      const gchar      *dest,
432                                      const gchar      *path,
433                                      const gchar      *interface_name,
434                                      const gchar      *method_name,
435                                      GError          **error)
436 {
437   GPtrArray *ret;
438   GVariant *result;
439   GDBusNodeInfo *node_info;
440   const gchar *xml_data;
441   GDBusInterfaceInfo *interface_info;
442   GDBusMethodInfo *method_info;
443   guint n;
444
445   ret = NULL;
446   result = NULL;
447   node_info = NULL;
448
449   result = g_dbus_connection_call_sync (c,
450                                         dest,
451                                         path,
452                                         "org.freedesktop.DBus.Introspectable",
453                                         "Introspect",
454                                         NULL,
455                                         G_VARIANT_TYPE ("(s)"),
456                                         G_DBUS_CALL_FLAGS_NONE,
457                                         3000, /* 3 secs */
458                                         NULL,
459                                         error);
460   if (result == NULL)
461     goto out;
462
463   g_variant_get (result, "(&s)", &xml_data);
464   node_info = g_dbus_node_info_new_for_xml (xml_data, error);
465   if (node_info == NULL)
466       goto out;
467
468   interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
469   if (interface_info == NULL)
470     {
471       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
472                    _("Warning: According to introspection data, interface '%s' does not exist\n"),
473                    interface_name);
474       goto out;
475     }
476
477   method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
478   if (method_info == NULL)
479     {
480       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
481                    _("Warning: According to introspection data, method '%s' does not exist on interface '%s'\n"),
482                    method_name,
483                    interface_name);
484       goto out;
485     }
486
487   ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
488   for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
489     {
490       g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
491     }
492
493  out:
494   if (node_info != NULL)
495     g_dbus_node_info_unref (node_info);
496   if (result != NULL)
497     g_variant_unref (result);
498
499   return ret;
500 }
501
502 /* ---------------------------------------------------------------------------------------------------- */
503
504 static GVariant *
505 _g_variant_parse_me_harder (GVariantType   *type,
506                             const gchar    *given_str,
507                             GError        **error)
508 {
509   GVariant *value;
510   gchar *s;
511   guint n;
512   GString *str;
513
514   str = g_string_new ("\"");
515   for (n = 0; given_str[n] != '\0'; n++)
516     {
517       if (G_UNLIKELY (given_str[n] == '\"'))
518         g_string_append (str, "\\\"");
519       else
520         g_string_append_c (str, given_str[n]);
521     }
522   g_string_append_c (str, '"');
523   s = g_string_free (str, FALSE);
524
525   value = g_variant_parse (type,
526                            s,
527                            NULL,
528                            NULL,
529                            error);
530   g_free (s);
531
532   return value;
533 }
534
535 /* ---------------------------------------------------------------------------------------------------- */
536
537 static gchar *opt_emit_dest = NULL;
538 static gchar *opt_emit_object_path = NULL;
539 static gchar *opt_emit_signal = NULL;
540
541 static const GOptionEntry emit_entries[] =
542 {
543   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
544   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
545   { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
546   { NULL }
547 };
548
549 static gboolean
550 handle_emit (gint        *argc,
551              gchar      **argv[],
552              gboolean     request_completion,
553              const gchar *completion_cur,
554              const gchar *completion_prev)
555 {
556   gint ret;
557   GOptionContext *o;
558   gchar *s;
559   GError *error;
560   GDBusConnection *c;
561   GVariant *parameters;
562   gchar *interface_name;
563   gchar *signal_name;
564   GVariantBuilder builder;
565   guint n;
566
567   ret = FALSE;
568   c = NULL;
569   parameters = NULL;
570   interface_name = NULL;
571   signal_name = NULL;
572
573   modify_argv0_for_command (argc, argv, "emit");
574
575   o = g_option_context_new (NULL);
576   g_option_context_set_help_enabled (o, FALSE);
577   g_option_context_set_summary (o, _("Emit a signal."));
578   g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE);
579   g_option_context_add_group (o, connection_get_group ());
580
581   if (!g_option_context_parse (o, argc, argv, NULL))
582     {
583       if (!request_completion)
584         {
585           s = g_option_context_get_help (o, FALSE, NULL);
586           g_printerr ("%s", s);
587           g_free (s);
588           goto out;
589         }
590     }
591
592   error = NULL;
593   c = connection_get_dbus_connection (&error);
594   if (c == NULL)
595     {
596       if (request_completion)
597         {
598           if (g_strcmp0 (completion_prev, "--address") == 0)
599             {
600               g_print ("unix:\n"
601                        "tcp:\n"
602                        "nonce-tcp:\n");
603             }
604           else
605             {
606               g_print ("--system \n--session \n--address \n");
607             }
608         }
609       else
610         {
611           g_printerr (_("Error connecting: %s\n"), error->message);
612           g_error_free (error);
613         }
614       goto out;
615     }
616
617   /* All done with completion now */
618   if (request_completion)
619     goto out;
620
621   if (opt_emit_object_path == NULL)
622     {
623       g_printerr (_("Error: object path not specified.\n"));
624       goto out;
625     }
626   if (!g_variant_is_object_path (opt_emit_object_path))
627     {
628       g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
629       goto out;
630     }
631
632   if (opt_emit_signal == NULL)
633     {
634       g_printerr (_("Error: signal not specified.\n"));
635       goto out;
636     }
637
638   s = strrchr (opt_emit_signal, '.');
639   if (s == NULL)
640     {
641       g_printerr (_("Error: signal must be the fully-qualified name.\n"));
642       goto out;
643     }
644   signal_name = g_strdup (s + 1);
645   interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
646
647   if (!g_dbus_is_interface_name (interface_name))
648     {
649       g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
650       goto out;
651     }
652
653   if (!g_dbus_is_member_name (signal_name))
654     {
655       g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
656       goto out;
657     }
658
659   if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
660     {
661       g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
662       goto out;
663     }
664
665   /* Read parameters */
666   g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
667   for (n = 1; n < (guint) *argc; n++)
668     {
669       GVariant *value;
670
671       error = NULL;
672       value = g_variant_parse (NULL,
673                                (*argv)[n],
674                                NULL,
675                                NULL,
676                                &error);
677       if (value == NULL)
678         {
679           gchar *context;
680
681           context = g_variant_parse_error_print_context (error, (*argv)[n]);
682           g_error_free (error);
683           error = NULL;
684           value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
685           if (value == NULL)
686             {
687               /* Use the original non-"parse-me-harder" error */
688               g_printerr (_("Error parsing parameter %d: %s\n"),
689                           n,
690                           context);
691               g_error_free (error);
692               g_free (context);
693               g_variant_builder_clear (&builder);
694               goto out;
695             }
696           g_free (context);
697         }
698       g_variant_builder_add_value (&builder, value);
699     }
700   parameters = g_variant_builder_end (&builder);
701
702   if (parameters != NULL)
703     parameters = g_variant_ref_sink (parameters);
704   if (!g_dbus_connection_emit_signal (c,
705                                       opt_emit_dest,
706                                       opt_emit_object_path,
707                                       interface_name,
708                                       signal_name,
709                                       parameters,
710                                       &error))
711     {
712       g_printerr (_("Error: %s\n"), error->message);
713       g_error_free (error);
714       goto out;
715     }
716
717   if (!g_dbus_connection_flush_sync (c, NULL, &error))
718     {
719       g_printerr (_("Error flushing connection: %s\n"), error->message);
720       g_error_free (error);
721       goto out;
722     }
723
724   ret = TRUE;
725
726  out:
727   if (c != NULL)
728     g_object_unref (c);
729   if (parameters != NULL)
730     g_variant_unref (parameters);
731   g_free (interface_name);
732   g_free (signal_name);
733   g_option_context_free (o);
734   return ret;
735 }
736
737 /* ---------------------------------------------------------------------------------------------------- */
738
739 static gchar *opt_call_dest = NULL;
740 static gchar *opt_call_object_path = NULL;
741 static gchar *opt_call_method = NULL;
742 static gint opt_call_timeout = -1;
743
744 static const GOptionEntry call_entries[] =
745 {
746   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
747   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
748   { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
749   { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
750   { NULL }
751 };
752
753 static gboolean
754 handle_call (gint        *argc,
755              gchar      **argv[],
756              gboolean     request_completion,
757              const gchar *completion_cur,
758              const gchar *completion_prev)
759 {
760   gint ret;
761   GOptionContext *o;
762   gchar *s;
763   GError *error;
764   GDBusConnection *c;
765   GVariant *parameters;
766   gchar *interface_name;
767   gchar *method_name;
768   GVariant *result;
769   GPtrArray *in_signature_types;
770   gboolean complete_names;
771   gboolean complete_paths;
772   gboolean complete_methods;
773   GVariantBuilder builder;
774   guint n;
775
776   ret = FALSE;
777   c = NULL;
778   parameters = NULL;
779   interface_name = NULL;
780   method_name = NULL;
781   result = NULL;
782   in_signature_types = NULL;
783
784   modify_argv0_for_command (argc, argv, "call");
785
786   o = g_option_context_new (NULL);
787   g_option_context_set_help_enabled (o, FALSE);
788   g_option_context_set_summary (o, _("Invoke a method on a remote object."));
789   g_option_context_add_main_entries (o, call_entries, GETTEXT_PACKAGE);
790   g_option_context_add_group (o, connection_get_group ());
791
792   complete_names = FALSE;
793   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
794     {
795       complete_names = TRUE;
796       remove_arg ((*argc) - 1, argc, argv);
797     }
798
799   complete_paths = FALSE;
800   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
801     {
802       complete_paths = TRUE;
803       remove_arg ((*argc) - 1, argc, argv);
804     }
805
806   complete_methods = FALSE;
807   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
808     {
809       complete_methods = TRUE;
810       remove_arg ((*argc) - 1, argc, argv);
811     }
812
813   if (!g_option_context_parse (o, argc, argv, NULL))
814     {
815       if (!request_completion)
816         {
817           s = g_option_context_get_help (o, FALSE, NULL);
818           g_printerr ("%s", s);
819           g_free (s);
820           goto out;
821         }
822     }
823
824   error = NULL;
825   c = connection_get_dbus_connection (&error);
826   if (c == NULL)
827     {
828       if (request_completion)
829         {
830           if (g_strcmp0 (completion_prev, "--address") == 0)
831             {
832               g_print ("unix:\n"
833                        "tcp:\n"
834                        "nonce-tcp:\n");
835             }
836           else
837             {
838               g_print ("--system \n--session \n--address \n");
839             }
840         }
841       else
842         {
843           g_printerr (_("Error connecting: %s\n"), error->message);
844           g_error_free (error);
845         }
846       goto out;
847     }
848
849   /* validate and complete destination (bus name) */
850   if (g_dbus_connection_get_unique_name (c) != NULL)
851     {
852       /* this only makes sense on message bus connections */
853       if (complete_names)
854         {
855           print_names (c, FALSE);
856           goto out;
857         }
858       if (opt_call_dest == NULL)
859         {
860           if (request_completion)
861             g_print ("--dest \n");
862           else
863             g_printerr (_("Error: Destination is not specified\n"));
864           goto out;
865         }
866       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
867         {
868           print_names (c, g_str_has_prefix (opt_call_dest, ":"));
869           goto out;
870         }
871     }
872
873   /* validate and complete object path */
874   if (complete_paths)
875     {
876       print_paths (c, opt_call_dest, "/");
877       goto out;
878     }
879   if (opt_call_object_path == NULL)
880     {
881       if (request_completion)
882         g_print ("--object-path \n");
883       else
884         g_printerr (_("Error: Object path is not specified\n"));
885       goto out;
886     }
887   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
888     {
889       gchar *p;
890       s = g_strdup (opt_call_object_path);
891       p = strrchr (s, '/');
892       if (p != NULL)
893         {
894           if (p == s)
895             p++;
896           *p = '\0';
897         }
898       print_paths (c, opt_call_dest, s);
899       g_free (s);
900       goto out;
901     }
902   if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
903     {
904       g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
905       goto out;
906     }
907
908   /* validate and complete method (interface + method name) */
909   if (complete_methods)
910     {
911       print_methods (c, opt_call_dest, opt_call_object_path);
912       goto out;
913     }
914   if (opt_call_method == NULL)
915     {
916       if (request_completion)
917         g_print ("--method \n");
918       else
919         g_printerr (_("Error: Method name is not specified\n"));
920       goto out;
921     }
922   if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
923     {
924       print_methods (c, opt_call_dest, opt_call_object_path);
925       goto out;
926     }
927   s = strrchr (opt_call_method, '.');
928   if (!request_completion && s == NULL)
929     {
930       g_printerr (_("Error: Method name '%s' is invalid\n"), opt_call_method);
931       goto out;
932     }
933   method_name = g_strdup (s + 1);
934   interface_name = g_strndup (opt_call_method, s - opt_call_method);
935
936   /* All done with completion now */
937   if (request_completion)
938     goto out;
939
940   /* Introspect, for easy conversion - it's not fatal if we can't do this */
941   in_signature_types = call_helper_get_method_in_signature (c,
942                                                             opt_call_dest,
943                                                             opt_call_object_path,
944                                                             interface_name,
945                                                             method_name,
946                                                             &error);
947   if (in_signature_types == NULL)
948     {
949       //g_printerr ("Error getting introspection data: %s\n", error->message);
950       g_error_free (error);
951       error = NULL;
952     }
953
954   /* Read parameters */
955   g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
956   for (n = 1; n < (guint) *argc; n++)
957     {
958       GVariant *value;
959       GVariantType *type;
960
961       type = NULL;
962       if (in_signature_types != NULL)
963         {
964           if (n - 1 >= in_signature_types->len)
965             {
966               /* Only warn for the first param */
967               if (n - 1 == in_signature_types->len)
968                 {
969                   g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
970                               in_signature_types->len);
971                 }
972             }
973           else
974             {
975               type = in_signature_types->pdata[n - 1];
976             }
977         }
978
979       error = NULL;
980       value = g_variant_parse (type,
981                                (*argv)[n],
982                                NULL,
983                                NULL,
984                                &error);
985       if (value == NULL)
986         {
987           gchar *context;
988
989           context = g_variant_parse_error_print_context (error, (*argv)[n]);
990           g_error_free (error);
991           error = NULL;
992           value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
993           if (value == NULL)
994             {
995               if (type != NULL)
996                 {
997                   s = g_variant_type_dup_string (type);
998                   g_printerr (_("Error parsing parameter %d of type '%s': %s\n"),
999                               n,
1000                               s,
1001                               context);
1002                   g_free (s);
1003                 }
1004               else
1005                 {
1006                   g_printerr (_("Error parsing parameter %d: %s\n"),
1007                               n,
1008                               context);
1009                 }
1010               g_error_free (error);
1011               g_variant_builder_clear (&builder);
1012               g_free (context);
1013               goto out;
1014             }
1015           g_free (context);
1016         }
1017       g_variant_builder_add_value (&builder, value);
1018     }
1019   parameters = g_variant_builder_end (&builder);
1020
1021   if (parameters != NULL)
1022     parameters = g_variant_ref_sink (parameters);
1023   result = g_dbus_connection_call_sync (c,
1024                                         opt_call_dest,
1025                                         opt_call_object_path,
1026                                         interface_name,
1027                                         method_name,
1028                                         parameters,
1029                                         NULL,
1030                                         G_DBUS_CALL_FLAGS_NONE,
1031                                         opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1032                                         NULL,
1033                                         &error);
1034   if (result == NULL)
1035     {
1036       if (error)
1037         {
1038           g_printerr (_("Error: %s\n"), error->message);
1039           g_error_free (error);
1040         }
1041       if (in_signature_types != NULL)
1042         {
1043           GString *s;
1044           s = g_string_new (NULL);
1045           for (n = 0; n < in_signature_types->len; n++)
1046             {
1047               GVariantType *type = in_signature_types->pdata[n];
1048               g_string_append_len (s,
1049                                    g_variant_type_peek_string (type),
1050                                    g_variant_type_get_string_length (type));
1051             }
1052           g_printerr ("(According to introspection data, you need to pass '%s')\n", s->str);
1053           g_string_free (s, TRUE);
1054         }
1055       goto out;
1056     }
1057
1058   s = g_variant_print (result, TRUE);
1059   g_print ("%s\n", s);
1060   g_free (s);
1061
1062   ret = TRUE;
1063
1064  out:
1065   if (in_signature_types != NULL)
1066     g_ptr_array_unref (in_signature_types);
1067   if (result != NULL)
1068     g_variant_unref (result);
1069   if (c != NULL)
1070     g_object_unref (c);
1071   if (parameters != NULL)
1072     g_variant_unref (parameters);
1073   g_free (interface_name);
1074   g_free (method_name);
1075   g_option_context_free (o);
1076   return ret;
1077 }
1078
1079 /* ---------------------------------------------------------------------------------------------------- */
1080
1081 static gchar *opt_introspect_dest = NULL;
1082 static gchar *opt_introspect_object_path = NULL;
1083 static gboolean opt_introspect_xml = FALSE;
1084 static gboolean opt_introspect_recurse = FALSE;
1085 static gboolean opt_introspect_only_properties = FALSE;
1086
1087 static void
1088 dump_annotation (const GDBusAnnotationInfo *o,
1089                  guint indent,
1090                  gboolean ignore_indent)
1091 {
1092   guint n;
1093   g_print ("%*s@%s(\"%s\")\n",
1094            ignore_indent ? 0 : indent, "",
1095            o->key,
1096            o->value);
1097   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1098     dump_annotation (o->annotations[n], indent + 2, FALSE);
1099 }
1100
1101 static void
1102 dump_arg (const GDBusArgInfo *o,
1103           guint indent,
1104           const gchar *direction,
1105           gboolean ignore_indent,
1106           gboolean include_newline)
1107 {
1108   guint n;
1109
1110   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1111     {
1112       dump_annotation (o->annotations[n], indent, ignore_indent);
1113       ignore_indent = FALSE;
1114     }
1115
1116   g_print ("%*s%s%s %s%s",
1117            ignore_indent ? 0 : indent, "",
1118            direction,
1119            o->signature,
1120            o->name,
1121            include_newline ? ",\n" : "");
1122 }
1123
1124 static guint
1125 count_args (GDBusArgInfo **args)
1126 {
1127   guint n;
1128   n = 0;
1129   if (args == NULL)
1130     goto out;
1131   while (args[n] != NULL)
1132     n++;
1133  out:
1134   return n;
1135 }
1136
1137 static void
1138 dump_method (const GDBusMethodInfo *o,
1139              guint                  indent)
1140 {
1141   guint n;
1142   guint m;
1143   guint name_len;
1144   guint total_num_args;
1145
1146   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1147     dump_annotation (o->annotations[n], indent, FALSE);
1148
1149   g_print ("%*s%s(", indent, "", o->name);
1150   name_len = strlen (o->name);
1151   total_num_args = count_args (o->in_args) + count_args (o->out_args);
1152   for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1153     {
1154       gboolean ignore_indent = (m == 0);
1155       gboolean include_newline = (m != total_num_args - 1);
1156
1157       dump_arg (o->in_args[n],
1158                 indent + name_len + 1,
1159                 "in  ",
1160                 ignore_indent,
1161                 include_newline);
1162     }
1163   for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1164     {
1165       gboolean ignore_indent = (m == 0);
1166       gboolean include_newline = (m != total_num_args - 1);
1167       dump_arg (o->out_args[n],
1168                 indent + name_len + 1,
1169                 "out ",
1170                 ignore_indent,
1171                 include_newline);
1172     }
1173   g_print (");\n");
1174 }
1175
1176 static void
1177 dump_signal (const GDBusSignalInfo *o,
1178              guint                  indent)
1179 {
1180   guint n;
1181   guint name_len;
1182   guint total_num_args;
1183
1184   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1185     dump_annotation (o->annotations[n], indent, FALSE);
1186
1187   g_print ("%*s%s(", indent, "", o->name);
1188   name_len = strlen (o->name);
1189   total_num_args = count_args (o->args);
1190   for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1191     {
1192       gboolean ignore_indent = (n == 0);
1193       gboolean include_newline = (n != total_num_args - 1);
1194       dump_arg (o->args[n],
1195                 indent + name_len + 1,
1196                 "",
1197                 ignore_indent,
1198                 include_newline);
1199     }
1200   g_print (");\n");
1201 }
1202
1203 static void
1204 dump_property (const GDBusPropertyInfo *o,
1205                guint                    indent,
1206                GVariant                *value)
1207 {
1208   const gchar *access;
1209   guint n;
1210
1211   if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1212     access = "readonly";
1213   else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1214     access = "writeonly";
1215   else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1216     access = "readwrite";
1217   else
1218     g_assert_not_reached ();
1219
1220   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1221     dump_annotation (o->annotations[n], indent, FALSE);
1222
1223   if (value != NULL)
1224     {
1225       gchar *s = g_variant_print (value, FALSE);
1226       g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
1227       g_free (s);
1228     }
1229   else
1230     {
1231       g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1232     }
1233 }
1234
1235 static void
1236 dump_interface (GDBusConnection          *c,
1237                 const gchar              *name,
1238                 const GDBusInterfaceInfo *o,
1239                 guint                     indent,
1240                 const gchar              *object_path)
1241 {
1242   guint n;
1243   GHashTable *properties;
1244
1245   properties = g_hash_table_new_full (g_str_hash,
1246                                       g_str_equal,
1247                                       g_free,
1248                                       (GDestroyNotify) g_variant_unref);
1249
1250   /* Try to get properties */
1251   if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1252     {
1253       GVariant *result;
1254       result = g_dbus_connection_call_sync (c,
1255                                             name,
1256                                             object_path,
1257                                             "org.freedesktop.DBus.Properties",
1258                                             "GetAll",
1259                                             g_variant_new ("(s)", o->name),
1260                                             NULL,
1261                                             G_DBUS_CALL_FLAGS_NONE,
1262                                             3000,
1263                                             NULL,
1264                                             NULL);
1265       if (result != NULL)
1266         {
1267           if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1268             {
1269               GVariantIter *iter;
1270               GVariant *item;
1271               g_variant_get (result,
1272                              "(a{sv})",
1273                              &iter);
1274               while ((item = g_variant_iter_next_value (iter)))
1275                 {
1276                   gchar *key;
1277                   GVariant *value;
1278                   g_variant_get (item,
1279                                  "{sv}",
1280                                  &key,
1281                                  &value);
1282
1283                   g_hash_table_insert (properties, key, g_variant_ref (value));
1284                 }
1285             }
1286           g_variant_unref (result);
1287         }
1288       else
1289         {
1290           guint n;
1291           for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1292             {
1293               result = g_dbus_connection_call_sync (c,
1294                                                     name,
1295                                                     object_path,
1296                                                     "org.freedesktop.DBus.Properties",
1297                                                     "Get",
1298                                                     g_variant_new ("(ss)", o->name, o->properties[n]->name),
1299                                                     G_VARIANT_TYPE ("(v)"),
1300                                                     G_DBUS_CALL_FLAGS_NONE,
1301                                                     3000,
1302                                                     NULL,
1303                                                     NULL);
1304               if (result != NULL)
1305                 {
1306                   GVariant *property_value;
1307                   g_variant_get (result,
1308                                  "(v)",
1309                                  &property_value);
1310                   g_hash_table_insert (properties,
1311                                        g_strdup (o->properties[n]->name),
1312                                        g_variant_ref (property_value));
1313                   g_variant_unref (result);
1314                 }
1315             }
1316         }
1317     }
1318
1319   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1320     dump_annotation (o->annotations[n], indent, FALSE);
1321
1322   g_print ("%*sinterface %s {\n", indent, "", o->name);
1323   if (o->methods != NULL && !opt_introspect_only_properties)
1324     {
1325       g_print ("%*s  methods:\n", indent, "");
1326       for (n = 0; o->methods[n] != NULL; n++)
1327         dump_method (o->methods[n], indent + 4);
1328     }
1329   if (o->signals != NULL && !opt_introspect_only_properties)
1330     {
1331       g_print ("%*s  signals:\n", indent, "");
1332       for (n = 0; o->signals[n] != NULL; n++)
1333         dump_signal (o->signals[n], indent + 4);
1334     }
1335   if (o->properties != NULL)
1336     {
1337       g_print ("%*s  properties:\n", indent, "");
1338       for (n = 0; o->properties[n] != NULL; n++)
1339         {
1340           dump_property (o->properties[n],
1341                          indent + 4,
1342                          g_hash_table_lookup (properties, (o->properties[n])->name));
1343         }
1344     }
1345   g_print ("%*s};\n",
1346            indent, "");
1347
1348   g_hash_table_unref (properties);
1349 }
1350
1351 static gboolean
1352 introspect_do (GDBusConnection *c,
1353                const gchar     *object_path,
1354                guint            indent);
1355
1356 static void
1357 dump_node (GDBusConnection      *c,
1358            const gchar          *name,
1359            const GDBusNodeInfo  *o,
1360            guint                 indent,
1361            const gchar          *object_path,
1362            gboolean              recurse)
1363 {
1364   guint n;
1365   const gchar *object_path_to_print;
1366
1367   object_path_to_print = object_path;
1368   if (o->path != NULL)
1369     object_path_to_print = o->path;
1370
1371   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1372     dump_annotation (o->annotations[n], indent, FALSE);
1373
1374   g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
1375   if (o->interfaces != NULL || o->nodes != NULL)
1376     {
1377       g_print (" {\n");
1378       for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1379         {
1380           if (opt_introspect_only_properties)
1381             {
1382               if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1383                 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1384             }
1385           else
1386             {
1387               dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1388             }
1389         }
1390       for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1391         {
1392           if (recurse)
1393             {
1394               gchar *child_path;
1395               if (g_variant_is_object_path (o->nodes[n]->path))
1396                 {
1397                   child_path = g_strdup (o->nodes[n]->path);
1398                   /* avoid infinite loops */
1399                   if (g_str_has_prefix (child_path, object_path))
1400                     {
1401                       introspect_do (c, child_path, indent + 2);
1402                     }
1403                   else
1404                     {
1405                       g_print ("Skipping path %s that is not enclosed by parent %s\n",
1406                                child_path, object_path);
1407                     }
1408                 }
1409               else
1410                 {
1411                   if (g_strcmp0 (object_path, "/") == 0)
1412                     child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1413                   else
1414                     child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1415                   introspect_do (c, child_path, indent + 2);
1416                 }
1417               g_free (child_path);
1418             }
1419           else
1420             {
1421               dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
1422             }
1423         }
1424       g_print ("%*s};\n",
1425                indent, "");
1426     }
1427   else
1428     {
1429       g_print ("\n");
1430     }
1431 }
1432
1433 static const GOptionEntry introspect_entries[] =
1434 {
1435   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1436   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1437   { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1438   { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1439   { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1440   { NULL }
1441 };
1442
1443 static gboolean
1444 introspect_do (GDBusConnection *c,
1445                const gchar     *object_path,
1446                guint            indent)
1447 {
1448   GError *error;
1449   GVariant *result;
1450   GDBusNodeInfo *node;
1451   gboolean ret;
1452   const gchar *xml_data;
1453
1454   ret = FALSE;
1455   node = NULL;
1456   result = NULL;
1457
1458   error = NULL;
1459   result = g_dbus_connection_call_sync (c,
1460                                         opt_introspect_dest,
1461                                         object_path,
1462                                         "org.freedesktop.DBus.Introspectable",
1463                                         "Introspect",
1464                                         NULL,
1465                                         G_VARIANT_TYPE ("(s)"),
1466                                         G_DBUS_CALL_FLAGS_NONE,
1467                                         3000, /* 3 sec */
1468                                         NULL,
1469                                         &error);
1470   if (result == NULL)
1471     {
1472       g_printerr (_("Error: %s\n"), error->message);
1473       g_error_free (error);
1474       goto out;
1475     }
1476   g_variant_get (result, "(&s)", &xml_data);
1477
1478   if (opt_introspect_xml)
1479     {
1480       g_print ("%s", xml_data);
1481     }
1482   else
1483     {
1484       error = NULL;
1485       node = g_dbus_node_info_new_for_xml (xml_data, &error);
1486       if (node == NULL)
1487         {
1488           g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1489           g_error_free (error);
1490           goto out;
1491         }
1492
1493       dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
1494     }
1495
1496   ret = TRUE;
1497
1498  out:
1499   if (node != NULL)
1500     g_dbus_node_info_unref (node);
1501   if (result != NULL)
1502     g_variant_unref (result);
1503   return ret;
1504 }
1505
1506 static gboolean
1507 handle_introspect (gint        *argc,
1508                    gchar      **argv[],
1509                    gboolean     request_completion,
1510                    const gchar *completion_cur,
1511                    const gchar *completion_prev)
1512 {
1513   gint ret;
1514   GOptionContext *o;
1515   gchar *s;
1516   GError *error;
1517   GDBusConnection *c;
1518   gboolean complete_names;
1519   gboolean complete_paths;
1520
1521   ret = FALSE;
1522   c = NULL;
1523
1524   modify_argv0_for_command (argc, argv, "introspect");
1525
1526   o = g_option_context_new (NULL);
1527   if (request_completion)
1528     g_option_context_set_ignore_unknown_options (o, TRUE);
1529   g_option_context_set_help_enabled (o, FALSE);
1530   g_option_context_set_summary (o, _("Introspect a remote object."));
1531   g_option_context_add_main_entries (o, introspect_entries, GETTEXT_PACKAGE);
1532   g_option_context_add_group (o, connection_get_group ());
1533
1534   complete_names = FALSE;
1535   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1536     {
1537       complete_names = TRUE;
1538       remove_arg ((*argc) - 1, argc, argv);
1539     }
1540
1541   complete_paths = FALSE;
1542   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1543     {
1544       complete_paths = TRUE;
1545       remove_arg ((*argc) - 1, argc, argv);
1546     }
1547
1548   if (!g_option_context_parse (o, argc, argv, NULL))
1549     {
1550       if (!request_completion)
1551         {
1552           s = g_option_context_get_help (o, FALSE, NULL);
1553           g_printerr ("%s", s);
1554           g_free (s);
1555           goto out;
1556         }
1557     }
1558
1559   error = NULL;
1560   c = connection_get_dbus_connection (&error);
1561   if (c == NULL)
1562     {
1563       if (request_completion)
1564         {
1565           if (g_strcmp0 (completion_prev, "--address") == 0)
1566             {
1567               g_print ("unix:\n"
1568                        "tcp:\n"
1569                        "nonce-tcp:\n");
1570             }
1571           else
1572             {
1573               g_print ("--system \n--session \n--address \n");
1574             }
1575         }
1576       else
1577         {
1578           g_printerr (_("Error connecting: %s\n"), error->message);
1579           g_error_free (error);
1580         }
1581       goto out;
1582     }
1583
1584   if (g_dbus_connection_get_unique_name (c) != NULL)
1585     {
1586       if (complete_names)
1587         {
1588           print_names (c, FALSE);
1589           goto out;
1590         }
1591       /* this only makes sense on message bus connections */
1592       if (opt_introspect_dest == NULL)
1593         {
1594           if (request_completion)
1595             g_print ("--dest \n");
1596           else
1597             g_printerr (_("Error: Destination is not specified\n"));
1598           goto out;
1599         }
1600       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1601         {
1602           print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1603           goto out;
1604         }
1605     }
1606   if (complete_paths)
1607     {
1608       print_paths (c, opt_introspect_dest, "/");
1609       goto out;
1610     }
1611   if (opt_introspect_object_path == NULL)
1612     {
1613       if (request_completion)
1614         g_print ("--object-path \n");
1615       else
1616         g_printerr (_("Error: Object path is not specified\n"));
1617       goto out;
1618     }
1619   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1620     {
1621       gchar *p;
1622       s = g_strdup (opt_introspect_object_path);
1623       p = strrchr (s, '/');
1624       if (p != NULL)
1625         {
1626           if (p == s)
1627             p++;
1628           *p = '\0';
1629         }
1630       print_paths (c, opt_introspect_dest, s);
1631       g_free (s);
1632       goto out;
1633     }
1634   if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1635     {
1636       g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1637       goto out;
1638     }
1639
1640   if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1641     {
1642       g_print ("--recurse \n");
1643     }
1644
1645   if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1646     {
1647       g_print ("--only-properties \n");
1648     }
1649
1650   /* All done with completion now */
1651   if (request_completion)
1652     goto out;
1653
1654   if (!introspect_do (c, opt_introspect_object_path, 0))
1655     goto out;
1656
1657   ret = TRUE;
1658
1659  out:
1660   if (c != NULL)
1661     g_object_unref (c);
1662   g_option_context_free (o);
1663   return ret;
1664 }
1665
1666 /* ---------------------------------------------------------------------------------------------------- */
1667
1668 static gchar *opt_monitor_dest = NULL;
1669 static gchar *opt_monitor_object_path = NULL;
1670
1671 static guint monitor_filter_id = 0;
1672
1673 static void
1674 monitor_signal_cb (GDBusConnection *connection,
1675                    const gchar     *sender_name,
1676                    const gchar     *object_path,
1677                    const gchar     *interface_name,
1678                    const gchar     *signal_name,
1679                    GVariant        *parameters,
1680                    gpointer         user_data)
1681 {
1682   gchar *s;
1683   s = g_variant_print (parameters, TRUE);
1684   g_print ("%s: %s.%s %s\n",
1685            object_path,
1686            interface_name,
1687            signal_name,
1688            s);
1689   g_free (s);
1690 }
1691
1692 static void
1693 monitor_on_name_appeared (GDBusConnection *connection,
1694                           const gchar *name,
1695                           const gchar *name_owner,
1696                           gpointer user_data)
1697 {
1698   g_print ("The name %s is owned by %s\n", name, name_owner);
1699   g_assert (monitor_filter_id == 0);
1700   monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1701                                                           name_owner,
1702                                                           NULL,  /* any interface */
1703                                                           NULL,  /* any member */
1704                                                           opt_monitor_object_path,
1705                                                           NULL,  /* arg0 */
1706                                                           G_DBUS_SIGNAL_FLAGS_NONE,
1707                                                           monitor_signal_cb,
1708                                                           NULL,  /* user_data */
1709                                                           NULL); /* user_data destroy notify */
1710 }
1711
1712 static void
1713 monitor_on_name_vanished (GDBusConnection *connection,
1714                           const gchar *name,
1715                           gpointer user_data)
1716 {
1717   g_print ("The name %s does not have an owner\n", name);
1718
1719   if (monitor_filter_id != 0)
1720     {
1721       g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
1722       monitor_filter_id = 0;
1723     }
1724 }
1725
1726 static const GOptionEntry monitor_entries[] =
1727 {
1728   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1729   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1730   { NULL }
1731 };
1732
1733 static gboolean
1734 handle_monitor (gint        *argc,
1735                 gchar      **argv[],
1736                 gboolean     request_completion,
1737                 const gchar *completion_cur,
1738                 const gchar *completion_prev)
1739 {
1740   gint ret;
1741   GOptionContext *o;
1742   gchar *s;
1743   GError *error;
1744   GDBusConnection *c;
1745   gboolean complete_names;
1746   gboolean complete_paths;
1747   GMainLoop *loop;
1748
1749   ret = FALSE;
1750   c = NULL;
1751
1752   modify_argv0_for_command (argc, argv, "monitor");
1753
1754   o = g_option_context_new (NULL);
1755   if (request_completion)
1756     g_option_context_set_ignore_unknown_options (o, TRUE);
1757   g_option_context_set_help_enabled (o, FALSE);
1758   g_option_context_set_summary (o, _("Monitor a remote object."));
1759   g_option_context_add_main_entries (o, monitor_entries, GETTEXT_PACKAGE);
1760   g_option_context_add_group (o, connection_get_group ());
1761
1762   complete_names = FALSE;
1763   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1764     {
1765       complete_names = TRUE;
1766       remove_arg ((*argc) - 1, argc, argv);
1767     }
1768
1769   complete_paths = FALSE;
1770   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1771     {
1772       complete_paths = TRUE;
1773       remove_arg ((*argc) - 1, argc, argv);
1774     }
1775
1776   if (!g_option_context_parse (o, argc, argv, NULL))
1777     {
1778       if (!request_completion)
1779         {
1780           s = g_option_context_get_help (o, FALSE, NULL);
1781           g_printerr ("%s", s);
1782           g_free (s);
1783           goto out;
1784         }
1785     }
1786
1787   error = NULL;
1788   c = connection_get_dbus_connection (&error);
1789   if (c == NULL)
1790     {
1791       if (request_completion)
1792         {
1793           if (g_strcmp0 (completion_prev, "--address") == 0)
1794             {
1795               g_print ("unix:\n"
1796                        "tcp:\n"
1797                        "nonce-tcp:\n");
1798             }
1799           else
1800             {
1801               g_print ("--system \n--session \n--address \n");
1802             }
1803         }
1804       else
1805         {
1806           g_printerr (_("Error connecting: %s\n"), error->message);
1807           g_error_free (error);
1808         }
1809       goto out;
1810     }
1811
1812   if (g_dbus_connection_get_unique_name (c) != NULL)
1813     {
1814       if (complete_names)
1815         {
1816           print_names (c, FALSE);
1817           goto out;
1818         }
1819       /* this only makes sense on message bus connections */
1820       if (opt_monitor_dest == NULL)
1821         {
1822           if (request_completion)
1823             g_print ("--dest \n");
1824           else
1825             g_printerr (_("Error: Destination is not specified\n"));
1826           goto out;
1827         }
1828       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1829         {
1830           print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
1831           goto out;
1832         }
1833     }
1834   if (complete_paths)
1835     {
1836       print_paths (c, opt_monitor_dest, "/");
1837       goto out;
1838     }
1839   if (opt_monitor_object_path == NULL)
1840     {
1841       if (request_completion)
1842         {
1843           g_print ("--object-path \n");
1844           goto out;
1845         }
1846       /* it's fine to not have an object path */
1847     }
1848   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1849     {
1850       gchar *p;
1851       s = g_strdup (opt_monitor_object_path);
1852       p = strrchr (s, '/');
1853       if (p != NULL)
1854         {
1855           if (p == s)
1856             p++;
1857           *p = '\0';
1858         }
1859       print_paths (c, opt_monitor_dest, s);
1860       g_free (s);
1861       goto out;
1862     }
1863   if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
1864     {
1865       g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
1866       goto out;
1867     }
1868
1869   /* All done with completion now */
1870   if (request_completion)
1871     goto out;
1872
1873   if (opt_monitor_object_path != NULL)
1874     g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
1875   else
1876     g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
1877
1878   loop = g_main_loop_new (NULL, FALSE);
1879   g_bus_watch_name_on_connection (c,
1880                                   opt_monitor_dest,
1881                                   G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
1882                                   monitor_on_name_appeared,
1883                                   monitor_on_name_vanished,
1884                                   NULL,
1885                                   NULL);
1886
1887   g_main_loop_run (loop);
1888   g_main_loop_unref (loop);
1889
1890   ret = TRUE;
1891
1892  out:
1893   if (c != NULL)
1894     g_object_unref (c);
1895   g_option_context_free (o);
1896   return ret;
1897 }
1898
1899 /* ---------------------------------------------------------------------------------------------------- */
1900
1901 static gchar *
1902 pick_word_at (const gchar  *s,
1903               gint          cursor,
1904               gint         *out_word_begins_at)
1905 {
1906   gint begin;
1907   gint end;
1908
1909   if (s[0] == '\0')
1910     {
1911       if (out_word_begins_at != NULL)
1912         *out_word_begins_at = -1;
1913       return NULL;
1914     }
1915
1916   if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
1917     {
1918       if (out_word_begins_at != NULL)
1919         *out_word_begins_at = cursor;
1920       return g_strdup ("");
1921     }
1922
1923   while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
1924     cursor--;
1925   begin = cursor;
1926
1927   end = begin;
1928   while (!g_ascii_isspace (s[end]) && s[end] != '\0')
1929     end++;
1930
1931   if (out_word_begins_at != NULL)
1932     *out_word_begins_at = begin;
1933
1934   return g_strndup (s + begin, end - begin);
1935 }
1936
1937 gint
1938 main (gint argc, gchar *argv[])
1939 {
1940   gint ret;
1941   const gchar *command;
1942   gboolean request_completion;
1943   gchar *completion_cur;
1944   gchar *completion_prev;
1945 #ifdef G_OS_WIN32
1946   gchar *tmp;
1947 #endif
1948
1949   setlocale (LC_ALL, "");
1950   textdomain (GETTEXT_PACKAGE);
1951
1952 #ifdef G_OS_WIN32
1953   tmp = _glib_get_locale_dir ();
1954   bindtextdomain (GETTEXT_PACKAGE, tmp);
1955   g_free (tmp);
1956 #else
1957   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
1958 #endif
1959
1960 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
1961   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1962 #endif
1963
1964   ret = 1;
1965   completion_cur = NULL;
1966   completion_prev = NULL;
1967
1968   if (argc < 2)
1969     {
1970       usage (&argc, &argv, FALSE);
1971       goto out;
1972     }
1973
1974   request_completion = FALSE;
1975
1976   //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
1977
1978  again:
1979   command = argv[1];
1980   if (g_strcmp0 (command, "help") == 0)
1981     {
1982       if (request_completion)
1983         {
1984           /* do nothing */
1985         }
1986       else
1987         {
1988           usage (&argc, &argv, TRUE);
1989           ret = 0;
1990         }
1991       goto out;
1992     }
1993   else if (g_strcmp0 (command, "emit") == 0)
1994     {
1995       if (handle_emit (&argc,
1996                        &argv,
1997                        request_completion,
1998                        completion_cur,
1999                        completion_prev))
2000         ret = 0;
2001       goto out;
2002     }
2003   else if (g_strcmp0 (command, "call") == 0)
2004     {
2005       if (handle_call (&argc,
2006                        &argv,
2007                        request_completion,
2008                        completion_cur,
2009                        completion_prev))
2010         ret = 0;
2011       goto out;
2012     }
2013   else if (g_strcmp0 (command, "introspect") == 0)
2014     {
2015       if (handle_introspect (&argc,
2016                              &argv,
2017                              request_completion,
2018                              completion_cur,
2019                              completion_prev))
2020         ret = 0;
2021       goto out;
2022     }
2023   else if (g_strcmp0 (command, "monitor") == 0)
2024     {
2025       if (handle_monitor (&argc,
2026                           &argv,
2027                           request_completion,
2028                           completion_cur,
2029                           completion_prev))
2030         ret = 0;
2031       goto out;
2032     }
2033   else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2034     {
2035       const gchar *completion_line;
2036       gchar **completion_argv;
2037       gint completion_argc;
2038       gint completion_point;
2039       gchar *endp;
2040       gint cur_begin;
2041
2042       request_completion = TRUE;
2043
2044       completion_line = argv[2];
2045       completion_point = strtol (argv[3], &endp, 10);
2046       if (endp == argv[3] || *endp != '\0')
2047         goto out;
2048
2049 #if 0
2050       completion_debug ("completion_point=%d", completion_point);
2051       completion_debug ("----");
2052       completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2053       completion_debug ("'%s'", completion_line);
2054       completion_debug (" %*s^",
2055                          completion_point, "");
2056       completion_debug ("----");
2057 #endif
2058
2059       if (!g_shell_parse_argv (completion_line,
2060                                &completion_argc,
2061                                &completion_argv,
2062                                NULL))
2063         {
2064           /* it's very possible the command line can't be parsed (for
2065            * example, missing quotes etc) - in that case, we just
2066            * don't autocomplete at all
2067            */
2068           goto out;
2069         }
2070
2071       /* compute cur and prev */
2072       completion_prev = NULL;
2073       completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2074       if (cur_begin > 0)
2075         {
2076           gint prev_end;
2077           for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2078             {
2079               if (!g_ascii_isspace (completion_line[prev_end]))
2080                 {
2081                   completion_prev = pick_word_at (completion_line, prev_end, NULL);
2082                   break;
2083                 }
2084             }
2085         }
2086 #if 0
2087       completion_debug (" cur='%s'", completion_cur);
2088       completion_debug ("prev='%s'", completion_prev);
2089 #endif
2090
2091       argc = completion_argc;
2092       argv = completion_argv;
2093
2094       ret = 0;
2095
2096       goto again;
2097     }
2098   else
2099     {
2100       if (request_completion)
2101         {
2102           g_print ("help \nemit \ncall \nintrospect \nmonitor \n");
2103           ret = 0;
2104           goto out;
2105         }
2106       else
2107         {
2108           g_printerr ("Unknown command '%s'\n", command);
2109           usage (&argc, &argv, FALSE);
2110           goto out;
2111         }
2112     }
2113
2114  out:
2115   g_free (completion_cur);
2116   g_free (completion_prev);
2117   return ret;
2118 }