xdgmime: plug a small leak
[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
629   s = strrchr (opt_emit_signal, '.');
630   if (s == NULL)
631     {
632       g_printerr (_("Error: signal must be the fully-qualified name.\n"));
633       goto out;
634     }
635   signal_name = g_strdup (s + 1);
636   interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
637
638   if (!g_dbus_is_interface_name (interface_name))
639     {
640       g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
641       goto out;
642     }
643
644   if (!g_dbus_is_member_name (signal_name))
645     {
646       g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
647       goto out;
648     }
649
650   if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
651     {
652       g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
653       goto out;
654     }
655
656   /* Read parameters */
657   g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
658   for (n = 1; n < (guint) *argc; n++)
659     {
660       GVariant *value;
661
662       error = NULL;
663       value = g_variant_parse (NULL,
664                                (*argv)[n],
665                                NULL,
666                                NULL,
667                                &error);
668       if (value == NULL)
669         {
670           g_error_free (error);
671           error = NULL;
672           value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
673           if (value == NULL)
674             {
675               g_printerr (_("Error parsing parameter %d: %s\n"),
676                           n,
677                           error->message);
678               g_error_free (error);
679               g_variant_builder_clear (&builder);
680               goto out;
681             }
682         }
683       g_variant_builder_add_value (&builder, value);
684     }
685   parameters = g_variant_builder_end (&builder);
686
687   if (parameters != NULL)
688     parameters = g_variant_ref_sink (parameters);
689   if (!g_dbus_connection_emit_signal (c,
690                                       opt_emit_dest,
691                                       opt_emit_object_path,
692                                       interface_name,
693                                       signal_name,
694                                       parameters,
695                                       &error))
696     {
697       g_printerr (_("Error: %s\n"), error->message);
698       g_error_free (error);
699       goto out;
700     }
701
702   if (!g_dbus_connection_flush_sync (c, NULL, &error))
703     {
704       g_printerr (_("Error flushing connection: %s\n"), error->message);
705       g_error_free (error);
706       goto out;
707     }
708
709   ret = TRUE;
710
711  out:
712   if (c != NULL)
713     g_object_unref (c);
714   if (parameters != NULL)
715     g_variant_unref (parameters);
716   g_free (interface_name);
717   g_free (signal_name);
718   g_option_context_free (o);
719   return ret;
720 }
721
722 /* ---------------------------------------------------------------------------------------------------- */
723
724 static gchar *opt_call_dest = NULL;
725 static gchar *opt_call_object_path = NULL;
726 static gchar *opt_call_method = NULL;
727 static gint opt_call_timeout = -1;
728
729 static const GOptionEntry call_entries[] =
730 {
731   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
732   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
733   { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
734   { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
735   { NULL }
736 };
737
738 static gboolean
739 handle_call (gint        *argc,
740              gchar      **argv[],
741              gboolean     request_completion,
742              const gchar *completion_cur,
743              const gchar *completion_prev)
744 {
745   gint ret;
746   GOptionContext *o;
747   gchar *s;
748   GError *error;
749   GDBusConnection *c;
750   GVariant *parameters;
751   gchar *interface_name;
752   gchar *method_name;
753   GVariant *result;
754   GPtrArray *in_signature_types;
755   gboolean complete_names;
756   gboolean complete_paths;
757   gboolean complete_methods;
758   GVariantBuilder builder;
759   guint n;
760
761   ret = FALSE;
762   c = NULL;
763   parameters = NULL;
764   interface_name = NULL;
765   method_name = NULL;
766   result = NULL;
767   in_signature_types = NULL;
768
769   modify_argv0_for_command (argc, argv, "call");
770
771   o = g_option_context_new (NULL);
772   g_option_context_set_help_enabled (o, FALSE);
773   g_option_context_set_summary (o, _("Invoke a method on a remote object."));
774   g_option_context_add_main_entries (o, call_entries, GETTEXT_PACKAGE);
775   g_option_context_add_group (o, connection_get_group ());
776
777   complete_names = FALSE;
778   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
779     {
780       complete_names = TRUE;
781       remove_arg ((*argc) - 1, argc, argv);
782     }
783
784   complete_paths = FALSE;
785   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
786     {
787       complete_paths = TRUE;
788       remove_arg ((*argc) - 1, argc, argv);
789     }
790
791   complete_methods = FALSE;
792   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
793     {
794       complete_methods = TRUE;
795       remove_arg ((*argc) - 1, argc, argv);
796     }
797
798   if (!g_option_context_parse (o, argc, argv, NULL))
799     {
800       if (!request_completion)
801         {
802           s = g_option_context_get_help (o, FALSE, NULL);
803           g_printerr ("%s", s);
804           g_free (s);
805           goto out;
806         }
807     }
808
809   error = NULL;
810   c = connection_get_dbus_connection (&error);
811   if (c == NULL)
812     {
813       if (request_completion)
814         {
815           if (g_strcmp0 (completion_prev, "--address") == 0)
816             {
817               g_print ("unix:\n"
818                        "tcp:\n"
819                        "nonce-tcp:\n");
820             }
821           else
822             {
823               g_print ("--system \n--session \n--address \n");
824             }
825         }
826       else
827         {
828           g_printerr (_("Error connecting: %s\n"), error->message);
829           g_error_free (error);
830         }
831       goto out;
832     }
833
834   /* validate and complete destination (bus name) */
835   if (g_dbus_connection_get_unique_name (c) != NULL)
836     {
837       /* this only makes sense on message bus connections */
838       if (complete_names)
839         {
840           print_names (c, FALSE);
841           goto out;
842         }
843       if (opt_call_dest == NULL)
844         {
845           if (request_completion)
846             g_print ("--dest \n");
847           else
848             g_printerr (_("Error: Destination is not specified\n"));
849           goto out;
850         }
851       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
852         {
853           print_names (c, g_str_has_prefix (opt_call_dest, ":"));
854           goto out;
855         }
856     }
857
858   /* validate and complete object path */
859   if (complete_paths)
860     {
861       print_paths (c, opt_call_dest, "/");
862       goto out;
863     }
864   if (opt_call_object_path == NULL)
865     {
866       if (request_completion)
867         g_print ("--object-path \n");
868       else
869         g_printerr (_("Error: Object path is not specified\n"));
870       goto out;
871     }
872   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
873     {
874       gchar *p;
875       s = g_strdup (opt_call_object_path);
876       p = strrchr (s, '/');
877       if (p != NULL)
878         {
879           if (p == s)
880             p++;
881           *p = '\0';
882         }
883       print_paths (c, opt_call_dest, s);
884       g_free (s);
885       goto out;
886     }
887   if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
888     {
889       g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
890       goto out;
891     }
892
893   /* validate and complete method (interface + method name) */
894   if (complete_methods)
895     {
896       print_methods (c, opt_call_dest, opt_call_object_path);
897       goto out;
898     }
899   if (opt_call_method == NULL)
900     {
901       if (request_completion)
902         g_print ("--method \n");
903       else
904         g_printerr (_("Error: Method name is not specified\n"));
905       goto out;
906     }
907   if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
908     {
909       print_methods (c, opt_call_dest, opt_call_object_path);
910       goto out;
911     }
912   s = strrchr (opt_call_method, '.');
913   if (!request_completion && s == NULL)
914     {
915       g_printerr (_("Error: Method name `%s' is invalid\n"), opt_call_method);
916       goto out;
917     }
918   method_name = g_strdup (s + 1);
919   interface_name = g_strndup (opt_call_method, s - opt_call_method);
920
921   /* All done with completion now */
922   if (request_completion)
923     goto out;
924
925   /* Introspect, for easy conversion - it's not fatal if we can't do this */
926   in_signature_types = call_helper_get_method_in_signature (c,
927                                                             opt_call_dest,
928                                                             opt_call_object_path,
929                                                             interface_name,
930                                                             method_name,
931                                                             &error);
932   if (in_signature_types == NULL)
933     {
934       //g_printerr ("Error getting introspection data: %s\n", error->message);
935       g_error_free (error);
936       error = NULL;
937     }
938
939   /* Read parameters */
940   g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
941   for (n = 1; n < (guint) *argc; n++)
942     {
943       GVariant *value;
944       GVariantType *type;
945
946       type = NULL;
947       if (in_signature_types != NULL)
948         {
949           if (n - 1 >= in_signature_types->len)
950             {
951               /* Only warn for the first param */
952               if (n - 1 == in_signature_types->len)
953                 {
954                   g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
955                               in_signature_types->len);
956                 }
957             }
958           else
959             {
960               type = in_signature_types->pdata[n - 1];
961             }
962         }
963
964       error = NULL;
965       value = g_variant_parse (type,
966                                (*argv)[n],
967                                NULL,
968                                NULL,
969                                &error);
970       if (value == NULL)
971         {
972           g_error_free (error);
973           error = NULL;
974           value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
975           if (value == NULL)
976             {
977               if (type != NULL)
978                 {
979                   s = g_variant_type_dup_string (type);
980                   g_printerr (_("Error parsing parameter %d of type `%s': %s\n"),
981                               n,
982                               s,
983                               error->message);
984                   g_free (s);
985                 }
986               else
987                 {
988                   g_printerr (_("Error parsing parameter %d: %s\n"),
989                               n,
990                               error->message);
991                 }
992               g_error_free (error);
993               g_variant_builder_clear (&builder);
994               goto out;
995             }
996         }
997       g_variant_builder_add_value (&builder, value);
998     }
999   parameters = g_variant_builder_end (&builder);
1000
1001   if (parameters != NULL)
1002     parameters = g_variant_ref_sink (parameters);
1003   result = g_dbus_connection_call_sync (c,
1004                                         opt_call_dest,
1005                                         opt_call_object_path,
1006                                         interface_name,
1007                                         method_name,
1008                                         parameters,
1009                                         NULL,
1010                                         G_DBUS_CALL_FLAGS_NONE,
1011                                         opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1012                                         NULL,
1013                                         &error);
1014   if (result == NULL)
1015     {
1016       g_printerr (_("Error: %s\n"), error->message);
1017       g_error_free (error);
1018       if (in_signature_types != NULL)
1019         {
1020           GString *s;
1021           s = g_string_new (NULL);
1022           for (n = 0; n < in_signature_types->len; n++)
1023             {
1024               GVariantType *type = in_signature_types->pdata[n];
1025               g_string_append_len (s,
1026                                    g_variant_type_peek_string (type),
1027                                    g_variant_type_get_string_length (type));
1028             }
1029           g_printerr ("(According to introspection data, you need to pass `%s')\n", s->str);
1030           g_string_free (s, TRUE);
1031         }
1032       goto out;
1033     }
1034
1035   s = g_variant_print (result, TRUE);
1036   g_print ("%s\n", s);
1037   g_free (s);
1038
1039   ret = TRUE;
1040
1041  out:
1042   if (in_signature_types != NULL)
1043     g_ptr_array_unref (in_signature_types);
1044   if (result != NULL)
1045     g_variant_unref (result);
1046   if (c != NULL)
1047     g_object_unref (c);
1048   if (parameters != NULL)
1049     g_variant_unref (parameters);
1050   g_free (interface_name);
1051   g_free (method_name);
1052   g_option_context_free (o);
1053   return ret;
1054 }
1055
1056 /* ---------------------------------------------------------------------------------------------------- */
1057
1058 static gchar *opt_introspect_dest = NULL;
1059 static gchar *opt_introspect_object_path = NULL;
1060 static gboolean opt_introspect_xml = FALSE;
1061 static gboolean opt_introspect_recurse = FALSE;
1062 static gboolean opt_introspect_only_properties = FALSE;
1063
1064 static void
1065 dump_annotation (const GDBusAnnotationInfo *o,
1066                  guint indent,
1067                  gboolean ignore_indent)
1068 {
1069   guint n;
1070   g_print ("%*s@%s(\"%s\")\n",
1071            ignore_indent ? 0 : indent, "",
1072            o->key,
1073            o->value);
1074   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1075     dump_annotation (o->annotations[n], indent + 2, FALSE);
1076 }
1077
1078 static void
1079 dump_arg (const GDBusArgInfo *o,
1080           guint indent,
1081           const gchar *direction,
1082           gboolean ignore_indent,
1083           gboolean include_newline)
1084 {
1085   guint n;
1086
1087   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1088     {
1089       dump_annotation (o->annotations[n], indent, ignore_indent);
1090       ignore_indent = FALSE;
1091     }
1092
1093   g_print ("%*s%s%s %s%s",
1094            ignore_indent ? 0 : indent, "",
1095            direction,
1096            o->signature,
1097            o->name,
1098            include_newline ? ",\n" : "");
1099 }
1100
1101 static guint
1102 count_args (GDBusArgInfo **args)
1103 {
1104   guint n;
1105   n = 0;
1106   if (args == NULL)
1107     goto out;
1108   while (args[n] != NULL)
1109     n++;
1110  out:
1111   return n;
1112 }
1113
1114 static void
1115 dump_method (const GDBusMethodInfo *o,
1116              guint                  indent)
1117 {
1118   guint n;
1119   guint m;
1120   guint name_len;
1121   guint total_num_args;
1122
1123   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1124     dump_annotation (o->annotations[n], indent, FALSE);
1125
1126   g_print ("%*s%s(", indent, "", o->name);
1127   name_len = strlen (o->name);
1128   total_num_args = count_args (o->in_args) + count_args (o->out_args);
1129   for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1130     {
1131       gboolean ignore_indent = (m == 0);
1132       gboolean include_newline = (m != total_num_args - 1);
1133
1134       dump_arg (o->in_args[n],
1135                 indent + name_len + 1,
1136                 "in  ",
1137                 ignore_indent,
1138                 include_newline);
1139     }
1140   for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1141     {
1142       gboolean ignore_indent = (m == 0);
1143       gboolean include_newline = (m != total_num_args - 1);
1144       dump_arg (o->out_args[n],
1145                 indent + name_len + 1,
1146                 "out ",
1147                 ignore_indent,
1148                 include_newline);
1149     }
1150   g_print (");\n");
1151 }
1152
1153 static void
1154 dump_signal (const GDBusSignalInfo *o,
1155              guint                  indent)
1156 {
1157   guint n;
1158   guint name_len;
1159   guint total_num_args;
1160
1161   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1162     dump_annotation (o->annotations[n], indent, FALSE);
1163
1164   g_print ("%*s%s(", indent, "", o->name);
1165   name_len = strlen (o->name);
1166   total_num_args = count_args (o->args);
1167   for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1168     {
1169       gboolean ignore_indent = (n == 0);
1170       gboolean include_newline = (n != total_num_args - 1);
1171       dump_arg (o->args[n],
1172                 indent + name_len + 1,
1173                 "",
1174                 ignore_indent,
1175                 include_newline);
1176     }
1177   g_print (");\n");
1178 }
1179
1180 static void
1181 dump_property (const GDBusPropertyInfo *o,
1182                guint                    indent,
1183                GVariant                *value)
1184 {
1185   const gchar *access;
1186   guint n;
1187
1188   if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1189     access = "readonly";
1190   else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1191     access = "writeonly";
1192   else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1193     access = "readwrite";
1194   else
1195     g_assert_not_reached ();
1196
1197   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1198     dump_annotation (o->annotations[n], indent, FALSE);
1199
1200   if (value != NULL)
1201     {
1202       gchar *s = g_variant_print (value, FALSE);
1203       g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
1204       g_free (s);
1205     }
1206   else
1207     {
1208       g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1209     }
1210 }
1211
1212 static void
1213 dump_interface (GDBusConnection          *c,
1214                 const gchar              *name,
1215                 const GDBusInterfaceInfo *o,
1216                 guint                     indent,
1217                 const gchar              *object_path)
1218 {
1219   guint n;
1220   GHashTable *properties;
1221
1222   properties = g_hash_table_new_full (g_str_hash,
1223                                       g_str_equal,
1224                                       g_free,
1225                                       (GDestroyNotify) g_variant_unref);
1226
1227   /* Try to get properties */
1228   if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1229     {
1230       GVariant *result;
1231       result = g_dbus_connection_call_sync (c,
1232                                             name,
1233                                             object_path,
1234                                             "org.freedesktop.DBus.Properties",
1235                                             "GetAll",
1236                                             g_variant_new ("(s)", o->name),
1237                                             NULL,
1238                                             G_DBUS_CALL_FLAGS_NONE,
1239                                             3000,
1240                                             NULL,
1241                                             NULL);
1242       if (result != NULL)
1243         {
1244           if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1245             {
1246               GVariantIter *iter;
1247               GVariant *item;
1248               g_variant_get (result,
1249                              "(a{sv})",
1250                              &iter);
1251               while ((item = g_variant_iter_next_value (iter)))
1252                 {
1253                   gchar *key;
1254                   GVariant *value;
1255                   g_variant_get (item,
1256                                  "{sv}",
1257                                  &key,
1258                                  &value);
1259
1260                   g_hash_table_insert (properties, key, g_variant_ref (value));
1261                 }
1262             }
1263           g_variant_unref (result);
1264         }
1265       else
1266         {
1267           guint n;
1268           for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1269             {
1270               result = g_dbus_connection_call_sync (c,
1271                                                     name,
1272                                                     object_path,
1273                                                     "org.freedesktop.DBus.Properties",
1274                                                     "Get",
1275                                                     g_variant_new ("(ss)", o->name, o->properties[n]->name),
1276                                                     G_VARIANT_TYPE ("(v)"),
1277                                                     G_DBUS_CALL_FLAGS_NONE,
1278                                                     3000,
1279                                                     NULL,
1280                                                     NULL);
1281               if (result != NULL)
1282                 {
1283                   GVariant *property_value;
1284                   g_variant_get (result,
1285                                  "(v)",
1286                                  &property_value);
1287                   g_hash_table_insert (properties,
1288                                        g_strdup (o->properties[n]->name),
1289                                        g_variant_ref (property_value));
1290                   g_variant_unref (result);
1291                 }
1292             }
1293         }
1294     }
1295
1296   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1297     dump_annotation (o->annotations[n], indent, FALSE);
1298
1299   g_print ("%*sinterface %s {\n", indent, "", o->name);
1300   if (o->methods != NULL && !opt_introspect_only_properties)
1301     {
1302       g_print ("%*s  methods:\n", indent, "");
1303       for (n = 0; o->methods[n] != NULL; n++)
1304         dump_method (o->methods[n], indent + 4);
1305     }
1306   if (o->signals != NULL && !opt_introspect_only_properties)
1307     {
1308       g_print ("%*s  signals:\n", indent, "");
1309       for (n = 0; o->signals[n] != NULL; n++)
1310         dump_signal (o->signals[n], indent + 4);
1311     }
1312   if (o->properties != NULL)
1313     {
1314       g_print ("%*s  properties:\n", indent, "");
1315       for (n = 0; o->properties[n] != NULL; n++)
1316         {
1317           dump_property (o->properties[n],
1318                          indent + 4,
1319                          g_hash_table_lookup (properties, (o->properties[n])->name));
1320         }
1321     }
1322   g_print ("%*s};\n",
1323            indent, "");
1324
1325   g_hash_table_unref (properties);
1326 }
1327
1328 static gboolean
1329 introspect_do (GDBusConnection *c,
1330                const gchar     *object_path,
1331                guint            indent);
1332
1333 static void
1334 dump_node (GDBusConnection      *c,
1335            const gchar          *name,
1336            const GDBusNodeInfo  *o,
1337            guint                 indent,
1338            const gchar          *object_path,
1339            gboolean              recurse)
1340 {
1341   guint n;
1342   const gchar *object_path_to_print;
1343
1344   object_path_to_print = object_path;
1345   if (o->path != NULL)
1346     object_path_to_print = o->path;
1347
1348   for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1349     dump_annotation (o->annotations[n], indent, FALSE);
1350
1351   g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
1352   if (o->interfaces != NULL || o->nodes != NULL)
1353     {
1354       g_print (" {\n");
1355       for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1356         {
1357           if (opt_introspect_only_properties)
1358             {
1359               if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1360                 dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1361             }
1362           else
1363             {
1364               dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
1365             }
1366         }
1367       for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1368         {
1369           if (recurse)
1370             {
1371               gchar *child_path;
1372               if (g_variant_is_object_path (o->nodes[n]->path))
1373                 {
1374                   child_path = g_strdup (o->nodes[n]->path);
1375                   /* avoid infinite loops */
1376                   if (g_str_has_prefix (child_path, object_path))
1377                     {
1378                       introspect_do (c, child_path, indent + 2);
1379                     }
1380                   else
1381                     {
1382                       g_print ("Skipping path %s that is not enclosed by parent %s\n",
1383                                child_path, object_path);
1384                     }
1385                 }
1386               else
1387                 {
1388                   if (g_strcmp0 (object_path, "/") == 0)
1389                     child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1390                   else
1391                     child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1392                   introspect_do (c, child_path, indent + 2);
1393                 }
1394               g_free (child_path);
1395             }
1396           else
1397             {
1398               dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
1399             }
1400         }
1401       g_print ("%*s};\n",
1402                indent, "");
1403     }
1404   else
1405     {
1406       g_print ("\n");
1407     }
1408 }
1409
1410 static const GOptionEntry introspect_entries[] =
1411 {
1412   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1413   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1414   { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1415   { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1416   { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1417   { NULL }
1418 };
1419
1420 static gboolean
1421 introspect_do (GDBusConnection *c,
1422                const gchar     *object_path,
1423                guint            indent)
1424 {
1425   GError *error;
1426   GVariant *result;
1427   GDBusNodeInfo *node;
1428   gboolean ret;
1429   const gchar *xml_data;
1430
1431   ret = FALSE;
1432   node = NULL;
1433   result = NULL;
1434
1435   error = NULL;
1436   result = g_dbus_connection_call_sync (c,
1437                                         opt_introspect_dest,
1438                                         object_path,
1439                                         "org.freedesktop.DBus.Introspectable",
1440                                         "Introspect",
1441                                         NULL,
1442                                         G_VARIANT_TYPE ("(s)"),
1443                                         G_DBUS_CALL_FLAGS_NONE,
1444                                         3000, /* 3 sec */
1445                                         NULL,
1446                                         &error);
1447   if (result == NULL)
1448     {
1449       g_printerr (_("Error: %s\n"), error->message);
1450       g_error_free (error);
1451       goto out;
1452     }
1453   g_variant_get (result, "(&s)", &xml_data);
1454
1455   if (opt_introspect_xml)
1456     {
1457       g_print ("%s", xml_data);
1458     }
1459   else
1460     {
1461       error = NULL;
1462       node = g_dbus_node_info_new_for_xml (xml_data, &error);
1463       if (node == NULL)
1464         {
1465           g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1466           g_error_free (error);
1467           goto out;
1468         }
1469
1470       dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
1471     }
1472
1473   ret = TRUE;
1474
1475  out:
1476   if (node != NULL)
1477     g_dbus_node_info_unref (node);
1478   if (result != NULL)
1479     g_variant_unref (result);
1480   return ret;
1481 }
1482
1483 static gboolean
1484 handle_introspect (gint        *argc,
1485                    gchar      **argv[],
1486                    gboolean     request_completion,
1487                    const gchar *completion_cur,
1488                    const gchar *completion_prev)
1489 {
1490   gint ret;
1491   GOptionContext *o;
1492   gchar *s;
1493   GError *error;
1494   GDBusConnection *c;
1495   gboolean complete_names;
1496   gboolean complete_paths;
1497
1498   ret = FALSE;
1499   c = NULL;
1500
1501   modify_argv0_for_command (argc, argv, "introspect");
1502
1503   o = g_option_context_new (NULL);
1504   if (request_completion)
1505     g_option_context_set_ignore_unknown_options (o, TRUE);
1506   g_option_context_set_help_enabled (o, FALSE);
1507   g_option_context_set_summary (o, _("Introspect a remote object."));
1508   g_option_context_add_main_entries (o, introspect_entries, GETTEXT_PACKAGE);
1509   g_option_context_add_group (o, connection_get_group ());
1510
1511   complete_names = FALSE;
1512   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1513     {
1514       complete_names = TRUE;
1515       remove_arg ((*argc) - 1, argc, argv);
1516     }
1517
1518   complete_paths = FALSE;
1519   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1520     {
1521       complete_paths = TRUE;
1522       remove_arg ((*argc) - 1, argc, argv);
1523     }
1524
1525   if (!g_option_context_parse (o, argc, argv, NULL))
1526     {
1527       if (!request_completion)
1528         {
1529           s = g_option_context_get_help (o, FALSE, NULL);
1530           g_printerr ("%s", s);
1531           g_free (s);
1532           goto out;
1533         }
1534     }
1535
1536   error = NULL;
1537   c = connection_get_dbus_connection (&error);
1538   if (c == NULL)
1539     {
1540       if (request_completion)
1541         {
1542           if (g_strcmp0 (completion_prev, "--address") == 0)
1543             {
1544               g_print ("unix:\n"
1545                        "tcp:\n"
1546                        "nonce-tcp:\n");
1547             }
1548           else
1549             {
1550               g_print ("--system \n--session \n--address \n");
1551             }
1552         }
1553       else
1554         {
1555           g_printerr (_("Error connecting: %s\n"), error->message);
1556           g_error_free (error);
1557         }
1558       goto out;
1559     }
1560
1561   if (g_dbus_connection_get_unique_name (c) != NULL)
1562     {
1563       if (complete_names)
1564         {
1565           print_names (c, FALSE);
1566           goto out;
1567         }
1568       /* this only makes sense on message bus connections */
1569       if (opt_introspect_dest == NULL)
1570         {
1571           if (request_completion)
1572             g_print ("--dest \n");
1573           else
1574             g_printerr (_("Error: Destination is not specified\n"));
1575           goto out;
1576         }
1577       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1578         {
1579           print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1580           goto out;
1581         }
1582     }
1583   if (complete_paths)
1584     {
1585       print_paths (c, opt_introspect_dest, "/");
1586       goto out;
1587     }
1588   if (opt_introspect_object_path == NULL)
1589     {
1590       if (request_completion)
1591         g_print ("--object-path \n");
1592       else
1593         g_printerr (_("Error: Object path is not specified\n"));
1594       goto out;
1595     }
1596   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1597     {
1598       gchar *p;
1599       s = g_strdup (opt_introspect_object_path);
1600       p = strrchr (s, '/');
1601       if (p != NULL)
1602         {
1603           if (p == s)
1604             p++;
1605           *p = '\0';
1606         }
1607       print_paths (c, opt_introspect_dest, s);
1608       g_free (s);
1609       goto out;
1610     }
1611   if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1612     {
1613       g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1614       goto out;
1615     }
1616
1617   if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1618     {
1619       g_print ("--recurse \n");
1620     }
1621
1622   if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1623     {
1624       g_print ("--only-properties \n");
1625     }
1626
1627   /* All done with completion now */
1628   if (request_completion)
1629     goto out;
1630
1631   if (!introspect_do (c, opt_introspect_object_path, 0))
1632     goto out;
1633
1634   ret = TRUE;
1635
1636  out:
1637   if (c != NULL)
1638     g_object_unref (c);
1639   g_option_context_free (o);
1640   return ret;
1641 }
1642
1643 /* ---------------------------------------------------------------------------------------------------- */
1644
1645 static gchar *opt_monitor_dest = NULL;
1646 static gchar *opt_monitor_object_path = NULL;
1647
1648 static guint monitor_filter_id = 0;
1649
1650 static void
1651 monitor_signal_cb (GDBusConnection *connection,
1652                    const gchar     *sender_name,
1653                    const gchar     *object_path,
1654                    const gchar     *interface_name,
1655                    const gchar     *signal_name,
1656                    GVariant        *parameters,
1657                    gpointer         user_data)
1658 {
1659   gchar *s;
1660   s = g_variant_print (parameters, TRUE);
1661   g_print ("%s: %s.%s %s\n",
1662            object_path,
1663            interface_name,
1664            signal_name,
1665            s);
1666   g_free (s);
1667 }
1668
1669 static void
1670 monitor_on_name_appeared (GDBusConnection *connection,
1671                           const gchar *name,
1672                           const gchar *name_owner,
1673                           gpointer user_data)
1674 {
1675   g_print ("The name %s is owned by %s\n", name, name_owner);
1676   g_assert (monitor_filter_id == 0);
1677   monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1678                                                           name_owner,
1679                                                           NULL,  /* any interface */
1680                                                           NULL,  /* any member */
1681                                                           opt_monitor_object_path,
1682                                                           NULL,  /* arg0 */
1683                                                           G_DBUS_SIGNAL_FLAGS_NONE,
1684                                                           monitor_signal_cb,
1685                                                           NULL,  /* user_data */
1686                                                           NULL); /* user_data destroy notify */
1687 }
1688
1689 static void
1690 monitor_on_name_vanished (GDBusConnection *connection,
1691                           const gchar *name,
1692                           gpointer user_data)
1693 {
1694   g_print ("The name %s does not have an owner\n", name);
1695
1696   if (monitor_filter_id != 0)
1697     {
1698       g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
1699       monitor_filter_id = 0;
1700     }
1701 }
1702
1703 static const GOptionEntry monitor_entries[] =
1704 {
1705   { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1706   { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1707   { NULL }
1708 };
1709
1710 static gboolean
1711 handle_monitor (gint        *argc,
1712                 gchar      **argv[],
1713                 gboolean     request_completion,
1714                 const gchar *completion_cur,
1715                 const gchar *completion_prev)
1716 {
1717   gint ret;
1718   GOptionContext *o;
1719   gchar *s;
1720   GError *error;
1721   GDBusConnection *c;
1722   GVariant *result;
1723   GDBusNodeInfo *node;
1724   gboolean complete_names;
1725   gboolean complete_paths;
1726   GMainLoop *loop;
1727
1728   ret = FALSE;
1729   c = NULL;
1730   node = NULL;
1731   result = NULL;
1732
1733   modify_argv0_for_command (argc, argv, "monitor");
1734
1735   o = g_option_context_new (NULL);
1736   if (request_completion)
1737     g_option_context_set_ignore_unknown_options (o, TRUE);
1738   g_option_context_set_help_enabled (o, FALSE);
1739   g_option_context_set_summary (o, _("Monitor a remote object."));
1740   g_option_context_add_main_entries (o, monitor_entries, GETTEXT_PACKAGE);
1741   g_option_context_add_group (o, connection_get_group ());
1742
1743   complete_names = FALSE;
1744   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1745     {
1746       complete_names = TRUE;
1747       remove_arg ((*argc) - 1, argc, argv);
1748     }
1749
1750   complete_paths = FALSE;
1751   if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1752     {
1753       complete_paths = TRUE;
1754       remove_arg ((*argc) - 1, argc, argv);
1755     }
1756
1757   if (!g_option_context_parse (o, argc, argv, NULL))
1758     {
1759       if (!request_completion)
1760         {
1761           s = g_option_context_get_help (o, FALSE, NULL);
1762           g_printerr ("%s", s);
1763           g_free (s);
1764           goto out;
1765         }
1766     }
1767
1768   error = NULL;
1769   c = connection_get_dbus_connection (&error);
1770   if (c == NULL)
1771     {
1772       if (request_completion)
1773         {
1774           if (g_strcmp0 (completion_prev, "--address") == 0)
1775             {
1776               g_print ("unix:\n"
1777                        "tcp:\n"
1778                        "nonce-tcp:\n");
1779             }
1780           else
1781             {
1782               g_print ("--system \n--session \n--address \n");
1783             }
1784         }
1785       else
1786         {
1787           g_printerr (_("Error connecting: %s\n"), error->message);
1788           g_error_free (error);
1789         }
1790       goto out;
1791     }
1792
1793   if (g_dbus_connection_get_unique_name (c) != NULL)
1794     {
1795       if (complete_names)
1796         {
1797           print_names (c, FALSE);
1798           goto out;
1799         }
1800       /* this only makes sense on message bus connections */
1801       if (opt_monitor_dest == NULL)
1802         {
1803           if (request_completion)
1804             g_print ("--dest \n");
1805           else
1806             g_printerr (_("Error: Destination is not specified\n"));
1807           goto out;
1808         }
1809       if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1810         {
1811           print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
1812           goto out;
1813         }
1814     }
1815   if (complete_paths)
1816     {
1817       print_paths (c, opt_monitor_dest, "/");
1818       goto out;
1819     }
1820   if (opt_monitor_object_path == NULL)
1821     {
1822       if (request_completion)
1823         {
1824           g_print ("--object-path \n");
1825           goto out;
1826         }
1827       /* it's fine to not have an object path */
1828     }
1829   if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1830     {
1831       gchar *p;
1832       s = g_strdup (opt_monitor_object_path);
1833       p = strrchr (s, '/');
1834       if (p != NULL)
1835         {
1836           if (p == s)
1837             p++;
1838           *p = '\0';
1839         }
1840       print_paths (c, opt_monitor_dest, s);
1841       g_free (s);
1842       goto out;
1843     }
1844   if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
1845     {
1846       g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
1847       goto out;
1848     }
1849
1850   /* All done with completion now */
1851   if (request_completion)
1852     goto out;
1853
1854   if (opt_monitor_object_path != NULL)
1855     g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
1856   else
1857     g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
1858
1859   loop = g_main_loop_new (NULL, FALSE);
1860   g_bus_watch_name_on_connection (c,
1861                                   opt_monitor_dest,
1862                                   G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
1863                                   monitor_on_name_appeared,
1864                                   monitor_on_name_vanished,
1865                                   NULL,
1866                                   NULL);
1867
1868   g_main_loop_run (loop);
1869   g_main_loop_unref (loop);
1870
1871   ret = TRUE;
1872
1873  out:
1874   if (node != NULL)
1875     g_dbus_node_info_unref (node);
1876   if (result != NULL)
1877     g_variant_unref (result);
1878   if (c != NULL)
1879     g_object_unref (c);
1880   g_option_context_free (o);
1881   return ret;
1882 }
1883
1884 /* ---------------------------------------------------------------------------------------------------- */
1885
1886 static gchar *
1887 pick_word_at (const gchar  *s,
1888               gint          cursor,
1889               gint         *out_word_begins_at)
1890 {
1891   gint begin;
1892   gint end;
1893
1894   if (s[0] == '\0')
1895     {
1896       if (out_word_begins_at != NULL)
1897         *out_word_begins_at = -1;
1898       return NULL;
1899     }
1900
1901   if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
1902     {
1903       if (out_word_begins_at != NULL)
1904         *out_word_begins_at = cursor;
1905       return g_strdup ("");
1906     }
1907
1908   while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
1909     cursor--;
1910   begin = cursor;
1911
1912   end = begin;
1913   while (!g_ascii_isspace (s[end]) && s[end] != '\0')
1914     end++;
1915
1916   if (out_word_begins_at != NULL)
1917     *out_word_begins_at = begin;
1918
1919   return g_strndup (s + begin, end - begin);
1920 }
1921
1922 gint
1923 main (gint argc, gchar *argv[])
1924 {
1925   gint ret;
1926   const gchar *command;
1927   gboolean request_completion;
1928   gchar *completion_cur;
1929   gchar *completion_prev;
1930
1931   setlocale (LC_ALL, "");
1932   textdomain (GETTEXT_PACKAGE);
1933
1934 #ifdef G_OS_WIN32
1935   extern gchar *_glib_get_locale_dir (void);
1936   gchar *tmp = _glib_get_locale_dir ();
1937   bindtextdomain (GETTEXT_PACKAGE, tmp);
1938   g_free (tmp);
1939 #else
1940   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
1941 #endif
1942
1943 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
1944   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1945 #endif
1946
1947   ret = 1;
1948   completion_cur = NULL;
1949   completion_prev = NULL;
1950
1951   g_type_init ();
1952
1953   if (argc < 2)
1954     {
1955       usage (&argc, &argv, FALSE);
1956       goto out;
1957     }
1958
1959   request_completion = FALSE;
1960
1961   //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
1962
1963  again:
1964   command = argv[1];
1965   if (g_strcmp0 (command, "help") == 0)
1966     {
1967       if (request_completion)
1968         {
1969           /* do nothing */
1970         }
1971       else
1972         {
1973           usage (&argc, &argv, TRUE);
1974           ret = 0;
1975         }
1976       goto out;
1977     }
1978   else if (g_strcmp0 (command, "emit") == 0)
1979     {
1980       if (handle_emit (&argc,
1981                        &argv,
1982                        request_completion,
1983                        completion_cur,
1984                        completion_prev))
1985         ret = 0;
1986       goto out;
1987     }
1988   else if (g_strcmp0 (command, "call") == 0)
1989     {
1990       if (handle_call (&argc,
1991                        &argv,
1992                        request_completion,
1993                        completion_cur,
1994                        completion_prev))
1995         ret = 0;
1996       goto out;
1997     }
1998   else if (g_strcmp0 (command, "introspect") == 0)
1999     {
2000       if (handle_introspect (&argc,
2001                              &argv,
2002                              request_completion,
2003                              completion_cur,
2004                              completion_prev))
2005         ret = 0;
2006       goto out;
2007     }
2008   else if (g_strcmp0 (command, "monitor") == 0)
2009     {
2010       if (handle_monitor (&argc,
2011                           &argv,
2012                           request_completion,
2013                           completion_cur,
2014                           completion_prev))
2015         ret = 0;
2016       goto out;
2017     }
2018   else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2019     {
2020       const gchar *completion_line;
2021       gchar **completion_argv;
2022       gint completion_argc;
2023       gint completion_point;
2024       gchar *endp;
2025       gint cur_begin;
2026
2027       request_completion = TRUE;
2028
2029       completion_line = argv[2];
2030       completion_point = strtol (argv[3], &endp, 10);
2031       if (endp == argv[3] || *endp != '\0')
2032         goto out;
2033
2034 #if 0
2035       completion_debug ("completion_point=%d", completion_point);
2036       completion_debug ("----");
2037       completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2038       completion_debug ("`%s'", completion_line);
2039       completion_debug (" %*s^",
2040                          completion_point, "");
2041       completion_debug ("----");
2042 #endif
2043
2044       if (!g_shell_parse_argv (completion_line,
2045                                &completion_argc,
2046                                &completion_argv,
2047                                NULL))
2048         {
2049           /* it's very possible the command line can't be parsed (for
2050            * example, missing quotes etc) - in that case, we just
2051            * don't autocomplete at all
2052            */
2053           goto out;
2054         }
2055
2056       /* compute cur and prev */
2057       completion_prev = NULL;
2058       completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2059       if (cur_begin > 0)
2060         {
2061           gint prev_end;
2062           for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2063             {
2064               if (!g_ascii_isspace (completion_line[prev_end]))
2065                 {
2066                   completion_prev = pick_word_at (completion_line, prev_end, NULL);
2067                   break;
2068                 }
2069             }
2070         }
2071 #if 0
2072       completion_debug (" cur=`%s'", completion_cur);
2073       completion_debug ("prev=`%s'", completion_prev);
2074 #endif
2075
2076       argc = completion_argc;
2077       argv = completion_argv;
2078
2079       ret = 0;
2080
2081       goto again;
2082     }
2083   else
2084     {
2085       if (request_completion)
2086         {
2087           g_print ("help \nemit \ncall \nintrospect \nmonitor \n");
2088           ret = 0;
2089           goto out;
2090         }
2091       else
2092         {
2093           g_printerr ("Unknown command `%s'\n", command);
2094           usage (&argc, &argv, FALSE);
2095           goto out;
2096         }
2097     }
2098
2099  out:
2100   g_free (completion_cur);
2101   g_free (completion_prev);
2102   return ret;
2103 }