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