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