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