Branch data Line data Source code
1 : : /* GDBus - GLib D-Bus Library
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 : : #ifdef G_OS_UNIX
33 : : #include <gio/gunixfdlist.h>
34 : : #endif
35 : :
36 : : #include <gi18n.h>
37 : : #include <glib/gstdio.h>
38 : :
39 : : #ifdef G_OS_WIN32
40 : : #include "glib/glib-private.h"
41 : : #endif
42 : :
43 : : #include "gdbusprivate.h"
44 : :
45 : : /* ---------------------------------------------------------------------------------------------------- */
46 : :
47 : : /* Escape values for console colors */
48 : : #define UNDERLINE "\033[4m"
49 : : #define BLUE "\033[34m"
50 : : #define CYAN "\033[36m"
51 : : #define GREEN "\033[32m"
52 : : #define MAGENTA "\033[35m"
53 : : #define RED "\033[31m"
54 : : #define YELLOW "\033[33m"
55 : :
56 : : /* ---------------------------------------------------------------------------------------------------- */
57 : :
58 : : G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
59 : :
60 : : /* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
61 : : * to not have it interfere with stdout/stderr)
62 : : */
63 : : #if 0
64 : : G_GNUC_UNUSED static void
65 : : completion_debug (const gchar *format, ...)
66 : : {
67 : : va_list var_args;
68 : : gchar *s;
69 : : static FILE *f = NULL;
70 : :
71 : : va_start (var_args, format);
72 : : s = g_strdup_vprintf (format, var_args);
73 : : if (f == NULL)
74 : : {
75 : : f = g_fopen ("/tmp/gdbus-completion-debug.txt", "a+e");
76 : : }
77 : : fprintf (f, "%s\n", s);
78 : : g_free (s);
79 : : }
80 : : #else
81 : : static void
82 : 0 : completion_debug (const gchar *format, ...)
83 : : {
84 : 0 : }
85 : : #endif
86 : :
87 : : /* ---------------------------------------------------------------------------------------------------- */
88 : :
89 : :
90 : : static void
91 : 2 : remove_arg (gint num, gint *argc, gchar **argv[])
92 : : {
93 : : gint n;
94 : :
95 : 2 : g_assert (num <= (*argc));
96 : :
97 : 18 : for (n = num; (*argv)[n] != NULL; n++)
98 : 16 : (*argv)[n] = (*argv)[n+1];
99 : 2 : (*argv)[n] = NULL;
100 : 2 : (*argc) = (*argc) - 1;
101 : 2 : }
102 : :
103 : : static void
104 : 3 : usage (gint *argc, gchar **argv[], gboolean use_stdout)
105 : : {
106 : : GOptionContext *o;
107 : : gchar *s;
108 : : gchar *program_name;
109 : :
110 : 3 : o = g_option_context_new (_("COMMAND"));
111 : 3 : g_option_context_set_help_enabled (o, FALSE);
112 : : /* Ignore parsing result */
113 : 3 : g_option_context_parse (o, argc, argv, NULL);
114 : 3 : program_name = (*argc > 0) ? g_path_get_basename ((*argv)[0]) : g_strdup ("gdbus-tool");
115 : 3 : s = g_strdup_printf (_("Commands:\n"
116 : : " help Shows this information\n"
117 : : " introspect Introspect a remote object\n"
118 : : " monitor Monitor a remote object\n"
119 : : " call Invoke a method on a remote object\n"
120 : : " emit Emit a signal\n"
121 : : " wait Wait for a bus name to appear\n"
122 : : "\n"
123 : : "Use “%s COMMAND --help” to get help on each command.\n"),
124 : : program_name);
125 : 3 : g_free (program_name);
126 : 3 : g_option_context_set_description (o, s);
127 : 3 : g_free (s);
128 : 3 : s = g_option_context_get_help (o, FALSE, NULL);
129 : 3 : if (use_stdout)
130 : 2 : g_print ("%s", s);
131 : : else
132 : 1 : g_printerr ("%s", s);
133 : 3 : g_free (s);
134 : 3 : g_option_context_free (o);
135 : 3 : }
136 : :
137 : : static void
138 : 2 : modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
139 : : {
140 : : gchar *s;
141 : : gchar *program_name;
142 : :
143 : : /* TODO:
144 : : * 1. get a g_set_prgname() ?; or
145 : : * 2. save old argv[0] and restore later
146 : : */
147 : :
148 : 2 : g_assert (*argc > 1);
149 : 2 : g_assert (g_strcmp0 ((*argv)[1], command) == 0);
150 : 2 : remove_arg (1, argc, argv);
151 : :
152 : 2 : program_name = g_path_get_basename ((*argv)[0]);
153 : 2 : s = g_strdup_printf ("%s %s", program_name, command);
154 : 2 : (*argv)[0] = s;
155 : 2 : g_free (program_name);
156 : 2 : }
157 : :
158 : : static GOptionContext *
159 : 2 : command_option_context_new (const gchar *parameter_string,
160 : : const gchar *summary,
161 : : const GOptionEntry *entries,
162 : : gboolean request_completion)
163 : : {
164 : 2 : GOptionContext *o = NULL;
165 : :
166 : 2 : o = g_option_context_new (parameter_string);
167 : 2 : if (request_completion)
168 : 0 : g_option_context_set_ignore_unknown_options (o, TRUE);
169 : 2 : g_option_context_set_help_enabled (o, FALSE);
170 : 2 : g_option_context_set_summary (o, summary);
171 : 2 : g_option_context_add_main_entries (o, entries, GETTEXT_PACKAGE);
172 : :
173 : 2 : return g_steal_pointer (&o);
174 : : }
175 : :
176 : : /* ---------------------------------------------------------------------------------------------------- */
177 : :
178 : : static void
179 : 0 : print_methods_and_signals (GDBusConnection *c,
180 : : const gchar *name,
181 : : const gchar *path,
182 : : gboolean print_methods,
183 : : gboolean print_signals)
184 : : {
185 : : GVariant *result;
186 : : GError *error;
187 : : const gchar *xml_data;
188 : : GDBusNodeInfo *node;
189 : : guint n;
190 : : guint m;
191 : :
192 : 0 : error = NULL;
193 : 0 : result = g_dbus_connection_call_sync (c,
194 : : name,
195 : : path,
196 : : DBUS_INTERFACE_INTROSPECTABLE,
197 : : "Introspect",
198 : : NULL,
199 : : G_VARIANT_TYPE ("(s)"),
200 : : G_DBUS_CALL_FLAGS_NONE,
201 : : 3000, /* 3 secs */
202 : : NULL,
203 : : &error);
204 : 0 : if (result == NULL)
205 : : {
206 : 0 : g_printerr (_("Error: %s\n"), error->message);
207 : 0 : g_error_free (error);
208 : 0 : goto out;
209 : : }
210 : 0 : g_variant_get (result, "(&s)", &xml_data);
211 : :
212 : 0 : error = NULL;
213 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
214 : 0 : g_variant_unref (result);
215 : 0 : if (node == NULL)
216 : : {
217 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
218 : 0 : g_error_free (error);
219 : 0 : goto out;
220 : : }
221 : :
222 : 0 : for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
223 : : {
224 : 0 : const GDBusInterfaceInfo *iface = node->interfaces[n];
225 : 0 : for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++)
226 : : {
227 : 0 : const GDBusMethodInfo *method = iface->methods[m];
228 : 0 : g_print ("%s.%s \n", iface->name, method->name);
229 : : }
230 : 0 : for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++)
231 : : {
232 : 0 : const GDBusSignalInfo *signal = iface->signals[m];
233 : 0 : g_print ("%s.%s \n", iface->name, signal->name);
234 : : }
235 : : }
236 : 0 : g_dbus_node_info_unref (node);
237 : :
238 : 0 : out:
239 : : ;
240 : 0 : }
241 : :
242 : : static void
243 : 0 : print_paths (GDBusConnection *c,
244 : : const gchar *name,
245 : : const gchar *path)
246 : : {
247 : : GVariant *result;
248 : : GError *error;
249 : : const gchar *xml_data;
250 : : GDBusNodeInfo *node;
251 : : guint n;
252 : :
253 : 0 : if (!g_dbus_is_name (name))
254 : : {
255 : 0 : g_printerr (_("Error: %s is not a valid name\n"), name);
256 : 0 : goto out;
257 : : }
258 : 0 : if (!g_variant_is_object_path (path))
259 : : {
260 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), path);
261 : 0 : goto out;
262 : : }
263 : :
264 : 0 : error = NULL;
265 : 0 : result = g_dbus_connection_call_sync (c,
266 : : name,
267 : : path,
268 : : DBUS_INTERFACE_INTROSPECTABLE,
269 : : "Introspect",
270 : : NULL,
271 : : G_VARIANT_TYPE ("(s)"),
272 : : G_DBUS_CALL_FLAGS_NONE,
273 : : 3000, /* 3 secs */
274 : : NULL,
275 : : &error);
276 : 0 : if (result == NULL)
277 : : {
278 : 0 : g_printerr (_("Error: %s\n"), error->message);
279 : 0 : g_error_free (error);
280 : 0 : goto out;
281 : : }
282 : 0 : g_variant_get (result, "(&s)", &xml_data);
283 : :
284 : : //g_printerr ("xml='%s'", xml_data);
285 : :
286 : 0 : error = NULL;
287 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
288 : 0 : g_variant_unref (result);
289 : 0 : if (node == NULL)
290 : : {
291 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
292 : 0 : g_error_free (error);
293 : 0 : goto out;
294 : : }
295 : :
296 : : //g_printerr ("bar '%s'\n", path);
297 : :
298 : 0 : if (node->interfaces != NULL)
299 : 0 : g_print ("%s \n", path);
300 : :
301 : 0 : for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
302 : : {
303 : : gchar *s;
304 : :
305 : : //g_printerr ("foo '%s'\n", node->nodes[n].path);
306 : :
307 : 0 : if (g_strcmp0 (path, "/") == 0)
308 : 0 : s = g_strdup_printf ("/%s", node->nodes[n]->path);
309 : : else
310 : 0 : s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
311 : :
312 : 0 : print_paths (c, name, s);
313 : :
314 : 0 : g_free (s);
315 : : }
316 : 0 : g_dbus_node_info_unref (node);
317 : :
318 : 0 : out:
319 : : ;
320 : 0 : }
321 : :
322 : : static void
323 : 0 : print_names (GDBusConnection *c,
324 : : gboolean include_unique_names)
325 : : {
326 : : GVariant *result;
327 : : GError *error;
328 : : GVariantIter *iter;
329 : : gchar *str;
330 : : GHashTable *name_set;
331 : : GPtrArray *keys;
332 : :
333 : 0 : name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
334 : :
335 : 0 : error = NULL;
336 : 0 : result = g_dbus_connection_call_sync (c,
337 : : DBUS_SERVICE_DBUS,
338 : : DBUS_PATH_DBUS,
339 : : DBUS_INTERFACE_DBUS,
340 : : "ListNames",
341 : : NULL,
342 : : G_VARIANT_TYPE ("(as)"),
343 : : G_DBUS_CALL_FLAGS_NONE,
344 : : 3000, /* 3 secs */
345 : : NULL,
346 : : &error);
347 : 0 : if (result == NULL)
348 : : {
349 : 0 : g_printerr (_("Error: %s\n"), error->message);
350 : 0 : g_error_free (error);
351 : 0 : goto out;
352 : : }
353 : 0 : g_variant_get (result, "(as)", &iter);
354 : 0 : while (g_variant_iter_loop (iter, "s", &str))
355 : 0 : g_hash_table_add (name_set, g_strdup (str));
356 : 0 : g_variant_iter_free (iter);
357 : 0 : g_variant_unref (result);
358 : :
359 : 0 : error = NULL;
360 : 0 : result = g_dbus_connection_call_sync (c,
361 : : DBUS_SERVICE_DBUS,
362 : : DBUS_PATH_DBUS,
363 : : DBUS_INTERFACE_DBUS,
364 : : "ListActivatableNames",
365 : : NULL,
366 : : G_VARIANT_TYPE ("(as)"),
367 : : G_DBUS_CALL_FLAGS_NONE,
368 : : 3000, /* 3 secs */
369 : : NULL,
370 : : &error);
371 : 0 : if (result == NULL)
372 : : {
373 : 0 : g_printerr (_("Error: %s\n"), error->message);
374 : 0 : g_error_free (error);
375 : 0 : goto out;
376 : : }
377 : 0 : g_variant_get (result, "(as)", &iter);
378 : 0 : while (g_variant_iter_loop (iter, "s", &str))
379 : 0 : g_hash_table_add (name_set, g_strdup (str));
380 : 0 : g_variant_iter_free (iter);
381 : 0 : g_variant_unref (result);
382 : :
383 : 0 : keys = g_hash_table_steal_all_keys (name_set);
384 : 0 : g_ptr_array_sort_values (keys, (GCompareFunc) g_strcmp0);
385 : 0 : for (guint i = 0; i < keys->len; ++i)
386 : : {
387 : 0 : const gchar *name = g_ptr_array_index (keys, i);
388 : 0 : if (!include_unique_names && g_str_has_prefix (name, ":"))
389 : 0 : continue;
390 : :
391 : 0 : g_print ("%s \n", name);
392 : : }
393 : 0 : g_clear_pointer (&keys, g_ptr_array_unref);
394 : :
395 : 0 : out:
396 : 0 : g_hash_table_unref (name_set);
397 : 0 : }
398 : :
399 : : /* ---------------------------------------------------------------------------------------------------- */
400 : :
401 : : static gboolean opt_connection_system = FALSE;
402 : : static gboolean opt_connection_session = FALSE;
403 : : static gchar *opt_connection_address = NULL;
404 : :
405 : : static const GOptionEntry connection_entries[] =
406 : : {
407 : : { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
408 : : { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
409 : : { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), N_("ADDRESS") },
410 : : G_OPTION_ENTRY_NULL
411 : : };
412 : :
413 : : static GOptionGroup *
414 : 2 : connection_get_group (void)
415 : : {
416 : : static GOptionGroup *g;
417 : :
418 : 2 : g = g_option_group_new ("connection",
419 : : N_("Connection Endpoint Options:"),
420 : : N_("Options specifying the connection endpoint"),
421 : : NULL,
422 : : NULL);
423 : 2 : g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
424 : 2 : g_option_group_add_entries (g, connection_entries);
425 : :
426 : 2 : return g;
427 : : }
428 : :
429 : : static GDBusConnection *
430 : 2 : connection_get_dbus_connection (gboolean require_message_bus,
431 : : GError **error)
432 : : {
433 : : GDBusConnection *c;
434 : :
435 : 2 : c = NULL;
436 : :
437 : : /* First, ensure we have exactly one connect */
438 : 2 : if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
439 : : {
440 : 0 : g_set_error (error,
441 : : G_IO_ERROR,
442 : : G_IO_ERROR_FAILED,
443 : 0 : _("No connection endpoint specified"));
444 : 0 : goto out;
445 : : }
446 : 2 : else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
447 : 2 : (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
448 : 2 : (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
449 : : {
450 : 0 : g_set_error (error,
451 : : G_IO_ERROR,
452 : : G_IO_ERROR_FAILED,
453 : 0 : _("Multiple connection endpoints specified"));
454 : 0 : goto out;
455 : : }
456 : :
457 : 2 : if (opt_connection_system)
458 : : {
459 : 0 : c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
460 : : }
461 : 2 : else if (opt_connection_session)
462 : : {
463 : 2 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
464 : : }
465 : 0 : else if (opt_connection_address != NULL)
466 : : {
467 : 0 : GDBusConnectionFlags flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT;
468 : 0 : if (require_message_bus)
469 : 0 : flags |= G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION;
470 : 0 : c = g_dbus_connection_new_for_address_sync (opt_connection_address,
471 : : flags,
472 : : NULL, /* GDBusAuthObserver */
473 : : NULL, /* GCancellable */
474 : : error);
475 : : }
476 : :
477 : 0 : out:
478 : 2 : return c;
479 : : }
480 : :
481 : : /* ---------------------------------------------------------------------------------------------------- */
482 : :
483 : : static GPtrArray *
484 : 1 : call_helper_get_method_in_signature (GDBusConnection *c,
485 : : const gchar *dest,
486 : : const gchar *path,
487 : : const gchar *interface_name,
488 : : const gchar *method_name,
489 : : GError **error)
490 : : {
491 : : GPtrArray *ret;
492 : : GVariant *result;
493 : : GDBusNodeInfo *node_info;
494 : : const gchar *xml_data;
495 : : GDBusInterfaceInfo *interface_info;
496 : : GDBusMethodInfo *method_info;
497 : : guint n;
498 : :
499 : 1 : ret = NULL;
500 : 1 : result = NULL;
501 : 1 : node_info = NULL;
502 : :
503 : 1 : result = g_dbus_connection_call_sync (c,
504 : : dest,
505 : : path,
506 : : DBUS_INTERFACE_INTROSPECTABLE,
507 : : "Introspect",
508 : : NULL,
509 : : G_VARIANT_TYPE ("(s)"),
510 : : G_DBUS_CALL_FLAGS_NONE,
511 : : 3000, /* 3 secs */
512 : : NULL,
513 : : error);
514 : 1 : if (result == NULL)
515 : 0 : goto out;
516 : :
517 : 1 : g_variant_get (result, "(&s)", &xml_data);
518 : 1 : node_info = g_dbus_node_info_new_for_xml (xml_data, error);
519 : 1 : if (node_info == NULL)
520 : 0 : goto out;
521 : :
522 : 1 : interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
523 : 1 : if (interface_info == NULL)
524 : : {
525 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
526 : 0 : _("Warning: According to introspection data, interface “%s” does not exist\n"),
527 : : interface_name);
528 : 0 : goto out;
529 : : }
530 : :
531 : 1 : method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
532 : 1 : if (method_info == NULL)
533 : : {
534 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
535 : 0 : _("Warning: According to introspection data, method “%s” does not exist on interface “%s”\n"),
536 : : method_name,
537 : : interface_name);
538 : 0 : goto out;
539 : : }
540 : :
541 : 1 : ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
542 : 1 : for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
543 : : {
544 : 0 : g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
545 : : }
546 : :
547 : 1 : out:
548 : 1 : if (node_info != NULL)
549 : 1 : g_dbus_node_info_unref (node_info);
550 : 1 : if (result != NULL)
551 : 1 : g_variant_unref (result);
552 : :
553 : 1 : return ret;
554 : : }
555 : :
556 : : /* ---------------------------------------------------------------------------------------------------- */
557 : :
558 : : static GVariant *
559 : 0 : _g_variant_parse_me_harder (GVariantType *type,
560 : : const gchar *given_str,
561 : : GError **error)
562 : : {
563 : : GVariant *value;
564 : : gchar *s;
565 : : guint n;
566 : : GString *str;
567 : :
568 : 0 : str = g_string_new ("\"");
569 : 0 : for (n = 0; given_str[n] != '\0'; n++)
570 : : {
571 : 0 : if (G_UNLIKELY (given_str[n] == '\"'))
572 : 0 : g_string_append (str, "\\\"");
573 : : else
574 : 0 : g_string_append_c (str, given_str[n]);
575 : : }
576 : : g_string_append_c (str, '"');
577 : 0 : s = g_string_free (str, FALSE);
578 : :
579 : 0 : value = g_variant_parse (type,
580 : : s,
581 : : NULL,
582 : : NULL,
583 : : error);
584 : 0 : g_free (s);
585 : :
586 : 0 : return value;
587 : : }
588 : :
589 : : /* ---------------------------------------------------------------------------------------------------- */
590 : :
591 : : #ifdef G_OS_UNIX
592 : : static gboolean
593 : 0 : walk_variant_for_handle (GVariantBuilder *builder,
594 : : GUnixFDList *fd_list,
595 : : GVariant *value)
596 : : {
597 : 0 : g_assert (!g_variant_is_floating (value));
598 : :
599 : 0 : if (g_variant_is_container (value))
600 : : {
601 : 0 : gboolean res = TRUE;
602 : : GVariantIter iter;
603 : : GVariant *child;
604 : :
605 : 0 : g_variant_iter_init (&iter, value);
606 : :
607 : 0 : g_variant_builder_open (builder, g_variant_get_type (value));
608 : :
609 : 0 : while ((child = g_variant_iter_next_value (&iter)) && res)
610 : : {
611 : 0 : res = walk_variant_for_handle (builder, fd_list, child);
612 : 0 : g_variant_unref (child);
613 : : }
614 : :
615 : 0 : g_variant_builder_close (builder);
616 : :
617 : 0 : if (!res)
618 : 0 : return FALSE;
619 : : }
620 : 0 : else if (g_variant_is_of_type (value, G_VARIANT_TYPE_HANDLE))
621 : : {
622 : 0 : GError *error = NULL;
623 : 0 : int fd_id = -1;
624 : :
625 : 0 : if ((fd_id = g_unix_fd_list_append (fd_list, g_variant_get_handle (value), &error)) < 0)
626 : : {
627 : 0 : g_printerr (_("Error adding handle %d: %s\n"),
628 : 0 : g_variant_get_handle (value), error->message);
629 : 0 : g_error_free (error);
630 : 0 : return FALSE;
631 : : }
632 : :
633 : 0 : g_variant_builder_add_value (builder, g_variant_new_handle (fd_id));
634 : : }
635 : : else
636 : : {
637 : 0 : g_variant_builder_add_value (builder, value);
638 : : }
639 : :
640 : 0 : return TRUE;
641 : : }
642 : : #endif
643 : :
644 : : /* ---------------------------------------------------------------------------------------------------- */
645 : :
646 : : static gchar *opt_emit_dest = NULL;
647 : : static gchar *opt_emit_object_path = NULL;
648 : : static gchar *opt_emit_signal = NULL;
649 : :
650 : : static const GOptionEntry emit_entries[] =
651 : : {
652 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
653 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
654 : : { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
655 : : G_OPTION_ENTRY_NULL
656 : : };
657 : :
658 : : static gboolean
659 : 0 : handle_emit (gint *argc,
660 : : gchar **argv[],
661 : : gboolean request_completion,
662 : : const gchar *completion_cur,
663 : : const gchar *completion_prev)
664 : : {
665 : : gint ret;
666 : : GOptionContext *o;
667 : : gchar *s;
668 : : GError *error;
669 : : GDBusConnection *c;
670 : : GVariant *parameters;
671 : : gchar *interface_name;
672 : : gchar *signal_name;
673 : : GVariantBuilder builder;
674 : : gboolean skip_dashes;
675 : : guint parm;
676 : : guint n;
677 : : gboolean complete_names, complete_paths, complete_signals;
678 : :
679 : 0 : ret = FALSE;
680 : 0 : c = NULL;
681 : 0 : parameters = NULL;
682 : 0 : interface_name = NULL;
683 : 0 : signal_name = NULL;
684 : :
685 : 0 : modify_argv0_for_command (argc, argv, "emit");
686 : :
687 : 0 : o = command_option_context_new (NULL, _("Emit a signal."),
688 : : emit_entries, request_completion);
689 : 0 : g_option_context_add_group (o, connection_get_group ());
690 : :
691 : 0 : complete_names = FALSE;
692 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
693 : : {
694 : 0 : complete_names = TRUE;
695 : 0 : remove_arg ((*argc) - 1, argc, argv);
696 : : }
697 : :
698 : 0 : complete_paths = FALSE;
699 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
700 : : {
701 : 0 : complete_paths = TRUE;
702 : 0 : remove_arg ((*argc) - 1, argc, argv);
703 : : }
704 : :
705 : 0 : complete_signals = FALSE;
706 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
707 : : {
708 : 0 : complete_signals = TRUE;
709 : 0 : remove_arg ((*argc) - 1, argc, argv);
710 : : }
711 : :
712 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
713 : : {
714 : 0 : if (!request_completion)
715 : : {
716 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
717 : 0 : g_printerr ("%s", s);
718 : 0 : g_free (s);
719 : 0 : goto out;
720 : : }
721 : : }
722 : :
723 : 0 : error = NULL;
724 : 0 : c = connection_get_dbus_connection ((opt_emit_dest != NULL), &error);
725 : 0 : if (c == NULL)
726 : : {
727 : 0 : if (request_completion)
728 : : {
729 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
730 : : {
731 : 0 : g_print ("unix:\n"
732 : : "tcp:\n"
733 : : "nonce-tcp:\n");
734 : : }
735 : : else
736 : : {
737 : 0 : g_print ("--system \n--session \n--address \n");
738 : : }
739 : : }
740 : : else
741 : : {
742 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
743 : : }
744 : 0 : g_error_free (error);
745 : 0 : goto out;
746 : : }
747 : :
748 : : /* validate and complete destination (bus name) */
749 : 0 : if (complete_names)
750 : : {
751 : 0 : print_names (c, FALSE);
752 : 0 : goto out;
753 : : }
754 : 0 : if (request_completion && opt_emit_dest != NULL && g_strcmp0 ("--dest", completion_prev) == 0)
755 : : {
756 : 0 : print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
757 : 0 : goto out;
758 : : }
759 : :
760 : 0 : if (!request_completion && opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
761 : : {
762 : 0 : g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
763 : 0 : goto out;
764 : : }
765 : :
766 : 0 : if (opt_emit_dest == NULL && opt_emit_object_path == NULL && request_completion)
767 : : {
768 : 0 : g_print ("--dest \n");
769 : : }
770 : : /* validate and complete object path */
771 : 0 : if (opt_emit_dest != NULL && complete_paths)
772 : : {
773 : 0 : print_paths (c, opt_emit_dest, "/");
774 : 0 : goto out;
775 : : }
776 : 0 : if (opt_emit_object_path == NULL)
777 : : {
778 : 0 : if (request_completion)
779 : 0 : g_print ("--object-path \n");
780 : : else
781 : 0 : g_printerr (_("Error: Object path is not specified\n"));
782 : 0 : goto out;
783 : : }
784 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
785 : : {
786 : 0 : if (opt_emit_dest != NULL)
787 : : {
788 : : gchar *p;
789 : 0 : s = g_strdup (opt_emit_object_path);
790 : 0 : p = strrchr (s, '/');
791 : 0 : if (p != NULL)
792 : : {
793 : 0 : if (p == s)
794 : 0 : p++;
795 : 0 : *p = '\0';
796 : : }
797 : 0 : print_paths (c, opt_emit_dest, s);
798 : 0 : g_free (s);
799 : : }
800 : 0 : goto out;
801 : : }
802 : 0 : if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
803 : : {
804 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
805 : 0 : goto out;
806 : : }
807 : :
808 : : /* validate and complete signal (interface + signal name) */
809 : 0 : if (opt_emit_dest != NULL && opt_emit_object_path != NULL && complete_signals)
810 : : {
811 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
812 : 0 : goto out;
813 : : }
814 : 0 : if (opt_emit_signal == NULL)
815 : : {
816 : : /* don't keep repeatedly completing --signal */
817 : 0 : if (request_completion)
818 : : {
819 : 0 : if (g_strcmp0 ("--signal", completion_prev) != 0)
820 : 0 : g_print ("--signal \n");
821 : : }
822 : : else
823 : : {
824 : 0 : g_printerr (_("Error: Signal name is not specified\n"));
825 : : }
826 : :
827 : 0 : goto out;
828 : : }
829 : 0 : if (request_completion && opt_emit_dest != NULL && opt_emit_object_path != NULL &&
830 : 0 : g_strcmp0 ("--signal", completion_prev) == 0)
831 : : {
832 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
833 : 0 : goto out;
834 : : }
835 : 0 : s = strrchr (opt_emit_signal, '.');
836 : 0 : if (!request_completion && s == NULL)
837 : : {
838 : 0 : g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
839 : 0 : goto out;
840 : : }
841 : 0 : signal_name = g_strdup (s + 1);
842 : 0 : interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
843 : :
844 : : /* All done with completion now */
845 : 0 : if (request_completion)
846 : 0 : goto out;
847 : :
848 : 0 : if (!g_dbus_is_interface_name (interface_name))
849 : : {
850 : 0 : g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
851 : 0 : goto out;
852 : : }
853 : :
854 : 0 : if (!g_dbus_is_member_name (signal_name))
855 : : {
856 : 0 : g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
857 : 0 : goto out;
858 : : }
859 : :
860 : : /* Read parameters */
861 : 0 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE_TUPLE);
862 : 0 : skip_dashes = TRUE;
863 : 0 : parm = 0;
864 : 0 : for (n = 1; n < (guint) *argc; n++)
865 : : {
866 : : GVariant *value;
867 : :
868 : : /* Under certain conditions, g_option_context_parse returns the "--"
869 : : itself (setting off unparsed arguments), too: */
870 : 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
871 : : {
872 : 0 : skip_dashes = FALSE;
873 : 0 : continue;
874 : : }
875 : :
876 : 0 : error = NULL;
877 : 0 : value = g_variant_parse (NULL,
878 : 0 : (*argv)[n],
879 : : NULL,
880 : : NULL,
881 : : &error);
882 : 0 : if (value == NULL)
883 : : {
884 : : gchar *context;
885 : :
886 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
887 : 0 : g_error_free (error);
888 : 0 : error = NULL;
889 : 0 : value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
890 : 0 : if (value == NULL)
891 : : {
892 : : /* Use the original non-"parse-me-harder" error */
893 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
894 : : parm + 1,
895 : : context);
896 : 0 : g_error_free (error);
897 : 0 : g_free (context);
898 : 0 : g_variant_builder_clear (&builder);
899 : 0 : goto out;
900 : : }
901 : 0 : g_free (context);
902 : : }
903 : 0 : g_variant_builder_add_value (&builder, value);
904 : 0 : ++parm;
905 : : }
906 : 0 : parameters = g_variant_builder_end (&builder);
907 : :
908 : 0 : if (parameters != NULL)
909 : 0 : parameters = g_variant_ref_sink (parameters);
910 : 0 : if (!g_dbus_connection_emit_signal (c,
911 : : opt_emit_dest,
912 : : opt_emit_object_path,
913 : : interface_name,
914 : : signal_name,
915 : : parameters,
916 : : &error))
917 : : {
918 : 0 : g_printerr (_("Error: %s\n"), error->message);
919 : 0 : g_error_free (error);
920 : 0 : goto out;
921 : : }
922 : :
923 : 0 : if (!g_dbus_connection_flush_sync (c, NULL, &error))
924 : : {
925 : 0 : g_printerr (_("Error flushing connection: %s\n"), error->message);
926 : 0 : g_error_free (error);
927 : 0 : goto out;
928 : : }
929 : :
930 : 0 : ret = TRUE;
931 : :
932 : 0 : out:
933 : 0 : if (c != NULL)
934 : 0 : g_object_unref (c);
935 : 0 : if (parameters != NULL)
936 : 0 : g_variant_unref (parameters);
937 : 0 : g_free (interface_name);
938 : 0 : g_free (signal_name);
939 : 0 : g_option_context_free (o);
940 : 0 : return ret;
941 : : }
942 : :
943 : : /* ---------------------------------------------------------------------------------------------------- */
944 : :
945 : : static gchar *opt_call_dest = NULL;
946 : : static gchar *opt_call_object_path = NULL;
947 : : static gchar *opt_call_method = NULL;
948 : : static gint opt_call_timeout = -1;
949 : : static gboolean opt_call_interactive = FALSE;
950 : :
951 : : static const GOptionEntry call_entries[] =
952 : : {
953 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
954 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
955 : : { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
956 : : { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
957 : : { "interactive", 'i', 0, G_OPTION_ARG_NONE, &opt_call_interactive, N_("Allow interactive authorization"), NULL},
958 : : G_OPTION_ENTRY_NULL
959 : : };
960 : :
961 : : static gboolean
962 : 2 : handle_call (gint *argc,
963 : : gchar **argv[],
964 : : gboolean request_completion,
965 : : const gchar *completion_cur,
966 : : const gchar *completion_prev)
967 : : {
968 : : gint ret;
969 : : GOptionContext *o;
970 : : gchar *s;
971 : : GError *error;
972 : : GDBusConnection *c;
973 : : GVariant *parameters;
974 : : gchar *interface_name;
975 : : gchar *method_name;
976 : : GVariant *result;
977 : : GPtrArray *in_signature_types;
978 : : #ifdef G_OS_UNIX
979 : : GUnixFDList *fd_list;
980 : : #endif
981 : : gboolean complete_names;
982 : : gboolean complete_paths;
983 : : gboolean complete_methods;
984 : : GVariantBuilder builder;
985 : : gboolean skip_dashes;
986 : : guint parm;
987 : : guint n;
988 : : GDBusCallFlags flags;
989 : :
990 : 2 : ret = FALSE;
991 : 2 : c = NULL;
992 : 2 : parameters = NULL;
993 : 2 : interface_name = NULL;
994 : 2 : method_name = NULL;
995 : 2 : result = NULL;
996 : 2 : in_signature_types = NULL;
997 : : #ifdef G_OS_UNIX
998 : 2 : fd_list = g_unix_fd_list_new ();
999 : : #endif
1000 : :
1001 : 2 : modify_argv0_for_command (argc, argv, "call");
1002 : :
1003 : 2 : o = command_option_context_new (NULL, _("Invoke a method on a remote object."),
1004 : : call_entries, request_completion);
1005 : 2 : g_option_context_add_group (o, connection_get_group ());
1006 : :
1007 : 2 : complete_names = FALSE;
1008 : 2 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1009 : : {
1010 : 0 : complete_names = TRUE;
1011 : 0 : remove_arg ((*argc) - 1, argc, argv);
1012 : : }
1013 : :
1014 : 2 : complete_paths = FALSE;
1015 : 2 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1016 : : {
1017 : 0 : complete_paths = TRUE;
1018 : 0 : remove_arg ((*argc) - 1, argc, argv);
1019 : : }
1020 : :
1021 : 2 : complete_methods = FALSE;
1022 : 2 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
1023 : : {
1024 : 0 : complete_methods = TRUE;
1025 : 0 : remove_arg ((*argc) - 1, argc, argv);
1026 : : }
1027 : :
1028 : 2 : if (!g_option_context_parse (o, argc, argv, NULL))
1029 : : {
1030 : 0 : if (!request_completion)
1031 : : {
1032 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
1033 : 0 : g_printerr ("%s", s);
1034 : 0 : g_free (s);
1035 : 0 : goto out;
1036 : : }
1037 : : }
1038 : :
1039 : 2 : error = NULL;
1040 : 2 : c = connection_get_dbus_connection (TRUE, &error);
1041 : 2 : if (c == NULL)
1042 : : {
1043 : 0 : if (request_completion)
1044 : : {
1045 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
1046 : : {
1047 : 0 : g_print ("unix:\n"
1048 : : "tcp:\n"
1049 : : "nonce-tcp:\n");
1050 : : }
1051 : : else
1052 : : {
1053 : 0 : g_print ("--system \n--session \n--address \n");
1054 : : }
1055 : : }
1056 : : else
1057 : : {
1058 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1059 : : }
1060 : 0 : g_error_free (error);
1061 : 0 : goto out;
1062 : : }
1063 : :
1064 : : /* validate and complete destination (bus name) */
1065 : 2 : if (complete_names)
1066 : : {
1067 : 0 : print_names (c, FALSE);
1068 : 0 : goto out;
1069 : : }
1070 : 2 : if (opt_call_dest == NULL)
1071 : : {
1072 : 0 : if (request_completion)
1073 : 0 : g_print ("--dest \n");
1074 : : else
1075 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1076 : 0 : goto out;
1077 : : }
1078 : 2 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1079 : : {
1080 : 0 : print_names (c, g_str_has_prefix (opt_call_dest, ":"));
1081 : 0 : goto out;
1082 : : }
1083 : :
1084 : 2 : if (!request_completion && !g_dbus_is_name (opt_call_dest))
1085 : : {
1086 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
1087 : 0 : goto out;
1088 : : }
1089 : :
1090 : : /* validate and complete object path */
1091 : 2 : if (complete_paths)
1092 : : {
1093 : 0 : print_paths (c, opt_call_dest, "/");
1094 : 0 : goto out;
1095 : : }
1096 : 2 : if (opt_call_object_path == NULL)
1097 : : {
1098 : 0 : if (request_completion)
1099 : 0 : g_print ("--object-path \n");
1100 : : else
1101 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1102 : 0 : goto out;
1103 : : }
1104 : 2 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1105 : : {
1106 : : gchar *p;
1107 : 0 : s = g_strdup (opt_call_object_path);
1108 : 0 : p = strrchr (s, '/');
1109 : 0 : if (p != NULL)
1110 : : {
1111 : 0 : if (p == s)
1112 : 0 : p++;
1113 : 0 : *p = '\0';
1114 : : }
1115 : 0 : print_paths (c, opt_call_dest, s);
1116 : 0 : g_free (s);
1117 : 0 : goto out;
1118 : : }
1119 : 2 : if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
1120 : : {
1121 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
1122 : 0 : goto out;
1123 : : }
1124 : :
1125 : : /* validate and complete method (interface + method name) */
1126 : 2 : if (complete_methods)
1127 : : {
1128 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1129 : 0 : goto out;
1130 : : }
1131 : 2 : if (opt_call_method == NULL)
1132 : : {
1133 : 0 : if (request_completion)
1134 : 0 : g_print ("--method \n");
1135 : : else
1136 : 0 : g_printerr (_("Error: Method name is not specified\n"));
1137 : 0 : goto out;
1138 : : }
1139 : 2 : if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
1140 : : {
1141 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1142 : 0 : goto out;
1143 : : }
1144 : 2 : s = strrchr (opt_call_method, '.');
1145 : 2 : if (!request_completion && s == NULL)
1146 : : {
1147 : 0 : g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
1148 : 0 : goto out;
1149 : : }
1150 : 2 : method_name = g_strdup (s + 1);
1151 : 2 : interface_name = g_strndup (opt_call_method, s - opt_call_method);
1152 : 4 : if (!request_completion &&
1153 : 4 : (!g_dbus_is_interface_name (interface_name) || !g_dbus_is_member_name (method_name)))
1154 : : {
1155 : 1 : g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
1156 : 1 : goto out;
1157 : : }
1158 : :
1159 : : /* All done with completion now */
1160 : 1 : if (request_completion)
1161 : 0 : goto out;
1162 : :
1163 : : /* Introspect, for easy conversion - it's not fatal if we can't do this */
1164 : 1 : in_signature_types = call_helper_get_method_in_signature (c,
1165 : : opt_call_dest,
1166 : : opt_call_object_path,
1167 : : interface_name,
1168 : : method_name,
1169 : : &error);
1170 : 1 : if (in_signature_types == NULL)
1171 : : {
1172 : : //g_printerr ("Error getting introspection data: %s\n", error->message);
1173 : 0 : g_error_free (error);
1174 : 0 : error = NULL;
1175 : : }
1176 : :
1177 : : /* Read parameters */
1178 : 1 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE_TUPLE);
1179 : 1 : skip_dashes = TRUE;
1180 : 1 : parm = 0;
1181 : 1 : for (n = 1; n < (guint) *argc; n++)
1182 : : {
1183 : : GVariant *value;
1184 : : GVariantType *type;
1185 : :
1186 : : /* Under certain conditions, g_option_context_parse returns the "--"
1187 : : itself (setting off unparsed arguments), too: */
1188 : 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
1189 : : {
1190 : 0 : skip_dashes = FALSE;
1191 : 0 : continue;
1192 : : }
1193 : :
1194 : 0 : type = NULL;
1195 : 0 : if (in_signature_types != NULL)
1196 : : {
1197 : 0 : if (parm >= in_signature_types->len)
1198 : : {
1199 : : /* Only warn for the first param */
1200 : 0 : if (parm == in_signature_types->len)
1201 : : {
1202 : 0 : g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
1203 : : in_signature_types->len);
1204 : : }
1205 : : }
1206 : : else
1207 : : {
1208 : 0 : type = in_signature_types->pdata[parm];
1209 : : }
1210 : : }
1211 : :
1212 : 0 : error = NULL;
1213 : 0 : value = g_variant_parse (type,
1214 : 0 : (*argv)[n],
1215 : : NULL,
1216 : : NULL,
1217 : : &error);
1218 : 0 : if (value == NULL)
1219 : : {
1220 : : gchar *context;
1221 : :
1222 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
1223 : 0 : g_error_free (error);
1224 : 0 : error = NULL;
1225 : 0 : value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
1226 : 0 : if (value == NULL)
1227 : : {
1228 : 0 : if (type != NULL)
1229 : : {
1230 : 0 : s = g_variant_type_dup_string (type);
1231 : 0 : g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
1232 : : parm + 1,
1233 : : s,
1234 : : context);
1235 : 0 : g_free (s);
1236 : : }
1237 : : else
1238 : : {
1239 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
1240 : : parm + 1,
1241 : : context);
1242 : : }
1243 : 0 : g_error_free (error);
1244 : 0 : g_variant_builder_clear (&builder);
1245 : 0 : g_free (context);
1246 : 0 : goto out;
1247 : : }
1248 : 0 : g_free (context);
1249 : : }
1250 : : #ifdef G_OS_UNIX
1251 : 0 : if (!walk_variant_for_handle (&builder, fd_list, value))
1252 : : {
1253 : 0 : g_clear_pointer (&value, g_variant_unref);
1254 : 0 : g_variant_builder_clear (&builder);
1255 : 0 : goto out;
1256 : : }
1257 : : #else
1258 : : g_variant_builder_add_value (&builder, value);
1259 : : #endif
1260 : 0 : g_clear_pointer (&value, g_variant_unref);
1261 : 0 : ++parm;
1262 : : }
1263 : 1 : parameters = g_variant_builder_end (&builder);
1264 : :
1265 : 1 : if (parameters != NULL)
1266 : 1 : parameters = g_variant_ref_sink (parameters);
1267 : :
1268 : 1 : flags = G_DBUS_CALL_FLAGS_NONE;
1269 : 1 : if (opt_call_interactive)
1270 : 0 : flags |= G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
1271 : :
1272 : : #ifdef G_OS_UNIX
1273 : 1 : result = g_dbus_connection_call_with_unix_fd_list_sync (c,
1274 : : opt_call_dest,
1275 : : opt_call_object_path,
1276 : : interface_name,
1277 : : method_name,
1278 : : parameters,
1279 : : NULL,
1280 : : flags,
1281 : 1 : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1282 : : fd_list,
1283 : : NULL,
1284 : : NULL,
1285 : : &error);
1286 : : #else
1287 : : result = g_dbus_connection_call_sync (c,
1288 : : opt_call_dest,
1289 : : opt_call_object_path,
1290 : : interface_name,
1291 : : method_name,
1292 : : parameters,
1293 : : NULL,
1294 : : flags,
1295 : : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1296 : : NULL,
1297 : : &error);
1298 : : #endif
1299 : 1 : if (result == NULL)
1300 : : {
1301 : 0 : g_printerr (_("Error: %s\n"), error->message);
1302 : :
1303 : 0 : if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
1304 : : {
1305 : 0 : if (in_signature_types->len > 0)
1306 : : {
1307 : : GString *str;
1308 : 0 : str = g_string_new (NULL);
1309 : :
1310 : 0 : for (n = 0; n < in_signature_types->len; n++)
1311 : : {
1312 : 0 : GVariantType *type = in_signature_types->pdata[n];
1313 : 0 : g_string_append_len (str,
1314 : : g_variant_type_peek_string (type),
1315 : : g_variant_type_get_string_length (type));
1316 : : }
1317 : :
1318 : 0 : g_printerr ("(According to introspection data, you need to pass '%s')\n", str->str);
1319 : 0 : g_string_free (str, TRUE);
1320 : : }
1321 : : else
1322 : 0 : g_printerr ("(According to introspection data, you need to pass no arguments)\n");
1323 : : }
1324 : :
1325 : 0 : g_error_free (error);
1326 : 0 : goto out;
1327 : : }
1328 : :
1329 : 1 : s = g_variant_print (result, TRUE);
1330 : 1 : g_print ("%s\n", s);
1331 : 1 : g_free (s);
1332 : :
1333 : 1 : ret = TRUE;
1334 : :
1335 : 2 : out:
1336 : 2 : if (in_signature_types != NULL)
1337 : 1 : g_ptr_array_unref (in_signature_types);
1338 : 2 : if (result != NULL)
1339 : 1 : g_variant_unref (result);
1340 : 2 : if (c != NULL)
1341 : 2 : g_object_unref (c);
1342 : 2 : if (parameters != NULL)
1343 : 1 : g_variant_unref (parameters);
1344 : 2 : g_free (interface_name);
1345 : 2 : g_free (method_name);
1346 : 2 : g_option_context_free (o);
1347 : : #ifdef G_OS_UNIX
1348 : 2 : g_clear_object (&fd_list);
1349 : : #endif
1350 : 2 : return ret;
1351 : : }
1352 : :
1353 : : /* ---------------------------------------------------------------------------------------------------- */
1354 : :
1355 : : static gchar *opt_introspect_dest = NULL;
1356 : : static gchar *opt_introspect_object_path = NULL;
1357 : : static gboolean opt_introspect_xml = FALSE;
1358 : : static gboolean opt_introspect_recurse = FALSE;
1359 : : static gboolean opt_introspect_only_properties = FALSE;
1360 : :
1361 : : /* Introspect colors */
1362 : : #define RESET_COLOR (use_colors? "\033[0m": "")
1363 : : #define INTROSPECT_TITLE_COLOR (use_colors? UNDERLINE: "")
1364 : : #define INTROSPECT_NODE_COLOR (use_colors? RESET_COLOR: "")
1365 : : #define INTROSPECT_INTERFACE_COLOR (use_colors? YELLOW: "")
1366 : : #define INTROSPECT_METHOD_COLOR (use_colors? BLUE: "")
1367 : : #define INTROSPECT_SIGNAL_COLOR (use_colors? BLUE: "")
1368 : : #define INTROSPECT_PROPERTY_COLOR (use_colors? MAGENTA: "")
1369 : : #define INTROSPECT_INOUT_COLOR (use_colors? RESET_COLOR: "")
1370 : : #define INTROSPECT_TYPE_COLOR (use_colors? GREEN: "")
1371 : : #define INTROSPECT_ANNOTATION_COLOR (use_colors? RESET_COLOR: "")
1372 : :
1373 : : static void
1374 : 0 : dump_annotation (const GDBusAnnotationInfo *o,
1375 : : guint indent,
1376 : : gboolean ignore_indent,
1377 : : gboolean use_colors)
1378 : : {
1379 : : guint n;
1380 : 0 : g_print ("%*s%s@%s(\"%s\")%s\n",
1381 : : ignore_indent ? 0 : indent, "",
1382 : 0 : INTROSPECT_ANNOTATION_COLOR, o->key, o->value, RESET_COLOR);
1383 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1384 : 0 : dump_annotation (o->annotations[n], indent + 2, FALSE, use_colors);
1385 : 0 : }
1386 : :
1387 : : static void
1388 : 0 : dump_arg (const GDBusArgInfo *o,
1389 : : guint indent,
1390 : : const gchar *direction,
1391 : : gboolean ignore_indent,
1392 : : gboolean include_newline,
1393 : : gboolean use_colors)
1394 : : {
1395 : : guint n;
1396 : :
1397 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1398 : : {
1399 : 0 : dump_annotation (o->annotations[n], indent, ignore_indent, use_colors);
1400 : 0 : ignore_indent = FALSE;
1401 : : }
1402 : :
1403 : 0 : g_print ("%*s%s%s%s%s%s%s %s%s",
1404 : : ignore_indent ? 0 : indent, "",
1405 : : INTROSPECT_INOUT_COLOR, direction, RESET_COLOR,
1406 : 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1407 : 0 : o->name,
1408 : : include_newline ? ",\n" : "");
1409 : 0 : }
1410 : :
1411 : : static guint
1412 : 0 : count_args (GDBusArgInfo **args)
1413 : : {
1414 : : guint n;
1415 : 0 : n = 0;
1416 : 0 : if (args == NULL)
1417 : 0 : goto out;
1418 : 0 : while (args[n] != NULL)
1419 : 0 : n++;
1420 : 0 : out:
1421 : 0 : return n;
1422 : : }
1423 : :
1424 : : static void
1425 : 0 : dump_method (const GDBusMethodInfo *o,
1426 : : guint indent,
1427 : : gboolean use_colors)
1428 : : {
1429 : : guint n;
1430 : : guint m;
1431 : : size_t name_len;
1432 : : guint total_num_args;
1433 : :
1434 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1435 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1436 : :
1437 : 0 : g_print ("%*s%s%s%s(",
1438 : : indent, "",
1439 : 0 : INTROSPECT_METHOD_COLOR, o->name, RESET_COLOR);
1440 : 0 : name_len = strlen (o->name);
1441 : 0 : total_num_args = count_args (o->in_args) + count_args (o->out_args);
1442 : 0 : for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1443 : : {
1444 : 0 : gboolean ignore_indent = (m == 0);
1445 : 0 : gboolean include_newline = (m != total_num_args - 1);
1446 : :
1447 : 0 : dump_arg (o->in_args[n],
1448 : 0 : indent + name_len + 1,
1449 : : "in ",
1450 : : ignore_indent,
1451 : : include_newline,
1452 : : use_colors);
1453 : : }
1454 : 0 : for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1455 : : {
1456 : 0 : gboolean ignore_indent = (m == 0);
1457 : 0 : gboolean include_newline = (m != total_num_args - 1);
1458 : 0 : dump_arg (o->out_args[n],
1459 : 0 : indent + name_len + 1,
1460 : : "out ",
1461 : : ignore_indent,
1462 : : include_newline,
1463 : : use_colors);
1464 : : }
1465 : 0 : g_print (");\n");
1466 : 0 : }
1467 : :
1468 : : static void
1469 : 0 : dump_signal (const GDBusSignalInfo *o,
1470 : : guint indent,
1471 : : gboolean use_colors)
1472 : : {
1473 : : guint n;
1474 : : guint name_len;
1475 : : guint total_num_args;
1476 : :
1477 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1478 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1479 : :
1480 : 0 : g_print ("%*s%s%s%s(",
1481 : : indent, "",
1482 : 0 : INTROSPECT_SIGNAL_COLOR, o->name, RESET_COLOR);
1483 : 0 : name_len = strlen (o->name);
1484 : 0 : total_num_args = count_args (o->args);
1485 : 0 : for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1486 : : {
1487 : 0 : gboolean ignore_indent = (n == 0);
1488 : 0 : gboolean include_newline = (n != total_num_args - 1);
1489 : 0 : dump_arg (o->args[n],
1490 : 0 : indent + name_len + 1,
1491 : : "",
1492 : : ignore_indent,
1493 : : include_newline,
1494 : : use_colors);
1495 : : }
1496 : 0 : g_print (");\n");
1497 : 0 : }
1498 : :
1499 : : static void
1500 : 0 : dump_property (const GDBusPropertyInfo *o,
1501 : : guint indent,
1502 : : gboolean use_colors,
1503 : : GVariant *value)
1504 : : {
1505 : : const gchar *access;
1506 : : guint n;
1507 : :
1508 : 0 : if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1509 : 0 : access = "readonly";
1510 : 0 : else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1511 : 0 : access = "writeonly";
1512 : 0 : else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1513 : 0 : access = "readwrite";
1514 : : else
1515 : : g_assert_not_reached ();
1516 : :
1517 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1518 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1519 : :
1520 : 0 : if (value != NULL)
1521 : : {
1522 : 0 : gchar *s = g_variant_print (value, FALSE);
1523 : 0 : g_print ("%*s%s %s%s%s %s%s%s = %s;\n", indent, "", access,
1524 : 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1525 : 0 : INTROSPECT_PROPERTY_COLOR, o->name, RESET_COLOR,
1526 : : s);
1527 : 0 : g_free (s);
1528 : : }
1529 : : else
1530 : : {
1531 : 0 : g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1532 : : }
1533 : 0 : }
1534 : :
1535 : : static void
1536 : 0 : dump_interface (GDBusConnection *c,
1537 : : const gchar *name,
1538 : : const GDBusInterfaceInfo *o,
1539 : : guint indent,
1540 : : gboolean use_colors,
1541 : : const gchar *object_path)
1542 : : {
1543 : : guint n;
1544 : : GHashTable *properties;
1545 : :
1546 : 0 : properties = g_hash_table_new_full (g_str_hash,
1547 : : g_str_equal,
1548 : : g_free,
1549 : : (GDestroyNotify) g_variant_unref);
1550 : :
1551 : : /* Try to get properties */
1552 : 0 : if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1553 : : {
1554 : : GVariant *result;
1555 : 0 : result = g_dbus_connection_call_sync (c,
1556 : : name,
1557 : : object_path,
1558 : : DBUS_INTERFACE_PROPERTIES,
1559 : : "GetAll",
1560 : 0 : g_variant_new ("(s)", o->name),
1561 : : NULL,
1562 : : G_DBUS_CALL_FLAGS_NONE,
1563 : : 3000,
1564 : : NULL,
1565 : : NULL);
1566 : 0 : if (result != NULL)
1567 : : {
1568 : 0 : if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1569 : : {
1570 : : GVariantIter *iter;
1571 : : GVariant *item;
1572 : 0 : g_variant_get (result,
1573 : : "(a{sv})",
1574 : : &iter);
1575 : 0 : while ((item = g_variant_iter_next_value (iter)))
1576 : : {
1577 : : gchar *key;
1578 : : GVariant *value;
1579 : 0 : g_variant_get (item,
1580 : : "{sv}",
1581 : : &key,
1582 : : &value);
1583 : :
1584 : 0 : g_hash_table_insert (properties, key, g_variant_ref (value));
1585 : : }
1586 : : }
1587 : 0 : g_variant_unref (result);
1588 : : }
1589 : : else
1590 : : {
1591 : 0 : for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1592 : : {
1593 : 0 : result = g_dbus_connection_call_sync (c,
1594 : : name,
1595 : : object_path,
1596 : : DBUS_INTERFACE_PROPERTIES,
1597 : : "Get",
1598 : 0 : g_variant_new ("(ss)", o->name, o->properties[n]->name),
1599 : : G_VARIANT_TYPE ("(v)"),
1600 : : G_DBUS_CALL_FLAGS_NONE,
1601 : : 3000,
1602 : : NULL,
1603 : : NULL);
1604 : 0 : if (result != NULL)
1605 : : {
1606 : : GVariant *property_value;
1607 : 0 : g_variant_get (result,
1608 : : "(v)",
1609 : : &property_value);
1610 : 0 : g_hash_table_insert (properties,
1611 : 0 : g_strdup (o->properties[n]->name),
1612 : 0 : g_variant_ref (property_value));
1613 : 0 : g_variant_unref (result);
1614 : : }
1615 : : }
1616 : : }
1617 : : }
1618 : :
1619 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1620 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1621 : :
1622 : 0 : g_print ("%*s%sinterface %s%s {\n",
1623 : : indent, "",
1624 : 0 : INTROSPECT_INTERFACE_COLOR, o->name, RESET_COLOR);
1625 : 0 : if (o->methods != NULL && !opt_introspect_only_properties)
1626 : : {
1627 : 0 : g_print ("%*s %smethods%s:\n",
1628 : : indent, "",
1629 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1630 : 0 : for (n = 0; o->methods[n] != NULL; n++)
1631 : 0 : dump_method (o->methods[n], indent + 4, use_colors);
1632 : : }
1633 : 0 : if (o->signals != NULL && !opt_introspect_only_properties)
1634 : : {
1635 : 0 : g_print ("%*s %ssignals%s:\n",
1636 : : indent, "",
1637 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1638 : 0 : for (n = 0; o->signals[n] != NULL; n++)
1639 : 0 : dump_signal (o->signals[n], indent + 4, use_colors);
1640 : : }
1641 : 0 : if (o->properties != NULL)
1642 : : {
1643 : 0 : g_print ("%*s %sproperties%s:\n",
1644 : : indent, "",
1645 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1646 : 0 : for (n = 0; o->properties[n] != NULL; n++)
1647 : : {
1648 : 0 : dump_property (o->properties[n],
1649 : : indent + 4,
1650 : : use_colors,
1651 : 0 : g_hash_table_lookup (properties, (o->properties[n])->name));
1652 : : }
1653 : : }
1654 : 0 : g_print ("%*s};\n",
1655 : : indent, "");
1656 : :
1657 : 0 : g_hash_table_unref (properties);
1658 : 0 : }
1659 : :
1660 : : static gboolean
1661 : : introspect_do (GDBusConnection *c,
1662 : : const gchar *object_path,
1663 : : guint indent,
1664 : : gboolean use_colors);
1665 : :
1666 : : static void
1667 : 0 : dump_node (GDBusConnection *c,
1668 : : const gchar *name,
1669 : : const GDBusNodeInfo *o,
1670 : : guint indent,
1671 : : gboolean use_colors,
1672 : : const gchar *object_path,
1673 : : gboolean recurse)
1674 : : {
1675 : : guint n;
1676 : : const gchar *object_path_to_print;
1677 : :
1678 : 0 : object_path_to_print = object_path;
1679 : 0 : if (o->path != NULL)
1680 : 0 : object_path_to_print = o->path;
1681 : :
1682 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1683 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1684 : :
1685 : 0 : g_print ("%*s%snode %s%s",
1686 : : indent, "",
1687 : : INTROSPECT_NODE_COLOR,
1688 : : object_path_to_print != NULL ? object_path_to_print : "(not set)",
1689 : : RESET_COLOR);
1690 : 0 : if (o->interfaces != NULL || o->nodes != NULL)
1691 : : {
1692 : 0 : g_print (" {\n");
1693 : 0 : for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1694 : : {
1695 : 0 : if (opt_introspect_only_properties)
1696 : : {
1697 : 0 : if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1698 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1699 : : }
1700 : : else
1701 : : {
1702 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1703 : : }
1704 : : }
1705 : 0 : for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1706 : : {
1707 : 0 : if (recurse)
1708 : : {
1709 : : gchar *child_path;
1710 : 0 : if (g_variant_is_object_path (o->nodes[n]->path))
1711 : : {
1712 : 0 : child_path = g_strdup (o->nodes[n]->path);
1713 : : /* avoid infinite loops */
1714 : 0 : if (g_str_has_prefix (child_path, object_path))
1715 : : {
1716 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1717 : : }
1718 : : else
1719 : : {
1720 : 0 : g_print ("Skipping path %s that is not enclosed by parent %s\n",
1721 : : child_path, object_path);
1722 : : }
1723 : : }
1724 : : else
1725 : : {
1726 : 0 : if (g_strcmp0 (object_path, "/") == 0)
1727 : 0 : child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1728 : : else
1729 : 0 : child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1730 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1731 : : }
1732 : 0 : g_free (child_path);
1733 : : }
1734 : : else
1735 : : {
1736 : 0 : dump_node (NULL, NULL, o->nodes[n], indent + 2, use_colors, NULL, recurse);
1737 : : }
1738 : : }
1739 : 0 : g_print ("%*s};\n",
1740 : : indent, "");
1741 : : }
1742 : : else
1743 : : {
1744 : 0 : g_print ("\n");
1745 : : }
1746 : 0 : }
1747 : :
1748 : : static const GOptionEntry introspect_entries[] =
1749 : : {
1750 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1751 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1752 : : { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1753 : : { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1754 : : { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1755 : : G_OPTION_ENTRY_NULL
1756 : : };
1757 : :
1758 : : static gboolean
1759 : 0 : introspect_do (GDBusConnection *c,
1760 : : const gchar *object_path,
1761 : : guint indent,
1762 : : gboolean use_colors)
1763 : : {
1764 : : GError *error;
1765 : : GVariant *result;
1766 : : GDBusNodeInfo *node;
1767 : : gboolean ret;
1768 : : const gchar *xml_data;
1769 : :
1770 : 0 : ret = FALSE;
1771 : 0 : node = NULL;
1772 : 0 : result = NULL;
1773 : :
1774 : 0 : error = NULL;
1775 : 0 : result = g_dbus_connection_call_sync (c,
1776 : : opt_introspect_dest,
1777 : : object_path,
1778 : : DBUS_INTERFACE_INTROSPECTABLE,
1779 : : "Introspect",
1780 : : NULL,
1781 : : G_VARIANT_TYPE ("(s)"),
1782 : : G_DBUS_CALL_FLAGS_NONE,
1783 : : 3000, /* 3 sec */
1784 : : NULL,
1785 : : &error);
1786 : 0 : if (result == NULL)
1787 : : {
1788 : 0 : g_printerr (_("Error: %s\n"), error->message);
1789 : 0 : g_error_free (error);
1790 : 0 : goto out;
1791 : : }
1792 : 0 : g_variant_get (result, "(&s)", &xml_data);
1793 : :
1794 : 0 : if (opt_introspect_xml)
1795 : : {
1796 : 0 : g_print ("%s", xml_data);
1797 : : }
1798 : : else
1799 : : {
1800 : 0 : error = NULL;
1801 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
1802 : 0 : if (node == NULL)
1803 : : {
1804 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1805 : 0 : g_error_free (error);
1806 : 0 : goto out;
1807 : : }
1808 : :
1809 : 0 : dump_node (c, opt_introspect_dest, node, indent, use_colors, object_path, opt_introspect_recurse);
1810 : : }
1811 : :
1812 : 0 : ret = TRUE;
1813 : :
1814 : 0 : out:
1815 : 0 : if (node != NULL)
1816 : 0 : g_dbus_node_info_unref (node);
1817 : 0 : if (result != NULL)
1818 : 0 : g_variant_unref (result);
1819 : 0 : return ret;
1820 : : }
1821 : :
1822 : : static gboolean
1823 : 0 : handle_introspect (gint *argc,
1824 : : gchar **argv[],
1825 : : gboolean request_completion,
1826 : : const gchar *completion_cur,
1827 : : const gchar *completion_prev)
1828 : : {
1829 : : gint ret;
1830 : : GOptionContext *o;
1831 : : gchar *s;
1832 : : GError *error;
1833 : : GDBusConnection *c;
1834 : : gboolean complete_names;
1835 : : gboolean complete_paths;
1836 : : gboolean color_support;
1837 : :
1838 : 0 : ret = FALSE;
1839 : 0 : c = NULL;
1840 : :
1841 : 0 : modify_argv0_for_command (argc, argv, "introspect");
1842 : :
1843 : 0 : o = command_option_context_new (NULL, _("Introspect a remote object."),
1844 : : introspect_entries, request_completion);
1845 : 0 : g_option_context_add_group (o, connection_get_group ());
1846 : :
1847 : 0 : complete_names = FALSE;
1848 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1849 : : {
1850 : 0 : complete_names = TRUE;
1851 : 0 : remove_arg ((*argc) - 1, argc, argv);
1852 : : }
1853 : :
1854 : 0 : complete_paths = FALSE;
1855 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1856 : : {
1857 : 0 : complete_paths = TRUE;
1858 : 0 : remove_arg ((*argc) - 1, argc, argv);
1859 : : }
1860 : :
1861 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
1862 : : {
1863 : 0 : if (!request_completion)
1864 : : {
1865 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
1866 : 0 : g_printerr ("%s", s);
1867 : 0 : g_free (s);
1868 : 0 : goto out;
1869 : : }
1870 : : }
1871 : :
1872 : 0 : error = NULL;
1873 : 0 : c = connection_get_dbus_connection (TRUE, &error);
1874 : 0 : if (c == NULL)
1875 : : {
1876 : 0 : if (request_completion)
1877 : : {
1878 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
1879 : : {
1880 : 0 : g_print ("unix:\n"
1881 : : "tcp:\n"
1882 : : "nonce-tcp:\n");
1883 : : }
1884 : : else
1885 : : {
1886 : 0 : g_print ("--system \n--session \n--address \n");
1887 : : }
1888 : : }
1889 : : else
1890 : : {
1891 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1892 : : }
1893 : 0 : g_error_free (error);
1894 : 0 : goto out;
1895 : : }
1896 : :
1897 : 0 : if (complete_names)
1898 : : {
1899 : 0 : print_names (c, FALSE);
1900 : 0 : goto out;
1901 : : }
1902 : : /* this only makes sense on message bus connections */
1903 : 0 : if (opt_introspect_dest == NULL)
1904 : : {
1905 : 0 : if (request_completion)
1906 : 0 : g_print ("--dest \n");
1907 : : else
1908 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1909 : 0 : goto out;
1910 : : }
1911 : 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1912 : : {
1913 : 0 : print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1914 : 0 : goto out;
1915 : : }
1916 : :
1917 : 0 : if (complete_paths)
1918 : : {
1919 : 0 : print_paths (c, opt_introspect_dest, "/");
1920 : 0 : goto out;
1921 : : }
1922 : :
1923 : 0 : if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
1924 : : {
1925 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
1926 : 0 : goto out;
1927 : : }
1928 : :
1929 : 0 : if (opt_introspect_object_path == NULL)
1930 : : {
1931 : 0 : if (request_completion)
1932 : 0 : g_print ("--object-path \n");
1933 : : else
1934 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1935 : 0 : goto out;
1936 : : }
1937 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1938 : : {
1939 : : gchar *p;
1940 : 0 : s = g_strdup (opt_introspect_object_path);
1941 : 0 : p = strrchr (s, '/');
1942 : 0 : if (p != NULL)
1943 : : {
1944 : 0 : if (p == s)
1945 : 0 : p++;
1946 : 0 : *p = '\0';
1947 : : }
1948 : 0 : print_paths (c, opt_introspect_dest, s);
1949 : 0 : g_free (s);
1950 : 0 : goto out;
1951 : : }
1952 : 0 : if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1953 : : {
1954 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1955 : 0 : goto out;
1956 : : }
1957 : :
1958 : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1959 : : {
1960 : 0 : g_print ("--recurse \n");
1961 : : }
1962 : :
1963 : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1964 : : {
1965 : 0 : g_print ("--only-properties \n");
1966 : : }
1967 : :
1968 : : /* All done with completion now */
1969 : 0 : if (request_completion)
1970 : 0 : goto out;
1971 : :
1972 : : /* Before we start printing the actual info, check if we can do colors*/
1973 : 0 : color_support = g_log_writer_supports_color (fileno (stdout));
1974 : :
1975 : 0 : if (!introspect_do (c, opt_introspect_object_path, 0, color_support))
1976 : 0 : goto out;
1977 : :
1978 : 0 : ret = TRUE;
1979 : :
1980 : 0 : out:
1981 : 0 : if (c != NULL)
1982 : 0 : g_object_unref (c);
1983 : 0 : g_option_context_free (o);
1984 : 0 : return ret;
1985 : : }
1986 : :
1987 : : /* ---------------------------------------------------------------------------------------------------- */
1988 : :
1989 : : static gchar *opt_monitor_dest = NULL;
1990 : : static gchar *opt_monitor_object_path = NULL;
1991 : :
1992 : : static guint monitor_filter_id = 0;
1993 : :
1994 : : static void
1995 : 0 : monitor_signal_cb (GDBusConnection *connection,
1996 : : const gchar *sender_name,
1997 : : const gchar *object_path,
1998 : : const gchar *interface_name,
1999 : : const gchar *signal_name,
2000 : : GVariant *parameters,
2001 : : gpointer user_data)
2002 : : {
2003 : : gchar *s;
2004 : 0 : s = g_variant_print (parameters, TRUE);
2005 : 0 : g_print ("%s: %s.%s %s\n",
2006 : : object_path,
2007 : : interface_name,
2008 : : signal_name,
2009 : : s);
2010 : 0 : g_free (s);
2011 : 0 : }
2012 : :
2013 : : static void
2014 : 0 : monitor_on_name_appeared (GDBusConnection *connection,
2015 : : const gchar *name,
2016 : : const gchar *name_owner,
2017 : : gpointer user_data)
2018 : : {
2019 : 0 : g_print ("The name %s is owned by %s\n", name, name_owner);
2020 : 0 : g_assert (monitor_filter_id == 0);
2021 : 0 : monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
2022 : : name_owner,
2023 : : NULL, /* any interface */
2024 : : NULL, /* any member */
2025 : : opt_monitor_object_path,
2026 : : NULL, /* arg0 */
2027 : : G_DBUS_SIGNAL_FLAGS_NONE,
2028 : : monitor_signal_cb,
2029 : : NULL, /* user_data */
2030 : : NULL); /* user_data destroy notify */
2031 : 0 : }
2032 : :
2033 : : static void
2034 : 0 : monitor_on_name_vanished (GDBusConnection *connection,
2035 : : const gchar *name,
2036 : : gpointer user_data)
2037 : : {
2038 : 0 : g_print ("The name %s does not have an owner\n", name);
2039 : :
2040 : 0 : if (monitor_filter_id != 0)
2041 : 0 : g_dbus_connection_signal_unsubscribe (connection, g_steal_handle_id (&monitor_filter_id));
2042 : 0 : }
2043 : :
2044 : : static const GOptionEntry monitor_entries[] =
2045 : : {
2046 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
2047 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
2048 : : G_OPTION_ENTRY_NULL
2049 : : };
2050 : :
2051 : : static gboolean
2052 : 0 : handle_monitor (gint *argc,
2053 : : gchar **argv[],
2054 : : gboolean request_completion,
2055 : : const gchar *completion_cur,
2056 : : const gchar *completion_prev)
2057 : : {
2058 : : gint ret;
2059 : : GOptionContext *o;
2060 : : gchar *s;
2061 : : GError *error;
2062 : : GDBusConnection *c;
2063 : : gboolean complete_names;
2064 : : gboolean complete_paths;
2065 : : GMainLoop *loop;
2066 : :
2067 : 0 : ret = FALSE;
2068 : 0 : c = NULL;
2069 : :
2070 : 0 : modify_argv0_for_command (argc, argv, "monitor");
2071 : :
2072 : 0 : o = command_option_context_new (NULL, _("Monitor a remote object."),
2073 : : monitor_entries, request_completion);
2074 : 0 : g_option_context_add_group (o, connection_get_group ());
2075 : :
2076 : 0 : complete_names = FALSE;
2077 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
2078 : : {
2079 : 0 : complete_names = TRUE;
2080 : 0 : remove_arg ((*argc) - 1, argc, argv);
2081 : : }
2082 : :
2083 : 0 : complete_paths = FALSE;
2084 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
2085 : : {
2086 : 0 : complete_paths = TRUE;
2087 : 0 : remove_arg ((*argc) - 1, argc, argv);
2088 : : }
2089 : :
2090 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2091 : : {
2092 : 0 : if (!request_completion)
2093 : : {
2094 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2095 : 0 : g_printerr ("%s", s);
2096 : 0 : g_free (s);
2097 : 0 : goto out;
2098 : : }
2099 : : }
2100 : :
2101 : 0 : error = NULL;
2102 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2103 : 0 : if (c == NULL)
2104 : : {
2105 : 0 : if (request_completion)
2106 : : {
2107 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2108 : : {
2109 : 0 : g_print ("unix:\n"
2110 : : "tcp:\n"
2111 : : "nonce-tcp:\n");
2112 : : }
2113 : : else
2114 : : {
2115 : 0 : g_print ("--system \n--session \n--address \n");
2116 : : }
2117 : : }
2118 : : else
2119 : : {
2120 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2121 : : }
2122 : 0 : g_error_free (error);
2123 : 0 : goto out;
2124 : : }
2125 : :
2126 : : /* Monitoring doesn’t make sense on a non-message-bus connection. */
2127 : 0 : if (g_dbus_connection_get_unique_name (c) == NULL)
2128 : : {
2129 : 0 : if (!request_completion)
2130 : 0 : g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
2131 : 0 : goto out;
2132 : : }
2133 : :
2134 : 0 : if (complete_names)
2135 : : {
2136 : 0 : print_names (c, FALSE);
2137 : 0 : goto out;
2138 : : }
2139 : : /* this only makes sense on message bus connections */
2140 : 0 : if (opt_monitor_dest == NULL)
2141 : : {
2142 : 0 : if (request_completion)
2143 : 0 : g_print ("--dest \n");
2144 : : else
2145 : 0 : g_printerr (_("Error: Destination is not specified\n"));
2146 : 0 : goto out;
2147 : : }
2148 : 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
2149 : : {
2150 : 0 : print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
2151 : 0 : goto out;
2152 : : }
2153 : :
2154 : 0 : if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
2155 : : {
2156 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
2157 : 0 : goto out;
2158 : : }
2159 : :
2160 : 0 : if (complete_paths)
2161 : : {
2162 : 0 : print_paths (c, opt_monitor_dest, "/");
2163 : 0 : goto out;
2164 : : }
2165 : 0 : if (opt_monitor_object_path == NULL)
2166 : : {
2167 : 0 : if (request_completion)
2168 : : {
2169 : 0 : g_print ("--object-path \n");
2170 : 0 : goto out;
2171 : : }
2172 : : /* it's fine to not have an object path */
2173 : : }
2174 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
2175 : : {
2176 : : gchar *p;
2177 : 0 : s = g_strdup (opt_monitor_object_path);
2178 : 0 : p = strrchr (s, '/');
2179 : 0 : if (p != NULL)
2180 : : {
2181 : 0 : if (p == s)
2182 : 0 : p++;
2183 : 0 : *p = '\0';
2184 : : }
2185 : 0 : print_paths (c, opt_monitor_dest, s);
2186 : 0 : g_free (s);
2187 : 0 : goto out;
2188 : : }
2189 : 0 : if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
2190 : : {
2191 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
2192 : 0 : goto out;
2193 : : }
2194 : :
2195 : : /* All done with completion now */
2196 : 0 : if (request_completion)
2197 : 0 : goto out;
2198 : :
2199 : 0 : if (opt_monitor_object_path != NULL)
2200 : 0 : g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
2201 : : else
2202 : 0 : g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
2203 : :
2204 : 0 : loop = g_main_loop_new (NULL, FALSE);
2205 : 0 : g_bus_watch_name_on_connection (c,
2206 : : opt_monitor_dest,
2207 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2208 : : monitor_on_name_appeared,
2209 : : monitor_on_name_vanished,
2210 : : NULL,
2211 : : NULL);
2212 : :
2213 : 0 : g_main_loop_run (loop);
2214 : 0 : g_main_loop_unref (loop);
2215 : :
2216 : 0 : ret = TRUE;
2217 : :
2218 : 0 : out:
2219 : 0 : if (c != NULL)
2220 : 0 : g_object_unref (c);
2221 : 0 : g_option_context_free (o);
2222 : 0 : return ret;
2223 : : }
2224 : :
2225 : : /* ---------------------------------------------------------------------------------------------------- */
2226 : :
2227 : : static gboolean opt_wait_activate_set = FALSE;
2228 : : static gchar *opt_wait_activate_name = NULL;
2229 : : static gint64 opt_wait_timeout_secs = 0; /* no timeout */
2230 : :
2231 : : typedef enum {
2232 : : WAIT_STATE_RUNNING, /* waiting to see the service */
2233 : : WAIT_STATE_SUCCESS, /* seen it successfully */
2234 : : WAIT_STATE_TIMEOUT, /* timed out before seeing it */
2235 : : } WaitState;
2236 : :
2237 : : static gboolean
2238 : 0 : opt_wait_activate_cb (const gchar *option_name,
2239 : : const gchar *value,
2240 : : gpointer data,
2241 : : GError **error)
2242 : : {
2243 : : /* @value may be NULL */
2244 : 0 : opt_wait_activate_set = TRUE;
2245 : 0 : opt_wait_activate_name = g_strdup (value);
2246 : :
2247 : 0 : return TRUE;
2248 : : }
2249 : :
2250 : : static const GOptionEntry wait_entries[] =
2251 : : {
2252 : : { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
2253 : : opt_wait_activate_cb,
2254 : : N_("Service to activate before waiting for the other one (well-known name)"),
2255 : : "[NAME]" },
2256 : : { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout_secs,
2257 : : N_("Timeout to wait for before exiting with an error (seconds); 0 for "
2258 : : "no timeout (default)"), "SECS" },
2259 : : G_OPTION_ENTRY_NULL
2260 : : };
2261 : :
2262 : : static void
2263 : 0 : wait_name_appeared_cb (GDBusConnection *connection,
2264 : : const gchar *name,
2265 : : const gchar *name_owner,
2266 : : gpointer user_data)
2267 : : {
2268 : 0 : WaitState *wait_state = user_data;
2269 : :
2270 : 0 : *wait_state = WAIT_STATE_SUCCESS;
2271 : 0 : }
2272 : :
2273 : : static gboolean
2274 : 0 : wait_timeout_cb (gpointer user_data)
2275 : : {
2276 : 0 : WaitState *wait_state = user_data;
2277 : :
2278 : 0 : *wait_state = WAIT_STATE_TIMEOUT;
2279 : :
2280 : : /* Removed in handle_wait(). */
2281 : 0 : return G_SOURCE_CONTINUE;
2282 : : }
2283 : :
2284 : : static gboolean
2285 : 0 : handle_wait (gint *argc,
2286 : : gchar **argv[],
2287 : : gboolean request_completion,
2288 : : const gchar *completion_cur,
2289 : : const gchar *completion_prev)
2290 : : {
2291 : : gint ret;
2292 : : GOptionContext *o;
2293 : : gchar *s;
2294 : : GError *error;
2295 : : GDBusConnection *c;
2296 : 0 : guint watch_id, timer_id = 0, activate_watch_id;
2297 : : const gchar *activate_service, *wait_service;
2298 : 0 : WaitState wait_state = WAIT_STATE_RUNNING;
2299 : :
2300 : 0 : ret = FALSE;
2301 : 0 : c = NULL;
2302 : :
2303 : 0 : modify_argv0_for_command (argc, argv, "wait");
2304 : :
2305 : 0 : o = command_option_context_new (_("[OPTION…] BUS-NAME"),
2306 : 0 : _("Wait for a bus name to appear."),
2307 : : wait_entries, request_completion);
2308 : 0 : g_option_context_add_group (o, connection_get_group ());
2309 : :
2310 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2311 : : {
2312 : 0 : if (!request_completion)
2313 : : {
2314 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2315 : 0 : g_printerr ("%s", s);
2316 : 0 : g_free (s);
2317 : 0 : goto out;
2318 : : }
2319 : : }
2320 : :
2321 : 0 : error = NULL;
2322 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2323 : 0 : if (c == NULL)
2324 : : {
2325 : 0 : if (request_completion)
2326 : : {
2327 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2328 : : {
2329 : 0 : g_print ("unix:\n"
2330 : : "tcp:\n"
2331 : : "nonce-tcp:\n");
2332 : : }
2333 : : else
2334 : : {
2335 : 0 : g_print ("--system \n--session \n--address \n");
2336 : : }
2337 : : }
2338 : : else
2339 : : {
2340 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2341 : : }
2342 : 0 : g_error_free (error);
2343 : 0 : goto out;
2344 : : }
2345 : :
2346 : : /* All done with completion now */
2347 : 0 : if (request_completion)
2348 : 0 : goto out;
2349 : :
2350 : : /*
2351 : : * Try and disentangle the command line arguments, with the aim of supporting:
2352 : : * gdbus wait --session --activate ActivateName WaitName
2353 : : * gdbus wait --session --activate ActivateAndWaitName
2354 : : * gdbus wait --activate --session ActivateAndWaitName
2355 : : * gdbus wait --session WaitName
2356 : : */
2357 : 0 : if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
2358 : : {
2359 : 0 : activate_service = opt_wait_activate_name;
2360 : 0 : wait_service = (*argv)[1];
2361 : : }
2362 : 0 : else if (*argc == 2 &&
2363 : 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2364 : : {
2365 : 0 : activate_service = (*argv)[1];
2366 : 0 : wait_service = (*argv)[1];
2367 : : }
2368 : 0 : else if (*argc == 2 && !opt_wait_activate_set)
2369 : : {
2370 : 0 : activate_service = NULL; /* disabled */
2371 : 0 : wait_service = (*argv)[1];
2372 : : }
2373 : 0 : else if (*argc == 1 &&
2374 : 0 : opt_wait_activate_set && opt_wait_activate_name != NULL)
2375 : : {
2376 : 0 : activate_service = opt_wait_activate_name;
2377 : 0 : wait_service = opt_wait_activate_name;
2378 : : }
2379 : 0 : else if (*argc == 1 &&
2380 : 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2381 : : {
2382 : 0 : g_printerr (_("Error: A service to activate for must be specified.\n"));
2383 : 0 : goto out;
2384 : : }
2385 : 0 : else if (*argc == 1 && !opt_wait_activate_set)
2386 : : {
2387 : 0 : g_printerr (_("Error: A service to wait for must be specified.\n"));
2388 : 0 : goto out;
2389 : : }
2390 : : else /* if (*argc > 2) */
2391 : : {
2392 : 0 : g_printerr (_("Error: Too many arguments.\n"));
2393 : 0 : goto out;
2394 : : }
2395 : :
2396 : 0 : if (activate_service != NULL &&
2397 : 0 : (!g_dbus_is_name (activate_service) ||
2398 : 0 : g_dbus_is_unique_name (activate_service)))
2399 : : {
2400 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2401 : : activate_service);
2402 : 0 : goto out;
2403 : : }
2404 : :
2405 : 0 : if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
2406 : : {
2407 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2408 : : wait_service);
2409 : 0 : goto out;
2410 : : }
2411 : :
2412 : : /* Start the prerequisite service if needed. */
2413 : 0 : if (activate_service != NULL)
2414 : : {
2415 : 0 : activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
2416 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2417 : : NULL, NULL,
2418 : : NULL, NULL);
2419 : : }
2420 : : else
2421 : : {
2422 : 0 : activate_watch_id = 0;
2423 : : }
2424 : :
2425 : : /* Wait for the expected name to appear. */
2426 : 0 : watch_id = g_bus_watch_name_on_connection (c,
2427 : : wait_service,
2428 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
2429 : : wait_name_appeared_cb,
2430 : : NULL, &wait_state, NULL);
2431 : :
2432 : : /* Safety timeout. */
2433 : 0 : if (opt_wait_timeout_secs > 0)
2434 : 0 : timer_id = g_timeout_add_seconds (opt_wait_timeout_secs, wait_timeout_cb, &wait_state);
2435 : :
2436 : 0 : while (wait_state == WAIT_STATE_RUNNING)
2437 : 0 : g_main_context_iteration (NULL, TRUE);
2438 : :
2439 : 0 : g_bus_unwatch_name (watch_id);
2440 : 0 : if (timer_id != 0)
2441 : 0 : g_source_remove (timer_id);
2442 : 0 : if (activate_watch_id != 0)
2443 : 0 : g_bus_unwatch_name (activate_watch_id);
2444 : :
2445 : 0 : ret = (wait_state == WAIT_STATE_SUCCESS);
2446 : :
2447 : 0 : out:
2448 : 0 : g_clear_object (&c);
2449 : 0 : g_option_context_free (o);
2450 : 0 : g_free (opt_wait_activate_name);
2451 : 0 : opt_wait_activate_name = NULL;
2452 : :
2453 : 0 : return ret;
2454 : : }
2455 : :
2456 : : /* ---------------------------------------------------------------------------------------------------- */
2457 : :
2458 : : static gchar *
2459 : 0 : pick_word_at (const gchar *s,
2460 : : gint cursor,
2461 : : gint *out_word_begins_at)
2462 : : {
2463 : : gint begin;
2464 : : gint end;
2465 : :
2466 : 0 : if (s[0] == '\0')
2467 : : {
2468 : 0 : if (out_word_begins_at != NULL)
2469 : 0 : *out_word_begins_at = -1;
2470 : 0 : return NULL;
2471 : : }
2472 : :
2473 : 0 : if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
2474 : : {
2475 : 0 : if (out_word_begins_at != NULL)
2476 : 0 : *out_word_begins_at = cursor;
2477 : 0 : return g_strdup ("");
2478 : : }
2479 : :
2480 : 0 : while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
2481 : 0 : cursor--;
2482 : 0 : begin = cursor;
2483 : :
2484 : 0 : end = begin;
2485 : 0 : while (!g_ascii_isspace (s[end]) && s[end] != '\0')
2486 : 0 : end++;
2487 : :
2488 : 0 : if (out_word_begins_at != NULL)
2489 : 0 : *out_word_begins_at = begin;
2490 : :
2491 : 0 : return g_strndup (s + begin, end - begin);
2492 : : }
2493 : :
2494 : : gint
2495 : 5 : main (gint argc, gchar *argv[])
2496 : : {
2497 : : gint ret;
2498 : : const gchar *command;
2499 : : gboolean request_completion;
2500 : : gchar *completion_cur;
2501 : : gchar *completion_prev;
2502 : : #ifdef G_OS_WIN32
2503 : : gchar *tmp;
2504 : : #endif
2505 : :
2506 : 5 : setlocale (LC_ALL, "");
2507 : 5 : textdomain (GETTEXT_PACKAGE);
2508 : :
2509 : : #ifdef G_OS_WIN32
2510 : : tmp = _glib_get_locale_dir ();
2511 : : bindtextdomain (GETTEXT_PACKAGE, tmp);
2512 : : g_free (tmp);
2513 : : #else
2514 : 5 : bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
2515 : : #endif
2516 : :
2517 : : #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2518 : 5 : bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2519 : : #endif
2520 : :
2521 : 5 : ret = 1;
2522 : 5 : completion_cur = NULL;
2523 : 5 : completion_prev = NULL;
2524 : :
2525 : 5 : if (argc < 2)
2526 : : {
2527 : 1 : usage (&argc, &argv, FALSE);
2528 : 1 : goto out;
2529 : : }
2530 : :
2531 : 4 : request_completion = FALSE;
2532 : :
2533 : : //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
2534 : :
2535 : 4 : again:
2536 : 4 : command = argv[1];
2537 : 7 : if (g_strcmp0 (command, "help") == 0 ||
2538 : 3 : g_strcmp0 (command, "--help") == 0)
2539 : : {
2540 : 2 : if (request_completion)
2541 : : {
2542 : : /* do nothing */
2543 : : }
2544 : : else
2545 : : {
2546 : 2 : usage (&argc, &argv, TRUE);
2547 : 2 : ret = 0;
2548 : : }
2549 : 2 : goto out;
2550 : : }
2551 : 2 : else if (g_strcmp0 (command, "emit") == 0)
2552 : : {
2553 : 0 : if (handle_emit (&argc,
2554 : : &argv,
2555 : : request_completion,
2556 : : completion_cur,
2557 : : completion_prev))
2558 : 0 : ret = 0;
2559 : 0 : goto out;
2560 : : }
2561 : 2 : else if (g_strcmp0 (command, "call") == 0)
2562 : : {
2563 : 2 : if (handle_call (&argc,
2564 : : &argv,
2565 : : request_completion,
2566 : : completion_cur,
2567 : : completion_prev))
2568 : 1 : ret = 0;
2569 : 2 : goto out;
2570 : : }
2571 : 0 : else if (g_strcmp0 (command, "introspect") == 0)
2572 : : {
2573 : 0 : if (handle_introspect (&argc,
2574 : : &argv,
2575 : : request_completion,
2576 : : completion_cur,
2577 : : completion_prev))
2578 : 0 : ret = 0;
2579 : 0 : goto out;
2580 : : }
2581 : 0 : else if (g_strcmp0 (command, "monitor") == 0)
2582 : : {
2583 : 0 : if (handle_monitor (&argc,
2584 : : &argv,
2585 : : request_completion,
2586 : : completion_cur,
2587 : : completion_prev))
2588 : 0 : ret = 0;
2589 : 0 : goto out;
2590 : : }
2591 : 0 : else if (g_strcmp0 (command, "wait") == 0)
2592 : : {
2593 : 0 : if (handle_wait (&argc,
2594 : : &argv,
2595 : : request_completion,
2596 : : completion_cur,
2597 : : completion_prev))
2598 : 0 : ret = 0;
2599 : 0 : goto out;
2600 : : }
2601 : : #ifdef G_OS_WIN32
2602 : : else if (g_strcmp0 (command, _GDBUS_ARG_WIN32_RUN_SESSION_BUS) == 0)
2603 : : {
2604 : : g_win32_run_session_bus (NULL, NULL, NULL, 0);
2605 : : ret = 0;
2606 : : goto out;
2607 : : }
2608 : : #endif
2609 : 0 : else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2610 : : {
2611 : : const gchar *completion_line;
2612 : : gchar **completion_argv;
2613 : : gint completion_argc;
2614 : : gint completion_point;
2615 : : gchar *endp;
2616 : : gint cur_begin;
2617 : :
2618 : 0 : request_completion = TRUE;
2619 : :
2620 : 0 : completion_line = argv[2];
2621 : 0 : completion_point = strtol (argv[3], &endp, 10);
2622 : 0 : if (endp == argv[3] || *endp != '\0')
2623 : 0 : goto out;
2624 : :
2625 : : #if 0
2626 : : completion_debug ("completion_point=%d", completion_point);
2627 : : completion_debug ("----");
2628 : : completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2629 : : completion_debug ("'%s'", completion_line);
2630 : : completion_debug (" %*s^",
2631 : : completion_point, "");
2632 : : completion_debug ("----");
2633 : : #endif
2634 : :
2635 : 0 : if (!g_shell_parse_argv (completion_line,
2636 : : &completion_argc,
2637 : : &completion_argv,
2638 : : NULL))
2639 : : {
2640 : : /* it's very possible the command line can't be parsed (for
2641 : : * example, missing quotes etc) - in that case, we just
2642 : : * don't autocomplete at all
2643 : : */
2644 : 0 : goto out;
2645 : : }
2646 : :
2647 : : /* compute cur and prev */
2648 : 0 : completion_prev = NULL;
2649 : 0 : completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2650 : 0 : if (cur_begin > 0)
2651 : : {
2652 : : gint prev_end;
2653 : 0 : for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2654 : : {
2655 : 0 : if (!g_ascii_isspace (completion_line[prev_end]))
2656 : : {
2657 : 0 : completion_prev = pick_word_at (completion_line, prev_end, NULL);
2658 : 0 : break;
2659 : : }
2660 : : }
2661 : : }
2662 : : #if 0
2663 : : completion_debug (" cur='%s'", completion_cur);
2664 : : completion_debug ("prev='%s'", completion_prev);
2665 : : #endif
2666 : :
2667 : 0 : argc = completion_argc;
2668 : 0 : argv = completion_argv;
2669 : :
2670 : 0 : ret = 0;
2671 : :
2672 : 0 : goto again;
2673 : : }
2674 : : else
2675 : : {
2676 : 0 : if (request_completion)
2677 : : {
2678 : 0 : g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
2679 : 0 : ret = 0;
2680 : 0 : goto out;
2681 : : }
2682 : : else
2683 : : {
2684 : 0 : g_printerr ("Unknown command '%s'\n", command);
2685 : 0 : usage (&argc, &argv, FALSE);
2686 : 0 : goto out;
2687 : : }
2688 : : }
2689 : :
2690 : 5 : out:
2691 : 5 : g_free (completion_cur);
2692 : 5 : g_free (completion_prev);
2693 : 5 : return ret;
2694 : : }
|