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