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