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