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