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