/* GDBus - GLib D-Bus Library
*
- * Copyright (C) 2008-2009 Red Hat, Inc.
+ * Copyright (C) 2008-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
#include "config.h"
-#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <locale.h>
#include <gio/gio.h>
-#include <stdio.h>
-#include <stdlib.h>
+
+#include <gi18n.h>
+
+#ifdef G_OS_WIN32
+#include "glib/glib-private.h"
+#endif
/* ---------------------------------------------------------------------------------------------------- */
s = g_strdup_printf (_("Commands:\n"
" help Shows this information\n"
" introspect Introspect a remote object\n"
+ " monitor Monitor a remote object\n"
" call Invoke a method on a remote object\n"
+ " emit Emit a signal\n"
"\n"
"Use \"%s COMMAND --help\" to get help on each command.\n"),
program_name);
guint m;
error = NULL;
- result = g_dbus_connection_invoke_method_sync (c,
- name,
- path,
- "org.freedesktop.DBus.Introspectable",
- "Introspect",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 secs */
- NULL,
- &error);
+ result = g_dbus_connection_call_sync (c,
+ name,
+ path,
+ "org.freedesktop.DBus.Introspectable",
+ "Introspect",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 secs */
+ NULL,
+ &error);
if (result == NULL)
{
g_printerr (_("Error: %s\n"), error->message);
g_error_free (error);
goto out;
}
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
- {
- g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
- g_variant_get_type_string (result));
- g_variant_unref (result);
- goto out;
- }
- g_variant_get (result, "(s)", &xml_data);
+ g_variant_get (result, "(&s)", &xml_data);
error = NULL;
node = g_dbus_node_info_new_for_xml (xml_data, &error);
guint n;
error = NULL;
- result = g_dbus_connection_invoke_method_sync (c,
- name,
- path,
- "org.freedesktop.DBus.Introspectable",
- "Introspect",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 secs */
- NULL,
- &error);
+ result = g_dbus_connection_call_sync (c,
+ name,
+ path,
+ "org.freedesktop.DBus.Introspectable",
+ "Introspect",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 secs */
+ NULL,
+ &error);
if (result == NULL)
{
g_printerr (_("Error: %s\n"), error->message);
g_error_free (error);
goto out;
}
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
- {
- g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
- g_variant_get_type_string (result));
- g_variant_unref (result);
- goto out;
- }
- g_variant_get (result, "(s)", &xml_data);
+ g_variant_get (result, "(&s)", &xml_data);
+
+ //g_printerr ("xml='%s'", xml_data);
error = NULL;
node = g_dbus_node_info_new_for_xml (xml_data, &error);
goto out;
}
- //g_printerr ("xml=`%s'", xml_data);
-
- //g_printerr ("bar `%s'\n", path);
+ //g_printerr ("bar '%s'\n", path);
if (node->interfaces != NULL)
g_print ("%s \n", path);
{
gchar *s;
- //g_printerr ("foo `%s'\n", node->nodes[n].path);
+ //g_printerr ("foo '%s'\n", node->nodes[n].path);
if (g_strcmp0 (path, "/") == 0)
s = g_strdup_printf ("/%s", node->nodes[n]->path);
name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
error = NULL;
- result = g_dbus_connection_invoke_method_sync (c,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "ListNames",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 secs */
- NULL,
- &error);
+ result = g_dbus_connection_call_sync (c,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "ListNames",
+ NULL,
+ G_VARIANT_TYPE ("(as)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 secs */
+ NULL,
+ &error);
if (result == NULL)
{
g_printerr (_("Error: %s\n"), error->message);
g_error_free (error);
goto out;
}
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
- {
- g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
- g_variant_unref (result);
- goto out;
- }
g_variant_get (result, "(as)", &iter);
while (g_variant_iter_loop (iter, "s", &str))
g_hash_table_insert (name_set, g_strdup (str), NULL);
g_variant_unref (result);
error = NULL;
- result = g_dbus_connection_invoke_method_sync (c,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "ListActivatableNames",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 secs */
- NULL,
- &error);
+ result = g_dbus_connection_call_sync (c,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "ListActivatableNames",
+ NULL,
+ G_VARIANT_TYPE ("(as)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 secs */
+ NULL,
+ &error);
if (result == NULL)
{
g_printerr (_("Error: %s\n"), error->message);
g_error_free (error);
goto out;
}
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
- {
- g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
- g_variant_unref (result);
- goto out;
- }
g_variant_get (result, "(as)", &iter);
while (g_variant_iter_loop (iter, "s", &str))
g_hash_table_insert (name_set, g_strdup (str), NULL);
N_("Options specifying the connection endpoint"),
NULL,
NULL);
+ g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
g_option_group_add_entries (g, connection_entries);
+
return g;
}
{
c = g_dbus_connection_new_for_address_sync (opt_connection_address,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, /* GDBusAuthObserver */
NULL, /* GCancellable */
error);
}
GVariant *result;
GDBusNodeInfo *node_info;
const gchar *xml_data;
- const GDBusInterfaceInfo *interface_info;
- const GDBusMethodInfo *method_info;
+ GDBusInterfaceInfo *interface_info;
+ GDBusMethodInfo *method_info;
guint n;
ret = NULL;
result = NULL;
node_info = NULL;
- result = g_dbus_connection_invoke_method_sync (c,
- dest,
- path,
- "org.freedesktop.DBus.Introspectable",
- "Introspect",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 secs */
- NULL,
- error);
+ result = g_dbus_connection_call_sync (c,
+ dest,
+ path,
+ "org.freedesktop.DBus.Introspectable",
+ "Introspect",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 secs */
+ NULL,
+ error);
if (result == NULL)
goto out;
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Error: Result is type `%s', expected `(s)'\n"),
- g_variant_get_type_string (result));
- goto out;
- }
-
- g_variant_get (result, "(s)", &xml_data);
+ g_variant_get (result, "(&s)", &xml_data);
node_info = g_dbus_node_info_new_for_xml (xml_data, error);
if (node_info == NULL)
goto out;
if (interface_info == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Warning: According to introspection data, interface `%s' does not exist\n"),
+ _("Warning: According to introspection data, interface '%s' does not exist\n"),
interface_name);
goto out;
}
if (method_info == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Warning: According to introspection data, method `%s' does not exist on interface `%s'\n"),
+ _("Warning: According to introspection data, method '%s' does not exist on interface '%s'\n"),
method_name,
interface_name);
goto out;
/* ---------------------------------------------------------------------------------------------------- */
+static gchar *opt_emit_dest = NULL;
+static gchar *opt_emit_object_path = NULL;
+static gchar *opt_emit_signal = NULL;
+
+static const GOptionEntry emit_entries[] =
+{
+ { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
+ { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
+ { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
+ { NULL }
+};
+
+static gboolean
+handle_emit (gint *argc,
+ gchar **argv[],
+ gboolean request_completion,
+ const gchar *completion_cur,
+ const gchar *completion_prev)
+{
+ gint ret;
+ GOptionContext *o;
+ gchar *s;
+ GError *error;
+ GDBusConnection *c;
+ GVariant *parameters;
+ gchar *interface_name;
+ gchar *signal_name;
+ GVariantBuilder builder;
+ guint n;
+
+ ret = FALSE;
+ c = NULL;
+ parameters = NULL;
+ interface_name = NULL;
+ signal_name = NULL;
+
+ modify_argv0_for_command (argc, argv, "emit");
+
+ o = g_option_context_new (NULL);
+ g_option_context_set_help_enabled (o, FALSE);
+ g_option_context_set_summary (o, _("Emit a signal."));
+ g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (o, connection_get_group ());
+
+ if (!g_option_context_parse (o, argc, argv, NULL))
+ {
+ if (!request_completion)
+ {
+ s = g_option_context_get_help (o, FALSE, NULL);
+ g_printerr ("%s", s);
+ g_free (s);
+ goto out;
+ }
+ }
+
+ error = NULL;
+ c = connection_get_dbus_connection (&error);
+ if (c == NULL)
+ {
+ if (request_completion)
+ {
+ if (g_strcmp0 (completion_prev, "--address") == 0)
+ {
+ g_print ("unix:\n"
+ "tcp:\n"
+ "nonce-tcp:\n");
+ }
+ else
+ {
+ g_print ("--system \n--session \n--address \n");
+ }
+ }
+ else
+ {
+ g_printerr (_("Error connecting: %s\n"), error->message);
+ g_error_free (error);
+ }
+ goto out;
+ }
+
+ /* All done with completion now */
+ if (request_completion)
+ goto out;
+
+ if (opt_emit_object_path == NULL)
+ {
+ g_printerr (_("Error: object path not specified.\n"));
+ goto out;
+ }
+ if (!g_variant_is_object_path (opt_emit_object_path))
+ {
+ g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
+ goto out;
+ }
+
+ if (opt_emit_signal == NULL)
+ {
+ g_printerr (_("Error: signal not specified.\n"));
+ goto out;
+ }
+
+ s = strrchr (opt_emit_signal, '.');
+ if (s == NULL)
+ {
+ g_printerr (_("Error: signal must be the fully-qualified name.\n"));
+ goto out;
+ }
+ signal_name = g_strdup (s + 1);
+ interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
+
+ if (!g_dbus_is_interface_name (interface_name))
+ {
+ g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
+ goto out;
+ }
+
+ if (!g_dbus_is_member_name (signal_name))
+ {
+ g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
+ goto out;
+ }
+
+ if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
+ {
+ g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
+ goto out;
+ }
+
+ /* Read parameters */
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+ for (n = 1; n < (guint) *argc; n++)
+ {
+ GVariant *value;
+
+ error = NULL;
+ value = g_variant_parse (NULL,
+ (*argv)[n],
+ NULL,
+ NULL,
+ &error);
+ if (value == NULL)
+ {
+ gchar *context;
+
+ context = g_variant_parse_error_print_context (error, (*argv)[n]);
+ g_error_free (error);
+ error = NULL;
+ value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
+ if (value == NULL)
+ {
+ /* Use the original non-"parse-me-harder" error */
+ g_printerr (_("Error parsing parameter %d: %s\n"),
+ n,
+ context);
+ g_error_free (error);
+ g_free (context);
+ g_variant_builder_clear (&builder);
+ goto out;
+ }
+ g_free (context);
+ }
+ g_variant_builder_add_value (&builder, value);
+ }
+ parameters = g_variant_builder_end (&builder);
+
+ if (parameters != NULL)
+ parameters = g_variant_ref_sink (parameters);
+ if (!g_dbus_connection_emit_signal (c,
+ opt_emit_dest,
+ opt_emit_object_path,
+ interface_name,
+ signal_name,
+ parameters,
+ &error))
+ {
+ g_printerr (_("Error: %s\n"), error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (!g_dbus_connection_flush_sync (c, NULL, &error))
+ {
+ g_printerr (_("Error flushing connection: %s\n"), error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ if (c != NULL)
+ g_object_unref (c);
+ if (parameters != NULL)
+ g_variant_unref (parameters);
+ g_free (interface_name);
+ g_free (signal_name);
+ g_option_context_free (o);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static gchar *opt_call_dest = NULL;
static gchar *opt_call_object_path = NULL;
static gchar *opt_call_method = NULL;
+static gint opt_call_timeout = -1;
static const GOptionEntry call_entries[] =
{
{ "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
{ "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
{ "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
+ { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
{ NULL }
};
o = g_option_context_new (NULL);
g_option_context_set_help_enabled (o, FALSE);
g_option_context_set_summary (o, _("Invoke a method on a remote object."));
- g_option_context_add_main_entries (o, call_entries, NULL /* GETTEXT_PACKAGE*/);
+ g_option_context_add_main_entries (o, call_entries, GETTEXT_PACKAGE);
g_option_context_add_group (o, connection_get_group ());
complete_names = FALSE;
s = strrchr (opt_call_method, '.');
if (!request_completion && s == NULL)
{
- g_printerr (_("Error: Method name `%s' is invalid\n"), opt_call_method);
+ g_printerr (_("Error: Method name '%s' is invalid\n"), opt_call_method);
goto out;
}
method_name = g_strdup (s + 1);
&error);
if (value == NULL)
{
+ gchar *context;
+
+ context = g_variant_parse_error_print_context (error, (*argv)[n]);
g_error_free (error);
error = NULL;
value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
if (type != NULL)
{
s = g_variant_type_dup_string (type);
- g_printerr (_("Error parsing parameter %d of type `%s': %s\n"),
+ g_printerr (_("Error parsing parameter %d of type '%s': %s\n"),
n,
s,
- error->message);
+ context);
g_free (s);
}
else
{
g_printerr (_("Error parsing parameter %d: %s\n"),
n,
- error->message);
+ context);
}
g_error_free (error);
g_variant_builder_clear (&builder);
+ g_free (context);
goto out;
}
+ g_free (context);
}
g_variant_builder_add_value (&builder, value);
}
if (parameters != NULL)
parameters = g_variant_ref_sink (parameters);
- result = g_dbus_connection_invoke_method_sync (c,
- opt_call_dest,
- opt_call_object_path,
- interface_name,
- method_name,
- parameters,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- -1,
- NULL,
- &error);
+ result = g_dbus_connection_call_sync (c,
+ opt_call_dest,
+ opt_call_object_path,
+ interface_name,
+ method_name,
+ parameters,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
+ NULL,
+ &error);
if (result == NULL)
{
- g_printerr (_("Error: %s\n"), error->message);
- g_error_free (error);
+ if (error)
+ {
+ g_printerr (_("Error: %s\n"), error->message);
+ g_error_free (error);
+ }
if (in_signature_types != NULL)
{
GString *s;
g_variant_type_peek_string (type),
g_variant_type_get_string_length (type));
}
- g_printerr ("(According to introspection data, you need to pass `%s')\n", s->str);
+ g_printerr ("(According to introspection data, you need to pass '%s')\n", s->str);
g_string_free (s, TRUE);
}
goto out;
/* ---------------------------------------------------------------------------------------------------- */
-/* TODO: dump annotations */
+static gchar *opt_introspect_dest = NULL;
+static gchar *opt_introspect_object_path = NULL;
+static gboolean opt_introspect_xml = FALSE;
+static gboolean opt_introspect_recurse = FALSE;
+static gboolean opt_introspect_only_properties = FALSE;
+
+static void
+dump_annotation (const GDBusAnnotationInfo *o,
+ guint indent,
+ gboolean ignore_indent)
+{
+ guint n;
+ g_print ("%*s@%s(\"%s\")\n",
+ ignore_indent ? 0 : indent, "",
+ o->key,
+ o->value);
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent + 2, FALSE);
+}
static void
dump_arg (const GDBusArgInfo *o,
gboolean ignore_indent,
gboolean include_newline)
{
+ guint n;
+
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ {
+ dump_annotation (o->annotations[n], indent, ignore_indent);
+ ignore_indent = FALSE;
+ }
+
g_print ("%*s%s%s %s%s",
ignore_indent ? 0 : indent, "",
direction,
guint m;
guint name_len;
guint total_num_args;
+
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent, FALSE);
+
g_print ("%*s%s(", indent, "", o->name);
name_len = strlen (o->name);
total_num_args = count_args (o->in_args) + count_args (o->out_args);
{
gboolean ignore_indent = (m == 0);
gboolean include_newline = (m != total_num_args - 1);
+
dump_arg (o->in_args[n],
indent + name_len + 1,
"in ",
guint n;
guint name_len;
guint total_num_args;
+
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent, FALSE);
+
g_print ("%*s%s(", indent, "", o->name);
name_len = strlen (o->name);
total_num_args = count_args (o->args);
GVariant *value)
{
const gchar *access;
+ guint n;
+
if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
access = "readonly";
else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
access = "readwrite";
else
g_assert_not_reached ();
+
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent, FALSE);
+
if (value != NULL)
{
gchar *s = g_variant_print (value, FALSE);
(GDestroyNotify) g_variant_unref);
/* Try to get properties */
- if (c != NULL && name != NULL && object_path != NULL)
+ if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
{
GVariant *result;
- result = g_dbus_connection_invoke_method_sync (c,
- name,
- object_path,
- "org.freedesktop.DBus.Properties",
- "GetAll",
- g_variant_new ("(s)", o->name),
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000,
- NULL,
- NULL);
+ result = g_dbus_connection_call_sync (c,
+ name,
+ object_path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ g_variant_new ("(s)", o->name),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000,
+ NULL,
+ NULL);
if (result != NULL)
{
if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
&iter);
while ((item = g_variant_iter_next_value (iter)))
{
- const gchar *key;
+ gchar *key;
GVariant *value;
g_variant_get (item,
"{sv}",
&key,
&value);
- g_hash_table_insert (properties, g_strdup (key), g_variant_ref (value));
+ g_hash_table_insert (properties, key, g_variant_ref (value));
}
}
g_variant_unref (result);
}
+ else
+ {
+ guint n;
+ for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
+ {
+ result = g_dbus_connection_call_sync (c,
+ name,
+ object_path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)", o->name, o->properties[n]->name),
+ G_VARIANT_TYPE ("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000,
+ NULL,
+ NULL);
+ if (result != NULL)
+ {
+ GVariant *property_value;
+ g_variant_get (result,
+ "(v)",
+ &property_value);
+ g_hash_table_insert (properties,
+ g_strdup (o->properties[n]->name),
+ g_variant_ref (property_value));
+ g_variant_unref (result);
+ }
+ }
+ }
}
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent, FALSE);
+
g_print ("%*sinterface %s {\n", indent, "", o->name);
- if (o->methods != NULL)
+ if (o->methods != NULL && !opt_introspect_only_properties)
{
g_print ("%*s methods:\n", indent, "");
for (n = 0; o->methods[n] != NULL; n++)
dump_method (o->methods[n], indent + 4);
}
- if (o->signals != NULL)
+ if (o->signals != NULL && !opt_introspect_only_properties)
{
g_print ("%*s signals:\n", indent, "");
for (n = 0; o->signals[n] != NULL; n++)
g_hash_table_unref (properties);
}
+static gboolean
+introspect_do (GDBusConnection *c,
+ const gchar *object_path,
+ guint indent);
+
static void
dump_node (GDBusConnection *c,
const gchar *name,
const GDBusNodeInfo *o,
guint indent,
- const gchar *object_path)
+ const gchar *object_path,
+ gboolean recurse)
{
guint n;
const gchar *object_path_to_print;
if (o->path != NULL)
object_path_to_print = o->path;
+ for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
+ dump_annotation (o->annotations[n], indent, FALSE);
+
g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
if (o->interfaces != NULL || o->nodes != NULL)
{
g_print (" {\n");
for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
- dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+ {
+ if (opt_introspect_only_properties)
+ {
+ if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
+ dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+ }
+ else
+ {
+ dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
+ }
+ }
for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
- dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL);
+ {
+ if (recurse)
+ {
+ gchar *child_path;
+ if (g_variant_is_object_path (o->nodes[n]->path))
+ {
+ child_path = g_strdup (o->nodes[n]->path);
+ /* avoid infinite loops */
+ if (g_str_has_prefix (child_path, object_path))
+ {
+ introspect_do (c, child_path, indent + 2);
+ }
+ else
+ {
+ g_print ("Skipping path %s that is not enclosed by parent %s\n",
+ child_path, object_path);
+ }
+ }
+ else
+ {
+ if (g_strcmp0 (object_path, "/") == 0)
+ child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
+ else
+ child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
+ introspect_do (c, child_path, indent + 2);
+ }
+ g_free (child_path);
+ }
+ else
+ {
+ dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
+ }
+ }
g_print ("%*s};\n",
indent, "");
}
}
}
-static gchar *opt_introspect_dest = NULL;
-static gchar *opt_introspect_object_path = NULL;
-
static const GOptionEntry introspect_entries[] =
{
{ "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
{ "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
+ { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
+ { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
+ { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
{ NULL }
};
static gboolean
+introspect_do (GDBusConnection *c,
+ const gchar *object_path,
+ guint indent)
+{
+ GError *error;
+ GVariant *result;
+ GDBusNodeInfo *node;
+ gboolean ret;
+ const gchar *xml_data;
+
+ ret = FALSE;
+ node = NULL;
+ result = NULL;
+
+ error = NULL;
+ result = g_dbus_connection_call_sync (c,
+ opt_introspect_dest,
+ object_path,
+ "org.freedesktop.DBus.Introspectable",
+ "Introspect",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 3000, /* 3 sec */
+ NULL,
+ &error);
+ if (result == NULL)
+ {
+ g_printerr (_("Error: %s\n"), error->message);
+ g_error_free (error);
+ goto out;
+ }
+ g_variant_get (result, "(&s)", &xml_data);
+
+ if (opt_introspect_xml)
+ {
+ g_print ("%s", xml_data);
+ }
+ else
+ {
+ error = NULL;
+ node = g_dbus_node_info_new_for_xml (xml_data, &error);
+ if (node == NULL)
+ {
+ g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
+ }
+
+ ret = TRUE;
+
+ out:
+ if (node != NULL)
+ g_dbus_node_info_unref (node);
+ if (result != NULL)
+ g_variant_unref (result);
+ return ret;
+}
+
+static gboolean
handle_introspect (gint *argc,
gchar **argv[],
gboolean request_completion,
gchar *s;
GError *error;
GDBusConnection *c;
- GVariant *result;
- const gchar *xml_data;
- GDBusNodeInfo *node;
gboolean complete_names;
gboolean complete_paths;
ret = FALSE;
c = NULL;
- node = NULL;
- result = NULL;
modify_argv0_for_command (argc, argv, "introspect");
g_option_context_set_ignore_unknown_options (o, TRUE);
g_option_context_set_help_enabled (o, FALSE);
g_option_context_set_summary (o, _("Introspect a remote object."));
- g_option_context_add_main_entries (o, introspect_entries, NULL /* GETTEXT_PACKAGE*/);
+ g_option_context_add_main_entries (o, introspect_entries, GETTEXT_PACKAGE);
g_option_context_add_group (o, connection_get_group ());
complete_names = FALSE;
goto out;
}
+ if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
+ {
+ g_print ("--recurse \n");
+ }
+
+ if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
+ {
+ g_print ("--only-properties \n");
+ }
+
/* All done with completion now */
if (request_completion)
goto out;
- result = g_dbus_connection_invoke_method_sync (c,
- opt_introspect_dest,
- opt_introspect_object_path,
- "org.freedesktop.DBus.Introspectable",
- "Introspect",
- NULL,
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- 3000, /* 3 sec */
- NULL,
- &error);
- if (result == NULL)
+ if (!introspect_do (c, opt_introspect_object_path, 0))
+ goto out;
+
+ ret = TRUE;
+
+ out:
+ if (c != NULL)
+ g_object_unref (c);
+ g_option_context_free (o);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *opt_monitor_dest = NULL;
+static gchar *opt_monitor_object_path = NULL;
+
+static guint monitor_filter_id = 0;
+
+static void
+monitor_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ gchar *s;
+ s = g_variant_print (parameters, TRUE);
+ g_print ("%s: %s.%s %s\n",
+ object_path,
+ interface_name,
+ signal_name,
+ s);
+ g_free (s);
+}
+
+static void
+monitor_on_name_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ g_print ("The name %s is owned by %s\n", name, name_owner);
+ g_assert (monitor_filter_id == 0);
+ monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
+ name_owner,
+ NULL, /* any interface */
+ NULL, /* any member */
+ opt_monitor_object_path,
+ NULL, /* arg0 */
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ monitor_signal_cb,
+ NULL, /* user_data */
+ NULL); /* user_data destroy notify */
+}
+
+static void
+monitor_on_name_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_print ("The name %s does not have an owner\n", name);
+
+ if (monitor_filter_id != 0)
{
- g_printerr (_("Error: %s\n"), error->message);
- g_error_free (error);
- goto out;
+ g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
+ monitor_filter_id = 0;
}
- if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
+}
+
+static const GOptionEntry monitor_entries[] =
+{
+ { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
+ { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
+ { NULL }
+};
+
+static gboolean
+handle_monitor (gint *argc,
+ gchar **argv[],
+ gboolean request_completion,
+ const gchar *completion_cur,
+ const gchar *completion_prev)
+{
+ gint ret;
+ GOptionContext *o;
+ gchar *s;
+ GError *error;
+ GDBusConnection *c;
+ gboolean complete_names;
+ gboolean complete_paths;
+ GMainLoop *loop;
+
+ ret = FALSE;
+ c = NULL;
+
+ modify_argv0_for_command (argc, argv, "monitor");
+
+ o = g_option_context_new (NULL);
+ if (request_completion)
+ g_option_context_set_ignore_unknown_options (o, TRUE);
+ g_option_context_set_help_enabled (o, FALSE);
+ g_option_context_set_summary (o, _("Monitor a remote object."));
+ g_option_context_add_main_entries (o, monitor_entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (o, connection_get_group ());
+
+ complete_names = FALSE;
+ if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
{
- g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
- g_variant_get_type_string (result));
- goto out;
+ complete_names = TRUE;
+ remove_arg ((*argc) - 1, argc, argv);
+ }
+
+ complete_paths = FALSE;
+ if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
+ {
+ complete_paths = TRUE;
+ remove_arg ((*argc) - 1, argc, argv);
+ }
+
+ if (!g_option_context_parse (o, argc, argv, NULL))
+ {
+ if (!request_completion)
+ {
+ s = g_option_context_get_help (o, FALSE, NULL);
+ g_printerr ("%s", s);
+ g_free (s);
+ goto out;
+ }
}
- g_variant_get (result, "(s)", &xml_data);
error = NULL;
- node = g_dbus_node_info_new_for_xml (xml_data, &error);
- if (node == NULL)
+ c = connection_get_dbus_connection (&error);
+ if (c == NULL)
{
- g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
- g_error_free (error);
+ if (request_completion)
+ {
+ if (g_strcmp0 (completion_prev, "--address") == 0)
+ {
+ g_print ("unix:\n"
+ "tcp:\n"
+ "nonce-tcp:\n");
+ }
+ else
+ {
+ g_print ("--system \n--session \n--address \n");
+ }
+ }
+ else
+ {
+ g_printerr (_("Error connecting: %s\n"), error->message);
+ g_error_free (error);
+ }
+ goto out;
+ }
+
+ if (g_dbus_connection_get_unique_name (c) != NULL)
+ {
+ if (complete_names)
+ {
+ print_names (c, FALSE);
+ goto out;
+ }
+ /* this only makes sense on message bus connections */
+ if (opt_monitor_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
+ goto out;
+ }
+ }
+ if (complete_paths)
+ {
+ print_paths (c, opt_monitor_dest, "/");
+ goto out;
+ }
+ if (opt_monitor_object_path == NULL)
+ {
+ if (request_completion)
+ {
+ g_print ("--object-path \n");
+ goto out;
+ }
+ /* it's fine to not have an object path */
+ }
+ if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
+ {
+ gchar *p;
+ s = g_strdup (opt_monitor_object_path);
+ p = strrchr (s, '/');
+ if (p != NULL)
+ {
+ if (p == s)
+ p++;
+ *p = '\0';
+ }
+ print_paths (c, opt_monitor_dest, s);
+ g_free (s);
+ goto out;
+ }
+ if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
+ {
+ g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
goto out;
}
- dump_node (c, opt_introspect_dest, node, 0, opt_introspect_object_path);
+ /* All done with completion now */
+ if (request_completion)
+ goto out;
+
+ if (opt_monitor_object_path != NULL)
+ g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
+ else
+ g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_bus_watch_name_on_connection (c,
+ opt_monitor_dest,
+ G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+ monitor_on_name_appeared,
+ monitor_on_name_vanished,
+ NULL,
+ NULL);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
ret = TRUE;
out:
- if (node != NULL)
- g_dbus_node_info_unref (node);
- if (result != NULL)
- g_variant_unref (result);
if (c != NULL)
g_object_unref (c);
g_option_context_free (o);
gboolean request_completion;
gchar *completion_cur;
gchar *completion_prev;
+#ifdef G_OS_WIN32
+ gchar *tmp;
+#endif
+
+ setlocale (LC_ALL, "");
+ textdomain (GETTEXT_PACKAGE);
+
+#ifdef G_OS_WIN32
+ tmp = _glib_get_locale_dir ();
+ bindtextdomain (GETTEXT_PACKAGE, tmp);
+ g_free (tmp);
+#else
+ bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#endif
+
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
ret = 1;
completion_cur = NULL;
completion_prev = NULL;
- g_type_init ();
-
if (argc < 2)
{
usage (&argc, &argv, FALSE);
}
goto out;
}
+ else if (g_strcmp0 (command, "emit") == 0)
+ {
+ if (handle_emit (&argc,
+ &argv,
+ request_completion,
+ completion_cur,
+ completion_prev))
+ ret = 0;
+ goto out;
+ }
else if (g_strcmp0 (command, "call") == 0)
{
if (handle_call (&argc,
ret = 0;
goto out;
}
+ else if (g_strcmp0 (command, "monitor") == 0)
+ {
+ if (handle_monitor (&argc,
+ &argv,
+ request_completion,
+ completion_cur,
+ completion_prev))
+ ret = 0;
+ goto out;
+ }
else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
{
const gchar *completion_line;
completion_debug ("completion_point=%d", completion_point);
completion_debug ("----");
completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
- completion_debug ("`%s'", completion_line);
+ completion_debug ("'%s'", completion_line);
completion_debug (" %*s^",
completion_point, "");
completion_debug ("----");
}
}
#if 0
- completion_debug (" cur=`%s'", completion_cur);
- completion_debug ("prev=`%s'", completion_prev);
+ completion_debug (" cur='%s'", completion_cur);
+ completion_debug ("prev='%s'", completion_prev);
#endif
argc = completion_argc;
{
if (request_completion)
{
- g_print ("help \ncall \nintrospect \n");
+ g_print ("help \nemit \ncall \nintrospect \nmonitor \n");
ret = 0;
goto out;
}
else
{
- g_printerr ("Unknown command `%s'\n", command);
+ g_printerr ("Unknown command '%s'\n", command);
usage (&argc, &argv, FALSE);
goto out;
}