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