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 : : static gchar *opt_emit_dest = NULL;
591 : : static gchar *opt_emit_object_path = NULL;
592 : : static gchar *opt_emit_signal = NULL;
593 : :
594 : : static const GOptionEntry emit_entries[] =
595 : : {
596 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
597 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
598 : : { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
599 : : G_OPTION_ENTRY_NULL
600 : : };
601 : :
602 : : static gboolean
603 : 0 : handle_emit (gint *argc,
604 : : gchar **argv[],
605 : : gboolean request_completion,
606 : : const gchar *completion_cur,
607 : : const gchar *completion_prev)
608 : : {
609 : : gint ret;
610 : : GOptionContext *o;
611 : : gchar *s;
612 : : GError *error;
613 : : GDBusConnection *c;
614 : : GVariant *parameters;
615 : : gchar *interface_name;
616 : : gchar *signal_name;
617 : : GVariantBuilder builder;
618 : : gboolean skip_dashes;
619 : : guint parm;
620 : : guint n;
621 : : gboolean complete_names, complete_paths, complete_signals;
622 : :
623 : 0 : ret = FALSE;
624 : 0 : c = NULL;
625 : 0 : parameters = NULL;
626 : 0 : interface_name = NULL;
627 : 0 : signal_name = NULL;
628 : :
629 : 0 : modify_argv0_for_command (argc, argv, "emit");
630 : :
631 : 0 : o = command_option_context_new (NULL, _("Emit a signal."),
632 : : emit_entries, request_completion);
633 : 0 : g_option_context_add_group (o, connection_get_group ());
634 : :
635 : 0 : complete_names = FALSE;
636 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
637 : : {
638 : 0 : complete_names = TRUE;
639 : 0 : remove_arg ((*argc) - 1, argc, argv);
640 : : }
641 : :
642 : 0 : complete_paths = FALSE;
643 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
644 : : {
645 : 0 : complete_paths = TRUE;
646 : 0 : remove_arg ((*argc) - 1, argc, argv);
647 : : }
648 : :
649 : 0 : complete_signals = FALSE;
650 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
651 : : {
652 : 0 : complete_signals = TRUE;
653 : 0 : remove_arg ((*argc) - 1, argc, argv);
654 : : }
655 : :
656 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
657 : : {
658 : 0 : if (!request_completion)
659 : : {
660 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
661 : 0 : g_printerr ("%s", s);
662 : 0 : g_free (s);
663 : 0 : goto out;
664 : : }
665 : : }
666 : :
667 : 0 : error = NULL;
668 : 0 : c = connection_get_dbus_connection ((opt_emit_dest != NULL), &error);
669 : 0 : if (c == NULL)
670 : : {
671 : 0 : if (request_completion)
672 : : {
673 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
674 : : {
675 : 0 : g_print ("unix:\n"
676 : : "tcp:\n"
677 : : "nonce-tcp:\n");
678 : : }
679 : : else
680 : : {
681 : 0 : g_print ("--system \n--session \n--address \n");
682 : : }
683 : : }
684 : : else
685 : : {
686 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
687 : : }
688 : 0 : g_error_free (error);
689 : 0 : goto out;
690 : : }
691 : :
692 : : /* validate and complete destination (bus name) */
693 : 0 : if (complete_names)
694 : : {
695 : 0 : print_names (c, FALSE);
696 : 0 : goto out;
697 : : }
698 : 0 : if (request_completion && opt_emit_dest != NULL && g_strcmp0 ("--dest", completion_prev) == 0)
699 : : {
700 : 0 : print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
701 : 0 : goto out;
702 : : }
703 : :
704 : 0 : if (!request_completion && opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
705 : : {
706 : 0 : g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
707 : 0 : goto out;
708 : : }
709 : :
710 : 0 : if (opt_emit_dest == NULL && opt_emit_object_path == NULL && request_completion)
711 : : {
712 : 0 : g_print ("--dest \n");
713 : : }
714 : : /* validate and complete object path */
715 : 0 : if (opt_emit_dest != NULL && complete_paths)
716 : : {
717 : 0 : print_paths (c, opt_emit_dest, "/");
718 : 0 : goto out;
719 : : }
720 : 0 : if (opt_emit_object_path == NULL)
721 : : {
722 : 0 : if (request_completion)
723 : 0 : g_print ("--object-path \n");
724 : : else
725 : 0 : g_printerr (_("Error: Object path is not specified\n"));
726 : 0 : goto out;
727 : : }
728 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
729 : : {
730 : 0 : if (opt_emit_dest != NULL)
731 : : {
732 : : gchar *p;
733 : 0 : s = g_strdup (opt_emit_object_path);
734 : 0 : p = strrchr (s, '/');
735 : 0 : if (p != NULL)
736 : : {
737 : 0 : if (p == s)
738 : 0 : p++;
739 : 0 : *p = '\0';
740 : : }
741 : 0 : print_paths (c, opt_emit_dest, s);
742 : 0 : g_free (s);
743 : : }
744 : 0 : goto out;
745 : : }
746 : 0 : if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
747 : : {
748 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
749 : 0 : goto out;
750 : : }
751 : :
752 : : /* validate and complete signal (interface + signal name) */
753 : 0 : if (opt_emit_dest != NULL && opt_emit_object_path != NULL && complete_signals)
754 : : {
755 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
756 : 0 : goto out;
757 : : }
758 : 0 : if (opt_emit_signal == NULL)
759 : : {
760 : : /* don't keep repeatedly completing --signal */
761 : 0 : if (request_completion)
762 : : {
763 : 0 : if (g_strcmp0 ("--signal", completion_prev) != 0)
764 : 0 : g_print ("--signal \n");
765 : : }
766 : : else
767 : : {
768 : 0 : g_printerr (_("Error: Signal name is not specified\n"));
769 : : }
770 : :
771 : 0 : goto out;
772 : : }
773 : 0 : if (request_completion && opt_emit_dest != NULL && opt_emit_object_path != NULL &&
774 : 0 : g_strcmp0 ("--signal", completion_prev) == 0)
775 : : {
776 : 0 : print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
777 : 0 : goto out;
778 : : }
779 : 0 : s = strrchr (opt_emit_signal, '.');
780 : 0 : if (!request_completion && s == NULL)
781 : : {
782 : 0 : g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
783 : 0 : goto out;
784 : : }
785 : 0 : signal_name = g_strdup (s + 1);
786 : 0 : interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
787 : :
788 : : /* All done with completion now */
789 : 0 : if (request_completion)
790 : 0 : goto out;
791 : :
792 : 0 : if (!g_dbus_is_interface_name (interface_name))
793 : : {
794 : 0 : g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
795 : 0 : goto out;
796 : : }
797 : :
798 : 0 : if (!g_dbus_is_member_name (signal_name))
799 : : {
800 : 0 : g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
801 : 0 : goto out;
802 : : }
803 : :
804 : : /* Read parameters */
805 : 0 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE_TUPLE);
806 : 0 : skip_dashes = TRUE;
807 : 0 : parm = 0;
808 : 0 : for (n = 1; n < (guint) *argc; n++)
809 : : {
810 : : GVariant *value;
811 : :
812 : : /* Under certain conditions, g_option_context_parse returns the "--"
813 : : itself (setting off unparsed arguments), too: */
814 : 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
815 : : {
816 : 0 : skip_dashes = FALSE;
817 : 0 : continue;
818 : : }
819 : :
820 : 0 : error = NULL;
821 : 0 : value = g_variant_parse (NULL,
822 : 0 : (*argv)[n],
823 : : NULL,
824 : : NULL,
825 : : &error);
826 : 0 : if (value == NULL)
827 : : {
828 : : gchar *context;
829 : :
830 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
831 : 0 : g_error_free (error);
832 : 0 : error = NULL;
833 : 0 : value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
834 : 0 : if (value == NULL)
835 : : {
836 : : /* Use the original non-"parse-me-harder" error */
837 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
838 : : parm + 1,
839 : : context);
840 : 0 : g_error_free (error);
841 : 0 : g_free (context);
842 : 0 : g_variant_builder_clear (&builder);
843 : 0 : goto out;
844 : : }
845 : 0 : g_free (context);
846 : : }
847 : 0 : g_variant_builder_add_value (&builder, value);
848 : 0 : ++parm;
849 : : }
850 : 0 : parameters = g_variant_builder_end (&builder);
851 : :
852 : 0 : if (parameters != NULL)
853 : 0 : parameters = g_variant_ref_sink (parameters);
854 : 0 : if (!g_dbus_connection_emit_signal (c,
855 : : opt_emit_dest,
856 : : opt_emit_object_path,
857 : : interface_name,
858 : : signal_name,
859 : : parameters,
860 : : &error))
861 : : {
862 : 0 : g_printerr (_("Error: %s\n"), error->message);
863 : 0 : g_error_free (error);
864 : 0 : goto out;
865 : : }
866 : :
867 : 0 : if (!g_dbus_connection_flush_sync (c, NULL, &error))
868 : : {
869 : 0 : g_printerr (_("Error flushing connection: %s\n"), error->message);
870 : 0 : g_error_free (error);
871 : 0 : goto out;
872 : : }
873 : :
874 : 0 : ret = TRUE;
875 : :
876 : 0 : out:
877 : 0 : if (c != NULL)
878 : 0 : g_object_unref (c);
879 : 0 : if (parameters != NULL)
880 : 0 : g_variant_unref (parameters);
881 : 0 : g_free (interface_name);
882 : 0 : g_free (signal_name);
883 : 0 : g_option_context_free (o);
884 : 0 : return ret;
885 : : }
886 : :
887 : : /* ---------------------------------------------------------------------------------------------------- */
888 : :
889 : : static gchar *opt_call_dest = NULL;
890 : : static gchar *opt_call_object_path = NULL;
891 : : static gchar *opt_call_method = NULL;
892 : : static gint opt_call_timeout = -1;
893 : : static gboolean opt_call_interactive = FALSE;
894 : :
895 : : static const GOptionEntry call_entries[] =
896 : : {
897 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
898 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
899 : : { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
900 : : { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
901 : : { "interactive", 'i', 0, G_OPTION_ARG_NONE, &opt_call_interactive, N_("Allow interactive authorization"), NULL},
902 : : G_OPTION_ENTRY_NULL
903 : : };
904 : :
905 : : static gboolean
906 : 0 : handle_call (gint *argc,
907 : : gchar **argv[],
908 : : gboolean request_completion,
909 : : const gchar *completion_cur,
910 : : const gchar *completion_prev)
911 : : {
912 : : gint ret;
913 : : GOptionContext *o;
914 : : gchar *s;
915 : : GError *error;
916 : : GDBusConnection *c;
917 : : GVariant *parameters;
918 : : gchar *interface_name;
919 : : gchar *method_name;
920 : : GVariant *result;
921 : : GPtrArray *in_signature_types;
922 : : #ifdef G_OS_UNIX
923 : : GUnixFDList *fd_list;
924 : : gint fd_id;
925 : : #endif
926 : : gboolean complete_names;
927 : : gboolean complete_paths;
928 : : gboolean complete_methods;
929 : : GVariantBuilder builder;
930 : : gboolean skip_dashes;
931 : : guint parm;
932 : : guint n;
933 : : GDBusCallFlags flags;
934 : :
935 : 0 : ret = FALSE;
936 : 0 : c = NULL;
937 : 0 : parameters = NULL;
938 : 0 : interface_name = NULL;
939 : 0 : method_name = NULL;
940 : 0 : result = NULL;
941 : 0 : in_signature_types = NULL;
942 : : #ifdef G_OS_UNIX
943 : 0 : fd_list = NULL;
944 : : #endif
945 : :
946 : 0 : modify_argv0_for_command (argc, argv, "call");
947 : :
948 : 0 : o = command_option_context_new (NULL, _("Invoke a method on a remote object."),
949 : : call_entries, request_completion);
950 : 0 : g_option_context_add_group (o, connection_get_group ());
951 : :
952 : 0 : complete_names = FALSE;
953 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
954 : : {
955 : 0 : complete_names = TRUE;
956 : 0 : remove_arg ((*argc) - 1, argc, argv);
957 : : }
958 : :
959 : 0 : complete_paths = FALSE;
960 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
961 : : {
962 : 0 : complete_paths = TRUE;
963 : 0 : remove_arg ((*argc) - 1, argc, argv);
964 : : }
965 : :
966 : 0 : complete_methods = FALSE;
967 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
968 : : {
969 : 0 : complete_methods = TRUE;
970 : 0 : remove_arg ((*argc) - 1, argc, argv);
971 : : }
972 : :
973 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
974 : : {
975 : 0 : if (!request_completion)
976 : : {
977 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
978 : 0 : g_printerr ("%s", s);
979 : 0 : g_free (s);
980 : 0 : goto out;
981 : : }
982 : : }
983 : :
984 : 0 : error = NULL;
985 : 0 : c = connection_get_dbus_connection (TRUE, &error);
986 : 0 : if (c == NULL)
987 : : {
988 : 0 : if (request_completion)
989 : : {
990 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
991 : : {
992 : 0 : g_print ("unix:\n"
993 : : "tcp:\n"
994 : : "nonce-tcp:\n");
995 : : }
996 : : else
997 : : {
998 : 0 : g_print ("--system \n--session \n--address \n");
999 : : }
1000 : : }
1001 : : else
1002 : : {
1003 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1004 : : }
1005 : 0 : g_error_free (error);
1006 : 0 : goto out;
1007 : : }
1008 : :
1009 : : /* validate and complete destination (bus name) */
1010 : 0 : if (complete_names)
1011 : : {
1012 : 0 : print_names (c, FALSE);
1013 : 0 : goto out;
1014 : : }
1015 : 0 : if (opt_call_dest == NULL)
1016 : : {
1017 : 0 : if (request_completion)
1018 : 0 : g_print ("--dest \n");
1019 : : else
1020 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1021 : 0 : goto out;
1022 : : }
1023 : 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1024 : : {
1025 : 0 : print_names (c, g_str_has_prefix (opt_call_dest, ":"));
1026 : 0 : goto out;
1027 : : }
1028 : :
1029 : 0 : if (!request_completion && !g_dbus_is_name (opt_call_dest))
1030 : : {
1031 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
1032 : 0 : goto out;
1033 : : }
1034 : :
1035 : : /* validate and complete object path */
1036 : 0 : if (complete_paths)
1037 : : {
1038 : 0 : print_paths (c, opt_call_dest, "/");
1039 : 0 : goto out;
1040 : : }
1041 : 0 : if (opt_call_object_path == NULL)
1042 : : {
1043 : 0 : if (request_completion)
1044 : 0 : g_print ("--object-path \n");
1045 : : else
1046 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1047 : 0 : goto out;
1048 : : }
1049 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1050 : : {
1051 : : gchar *p;
1052 : 0 : s = g_strdup (opt_call_object_path);
1053 : 0 : p = strrchr (s, '/');
1054 : 0 : if (p != NULL)
1055 : : {
1056 : 0 : if (p == s)
1057 : 0 : p++;
1058 : 0 : *p = '\0';
1059 : : }
1060 : 0 : print_paths (c, opt_call_dest, s);
1061 : 0 : g_free (s);
1062 : 0 : goto out;
1063 : : }
1064 : 0 : if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
1065 : : {
1066 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
1067 : 0 : goto out;
1068 : : }
1069 : :
1070 : : /* validate and complete method (interface + method name) */
1071 : 0 : if (complete_methods)
1072 : : {
1073 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1074 : 0 : goto out;
1075 : : }
1076 : 0 : if (opt_call_method == NULL)
1077 : : {
1078 : 0 : if (request_completion)
1079 : 0 : g_print ("--method \n");
1080 : : else
1081 : 0 : g_printerr (_("Error: Method name is not specified\n"));
1082 : 0 : goto out;
1083 : : }
1084 : 0 : if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
1085 : : {
1086 : 0 : print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
1087 : 0 : goto out;
1088 : : }
1089 : 0 : s = strrchr (opt_call_method, '.');
1090 : 0 : if (!request_completion && s == NULL)
1091 : : {
1092 : 0 : g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
1093 : 0 : goto out;
1094 : : }
1095 : 0 : method_name = g_strdup (s + 1);
1096 : 0 : interface_name = g_strndup (opt_call_method, s - opt_call_method);
1097 : :
1098 : : /* All done with completion now */
1099 : 0 : if (request_completion)
1100 : 0 : goto out;
1101 : :
1102 : : /* Introspect, for easy conversion - it's not fatal if we can't do this */
1103 : 0 : in_signature_types = call_helper_get_method_in_signature (c,
1104 : : opt_call_dest,
1105 : : opt_call_object_path,
1106 : : interface_name,
1107 : : method_name,
1108 : : &error);
1109 : 0 : if (in_signature_types == NULL)
1110 : : {
1111 : : //g_printerr ("Error getting introspection data: %s\n", error->message);
1112 : 0 : g_error_free (error);
1113 : 0 : error = NULL;
1114 : : }
1115 : :
1116 : : /* Read parameters */
1117 : 0 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE_TUPLE);
1118 : 0 : skip_dashes = TRUE;
1119 : 0 : parm = 0;
1120 : 0 : for (n = 1; n < (guint) *argc; n++)
1121 : : {
1122 : : GVariant *value;
1123 : : GVariantType *type;
1124 : :
1125 : : /* Under certain conditions, g_option_context_parse returns the "--"
1126 : : itself (setting off unparsed arguments), too: */
1127 : 0 : if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
1128 : : {
1129 : 0 : skip_dashes = FALSE;
1130 : 0 : continue;
1131 : : }
1132 : :
1133 : 0 : type = NULL;
1134 : 0 : if (in_signature_types != NULL)
1135 : : {
1136 : 0 : if (parm >= in_signature_types->len)
1137 : : {
1138 : : /* Only warn for the first param */
1139 : 0 : if (parm == in_signature_types->len)
1140 : : {
1141 : 0 : g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
1142 : : in_signature_types->len);
1143 : : }
1144 : : }
1145 : : else
1146 : : {
1147 : 0 : type = in_signature_types->pdata[parm];
1148 : : }
1149 : : }
1150 : :
1151 : 0 : error = NULL;
1152 : 0 : value = g_variant_parse (type,
1153 : 0 : (*argv)[n],
1154 : : NULL,
1155 : : NULL,
1156 : : &error);
1157 : 0 : if (value == NULL)
1158 : : {
1159 : : gchar *context;
1160 : :
1161 : 0 : context = g_variant_parse_error_print_context (error, (*argv)[n]);
1162 : 0 : g_error_free (error);
1163 : 0 : error = NULL;
1164 : 0 : value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
1165 : 0 : if (value == NULL)
1166 : : {
1167 : 0 : if (type != NULL)
1168 : : {
1169 : 0 : s = g_variant_type_dup_string (type);
1170 : 0 : g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
1171 : : parm + 1,
1172 : : s,
1173 : : context);
1174 : 0 : g_free (s);
1175 : : }
1176 : : else
1177 : : {
1178 : 0 : g_printerr (_("Error parsing parameter %d: %s\n"),
1179 : : parm + 1,
1180 : : context);
1181 : : }
1182 : 0 : g_error_free (error);
1183 : 0 : g_variant_builder_clear (&builder);
1184 : 0 : g_free (context);
1185 : 0 : goto out;
1186 : : }
1187 : 0 : g_free (context);
1188 : : }
1189 : : #ifdef G_OS_UNIX
1190 : 0 : if (g_variant_is_of_type (value, G_VARIANT_TYPE_HANDLE))
1191 : : {
1192 : 0 : if (!fd_list)
1193 : 0 : fd_list = g_unix_fd_list_new ();
1194 : 0 : if ((fd_id = g_unix_fd_list_append (fd_list, g_variant_get_handle (value), &error)) == -1)
1195 : : {
1196 : 0 : g_printerr (_("Error adding handle %d: %s\n"),
1197 : 0 : g_variant_get_handle (value), error->message);
1198 : 0 : g_variant_builder_clear (&builder);
1199 : 0 : g_error_free (error);
1200 : 0 : goto out;
1201 : : }
1202 : 0 : g_variant_unref (value);
1203 : 0 : value = g_variant_new_handle (fd_id);
1204 : : }
1205 : : #endif
1206 : 0 : g_variant_builder_add_value (&builder, value);
1207 : 0 : ++parm;
1208 : : }
1209 : 0 : parameters = g_variant_builder_end (&builder);
1210 : :
1211 : 0 : if (parameters != NULL)
1212 : 0 : parameters = g_variant_ref_sink (parameters);
1213 : :
1214 : 0 : flags = G_DBUS_CALL_FLAGS_NONE;
1215 : 0 : if (opt_call_interactive)
1216 : 0 : flags |= G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
1217 : :
1218 : : #ifdef G_OS_UNIX
1219 : 0 : result = g_dbus_connection_call_with_unix_fd_list_sync (c,
1220 : : opt_call_dest,
1221 : : opt_call_object_path,
1222 : : interface_name,
1223 : : method_name,
1224 : : parameters,
1225 : : NULL,
1226 : : flags,
1227 : 0 : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1228 : : fd_list,
1229 : : NULL,
1230 : : NULL,
1231 : : &error);
1232 : : #else
1233 : : result = g_dbus_connection_call_sync (c,
1234 : : opt_call_dest,
1235 : : opt_call_object_path,
1236 : : interface_name,
1237 : : method_name,
1238 : : parameters,
1239 : : NULL,
1240 : : flags,
1241 : : opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
1242 : : NULL,
1243 : : &error);
1244 : : #endif
1245 : 0 : if (result == NULL)
1246 : : {
1247 : 0 : g_printerr (_("Error: %s\n"), error->message);
1248 : :
1249 : 0 : if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
1250 : : {
1251 : 0 : if (in_signature_types->len > 0)
1252 : : {
1253 : : GString *str;
1254 : 0 : str = g_string_new (NULL);
1255 : :
1256 : 0 : for (n = 0; n < in_signature_types->len; n++)
1257 : : {
1258 : 0 : GVariantType *type = in_signature_types->pdata[n];
1259 : 0 : g_string_append_len (str,
1260 : : g_variant_type_peek_string (type),
1261 : : g_variant_type_get_string_length (type));
1262 : : }
1263 : :
1264 : 0 : g_printerr ("(According to introspection data, you need to pass '%s')\n", str->str);
1265 : 0 : g_string_free (str, TRUE);
1266 : : }
1267 : : else
1268 : 0 : g_printerr ("(According to introspection data, you need to pass no arguments)\n");
1269 : : }
1270 : :
1271 : 0 : g_error_free (error);
1272 : 0 : goto out;
1273 : : }
1274 : :
1275 : 0 : s = g_variant_print (result, TRUE);
1276 : 0 : g_print ("%s\n", s);
1277 : 0 : g_free (s);
1278 : :
1279 : 0 : ret = TRUE;
1280 : :
1281 : 0 : out:
1282 : 0 : if (in_signature_types != NULL)
1283 : 0 : g_ptr_array_unref (in_signature_types);
1284 : 0 : if (result != NULL)
1285 : 0 : g_variant_unref (result);
1286 : 0 : if (c != NULL)
1287 : 0 : g_object_unref (c);
1288 : 0 : if (parameters != NULL)
1289 : 0 : g_variant_unref (parameters);
1290 : 0 : g_free (interface_name);
1291 : 0 : g_free (method_name);
1292 : 0 : g_option_context_free (o);
1293 : : #ifdef G_OS_UNIX
1294 : 0 : g_clear_object (&fd_list);
1295 : : #endif
1296 : 0 : return ret;
1297 : : }
1298 : :
1299 : : /* ---------------------------------------------------------------------------------------------------- */
1300 : :
1301 : : static gchar *opt_introspect_dest = NULL;
1302 : : static gchar *opt_introspect_object_path = NULL;
1303 : : static gboolean opt_introspect_xml = FALSE;
1304 : : static gboolean opt_introspect_recurse = FALSE;
1305 : : static gboolean opt_introspect_only_properties = FALSE;
1306 : :
1307 : : /* Introspect colors */
1308 : : #define RESET_COLOR (use_colors? "\033[0m": "")
1309 : : #define INTROSPECT_TITLE_COLOR (use_colors? UNDERLINE: "")
1310 : : #define INTROSPECT_NODE_COLOR (use_colors? RESET_COLOR: "")
1311 : : #define INTROSPECT_INTERFACE_COLOR (use_colors? YELLOW: "")
1312 : : #define INTROSPECT_METHOD_COLOR (use_colors? BLUE: "")
1313 : : #define INTROSPECT_SIGNAL_COLOR (use_colors? BLUE: "")
1314 : : #define INTROSPECT_PROPERTY_COLOR (use_colors? MAGENTA: "")
1315 : : #define INTROSPECT_INOUT_COLOR (use_colors? RESET_COLOR: "")
1316 : : #define INTROSPECT_TYPE_COLOR (use_colors? GREEN: "")
1317 : : #define INTROSPECT_ANNOTATION_COLOR (use_colors? RESET_COLOR: "")
1318 : :
1319 : : static void
1320 : 0 : dump_annotation (const GDBusAnnotationInfo *o,
1321 : : guint indent,
1322 : : gboolean ignore_indent,
1323 : : gboolean use_colors)
1324 : : {
1325 : : guint n;
1326 : 0 : g_print ("%*s%s@%s(\"%s\")%s\n",
1327 : : ignore_indent ? 0 : indent, "",
1328 : 0 : INTROSPECT_ANNOTATION_COLOR, o->key, o->value, RESET_COLOR);
1329 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1330 : 0 : dump_annotation (o->annotations[n], indent + 2, FALSE, use_colors);
1331 : 0 : }
1332 : :
1333 : : static void
1334 : 0 : dump_arg (const GDBusArgInfo *o,
1335 : : guint indent,
1336 : : const gchar *direction,
1337 : : gboolean ignore_indent,
1338 : : gboolean include_newline,
1339 : : gboolean use_colors)
1340 : : {
1341 : : guint n;
1342 : :
1343 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1344 : : {
1345 : 0 : dump_annotation (o->annotations[n], indent, ignore_indent, use_colors);
1346 : 0 : ignore_indent = FALSE;
1347 : : }
1348 : :
1349 : 0 : g_print ("%*s%s%s%s%s%s%s %s%s",
1350 : : ignore_indent ? 0 : indent, "",
1351 : : INTROSPECT_INOUT_COLOR, direction, RESET_COLOR,
1352 : 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1353 : 0 : o->name,
1354 : : include_newline ? ",\n" : "");
1355 : 0 : }
1356 : :
1357 : : static guint
1358 : 0 : count_args (GDBusArgInfo **args)
1359 : : {
1360 : : guint n;
1361 : 0 : n = 0;
1362 : 0 : if (args == NULL)
1363 : 0 : goto out;
1364 : 0 : while (args[n] != NULL)
1365 : 0 : n++;
1366 : 0 : out:
1367 : 0 : return n;
1368 : : }
1369 : :
1370 : : static void
1371 : 0 : dump_method (const GDBusMethodInfo *o,
1372 : : guint indent,
1373 : : gboolean use_colors)
1374 : : {
1375 : : guint n;
1376 : : guint m;
1377 : : size_t name_len;
1378 : : guint total_num_args;
1379 : :
1380 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1381 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1382 : :
1383 : 0 : g_print ("%*s%s%s%s(",
1384 : : indent, "",
1385 : 0 : INTROSPECT_METHOD_COLOR, o->name, RESET_COLOR);
1386 : 0 : name_len = strlen (o->name);
1387 : 0 : total_num_args = count_args (o->in_args) + count_args (o->out_args);
1388 : 0 : for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
1389 : : {
1390 : 0 : gboolean ignore_indent = (m == 0);
1391 : 0 : gboolean include_newline = (m != total_num_args - 1);
1392 : :
1393 : 0 : dump_arg (o->in_args[n],
1394 : 0 : indent + name_len + 1,
1395 : : "in ",
1396 : : ignore_indent,
1397 : : include_newline,
1398 : : use_colors);
1399 : : }
1400 : 0 : for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
1401 : : {
1402 : 0 : gboolean ignore_indent = (m == 0);
1403 : 0 : gboolean include_newline = (m != total_num_args - 1);
1404 : 0 : dump_arg (o->out_args[n],
1405 : 0 : indent + name_len + 1,
1406 : : "out ",
1407 : : ignore_indent,
1408 : : include_newline,
1409 : : use_colors);
1410 : : }
1411 : 0 : g_print (");\n");
1412 : 0 : }
1413 : :
1414 : : static void
1415 : 0 : dump_signal (const GDBusSignalInfo *o,
1416 : : guint indent,
1417 : : gboolean use_colors)
1418 : : {
1419 : : guint n;
1420 : : guint name_len;
1421 : : guint total_num_args;
1422 : :
1423 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1424 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1425 : :
1426 : 0 : g_print ("%*s%s%s%s(",
1427 : : indent, "",
1428 : 0 : INTROSPECT_SIGNAL_COLOR, o->name, RESET_COLOR);
1429 : 0 : name_len = strlen (o->name);
1430 : 0 : total_num_args = count_args (o->args);
1431 : 0 : for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
1432 : : {
1433 : 0 : gboolean ignore_indent = (n == 0);
1434 : 0 : gboolean include_newline = (n != total_num_args - 1);
1435 : 0 : dump_arg (o->args[n],
1436 : 0 : indent + name_len + 1,
1437 : : "",
1438 : : ignore_indent,
1439 : : include_newline,
1440 : : use_colors);
1441 : : }
1442 : 0 : g_print (");\n");
1443 : 0 : }
1444 : :
1445 : : static void
1446 : 0 : dump_property (const GDBusPropertyInfo *o,
1447 : : guint indent,
1448 : : gboolean use_colors,
1449 : : GVariant *value)
1450 : : {
1451 : : const gchar *access;
1452 : : guint n;
1453 : :
1454 : 0 : if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
1455 : 0 : access = "readonly";
1456 : 0 : else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
1457 : 0 : access = "writeonly";
1458 : 0 : else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
1459 : 0 : access = "readwrite";
1460 : : else
1461 : : g_assert_not_reached ();
1462 : :
1463 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1464 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1465 : :
1466 : 0 : if (value != NULL)
1467 : : {
1468 : 0 : gchar *s = g_variant_print (value, FALSE);
1469 : 0 : g_print ("%*s%s %s%s%s %s%s%s = %s;\n", indent, "", access,
1470 : 0 : INTROSPECT_TYPE_COLOR, o->signature, RESET_COLOR,
1471 : 0 : INTROSPECT_PROPERTY_COLOR, o->name, RESET_COLOR,
1472 : : s);
1473 : 0 : g_free (s);
1474 : : }
1475 : : else
1476 : : {
1477 : 0 : g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
1478 : : }
1479 : 0 : }
1480 : :
1481 : : static void
1482 : 0 : dump_interface (GDBusConnection *c,
1483 : : const gchar *name,
1484 : : const GDBusInterfaceInfo *o,
1485 : : guint indent,
1486 : : gboolean use_colors,
1487 : : const gchar *object_path)
1488 : : {
1489 : : guint n;
1490 : : GHashTable *properties;
1491 : :
1492 : 0 : properties = g_hash_table_new_full (g_str_hash,
1493 : : g_str_equal,
1494 : : g_free,
1495 : : (GDestroyNotify) g_variant_unref);
1496 : :
1497 : : /* Try to get properties */
1498 : 0 : if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
1499 : : {
1500 : : GVariant *result;
1501 : 0 : result = g_dbus_connection_call_sync (c,
1502 : : name,
1503 : : object_path,
1504 : : DBUS_INTERFACE_PROPERTIES,
1505 : : "GetAll",
1506 : 0 : g_variant_new ("(s)", o->name),
1507 : : NULL,
1508 : : G_DBUS_CALL_FLAGS_NONE,
1509 : : 3000,
1510 : : NULL,
1511 : : NULL);
1512 : 0 : if (result != NULL)
1513 : : {
1514 : 0 : if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
1515 : : {
1516 : : GVariantIter *iter;
1517 : : GVariant *item;
1518 : 0 : g_variant_get (result,
1519 : : "(a{sv})",
1520 : : &iter);
1521 : 0 : while ((item = g_variant_iter_next_value (iter)))
1522 : : {
1523 : : gchar *key;
1524 : : GVariant *value;
1525 : 0 : g_variant_get (item,
1526 : : "{sv}",
1527 : : &key,
1528 : : &value);
1529 : :
1530 : 0 : g_hash_table_insert (properties, key, g_variant_ref (value));
1531 : : }
1532 : : }
1533 : 0 : g_variant_unref (result);
1534 : : }
1535 : : else
1536 : : {
1537 : 0 : for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
1538 : : {
1539 : 0 : result = g_dbus_connection_call_sync (c,
1540 : : name,
1541 : : object_path,
1542 : : DBUS_INTERFACE_PROPERTIES,
1543 : : "Get",
1544 : 0 : g_variant_new ("(ss)", o->name, o->properties[n]->name),
1545 : : G_VARIANT_TYPE ("(v)"),
1546 : : G_DBUS_CALL_FLAGS_NONE,
1547 : : 3000,
1548 : : NULL,
1549 : : NULL);
1550 : 0 : if (result != NULL)
1551 : : {
1552 : : GVariant *property_value;
1553 : 0 : g_variant_get (result,
1554 : : "(v)",
1555 : : &property_value);
1556 : 0 : g_hash_table_insert (properties,
1557 : 0 : g_strdup (o->properties[n]->name),
1558 : 0 : g_variant_ref (property_value));
1559 : 0 : g_variant_unref (result);
1560 : : }
1561 : : }
1562 : : }
1563 : : }
1564 : :
1565 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1566 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1567 : :
1568 : 0 : g_print ("%*s%sinterface %s%s {\n",
1569 : : indent, "",
1570 : 0 : INTROSPECT_INTERFACE_COLOR, o->name, RESET_COLOR);
1571 : 0 : if (o->methods != NULL && !opt_introspect_only_properties)
1572 : : {
1573 : 0 : g_print ("%*s %smethods%s:\n",
1574 : : indent, "",
1575 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1576 : 0 : for (n = 0; o->methods[n] != NULL; n++)
1577 : 0 : dump_method (o->methods[n], indent + 4, use_colors);
1578 : : }
1579 : 0 : if (o->signals != NULL && !opt_introspect_only_properties)
1580 : : {
1581 : 0 : g_print ("%*s %ssignals%s:\n",
1582 : : indent, "",
1583 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1584 : 0 : for (n = 0; o->signals[n] != NULL; n++)
1585 : 0 : dump_signal (o->signals[n], indent + 4, use_colors);
1586 : : }
1587 : 0 : if (o->properties != NULL)
1588 : : {
1589 : 0 : g_print ("%*s %sproperties%s:\n",
1590 : : indent, "",
1591 : : INTROSPECT_TITLE_COLOR, RESET_COLOR);
1592 : 0 : for (n = 0; o->properties[n] != NULL; n++)
1593 : : {
1594 : 0 : dump_property (o->properties[n],
1595 : : indent + 4,
1596 : : use_colors,
1597 : 0 : g_hash_table_lookup (properties, (o->properties[n])->name));
1598 : : }
1599 : : }
1600 : 0 : g_print ("%*s};\n",
1601 : : indent, "");
1602 : :
1603 : 0 : g_hash_table_unref (properties);
1604 : 0 : }
1605 : :
1606 : : static gboolean
1607 : : introspect_do (GDBusConnection *c,
1608 : : const gchar *object_path,
1609 : : guint indent,
1610 : : gboolean use_colors);
1611 : :
1612 : : static void
1613 : 0 : dump_node (GDBusConnection *c,
1614 : : const gchar *name,
1615 : : const GDBusNodeInfo *o,
1616 : : guint indent,
1617 : : gboolean use_colors,
1618 : : const gchar *object_path,
1619 : : gboolean recurse)
1620 : : {
1621 : : guint n;
1622 : : const gchar *object_path_to_print;
1623 : :
1624 : 0 : object_path_to_print = object_path;
1625 : 0 : if (o->path != NULL)
1626 : 0 : object_path_to_print = o->path;
1627 : :
1628 : 0 : for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
1629 : 0 : dump_annotation (o->annotations[n], indent, FALSE, use_colors);
1630 : :
1631 : 0 : g_print ("%*s%snode %s%s",
1632 : : indent, "",
1633 : : INTROSPECT_NODE_COLOR,
1634 : : object_path_to_print != NULL ? object_path_to_print : "(not set)",
1635 : : RESET_COLOR);
1636 : 0 : if (o->interfaces != NULL || o->nodes != NULL)
1637 : : {
1638 : 0 : g_print (" {\n");
1639 : 0 : for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
1640 : : {
1641 : 0 : if (opt_introspect_only_properties)
1642 : : {
1643 : 0 : if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
1644 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1645 : : }
1646 : : else
1647 : : {
1648 : 0 : dump_interface (c, name, o->interfaces[n], indent + 2, use_colors, object_path);
1649 : : }
1650 : : }
1651 : 0 : for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
1652 : : {
1653 : 0 : if (recurse)
1654 : : {
1655 : : gchar *child_path;
1656 : 0 : if (g_variant_is_object_path (o->nodes[n]->path))
1657 : : {
1658 : 0 : child_path = g_strdup (o->nodes[n]->path);
1659 : : /* avoid infinite loops */
1660 : 0 : if (g_str_has_prefix (child_path, object_path))
1661 : : {
1662 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1663 : : }
1664 : : else
1665 : : {
1666 : 0 : g_print ("Skipping path %s that is not enclosed by parent %s\n",
1667 : : child_path, object_path);
1668 : : }
1669 : : }
1670 : : else
1671 : : {
1672 : 0 : if (g_strcmp0 (object_path, "/") == 0)
1673 : 0 : child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
1674 : : else
1675 : 0 : child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
1676 : 0 : introspect_do (c, child_path, indent + 2, use_colors);
1677 : : }
1678 : 0 : g_free (child_path);
1679 : : }
1680 : : else
1681 : : {
1682 : 0 : dump_node (NULL, NULL, o->nodes[n], indent + 2, use_colors, NULL, recurse);
1683 : : }
1684 : : }
1685 : 0 : g_print ("%*s};\n",
1686 : : indent, "");
1687 : : }
1688 : : else
1689 : : {
1690 : 0 : g_print ("\n");
1691 : : }
1692 : 0 : }
1693 : :
1694 : : static const GOptionEntry introspect_entries[] =
1695 : : {
1696 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
1697 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
1698 : : { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
1699 : : { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
1700 : : { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
1701 : : G_OPTION_ENTRY_NULL
1702 : : };
1703 : :
1704 : : static gboolean
1705 : 0 : introspect_do (GDBusConnection *c,
1706 : : const gchar *object_path,
1707 : : guint indent,
1708 : : gboolean use_colors)
1709 : : {
1710 : : GError *error;
1711 : : GVariant *result;
1712 : : GDBusNodeInfo *node;
1713 : : gboolean ret;
1714 : : const gchar *xml_data;
1715 : :
1716 : 0 : ret = FALSE;
1717 : 0 : node = NULL;
1718 : 0 : result = NULL;
1719 : :
1720 : 0 : error = NULL;
1721 : 0 : result = g_dbus_connection_call_sync (c,
1722 : : opt_introspect_dest,
1723 : : object_path,
1724 : : DBUS_INTERFACE_INTROSPECTABLE,
1725 : : "Introspect",
1726 : : NULL,
1727 : : G_VARIANT_TYPE ("(s)"),
1728 : : G_DBUS_CALL_FLAGS_NONE,
1729 : : 3000, /* 3 sec */
1730 : : NULL,
1731 : : &error);
1732 : 0 : if (result == NULL)
1733 : : {
1734 : 0 : g_printerr (_("Error: %s\n"), error->message);
1735 : 0 : g_error_free (error);
1736 : 0 : goto out;
1737 : : }
1738 : 0 : g_variant_get (result, "(&s)", &xml_data);
1739 : :
1740 : 0 : if (opt_introspect_xml)
1741 : : {
1742 : 0 : g_print ("%s", xml_data);
1743 : : }
1744 : : else
1745 : : {
1746 : 0 : error = NULL;
1747 : 0 : node = g_dbus_node_info_new_for_xml (xml_data, &error);
1748 : 0 : if (node == NULL)
1749 : : {
1750 : 0 : g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
1751 : 0 : g_error_free (error);
1752 : 0 : goto out;
1753 : : }
1754 : :
1755 : 0 : dump_node (c, opt_introspect_dest, node, indent, use_colors, object_path, opt_introspect_recurse);
1756 : : }
1757 : :
1758 : 0 : ret = TRUE;
1759 : :
1760 : 0 : out:
1761 : 0 : if (node != NULL)
1762 : 0 : g_dbus_node_info_unref (node);
1763 : 0 : if (result != NULL)
1764 : 0 : g_variant_unref (result);
1765 : 0 : return ret;
1766 : : }
1767 : :
1768 : : static gboolean
1769 : 0 : handle_introspect (gint *argc,
1770 : : gchar **argv[],
1771 : : gboolean request_completion,
1772 : : const gchar *completion_cur,
1773 : : const gchar *completion_prev)
1774 : : {
1775 : : gint ret;
1776 : : GOptionContext *o;
1777 : : gchar *s;
1778 : : GError *error;
1779 : : GDBusConnection *c;
1780 : : gboolean complete_names;
1781 : : gboolean complete_paths;
1782 : : gboolean color_support;
1783 : :
1784 : 0 : ret = FALSE;
1785 : 0 : c = NULL;
1786 : :
1787 : 0 : modify_argv0_for_command (argc, argv, "introspect");
1788 : :
1789 : 0 : o = command_option_context_new (NULL, _("Introspect a remote object."),
1790 : : introspect_entries, request_completion);
1791 : 0 : g_option_context_add_group (o, connection_get_group ());
1792 : :
1793 : 0 : complete_names = FALSE;
1794 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
1795 : : {
1796 : 0 : complete_names = TRUE;
1797 : 0 : remove_arg ((*argc) - 1, argc, argv);
1798 : : }
1799 : :
1800 : 0 : complete_paths = FALSE;
1801 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
1802 : : {
1803 : 0 : complete_paths = TRUE;
1804 : 0 : remove_arg ((*argc) - 1, argc, argv);
1805 : : }
1806 : :
1807 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
1808 : : {
1809 : 0 : if (!request_completion)
1810 : : {
1811 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
1812 : 0 : g_printerr ("%s", s);
1813 : 0 : g_free (s);
1814 : 0 : goto out;
1815 : : }
1816 : : }
1817 : :
1818 : 0 : error = NULL;
1819 : 0 : c = connection_get_dbus_connection (TRUE, &error);
1820 : 0 : if (c == NULL)
1821 : : {
1822 : 0 : if (request_completion)
1823 : : {
1824 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
1825 : : {
1826 : 0 : g_print ("unix:\n"
1827 : : "tcp:\n"
1828 : : "nonce-tcp:\n");
1829 : : }
1830 : : else
1831 : : {
1832 : 0 : g_print ("--system \n--session \n--address \n");
1833 : : }
1834 : : }
1835 : : else
1836 : : {
1837 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
1838 : : }
1839 : 0 : g_error_free (error);
1840 : 0 : goto out;
1841 : : }
1842 : :
1843 : 0 : if (complete_names)
1844 : : {
1845 : 0 : print_names (c, FALSE);
1846 : 0 : goto out;
1847 : : }
1848 : : /* this only makes sense on message bus connections */
1849 : 0 : if (opt_introspect_dest == NULL)
1850 : : {
1851 : 0 : if (request_completion)
1852 : 0 : g_print ("--dest \n");
1853 : : else
1854 : 0 : g_printerr (_("Error: Destination is not specified\n"));
1855 : 0 : goto out;
1856 : : }
1857 : 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
1858 : : {
1859 : 0 : print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
1860 : 0 : goto out;
1861 : : }
1862 : :
1863 : 0 : if (complete_paths)
1864 : : {
1865 : 0 : print_paths (c, opt_introspect_dest, "/");
1866 : 0 : goto out;
1867 : : }
1868 : :
1869 : 0 : if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
1870 : : {
1871 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
1872 : 0 : goto out;
1873 : : }
1874 : :
1875 : 0 : if (opt_introspect_object_path == NULL)
1876 : : {
1877 : 0 : if (request_completion)
1878 : 0 : g_print ("--object-path \n");
1879 : : else
1880 : 0 : g_printerr (_("Error: Object path is not specified\n"));
1881 : 0 : goto out;
1882 : : }
1883 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
1884 : : {
1885 : : gchar *p;
1886 : 0 : s = g_strdup (opt_introspect_object_path);
1887 : 0 : p = strrchr (s, '/');
1888 : 0 : if (p != NULL)
1889 : : {
1890 : 0 : if (p == s)
1891 : 0 : p++;
1892 : 0 : *p = '\0';
1893 : : }
1894 : 0 : print_paths (c, opt_introspect_dest, s);
1895 : 0 : g_free (s);
1896 : 0 : goto out;
1897 : : }
1898 : 0 : if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
1899 : : {
1900 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
1901 : 0 : goto out;
1902 : : }
1903 : :
1904 : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
1905 : : {
1906 : 0 : g_print ("--recurse \n");
1907 : : }
1908 : :
1909 : 0 : if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
1910 : : {
1911 : 0 : g_print ("--only-properties \n");
1912 : : }
1913 : :
1914 : : /* All done with completion now */
1915 : 0 : if (request_completion)
1916 : 0 : goto out;
1917 : :
1918 : : /* Before we start printing the actual info, check if we can do colors*/
1919 : 0 : color_support = g_log_writer_supports_color (fileno (stdout));
1920 : :
1921 : 0 : if (!introspect_do (c, opt_introspect_object_path, 0, color_support))
1922 : 0 : goto out;
1923 : :
1924 : 0 : ret = TRUE;
1925 : :
1926 : 0 : out:
1927 : 0 : if (c != NULL)
1928 : 0 : g_object_unref (c);
1929 : 0 : g_option_context_free (o);
1930 : 0 : return ret;
1931 : : }
1932 : :
1933 : : /* ---------------------------------------------------------------------------------------------------- */
1934 : :
1935 : : static gchar *opt_monitor_dest = NULL;
1936 : : static gchar *opt_monitor_object_path = NULL;
1937 : :
1938 : : static guint monitor_filter_id = 0;
1939 : :
1940 : : static void
1941 : 0 : monitor_signal_cb (GDBusConnection *connection,
1942 : : const gchar *sender_name,
1943 : : const gchar *object_path,
1944 : : const gchar *interface_name,
1945 : : const gchar *signal_name,
1946 : : GVariant *parameters,
1947 : : gpointer user_data)
1948 : : {
1949 : : gchar *s;
1950 : 0 : s = g_variant_print (parameters, TRUE);
1951 : 0 : g_print ("%s: %s.%s %s\n",
1952 : : object_path,
1953 : : interface_name,
1954 : : signal_name,
1955 : : s);
1956 : 0 : g_free (s);
1957 : 0 : }
1958 : :
1959 : : static void
1960 : 0 : monitor_on_name_appeared (GDBusConnection *connection,
1961 : : const gchar *name,
1962 : : const gchar *name_owner,
1963 : : gpointer user_data)
1964 : : {
1965 : 0 : g_print ("The name %s is owned by %s\n", name, name_owner);
1966 : 0 : g_assert (monitor_filter_id == 0);
1967 : 0 : monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
1968 : : name_owner,
1969 : : NULL, /* any interface */
1970 : : NULL, /* any member */
1971 : : opt_monitor_object_path,
1972 : : NULL, /* arg0 */
1973 : : G_DBUS_SIGNAL_FLAGS_NONE,
1974 : : monitor_signal_cb,
1975 : : NULL, /* user_data */
1976 : : NULL); /* user_data destroy notify */
1977 : 0 : }
1978 : :
1979 : : static void
1980 : 0 : monitor_on_name_vanished (GDBusConnection *connection,
1981 : : const gchar *name,
1982 : : gpointer user_data)
1983 : : {
1984 : 0 : g_print ("The name %s does not have an owner\n", name);
1985 : :
1986 : 0 : if (monitor_filter_id != 0)
1987 : 0 : g_dbus_connection_signal_unsubscribe (connection, g_steal_handle_id (&monitor_filter_id));
1988 : 0 : }
1989 : :
1990 : : static const GOptionEntry monitor_entries[] =
1991 : : {
1992 : : { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
1993 : : { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
1994 : : G_OPTION_ENTRY_NULL
1995 : : };
1996 : :
1997 : : static gboolean
1998 : 0 : handle_monitor (gint *argc,
1999 : : gchar **argv[],
2000 : : gboolean request_completion,
2001 : : const gchar *completion_cur,
2002 : : const gchar *completion_prev)
2003 : : {
2004 : : gint ret;
2005 : : GOptionContext *o;
2006 : : gchar *s;
2007 : : GError *error;
2008 : : GDBusConnection *c;
2009 : : gboolean complete_names;
2010 : : gboolean complete_paths;
2011 : : GMainLoop *loop;
2012 : :
2013 : 0 : ret = FALSE;
2014 : 0 : c = NULL;
2015 : :
2016 : 0 : modify_argv0_for_command (argc, argv, "monitor");
2017 : :
2018 : 0 : o = command_option_context_new (NULL, _("Monitor a remote object."),
2019 : : monitor_entries, request_completion);
2020 : 0 : g_option_context_add_group (o, connection_get_group ());
2021 : :
2022 : 0 : complete_names = FALSE;
2023 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
2024 : : {
2025 : 0 : complete_names = TRUE;
2026 : 0 : remove_arg ((*argc) - 1, argc, argv);
2027 : : }
2028 : :
2029 : 0 : complete_paths = FALSE;
2030 : 0 : if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
2031 : : {
2032 : 0 : complete_paths = TRUE;
2033 : 0 : remove_arg ((*argc) - 1, argc, argv);
2034 : : }
2035 : :
2036 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2037 : : {
2038 : 0 : if (!request_completion)
2039 : : {
2040 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2041 : 0 : g_printerr ("%s", s);
2042 : 0 : g_free (s);
2043 : 0 : goto out;
2044 : : }
2045 : : }
2046 : :
2047 : 0 : error = NULL;
2048 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2049 : 0 : if (c == NULL)
2050 : : {
2051 : 0 : if (request_completion)
2052 : : {
2053 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2054 : : {
2055 : 0 : g_print ("unix:\n"
2056 : : "tcp:\n"
2057 : : "nonce-tcp:\n");
2058 : : }
2059 : : else
2060 : : {
2061 : 0 : g_print ("--system \n--session \n--address \n");
2062 : : }
2063 : : }
2064 : : else
2065 : : {
2066 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2067 : : }
2068 : 0 : g_error_free (error);
2069 : 0 : goto out;
2070 : : }
2071 : :
2072 : : /* Monitoring doesn’t make sense on a non-message-bus connection. */
2073 : 0 : if (g_dbus_connection_get_unique_name (c) == NULL)
2074 : : {
2075 : 0 : if (!request_completion)
2076 : 0 : g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
2077 : 0 : goto out;
2078 : : }
2079 : :
2080 : 0 : if (complete_names)
2081 : : {
2082 : 0 : print_names (c, FALSE);
2083 : 0 : goto out;
2084 : : }
2085 : : /* this only makes sense on message bus connections */
2086 : 0 : if (opt_monitor_dest == NULL)
2087 : : {
2088 : 0 : if (request_completion)
2089 : 0 : g_print ("--dest \n");
2090 : : else
2091 : 0 : g_printerr (_("Error: Destination is not specified\n"));
2092 : 0 : goto out;
2093 : : }
2094 : 0 : if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
2095 : : {
2096 : 0 : print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
2097 : 0 : goto out;
2098 : : }
2099 : :
2100 : 0 : if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
2101 : : {
2102 : 0 : g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
2103 : 0 : goto out;
2104 : : }
2105 : :
2106 : 0 : if (complete_paths)
2107 : : {
2108 : 0 : print_paths (c, opt_monitor_dest, "/");
2109 : 0 : goto out;
2110 : : }
2111 : 0 : if (opt_monitor_object_path == NULL)
2112 : : {
2113 : 0 : if (request_completion)
2114 : : {
2115 : 0 : g_print ("--object-path \n");
2116 : 0 : goto out;
2117 : : }
2118 : : /* it's fine to not have an object path */
2119 : : }
2120 : 0 : if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
2121 : : {
2122 : : gchar *p;
2123 : 0 : s = g_strdup (opt_monitor_object_path);
2124 : 0 : p = strrchr (s, '/');
2125 : 0 : if (p != NULL)
2126 : : {
2127 : 0 : if (p == s)
2128 : 0 : p++;
2129 : 0 : *p = '\0';
2130 : : }
2131 : 0 : print_paths (c, opt_monitor_dest, s);
2132 : 0 : g_free (s);
2133 : 0 : goto out;
2134 : : }
2135 : 0 : if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
2136 : : {
2137 : 0 : g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
2138 : 0 : goto out;
2139 : : }
2140 : :
2141 : : /* All done with completion now */
2142 : 0 : if (request_completion)
2143 : 0 : goto out;
2144 : :
2145 : 0 : if (opt_monitor_object_path != NULL)
2146 : 0 : g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
2147 : : else
2148 : 0 : g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
2149 : :
2150 : 0 : loop = g_main_loop_new (NULL, FALSE);
2151 : 0 : g_bus_watch_name_on_connection (c,
2152 : : opt_monitor_dest,
2153 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2154 : : monitor_on_name_appeared,
2155 : : monitor_on_name_vanished,
2156 : : NULL,
2157 : : NULL);
2158 : :
2159 : 0 : g_main_loop_run (loop);
2160 : 0 : g_main_loop_unref (loop);
2161 : :
2162 : 0 : ret = TRUE;
2163 : :
2164 : 0 : out:
2165 : 0 : if (c != NULL)
2166 : 0 : g_object_unref (c);
2167 : 0 : g_option_context_free (o);
2168 : 0 : return ret;
2169 : : }
2170 : :
2171 : : /* ---------------------------------------------------------------------------------------------------- */
2172 : :
2173 : : static gboolean opt_wait_activate_set = FALSE;
2174 : : static gchar *opt_wait_activate_name = NULL;
2175 : : static gint64 opt_wait_timeout_secs = 0; /* no timeout */
2176 : :
2177 : : typedef enum {
2178 : : WAIT_STATE_RUNNING, /* waiting to see the service */
2179 : : WAIT_STATE_SUCCESS, /* seen it successfully */
2180 : : WAIT_STATE_TIMEOUT, /* timed out before seeing it */
2181 : : } WaitState;
2182 : :
2183 : : static gboolean
2184 : 0 : opt_wait_activate_cb (const gchar *option_name,
2185 : : const gchar *value,
2186 : : gpointer data,
2187 : : GError **error)
2188 : : {
2189 : : /* @value may be NULL */
2190 : 0 : opt_wait_activate_set = TRUE;
2191 : 0 : opt_wait_activate_name = g_strdup (value);
2192 : :
2193 : 0 : return TRUE;
2194 : : }
2195 : :
2196 : : static const GOptionEntry wait_entries[] =
2197 : : {
2198 : : { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
2199 : : opt_wait_activate_cb,
2200 : : N_("Service to activate before waiting for the other one (well-known name)"),
2201 : : "[NAME]" },
2202 : : { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout_secs,
2203 : : N_("Timeout to wait for before exiting with an error (seconds); 0 for "
2204 : : "no timeout (default)"), "SECS" },
2205 : : G_OPTION_ENTRY_NULL
2206 : : };
2207 : :
2208 : : static void
2209 : 0 : wait_name_appeared_cb (GDBusConnection *connection,
2210 : : const gchar *name,
2211 : : const gchar *name_owner,
2212 : : gpointer user_data)
2213 : : {
2214 : 0 : WaitState *wait_state = user_data;
2215 : :
2216 : 0 : *wait_state = WAIT_STATE_SUCCESS;
2217 : 0 : }
2218 : :
2219 : : static gboolean
2220 : 0 : wait_timeout_cb (gpointer user_data)
2221 : : {
2222 : 0 : WaitState *wait_state = user_data;
2223 : :
2224 : 0 : *wait_state = WAIT_STATE_TIMEOUT;
2225 : :
2226 : : /* Removed in handle_wait(). */
2227 : 0 : return G_SOURCE_CONTINUE;
2228 : : }
2229 : :
2230 : : static gboolean
2231 : 0 : handle_wait (gint *argc,
2232 : : gchar **argv[],
2233 : : gboolean request_completion,
2234 : : const gchar *completion_cur,
2235 : : const gchar *completion_prev)
2236 : : {
2237 : : gint ret;
2238 : : GOptionContext *o;
2239 : : gchar *s;
2240 : : GError *error;
2241 : : GDBusConnection *c;
2242 : 0 : guint watch_id, timer_id = 0, activate_watch_id;
2243 : : const gchar *activate_service, *wait_service;
2244 : 0 : WaitState wait_state = WAIT_STATE_RUNNING;
2245 : :
2246 : 0 : ret = FALSE;
2247 : 0 : c = NULL;
2248 : :
2249 : 0 : modify_argv0_for_command (argc, argv, "wait");
2250 : :
2251 : 0 : o = command_option_context_new (_("[OPTION…] BUS-NAME"),
2252 : 0 : _("Wait for a bus name to appear."),
2253 : : wait_entries, request_completion);
2254 : 0 : g_option_context_add_group (o, connection_get_group ());
2255 : :
2256 : 0 : if (!g_option_context_parse (o, argc, argv, NULL))
2257 : : {
2258 : 0 : if (!request_completion)
2259 : : {
2260 : 0 : s = g_option_context_get_help (o, FALSE, NULL);
2261 : 0 : g_printerr ("%s", s);
2262 : 0 : g_free (s);
2263 : 0 : goto out;
2264 : : }
2265 : : }
2266 : :
2267 : 0 : error = NULL;
2268 : 0 : c = connection_get_dbus_connection (TRUE, &error);
2269 : 0 : if (c == NULL)
2270 : : {
2271 : 0 : if (request_completion)
2272 : : {
2273 : 0 : if (g_strcmp0 (completion_prev, "--address") == 0)
2274 : : {
2275 : 0 : g_print ("unix:\n"
2276 : : "tcp:\n"
2277 : : "nonce-tcp:\n");
2278 : : }
2279 : : else
2280 : : {
2281 : 0 : g_print ("--system \n--session \n--address \n");
2282 : : }
2283 : : }
2284 : : else
2285 : : {
2286 : 0 : g_printerr (_("Error connecting: %s\n"), error->message);
2287 : : }
2288 : 0 : g_error_free (error);
2289 : 0 : goto out;
2290 : : }
2291 : :
2292 : : /* All done with completion now */
2293 : 0 : if (request_completion)
2294 : 0 : goto out;
2295 : :
2296 : : /*
2297 : : * Try and disentangle the command line arguments, with the aim of supporting:
2298 : : * gdbus wait --session --activate ActivateName WaitName
2299 : : * gdbus wait --session --activate ActivateAndWaitName
2300 : : * gdbus wait --activate --session ActivateAndWaitName
2301 : : * gdbus wait --session WaitName
2302 : : */
2303 : 0 : if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
2304 : : {
2305 : 0 : activate_service = opt_wait_activate_name;
2306 : 0 : wait_service = (*argv)[1];
2307 : : }
2308 : 0 : else if (*argc == 2 &&
2309 : 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2310 : : {
2311 : 0 : activate_service = (*argv)[1];
2312 : 0 : wait_service = (*argv)[1];
2313 : : }
2314 : 0 : else if (*argc == 2 && !opt_wait_activate_set)
2315 : : {
2316 : 0 : activate_service = NULL; /* disabled */
2317 : 0 : wait_service = (*argv)[1];
2318 : : }
2319 : 0 : else if (*argc == 1 &&
2320 : 0 : opt_wait_activate_set && opt_wait_activate_name != NULL)
2321 : : {
2322 : 0 : activate_service = opt_wait_activate_name;
2323 : 0 : wait_service = opt_wait_activate_name;
2324 : : }
2325 : 0 : else if (*argc == 1 &&
2326 : 0 : opt_wait_activate_set && opt_wait_activate_name == NULL)
2327 : : {
2328 : 0 : g_printerr (_("Error: A service to activate for must be specified.\n"));
2329 : 0 : goto out;
2330 : : }
2331 : 0 : else if (*argc == 1 && !opt_wait_activate_set)
2332 : : {
2333 : 0 : g_printerr (_("Error: A service to wait for must be specified.\n"));
2334 : 0 : goto out;
2335 : : }
2336 : : else /* if (*argc > 2) */
2337 : : {
2338 : 0 : g_printerr (_("Error: Too many arguments.\n"));
2339 : 0 : goto out;
2340 : : }
2341 : :
2342 : 0 : if (activate_service != NULL &&
2343 : 0 : (!g_dbus_is_name (activate_service) ||
2344 : 0 : g_dbus_is_unique_name (activate_service)))
2345 : : {
2346 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2347 : : activate_service);
2348 : 0 : goto out;
2349 : : }
2350 : :
2351 : 0 : if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
2352 : : {
2353 : 0 : g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
2354 : : wait_service);
2355 : 0 : goto out;
2356 : : }
2357 : :
2358 : : /* Start the prerequisite service if needed. */
2359 : 0 : if (activate_service != NULL)
2360 : : {
2361 : 0 : activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
2362 : : G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
2363 : : NULL, NULL,
2364 : : NULL, NULL);
2365 : : }
2366 : : else
2367 : : {
2368 : 0 : activate_watch_id = 0;
2369 : : }
2370 : :
2371 : : /* Wait for the expected name to appear. */
2372 : 0 : watch_id = g_bus_watch_name_on_connection (c,
2373 : : wait_service,
2374 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
2375 : : wait_name_appeared_cb,
2376 : : NULL, &wait_state, NULL);
2377 : :
2378 : : /* Safety timeout. */
2379 : 0 : if (opt_wait_timeout_secs > 0)
2380 : 0 : timer_id = g_timeout_add_seconds (opt_wait_timeout_secs, wait_timeout_cb, &wait_state);
2381 : :
2382 : 0 : while (wait_state == WAIT_STATE_RUNNING)
2383 : 0 : g_main_context_iteration (NULL, TRUE);
2384 : :
2385 : 0 : g_bus_unwatch_name (watch_id);
2386 : 0 : if (timer_id != 0)
2387 : 0 : g_source_remove (timer_id);
2388 : 0 : if (activate_watch_id != 0)
2389 : 0 : g_bus_unwatch_name (activate_watch_id);
2390 : :
2391 : 0 : ret = (wait_state == WAIT_STATE_SUCCESS);
2392 : :
2393 : 0 : out:
2394 : 0 : g_clear_object (&c);
2395 : 0 : g_option_context_free (o);
2396 : 0 : g_free (opt_wait_activate_name);
2397 : 0 : opt_wait_activate_name = NULL;
2398 : :
2399 : 0 : return ret;
2400 : : }
2401 : :
2402 : : /* ---------------------------------------------------------------------------------------------------- */
2403 : :
2404 : : static gchar *
2405 : 0 : pick_word_at (const gchar *s,
2406 : : gint cursor,
2407 : : gint *out_word_begins_at)
2408 : : {
2409 : : gint begin;
2410 : : gint end;
2411 : :
2412 : 0 : if (s[0] == '\0')
2413 : : {
2414 : 0 : if (out_word_begins_at != NULL)
2415 : 0 : *out_word_begins_at = -1;
2416 : 0 : return NULL;
2417 : : }
2418 : :
2419 : 0 : if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
2420 : : {
2421 : 0 : if (out_word_begins_at != NULL)
2422 : 0 : *out_word_begins_at = cursor;
2423 : 0 : return g_strdup ("");
2424 : : }
2425 : :
2426 : 0 : while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
2427 : 0 : cursor--;
2428 : 0 : begin = cursor;
2429 : :
2430 : 0 : end = begin;
2431 : 0 : while (!g_ascii_isspace (s[end]) && s[end] != '\0')
2432 : 0 : end++;
2433 : :
2434 : 0 : if (out_word_begins_at != NULL)
2435 : 0 : *out_word_begins_at = begin;
2436 : :
2437 : 0 : return g_strndup (s + begin, end - begin);
2438 : : }
2439 : :
2440 : : gint
2441 : 0 : main (gint argc, gchar *argv[])
2442 : : {
2443 : : gint ret;
2444 : : const gchar *command;
2445 : : gboolean request_completion;
2446 : : gchar *completion_cur;
2447 : : gchar *completion_prev;
2448 : : #ifdef G_OS_WIN32
2449 : : gchar *tmp;
2450 : : #endif
2451 : :
2452 : 0 : setlocale (LC_ALL, "");
2453 : 0 : textdomain (GETTEXT_PACKAGE);
2454 : :
2455 : : #ifdef G_OS_WIN32
2456 : : tmp = _glib_get_locale_dir ();
2457 : : bindtextdomain (GETTEXT_PACKAGE, tmp);
2458 : : g_free (tmp);
2459 : : #else
2460 : 0 : bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
2461 : : #endif
2462 : :
2463 : : #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2464 : 0 : bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2465 : : #endif
2466 : :
2467 : 0 : ret = 1;
2468 : 0 : completion_cur = NULL;
2469 : 0 : completion_prev = NULL;
2470 : :
2471 : 0 : if (argc < 2)
2472 : : {
2473 : 0 : usage (&argc, &argv, FALSE);
2474 : 0 : goto out;
2475 : : }
2476 : :
2477 : 0 : request_completion = FALSE;
2478 : :
2479 : : //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
2480 : :
2481 : 0 : again:
2482 : 0 : command = argv[1];
2483 : 0 : if (g_strcmp0 (command, "help") == 0)
2484 : : {
2485 : 0 : if (request_completion)
2486 : : {
2487 : : /* do nothing */
2488 : : }
2489 : : else
2490 : : {
2491 : 0 : usage (&argc, &argv, TRUE);
2492 : 0 : ret = 0;
2493 : : }
2494 : 0 : goto out;
2495 : : }
2496 : 0 : else if (g_strcmp0 (command, "emit") == 0)
2497 : : {
2498 : 0 : if (handle_emit (&argc,
2499 : : &argv,
2500 : : request_completion,
2501 : : completion_cur,
2502 : : completion_prev))
2503 : 0 : ret = 0;
2504 : 0 : goto out;
2505 : : }
2506 : 0 : else if (g_strcmp0 (command, "call") == 0)
2507 : : {
2508 : 0 : if (handle_call (&argc,
2509 : : &argv,
2510 : : request_completion,
2511 : : completion_cur,
2512 : : completion_prev))
2513 : 0 : ret = 0;
2514 : 0 : goto out;
2515 : : }
2516 : 0 : else if (g_strcmp0 (command, "introspect") == 0)
2517 : : {
2518 : 0 : if (handle_introspect (&argc,
2519 : : &argv,
2520 : : request_completion,
2521 : : completion_cur,
2522 : : completion_prev))
2523 : 0 : ret = 0;
2524 : 0 : goto out;
2525 : : }
2526 : 0 : else if (g_strcmp0 (command, "monitor") == 0)
2527 : : {
2528 : 0 : if (handle_monitor (&argc,
2529 : : &argv,
2530 : : request_completion,
2531 : : completion_cur,
2532 : : completion_prev))
2533 : 0 : ret = 0;
2534 : 0 : goto out;
2535 : : }
2536 : 0 : else if (g_strcmp0 (command, "wait") == 0)
2537 : : {
2538 : 0 : if (handle_wait (&argc,
2539 : : &argv,
2540 : : request_completion,
2541 : : completion_cur,
2542 : : completion_prev))
2543 : 0 : ret = 0;
2544 : 0 : goto out;
2545 : : }
2546 : : #ifdef G_OS_WIN32
2547 : : else if (g_strcmp0 (command, _GDBUS_ARG_WIN32_RUN_SESSION_BUS) == 0)
2548 : : {
2549 : : g_win32_run_session_bus (NULL, NULL, NULL, 0);
2550 : : ret = 0;
2551 : : goto out;
2552 : : }
2553 : : #endif
2554 : 0 : else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
2555 : : {
2556 : : const gchar *completion_line;
2557 : : gchar **completion_argv;
2558 : : gint completion_argc;
2559 : : gint completion_point;
2560 : : gchar *endp;
2561 : : gint cur_begin;
2562 : :
2563 : 0 : request_completion = TRUE;
2564 : :
2565 : 0 : completion_line = argv[2];
2566 : 0 : completion_point = strtol (argv[3], &endp, 10);
2567 : 0 : if (endp == argv[3] || *endp != '\0')
2568 : 0 : goto out;
2569 : :
2570 : : #if 0
2571 : : completion_debug ("completion_point=%d", completion_point);
2572 : : completion_debug ("----");
2573 : : completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
2574 : : completion_debug ("'%s'", completion_line);
2575 : : completion_debug (" %*s^",
2576 : : completion_point, "");
2577 : : completion_debug ("----");
2578 : : #endif
2579 : :
2580 : 0 : if (!g_shell_parse_argv (completion_line,
2581 : : &completion_argc,
2582 : : &completion_argv,
2583 : : NULL))
2584 : : {
2585 : : /* it's very possible the command line can't be parsed (for
2586 : : * example, missing quotes etc) - in that case, we just
2587 : : * don't autocomplete at all
2588 : : */
2589 : 0 : goto out;
2590 : : }
2591 : :
2592 : : /* compute cur and prev */
2593 : 0 : completion_prev = NULL;
2594 : 0 : completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
2595 : 0 : if (cur_begin > 0)
2596 : : {
2597 : : gint prev_end;
2598 : 0 : for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
2599 : : {
2600 : 0 : if (!g_ascii_isspace (completion_line[prev_end]))
2601 : : {
2602 : 0 : completion_prev = pick_word_at (completion_line, prev_end, NULL);
2603 : 0 : break;
2604 : : }
2605 : : }
2606 : : }
2607 : : #if 0
2608 : : completion_debug (" cur='%s'", completion_cur);
2609 : : completion_debug ("prev='%s'", completion_prev);
2610 : : #endif
2611 : :
2612 : 0 : argc = completion_argc;
2613 : 0 : argv = completion_argv;
2614 : :
2615 : 0 : ret = 0;
2616 : :
2617 : 0 : goto again;
2618 : : }
2619 : : else
2620 : : {
2621 : 0 : if (request_completion)
2622 : : {
2623 : 0 : g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
2624 : 0 : ret = 0;
2625 : 0 : goto out;
2626 : : }
2627 : : else
2628 : : {
2629 : 0 : g_printerr ("Unknown command '%s'\n", command);
2630 : 0 : usage (&argc, &argv, FALSE);
2631 : 0 : goto out;
2632 : : }
2633 : : }
2634 : :
2635 : 0 : out:
2636 : 0 : g_free (completion_cur);
2637 : 0 : g_free (completion_prev);
2638 : 0 : return ret;
2639 : : }
|