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