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