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