Blame gio/gdbus-tool.c

Packit ae235b
/* GDBus - GLib D-Bus Library
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2008-2010 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: David Zeuthen <davidz@redhat.com>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include <stdlib.h>
Packit ae235b
#include <string.h>
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <locale.h>
Packit ae235b
Packit ae235b
#include <gio/gio.h>
Packit ae235b
Packit ae235b
#include <gi18n.h>
Packit ae235b
Packit ae235b
#ifdef G_OS_WIN32
Packit ae235b
#include "glib/glib-private.h"
Packit ae235b
#endif
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
G_GNUC_UNUSED static void completion_debug (const gchar *format, ...);
Packit ae235b
Packit ae235b
/* Uncomment to get debug traces in /tmp/gdbus-completion-debug.txt (nice
Packit ae235b
 * to not have it interfere with stdout/stderr)
Packit ae235b
 */
Packit ae235b
#if 0
Packit ae235b
G_GNUC_UNUSED static void
Packit ae235b
completion_debug (const gchar *format, ...)
Packit ae235b
{
Packit ae235b
  va_list var_args;
Packit ae235b
  gchar *s;
Packit ae235b
  static FILE *f = NULL;
Packit ae235b
Packit ae235b
  va_start (var_args, format);
Packit ae235b
  s = g_strdup_vprintf (format, var_args);
Packit ae235b
  if (f == NULL)
Packit ae235b
    {
Packit ae235b
      f = fopen ("/tmp/gdbus-completion-debug.txt", "a+");
Packit ae235b
    }
Packit ae235b
  fprintf (f, "%s\n", s);
Packit ae235b
  g_free (s);
Packit ae235b
}
Packit ae235b
#else
Packit ae235b
static void
Packit ae235b
completion_debug (const gchar *format, ...)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
#endif
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
Packit ae235b
static void
Packit ae235b
remove_arg (gint num, gint *argc, gchar **argv[])
Packit ae235b
{
Packit ae235b
  gint n;
Packit ae235b
Packit ae235b
  g_assert (num <= (*argc));
Packit ae235b
Packit ae235b
  for (n = num; (*argv)[n] != NULL; n++)
Packit ae235b
    (*argv)[n] = (*argv)[n+1];
Packit ae235b
  (*argv)[n] = NULL;
Packit ae235b
  (*argc) = (*argc) - 1;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
usage (gint *argc, gchar **argv[], gboolean use_stdout)
Packit ae235b
{
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  gchar *program_name;
Packit ae235b
Packit ae235b
  o = g_option_context_new (_("COMMAND"));
Packit ae235b
  g_option_context_set_help_enabled (o, FALSE);
Packit ae235b
  /* Ignore parsing result */
Packit ae235b
  g_option_context_parse (o, argc, argv, NULL);
Packit ae235b
  program_name = g_path_get_basename ((*argv)[0]);
Packit ae235b
  s = g_strdup_printf (_("Commands:\n"
Packit ae235b
                         "  help         Shows this information\n"
Packit ae235b
                         "  introspect   Introspect a remote object\n"
Packit ae235b
                         "  monitor      Monitor a remote object\n"
Packit ae235b
                         "  call         Invoke a method on a remote object\n"
Packit ae235b
                         "  emit         Emit a signal\n"
Packit ae235b
                         "  wait         Wait for a bus name to appear\n"
Packit ae235b
                         "\n"
Packit ae235b
                         "Use “%s COMMAND --help” to get help on each command.\n"),
Packit ae235b
                       program_name);
Packit ae235b
  g_free (program_name);
Packit ae235b
  g_option_context_set_description (o, s);
Packit ae235b
  g_free (s);
Packit ae235b
  s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
  if (use_stdout)
Packit ae235b
    g_print ("%s", s);
Packit ae235b
  else
Packit ae235b
    g_printerr ("%s", s);
Packit ae235b
  g_free (s);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
Packit ae235b
{
Packit ae235b
  gchar *s;
Packit ae235b
  gchar *program_name;
Packit ae235b
Packit ae235b
  /* TODO:
Packit ae235b
   *  1. get a g_set_prgname() ?; or
Packit ae235b
   *  2. save old argv[0] and restore later
Packit ae235b
   */
Packit ae235b
Packit ae235b
  g_assert (g_strcmp0 ((*argv)[1], command) == 0);
Packit ae235b
  remove_arg (1, argc, argv);
Packit ae235b
Packit ae235b
  program_name = g_path_get_basename ((*argv)[0]);
Packit ae235b
  s = g_strdup_printf ("%s %s", (*argv)[0], command);
Packit ae235b
  (*argv)[0] = s;
Packit ae235b
  g_free (program_name);
Packit ae235b
}
Packit ae235b
Packit ae235b
static GOptionContext *
Packit ae235b
command_option_context_new (const gchar        *parameter_string,
Packit ae235b
                            const gchar        *summary,
Packit ae235b
                            const GOptionEntry *entries,
Packit ae235b
                            gboolean            request_completion)
Packit ae235b
{
Packit ae235b
  GOptionContext *o = NULL;
Packit ae235b
Packit ae235b
  o = g_option_context_new (parameter_string);
Packit ae235b
  if (request_completion)
Packit ae235b
    g_option_context_set_ignore_unknown_options (o, TRUE);
Packit ae235b
  g_option_context_set_help_enabled (o, FALSE);
Packit ae235b
  g_option_context_set_summary (o, summary);
Packit ae235b
  g_option_context_add_main_entries (o, entries, GETTEXT_PACKAGE);
Packit ae235b
Packit ae235b
  return g_steal_pointer (&o);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_methods_and_signals (GDBusConnection *c,
Packit ae235b
                           const gchar     *name,
Packit ae235b
                           const gchar     *path,
Packit ae235b
                           gboolean         print_methods,
Packit ae235b
                           gboolean         print_signals)
Packit ae235b
{
Packit ae235b
  GVariant *result;
Packit ae235b
  GError *error;
Packit ae235b
  const gchar *xml_data;
Packit ae235b
  GDBusNodeInfo *node;
Packit ae235b
  guint n;
Packit ae235b
  guint m;
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        name,
Packit ae235b
                                        path,
Packit ae235b
                                        "org.freedesktop.DBus.Introspectable",
Packit ae235b
                                        "Introspect",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(s)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 secs */
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  g_variant_get (result, "(&s)", &xml_data);
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  node = g_dbus_node_info_new_for_xml (xml_data, &error);
Packit ae235b
  g_variant_unref (result);
Packit ae235b
  if (node == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
Packit ae235b
    {
Packit ae235b
      const GDBusInterfaceInfo *iface = node->interfaces[n];
Packit ae235b
      for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++)
Packit ae235b
        {
Packit ae235b
          const GDBusMethodInfo *method = iface->methods[m];
Packit ae235b
          g_print ("%s.%s \n", iface->name, method->name);
Packit ae235b
        }
Packit ae235b
      for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++)
Packit ae235b
        {
Packit ae235b
          const GDBusSignalInfo *signal = iface->signals[m];
Packit ae235b
          g_print ("%s.%s \n", iface->name, signal->name);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  g_dbus_node_info_unref (node);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  ;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_paths (GDBusConnection *c,
Packit ae235b
             const gchar *name,
Packit ae235b
             const gchar *path)
Packit ae235b
{
Packit ae235b
  GVariant *result;
Packit ae235b
  GError *error;
Packit ae235b
  const gchar *xml_data;
Packit ae235b
  GDBusNodeInfo *node;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  if (!g_dbus_is_name (name))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid name\n"), name);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        name,
Packit ae235b
                                        path,
Packit ae235b
                                        "org.freedesktop.DBus.Introspectable",
Packit ae235b
                                        "Introspect",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(s)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 secs */
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  g_variant_get (result, "(&s)", &xml_data);
Packit ae235b
Packit ae235b
  //g_printerr ("xml='%s'", xml_data);
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  node = g_dbus_node_info_new_for_xml (xml_data, &error);
Packit ae235b
  g_variant_unref (result);
Packit ae235b
  if (node == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  //g_printerr ("bar '%s'\n", path);
Packit ae235b
Packit ae235b
  if (node->interfaces != NULL)
Packit ae235b
    g_print ("%s \n", path);
Packit ae235b
Packit ae235b
  for (n = 0; node->nodes != NULL && node->nodes[n] != NULL; n++)
Packit ae235b
    {
Packit ae235b
      gchar *s;
Packit ae235b
Packit ae235b
      //g_printerr ("foo '%s'\n", node->nodes[n].path);
Packit ae235b
Packit ae235b
      if (g_strcmp0 (path, "/") == 0)
Packit ae235b
        s = g_strdup_printf ("/%s", node->nodes[n]->path);
Packit ae235b
      else
Packit ae235b
        s = g_strdup_printf ("%s/%s", path, node->nodes[n]->path);
Packit ae235b
Packit ae235b
      print_paths (c, name, s);
Packit ae235b
Packit ae235b
      g_free (s);
Packit ae235b
    }
Packit ae235b
  g_dbus_node_info_unref (node);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  ;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_names (GDBusConnection *c,
Packit ae235b
             gboolean         include_unique_names)
Packit ae235b
{
Packit ae235b
  GVariant *result;
Packit ae235b
  GError *error;
Packit ae235b
  GVariantIter *iter;
Packit ae235b
  gchar *str;
Packit ae235b
  GHashTable *name_set;
Packit ae235b
  GList *keys;
Packit ae235b
  GList *l;
Packit ae235b
Packit ae235b
  name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        "org.freedesktop.DBus",
Packit ae235b
                                        "/org/freedesktop/DBus",
Packit ae235b
                                        "org.freedesktop.DBus",
Packit ae235b
                                        "ListNames",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(as)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 secs */
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  g_variant_get (result, "(as)", &iter);
Packit ae235b
  while (g_variant_iter_loop (iter, "s", &str))
Packit ae235b
    g_hash_table_add (name_set, g_strdup (str));
Packit ae235b
  g_variant_iter_free (iter);
Packit ae235b
  g_variant_unref (result);
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        "org.freedesktop.DBus",
Packit ae235b
                                        "/org/freedesktop/DBus",
Packit ae235b
                                        "org.freedesktop.DBus",
Packit ae235b
                                        "ListActivatableNames",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(as)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 secs */
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  g_variant_get (result, "(as)", &iter);
Packit ae235b
  while (g_variant_iter_loop (iter, "s", &str))
Packit ae235b
    g_hash_table_add (name_set, g_strdup (str));
Packit ae235b
  g_variant_iter_free (iter);
Packit ae235b
  g_variant_unref (result);
Packit ae235b
Packit ae235b
  keys = g_hash_table_get_keys (name_set);
Packit ae235b
  keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
Packit ae235b
  for (l = keys; l != NULL; l = l->next)
Packit ae235b
    {
Packit ae235b
      const gchar *name = l->data;
Packit ae235b
      if (!include_unique_names && g_str_has_prefix (name, ":"))
Packit ae235b
        continue;
Packit ae235b
Packit ae235b
      g_print ("%s \n", name);
Packit ae235b
    }
Packit ae235b
  g_list_free (keys);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  g_hash_table_unref (name_set);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gboolean  opt_connection_system  = FALSE;
Packit ae235b
static gboolean  opt_connection_session = FALSE;
Packit ae235b
static gchar    *opt_connection_address = NULL;
Packit ae235b
Packit ae235b
static const GOptionEntry connection_entries[] =
Packit ae235b
{
Packit ae235b
  { "system", 'y', 0, G_OPTION_ARG_NONE, &opt_connection_system, N_("Connect to the system bus"), NULL},
Packit ae235b
  { "session", 'e', 0, G_OPTION_ARG_NONE, &opt_connection_session, N_("Connect to the session bus"), NULL},
Packit ae235b
  { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_connection_address, N_("Connect to given D-Bus address"), NULL},
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static GOptionGroup *
Packit ae235b
connection_get_group (void)
Packit ae235b
{
Packit ae235b
  static GOptionGroup *g;
Packit ae235b
Packit ae235b
  g = g_option_group_new ("connection",
Packit ae235b
                          N_("Connection Endpoint Options:"),
Packit ae235b
                          N_("Options specifying the connection endpoint"),
Packit ae235b
                          NULL,
Packit ae235b
                          NULL);
Packit ae235b
  g_option_group_set_translation_domain (g, GETTEXT_PACKAGE);
Packit ae235b
  g_option_group_add_entries (g, connection_entries);
Packit ae235b
Packit ae235b
  return g;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GDBusConnection *
Packit ae235b
connection_get_dbus_connection (GError **error)
Packit ae235b
{
Packit ae235b
  GDBusConnection *c;
Packit ae235b
Packit ae235b
  c = NULL;
Packit ae235b
Packit ae235b
  /* First, ensure we have exactly one connect */
Packit ae235b
  if (!opt_connection_system && !opt_connection_session && opt_connection_address == NULL)
Packit ae235b
    {
Packit ae235b
      g_set_error (error,
Packit ae235b
                   G_IO_ERROR,
Packit ae235b
                   G_IO_ERROR_FAILED,
Packit ae235b
                   _("No connection endpoint specified"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if ((opt_connection_system && (opt_connection_session || opt_connection_address != NULL)) ||
Packit ae235b
           (opt_connection_session && (opt_connection_system || opt_connection_address != NULL)) ||
Packit ae235b
           (opt_connection_address != NULL && (opt_connection_system || opt_connection_session)))
Packit ae235b
    {
Packit ae235b
      g_set_error (error,
Packit ae235b
                   G_IO_ERROR,
Packit ae235b
                   G_IO_ERROR_FAILED,
Packit ae235b
                   _("Multiple connection endpoints specified"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (opt_connection_system)
Packit ae235b
    {
Packit ae235b
      c = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
Packit ae235b
    }
Packit ae235b
  else if (opt_connection_session)
Packit ae235b
    {
Packit ae235b
      c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
Packit ae235b
    }
Packit ae235b
  else if (opt_connection_address != NULL)
Packit ae235b
    {
Packit ae235b
      c = g_dbus_connection_new_for_address_sync (opt_connection_address,
Packit ae235b
                                                  G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
Packit ae235b
                                                  NULL, /* GDBusAuthObserver */
Packit ae235b
                                                  NULL, /* GCancellable */
Packit ae235b
                                                  error);
Packit ae235b
    }
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return c;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static GPtrArray *
Packit ae235b
call_helper_get_method_in_signature (GDBusConnection  *c,
Packit ae235b
                                     const gchar      *dest,
Packit ae235b
                                     const gchar      *path,
Packit ae235b
                                     const gchar      *interface_name,
Packit ae235b
                                     const gchar      *method_name,
Packit ae235b
                                     GError          **error)
Packit ae235b
{
Packit ae235b
  GPtrArray *ret;
Packit ae235b
  GVariant *result;
Packit ae235b
  GDBusNodeInfo *node_info;
Packit ae235b
  const gchar *xml_data;
Packit ae235b
  GDBusInterfaceInfo *interface_info;
Packit ae235b
  GDBusMethodInfo *method_info;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  ret = NULL;
Packit ae235b
  result = NULL;
Packit ae235b
  node_info = NULL;
Packit ae235b
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        dest,
Packit ae235b
                                        path,
Packit ae235b
                                        "org.freedesktop.DBus.Introspectable",
Packit ae235b
                                        "Introspect",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(s)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 secs */
Packit ae235b
                                        NULL,
Packit ae235b
                                        error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  g_variant_get (result, "(&s)", &xml_data);
Packit ae235b
  node_info = g_dbus_node_info_new_for_xml (xml_data, error);
Packit ae235b
  if (node_info == NULL)
Packit ae235b
      goto out;
Packit ae235b
Packit ae235b
  interface_info = g_dbus_node_info_lookup_interface (node_info, interface_name);
Packit ae235b
  if (interface_info == NULL)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Packit ae235b
                   _("Warning: According to introspection data, interface “%s” does not exist\n"),
Packit ae235b
                   interface_name);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  method_info = g_dbus_interface_info_lookup_method (interface_info, method_name);
Packit ae235b
  if (method_info == NULL)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Packit ae235b
                   _("Warning: According to introspection data, method “%s” does not exist on interface “%s”\n"),
Packit ae235b
                   method_name,
Packit ae235b
                   interface_name);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  ret = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_type_free);
Packit ae235b
  for (n = 0; method_info->in_args != NULL && method_info->in_args[n] != NULL; n++)
Packit ae235b
    {
Packit ae235b
      g_ptr_array_add (ret, g_variant_type_new (method_info->in_args[n]->signature));
Packit ae235b
    }
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (node_info != NULL)
Packit ae235b
    g_dbus_node_info_unref (node_info);
Packit ae235b
  if (result != NULL)
Packit ae235b
    g_variant_unref (result);
Packit ae235b
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static GVariant *
Packit ae235b
_g_variant_parse_me_harder (GVariantType   *type,
Packit ae235b
                            const gchar    *given_str,
Packit ae235b
                            GError        **error)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
  gchar *s;
Packit ae235b
  guint n;
Packit ae235b
  GString *str;
Packit ae235b
Packit ae235b
  str = g_string_new ("\"");
Packit ae235b
  for (n = 0; given_str[n] != '\0'; n++)
Packit ae235b
    {
Packit ae235b
      if (G_UNLIKELY (given_str[n] == '\"'))
Packit ae235b
        g_string_append (str, "\\\"");
Packit ae235b
      else
Packit ae235b
        g_string_append_c (str, given_str[n]);
Packit ae235b
    }
Packit ae235b
  g_string_append_c (str, '"');
Packit ae235b
  s = g_string_free (str, FALSE);
Packit ae235b
Packit ae235b
  value = g_variant_parse (type,
Packit ae235b
                           s,
Packit ae235b
                           NULL,
Packit ae235b
                           NULL,
Packit ae235b
                           error);
Packit ae235b
  g_free (s);
Packit ae235b
Packit ae235b
  return value;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gchar *opt_emit_dest = NULL;
Packit ae235b
static gchar *opt_emit_object_path = NULL;
Packit ae235b
static gchar *opt_emit_signal = NULL;
Packit ae235b
Packit ae235b
static const GOptionEntry emit_entries[] =
Packit ae235b
{
Packit ae235b
  { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_emit_dest, N_("Optional destination for signal (unique name)"), NULL},
Packit ae235b
  { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_emit_object_path, N_("Object path to emit signal on"), NULL},
Packit ae235b
  { "signal", 's', 0, G_OPTION_ARG_STRING, &opt_emit_signal, N_("Signal and interface name"), NULL},
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
handle_emit (gint        *argc,
Packit ae235b
             gchar      **argv[],
Packit ae235b
             gboolean     request_completion,
Packit ae235b
             const gchar *completion_cur,
Packit ae235b
             const gchar *completion_prev)
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  GError *error;
Packit ae235b
  GDBusConnection *c;
Packit ae235b
  GVariant *parameters;
Packit ae235b
  gchar *interface_name;
Packit ae235b
  gchar *signal_name;
Packit ae235b
  GVariantBuilder builder;
Packit ae235b
  gboolean skip_dashes;
Packit ae235b
  guint parm;
Packit ae235b
  guint n;
Packit ae235b
  gboolean complete_names, complete_paths, complete_signals;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  c = NULL;
Packit ae235b
  parameters = NULL;
Packit ae235b
  interface_name = NULL;
Packit ae235b
  signal_name = NULL;
Packit ae235b
Packit ae235b
  modify_argv0_for_command (argc, argv, "emit");
Packit ae235b
Packit ae235b
  o = command_option_context_new (NULL, _("Emit a signal."),
Packit ae235b
                                  emit_entries, request_completion);
Packit ae235b
  g_option_context_add_group (o, connection_get_group ());
Packit ae235b
Packit ae235b
  complete_names = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
Packit ae235b
    {
Packit ae235b
      complete_names = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_paths = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
Packit ae235b
    {
Packit ae235b
      complete_paths = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_signals = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
Packit ae235b
    {
Packit ae235b
      complete_signals = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_option_context_parse (o, argc, argv, NULL))
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        {
Packit ae235b
          s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
          g_printerr ("%s", s);
Packit ae235b
          g_free (s);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  c = connection_get_dbus_connection (&error);
Packit ae235b
  if (c == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 (completion_prev, "--address") == 0)
Packit ae235b
            {
Packit ae235b
              g_print ("unix:\n"
Packit ae235b
                       "tcp:\n"
Packit ae235b
                       "nonce-tcp:\n");
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              g_print ("--system \n--session \n--address \n");
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error connecting: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* validate and complete destination (bus name) */
Packit ae235b
  if (complete_names)
Packit ae235b
    {
Packit ae235b
      print_names (c, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && opt_emit_dest != NULL && g_strcmp0 ("--dest", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!request_completion && opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (opt_emit_dest == NULL && opt_emit_object_path == NULL && request_completion)
Packit ae235b
    {
Packit ae235b
      g_print ("--dest \n");
Packit ae235b
    }
Packit ae235b
  /* validate and complete object path */
Packit ae235b
  if (opt_emit_dest != NULL && complete_paths)
Packit ae235b
    {
Packit ae235b
      print_paths (c, opt_emit_dest, "/");
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_emit_object_path == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--object-path \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Object path is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      if (opt_emit_dest != NULL)
Packit ae235b
        {
Packit ae235b
          gchar *p;
Packit ae235b
          s = g_strdup (opt_emit_object_path);
Packit ae235b
          p = strrchr (s, '/');
Packit ae235b
          if (p != NULL)
Packit ae235b
            {
Packit ae235b
              if (p == s)
Packit ae235b
                p++;
Packit ae235b
              *p = '\0';
Packit ae235b
            }
Packit ae235b
          print_paths (c, opt_emit_dest, s);
Packit ae235b
          g_free (s);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* validate and complete signal (interface + signal name) */
Packit ae235b
  if (opt_emit_dest != NULL && opt_emit_object_path != NULL && complete_signals)
Packit ae235b
    {
Packit ae235b
      print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_emit_signal == NULL)
Packit ae235b
    {
Packit ae235b
      /* don't keep repeatedly completing --signal */
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 ("--signal", completion_prev) != 0)
Packit ae235b
            g_print ("--signal \n");
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error: Signal name is not specified\n"));
Packit ae235b
        }
Packit ae235b
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && opt_emit_dest != NULL && opt_emit_object_path != NULL &&
Packit ae235b
      g_strcmp0 ("--signal", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  s = strrchr (opt_emit_signal, '.');
Packit ae235b
  if (!request_completion && s == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  signal_name = g_strdup (s + 1);
Packit ae235b
  interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
Packit ae235b
Packit ae235b
  /* All done with completion now */
Packit ae235b
  if (request_completion)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (!g_dbus_is_interface_name (interface_name))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_dbus_is_member_name (signal_name))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid member name\n"), signal_name);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Read parameters */
Packit ae235b
  g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
Packit ae235b
  skip_dashes = TRUE;
Packit ae235b
  parm = 0;
Packit ae235b
  for (n = 1; n < (guint) *argc; n++)
Packit ae235b
    {
Packit ae235b
      GVariant *value;
Packit ae235b
Packit ae235b
      /* Under certain conditions, g_option_context_parse returns the "--"
Packit ae235b
         itself (setting off unparsed arguments), too: */
Packit ae235b
      if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
Packit ae235b
        {
Packit ae235b
          skip_dashes = FALSE;
Packit ae235b
          continue;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      error = NULL;
Packit ae235b
      value = g_variant_parse (NULL,
Packit ae235b
                               (*argv)[n],
Packit ae235b
                               NULL,
Packit ae235b
                               NULL,
Packit ae235b
                               &error);
Packit ae235b
      if (value == NULL)
Packit ae235b
        {
Packit ae235b
          gchar *context;
Packit ae235b
Packit ae235b
          context = g_variant_parse_error_print_context (error, (*argv)[n]);
Packit ae235b
          g_error_free (error);
Packit ae235b
          error = NULL;
Packit ae235b
          value = _g_variant_parse_me_harder (NULL, (*argv)[n], &error);
Packit ae235b
          if (value == NULL)
Packit ae235b
            {
Packit ae235b
              /* Use the original non-"parse-me-harder" error */
Packit ae235b
              g_printerr (_("Error parsing parameter %d: %s\n"),
Packit ae235b
                          parm + 1,
Packit ae235b
                          context);
Packit ae235b
              g_error_free (error);
Packit ae235b
              g_free (context);
Packit ae235b
              g_variant_builder_clear (&builder);
Packit ae235b
              goto out;
Packit ae235b
            }
Packit ae235b
          g_free (context);
Packit ae235b
        }
Packit ae235b
      g_variant_builder_add_value (&builder, value);
Packit ae235b
      ++parm;
Packit ae235b
    }
Packit ae235b
  parameters = g_variant_builder_end (&builder);
Packit ae235b
Packit ae235b
  if (parameters != NULL)
Packit ae235b
    parameters = g_variant_ref_sink (parameters);
Packit ae235b
  if (!g_dbus_connection_emit_signal (c,
Packit ae235b
                                      opt_emit_dest,
Packit ae235b
                                      opt_emit_object_path,
Packit ae235b
                                      interface_name,
Packit ae235b
                                      signal_name,
Packit ae235b
                                      parameters,
Packit ae235b
                                      &error))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_dbus_connection_flush_sync (c, NULL, &error))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error flushing connection: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (c != NULL)
Packit ae235b
    g_object_unref (c);
Packit ae235b
  if (parameters != NULL)
Packit ae235b
    g_variant_unref (parameters);
Packit ae235b
  g_free (interface_name);
Packit ae235b
  g_free (signal_name);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gchar *opt_call_dest = NULL;
Packit ae235b
static gchar *opt_call_object_path = NULL;
Packit ae235b
static gchar *opt_call_method = NULL;
Packit ae235b
static gint opt_call_timeout = -1;
Packit ae235b
Packit ae235b
static const GOptionEntry call_entries[] =
Packit ae235b
{
Packit ae235b
  { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_call_dest, N_("Destination name to invoke method on"), NULL},
Packit ae235b
  { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_call_object_path, N_("Object path to invoke method on"), NULL},
Packit ae235b
  { "method", 'm', 0, G_OPTION_ARG_STRING, &opt_call_method, N_("Method and interface name"), NULL},
Packit ae235b
  { "timeout", 't', 0, G_OPTION_ARG_INT, &opt_call_timeout, N_("Timeout in seconds"), NULL},
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
handle_call (gint        *argc,
Packit ae235b
             gchar      **argv[],
Packit ae235b
             gboolean     request_completion,
Packit ae235b
             const gchar *completion_cur,
Packit ae235b
             const gchar *completion_prev)
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  GError *error;
Packit ae235b
  GDBusConnection *c;
Packit ae235b
  GVariant *parameters;
Packit ae235b
  gchar *interface_name;
Packit ae235b
  gchar *method_name;
Packit ae235b
  GVariant *result;
Packit ae235b
  GPtrArray *in_signature_types;
Packit ae235b
  gboolean complete_names;
Packit ae235b
  gboolean complete_paths;
Packit ae235b
  gboolean complete_methods;
Packit ae235b
  GVariantBuilder builder;
Packit ae235b
  gboolean skip_dashes;
Packit ae235b
  guint parm;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  c = NULL;
Packit ae235b
  parameters = NULL;
Packit ae235b
  interface_name = NULL;
Packit ae235b
  method_name = NULL;
Packit ae235b
  result = NULL;
Packit ae235b
  in_signature_types = NULL;
Packit ae235b
Packit ae235b
  modify_argv0_for_command (argc, argv, "call");
Packit ae235b
Packit ae235b
  o = command_option_context_new (NULL, _("Invoke a method on a remote object."),
Packit ae235b
                                  call_entries, request_completion);
Packit ae235b
  g_option_context_add_group (o, connection_get_group ());
Packit ae235b
Packit ae235b
  complete_names = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
Packit ae235b
    {
Packit ae235b
      complete_names = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_paths = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
Packit ae235b
    {
Packit ae235b
      complete_paths = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_methods = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--method") == 0)
Packit ae235b
    {
Packit ae235b
      complete_methods = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_option_context_parse (o, argc, argv, NULL))
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        {
Packit ae235b
          s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
          g_printerr ("%s", s);
Packit ae235b
          g_free (s);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  c = connection_get_dbus_connection (&error);
Packit ae235b
  if (c == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 (completion_prev, "--address") == 0)
Packit ae235b
            {
Packit ae235b
              g_print ("unix:\n"
Packit ae235b
                       "tcp:\n"
Packit ae235b
                       "nonce-tcp:\n");
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              g_print ("--system \n--session \n--address \n");
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error connecting: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* validate and complete destination (bus name) */
Packit ae235b
  if (complete_names)
Packit ae235b
    {
Packit ae235b
      print_names (c, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_call_dest == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--dest \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Destination is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_names (c, g_str_has_prefix (opt_call_dest, ":"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!request_completion && !g_dbus_is_name (opt_call_dest))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid bus name\n"), opt_call_dest);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* validate and complete object path */
Packit ae235b
  if (complete_paths)
Packit ae235b
    {
Packit ae235b
      print_paths (c, opt_call_dest, "/");
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_call_object_path == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--object-path \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Object path is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      gchar *p;
Packit ae235b
      s = g_strdup (opt_call_object_path);
Packit ae235b
      p = strrchr (s, '/');
Packit ae235b
      if (p != NULL)
Packit ae235b
        {
Packit ae235b
          if (p == s)
Packit ae235b
            p++;
Packit ae235b
          *p = '\0';
Packit ae235b
        }
Packit ae235b
      print_paths (c, opt_call_dest, s);
Packit ae235b
      g_free (s);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (!request_completion && !g_variant_is_object_path (opt_call_object_path))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid object path\n"), opt_call_object_path);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* validate and complete method (interface + method name) */
Packit ae235b
  if (complete_methods)
Packit ae235b
    {
Packit ae235b
      print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_call_method == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--method \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Method name is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  s = strrchr (opt_call_method, '.');
Packit ae235b
  if (!request_completion && s == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: Method name “%s” is invalid\n"), opt_call_method);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  method_name = g_strdup (s + 1);
Packit ae235b
  interface_name = g_strndup (opt_call_method, s - opt_call_method);
Packit ae235b
Packit ae235b
  /* All done with completion now */
Packit ae235b
  if (request_completion)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  /* Introspect, for easy conversion - it's not fatal if we can't do this */
Packit ae235b
  in_signature_types = call_helper_get_method_in_signature (c,
Packit ae235b
                                                            opt_call_dest,
Packit ae235b
                                                            opt_call_object_path,
Packit ae235b
                                                            interface_name,
Packit ae235b
                                                            method_name,
Packit ae235b
                                                            &error);
Packit ae235b
  if (in_signature_types == NULL)
Packit ae235b
    {
Packit ae235b
      //g_printerr ("Error getting introspection data: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      error = NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Read parameters */
Packit ae235b
  g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
Packit ae235b
  skip_dashes = TRUE;
Packit ae235b
  parm = 0;
Packit ae235b
  for (n = 1; n < (guint) *argc; n++)
Packit ae235b
    {
Packit ae235b
      GVariant *value;
Packit ae235b
      GVariantType *type;
Packit ae235b
Packit ae235b
      /* Under certain conditions, g_option_context_parse returns the "--"
Packit ae235b
         itself (setting off unparsed arguments), too: */
Packit ae235b
      if (skip_dashes && g_strcmp0 ((*argv)[n], "--") == 0)
Packit ae235b
        {
Packit ae235b
          skip_dashes = FALSE;
Packit ae235b
          continue;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      type = NULL;
Packit ae235b
      if (in_signature_types != NULL)
Packit ae235b
        {
Packit ae235b
          if (parm >= in_signature_types->len)
Packit ae235b
            {
Packit ae235b
              /* Only warn for the first param */
Packit ae235b
              if (parm == in_signature_types->len)
Packit ae235b
                {
Packit ae235b
                  g_printerr ("Warning: Introspection data indicates %d parameters but more was passed\n",
Packit ae235b
                              in_signature_types->len);
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              type = in_signature_types->pdata[parm];
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
Packit ae235b
      error = NULL;
Packit ae235b
      value = g_variant_parse (type,
Packit ae235b
                               (*argv)[n],
Packit ae235b
                               NULL,
Packit ae235b
                               NULL,
Packit ae235b
                               &error);
Packit ae235b
      if (value == NULL)
Packit ae235b
        {
Packit ae235b
          gchar *context;
Packit ae235b
Packit ae235b
          context = g_variant_parse_error_print_context (error, (*argv)[n]);
Packit ae235b
          g_error_free (error);
Packit ae235b
          error = NULL;
Packit ae235b
          value = _g_variant_parse_me_harder (type, (*argv)[n], &error);
Packit ae235b
          if (value == NULL)
Packit ae235b
            {
Packit ae235b
              if (type != NULL)
Packit ae235b
                {
Packit ae235b
                  s = g_variant_type_dup_string (type);
Packit ae235b
                  g_printerr (_("Error parsing parameter %d of type “%s”: %s\n"),
Packit ae235b
                              parm + 1,
Packit ae235b
                              s,
Packit ae235b
                              context);
Packit ae235b
                  g_free (s);
Packit ae235b
                }
Packit ae235b
              else
Packit ae235b
                {
Packit ae235b
                  g_printerr (_("Error parsing parameter %d: %s\n"),
Packit ae235b
                              parm + 1,
Packit ae235b
                              context);
Packit ae235b
                }
Packit ae235b
              g_error_free (error);
Packit ae235b
              g_variant_builder_clear (&builder);
Packit ae235b
              g_free (context);
Packit ae235b
              goto out;
Packit ae235b
            }
Packit ae235b
          g_free (context);
Packit ae235b
        }
Packit ae235b
      g_variant_builder_add_value (&builder, value);
Packit ae235b
      ++parm;
Packit ae235b
    }
Packit ae235b
  parameters = g_variant_builder_end (&builder);
Packit ae235b
Packit ae235b
  if (parameters != NULL)
Packit ae235b
    parameters = g_variant_ref_sink (parameters);
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        opt_call_dest,
Packit ae235b
                                        opt_call_object_path,
Packit ae235b
                                        interface_name,
Packit ae235b
                                        method_name,
Packit ae235b
                                        parameters,
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        opt_call_timeout > 0 ? opt_call_timeout * 1000 : opt_call_timeout,
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
Packit ae235b
      if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) && in_signature_types != NULL)
Packit ae235b
        {
Packit ae235b
          if (in_signature_types->len > 0)
Packit ae235b
            {
Packit ae235b
              GString *s;
Packit ae235b
              s = g_string_new (NULL);
Packit ae235b
Packit ae235b
              for (n = 0; n < in_signature_types->len; n++)
Packit ae235b
                {
Packit ae235b
                  GVariantType *type = in_signature_types->pdata[n];
Packit ae235b
                  g_string_append_len (s,
Packit ae235b
                                       g_variant_type_peek_string (type),
Packit ae235b
                                       g_variant_type_get_string_length (type));
Packit ae235b
                }
Packit ae235b
Packit ae235b
              g_printerr ("(According to introspection data, you need to pass '%s')\n", s->str);
Packit ae235b
              g_string_free (s, TRUE);
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            g_printerr ("(According to introspection data, you need to pass no arguments)\n");
Packit ae235b
        }
Packit ae235b
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  s = g_variant_print (result, TRUE);
Packit ae235b
  g_print ("%s\n", s);
Packit ae235b
  g_free (s);
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (in_signature_types != NULL)
Packit ae235b
    g_ptr_array_unref (in_signature_types);
Packit ae235b
  if (result != NULL)
Packit ae235b
    g_variant_unref (result);
Packit ae235b
  if (c != NULL)
Packit ae235b
    g_object_unref (c);
Packit ae235b
  if (parameters != NULL)
Packit ae235b
    g_variant_unref (parameters);
Packit ae235b
  g_free (interface_name);
Packit ae235b
  g_free (method_name);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gchar *opt_introspect_dest = NULL;
Packit ae235b
static gchar *opt_introspect_object_path = NULL;
Packit ae235b
static gboolean opt_introspect_xml = FALSE;
Packit ae235b
static gboolean opt_introspect_recurse = FALSE;
Packit ae235b
static gboolean opt_introspect_only_properties = FALSE;
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_annotation (const GDBusAnnotationInfo *o,
Packit ae235b
                 guint indent,
Packit ae235b
                 gboolean ignore_indent)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  g_print ("%*s@%s(\"%s\")\n",
Packit ae235b
           ignore_indent ? 0 : indent, "",
Packit ae235b
           o->key,
Packit ae235b
           o->value);
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent + 2, FALSE);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_arg (const GDBusArgInfo *o,
Packit ae235b
          guint indent,
Packit ae235b
          const gchar *direction,
Packit ae235b
          gboolean ignore_indent,
Packit ae235b
          gboolean include_newline)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    {
Packit ae235b
      dump_annotation (o->annotations[n], indent, ignore_indent);
Packit ae235b
      ignore_indent = FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_print ("%*s%s%s %s%s",
Packit ae235b
           ignore_indent ? 0 : indent, "",
Packit ae235b
           direction,
Packit ae235b
           o->signature,
Packit ae235b
           o->name,
Packit ae235b
           include_newline ? ",\n" : "");
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint
Packit ae235b
count_args (GDBusArgInfo **args)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  n = 0;
Packit ae235b
  if (args == NULL)
Packit ae235b
    goto out;
Packit ae235b
  while (args[n] != NULL)
Packit ae235b
    n++;
Packit ae235b
 out:
Packit ae235b
  return n;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_method (const GDBusMethodInfo *o,
Packit ae235b
             guint                  indent)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  guint m;
Packit ae235b
  guint name_len;
Packit ae235b
  guint total_num_args;
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent, FALSE);
Packit ae235b
Packit ae235b
  g_print ("%*s%s(", indent, "", o->name);
Packit ae235b
  name_len = strlen (o->name);
Packit ae235b
  total_num_args = count_args (o->in_args) + count_args (o->out_args);
Packit ae235b
  for (n = 0, m = 0; o->in_args != NULL && o->in_args[n] != NULL; n++, m++)
Packit ae235b
    {
Packit ae235b
      gboolean ignore_indent = (m == 0);
Packit ae235b
      gboolean include_newline = (m != total_num_args - 1);
Packit ae235b
Packit ae235b
      dump_arg (o->in_args[n],
Packit ae235b
                indent + name_len + 1,
Packit ae235b
                "in  ",
Packit ae235b
                ignore_indent,
Packit ae235b
                include_newline);
Packit ae235b
    }
Packit ae235b
  for (n = 0; o->out_args != NULL && o->out_args[n] != NULL; n++, m++)
Packit ae235b
    {
Packit ae235b
      gboolean ignore_indent = (m == 0);
Packit ae235b
      gboolean include_newline = (m != total_num_args - 1);
Packit ae235b
      dump_arg (o->out_args[n],
Packit ae235b
                indent + name_len + 1,
Packit ae235b
                "out ",
Packit ae235b
                ignore_indent,
Packit ae235b
                include_newline);
Packit ae235b
    }
Packit ae235b
  g_print (");\n");
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_signal (const GDBusSignalInfo *o,
Packit ae235b
             guint                  indent)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  guint name_len;
Packit ae235b
  guint total_num_args;
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent, FALSE);
Packit ae235b
Packit ae235b
  g_print ("%*s%s(", indent, "", o->name);
Packit ae235b
  name_len = strlen (o->name);
Packit ae235b
  total_num_args = count_args (o->args);
Packit ae235b
  for (n = 0; o->args != NULL && o->args[n] != NULL; n++)
Packit ae235b
    {
Packit ae235b
      gboolean ignore_indent = (n == 0);
Packit ae235b
      gboolean include_newline = (n != total_num_args - 1);
Packit ae235b
      dump_arg (o->args[n],
Packit ae235b
                indent + name_len + 1,
Packit ae235b
                "",
Packit ae235b
                ignore_indent,
Packit ae235b
                include_newline);
Packit ae235b
    }
Packit ae235b
  g_print (");\n");
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_property (const GDBusPropertyInfo *o,
Packit ae235b
               guint                    indent,
Packit ae235b
               GVariant                *value)
Packit ae235b
{
Packit ae235b
  const gchar *access;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
Packit ae235b
    access = "readonly";
Packit ae235b
  else if (o->flags == G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
Packit ae235b
    access = "writeonly";
Packit ae235b
  else if (o->flags == (G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
Packit ae235b
    access = "readwrite";
Packit ae235b
  else
Packit ae235b
    g_assert_not_reached ();
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent, FALSE);
Packit ae235b
Packit ae235b
  if (value != NULL)
Packit ae235b
    {
Packit ae235b
      gchar *s = g_variant_print (value, FALSE);
Packit ae235b
      g_print ("%*s%s %s %s = %s;\n", indent, "", access, o->signature, o->name, s);
Packit ae235b
      g_free (s);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_print ("%*s%s %s %s;\n", indent, "", access, o->signature, o->name);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_interface (GDBusConnection          *c,
Packit ae235b
                const gchar              *name,
Packit ae235b
                const GDBusInterfaceInfo *o,
Packit ae235b
                guint                     indent,
Packit ae235b
                const gchar              *object_path)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  GHashTable *properties;
Packit ae235b
Packit ae235b
  properties = g_hash_table_new_full (g_str_hash,
Packit ae235b
                                      g_str_equal,
Packit ae235b
                                      g_free,
Packit ae235b
                                      (GDestroyNotify) g_variant_unref);
Packit ae235b
Packit ae235b
  /* Try to get properties */
Packit ae235b
  if (c != NULL && name != NULL && object_path != NULL && o->properties != NULL)
Packit ae235b
    {
Packit ae235b
      GVariant *result;
Packit ae235b
      result = g_dbus_connection_call_sync (c,
Packit ae235b
                                            name,
Packit ae235b
                                            object_path,
Packit ae235b
                                            "org.freedesktop.DBus.Properties",
Packit ae235b
                                            "GetAll",
Packit ae235b
                                            g_variant_new ("(s)", o->name),
Packit ae235b
                                            NULL,
Packit ae235b
                                            G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                            3000,
Packit ae235b
                                            NULL,
Packit ae235b
                                            NULL);
Packit ae235b
      if (result != NULL)
Packit ae235b
        {
Packit ae235b
          if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(a{sv})")))
Packit ae235b
            {
Packit ae235b
              GVariantIter *iter;
Packit ae235b
              GVariant *item;
Packit ae235b
              g_variant_get (result,
Packit ae235b
                             "(a{sv})",
Packit ae235b
                             &iter);
Packit ae235b
              while ((item = g_variant_iter_next_value (iter)))
Packit ae235b
                {
Packit ae235b
                  gchar *key;
Packit ae235b
                  GVariant *value;
Packit ae235b
                  g_variant_get (item,
Packit ae235b
                                 "{sv}",
Packit ae235b
                                 &key,
Packit ae235b
                                 &value);
Packit ae235b
Packit ae235b
                  g_hash_table_insert (properties, key, g_variant_ref (value));
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
          g_variant_unref (result);
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          guint n;
Packit ae235b
          for (n = 0; o->properties != NULL && o->properties[n] != NULL; n++)
Packit ae235b
            {
Packit ae235b
              result = g_dbus_connection_call_sync (c,
Packit ae235b
                                                    name,
Packit ae235b
                                                    object_path,
Packit ae235b
                                                    "org.freedesktop.DBus.Properties",
Packit ae235b
                                                    "Get",
Packit ae235b
                                                    g_variant_new ("(ss)", o->name, o->properties[n]->name),
Packit ae235b
                                                    G_VARIANT_TYPE ("(v)"),
Packit ae235b
                                                    G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                                    3000,
Packit ae235b
                                                    NULL,
Packit ae235b
                                                    NULL);
Packit ae235b
              if (result != NULL)
Packit ae235b
                {
Packit ae235b
                  GVariant *property_value;
Packit ae235b
                  g_variant_get (result,
Packit ae235b
                                 "(v)",
Packit ae235b
                                 &property_value);
Packit ae235b
                  g_hash_table_insert (properties,
Packit ae235b
                                       g_strdup (o->properties[n]->name),
Packit ae235b
                                       g_variant_ref (property_value));
Packit ae235b
                  g_variant_unref (result);
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent, FALSE);
Packit ae235b
Packit ae235b
  g_print ("%*sinterface %s {\n", indent, "", o->name);
Packit ae235b
  if (o->methods != NULL && !opt_introspect_only_properties)
Packit ae235b
    {
Packit ae235b
      g_print ("%*s  methods:\n", indent, "");
Packit ae235b
      for (n = 0; o->methods[n] != NULL; n++)
Packit ae235b
        dump_method (o->methods[n], indent + 4);
Packit ae235b
    }
Packit ae235b
  if (o->signals != NULL && !opt_introspect_only_properties)
Packit ae235b
    {
Packit ae235b
      g_print ("%*s  signals:\n", indent, "");
Packit ae235b
      for (n = 0; o->signals[n] != NULL; n++)
Packit ae235b
        dump_signal (o->signals[n], indent + 4);
Packit ae235b
    }
Packit ae235b
  if (o->properties != NULL)
Packit ae235b
    {
Packit ae235b
      g_print ("%*s  properties:\n", indent, "");
Packit ae235b
      for (n = 0; o->properties[n] != NULL; n++)
Packit ae235b
        {
Packit ae235b
          dump_property (o->properties[n],
Packit ae235b
                         indent + 4,
Packit ae235b
                         g_hash_table_lookup (properties, (o->properties[n])->name));
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  g_print ("%*s};\n",
Packit ae235b
           indent, "");
Packit ae235b
Packit ae235b
  g_hash_table_unref (properties);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
introspect_do (GDBusConnection *c,
Packit ae235b
               const gchar     *object_path,
Packit ae235b
               guint            indent);
Packit ae235b
Packit ae235b
static void
Packit ae235b
dump_node (GDBusConnection      *c,
Packit ae235b
           const gchar          *name,
Packit ae235b
           const GDBusNodeInfo  *o,
Packit ae235b
           guint                 indent,
Packit ae235b
           const gchar          *object_path,
Packit ae235b
           gboolean              recurse)
Packit ae235b
{
Packit ae235b
  guint n;
Packit ae235b
  const gchar *object_path_to_print;
Packit ae235b
Packit ae235b
  object_path_to_print = object_path;
Packit ae235b
  if (o->path != NULL)
Packit ae235b
    object_path_to_print = o->path;
Packit ae235b
Packit ae235b
  for (n = 0; o->annotations != NULL && o->annotations[n] != NULL; n++)
Packit ae235b
    dump_annotation (o->annotations[n], indent, FALSE);
Packit ae235b
Packit ae235b
  g_print ("%*snode %s", indent, "", object_path_to_print != NULL ? object_path_to_print : "(not set)");
Packit ae235b
  if (o->interfaces != NULL || o->nodes != NULL)
Packit ae235b
    {
Packit ae235b
      g_print (" {\n");
Packit ae235b
      for (n = 0; o->interfaces != NULL && o->interfaces[n] != NULL; n++)
Packit ae235b
        {
Packit ae235b
          if (opt_introspect_only_properties)
Packit ae235b
            {
Packit ae235b
              if (o->interfaces[n]->properties != NULL && o->interfaces[n]->properties[0] != NULL)
Packit ae235b
                dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              dump_interface (c, name, o->interfaces[n], indent + 2, object_path);
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      for (n = 0; o->nodes != NULL && o->nodes[n] != NULL; n++)
Packit ae235b
        {
Packit ae235b
          if (recurse)
Packit ae235b
            {
Packit ae235b
              gchar *child_path;
Packit ae235b
              if (g_variant_is_object_path (o->nodes[n]->path))
Packit ae235b
                {
Packit ae235b
                  child_path = g_strdup (o->nodes[n]->path);
Packit ae235b
                  /* avoid infinite loops */
Packit ae235b
                  if (g_str_has_prefix (child_path, object_path))
Packit ae235b
                    {
Packit ae235b
                      introspect_do (c, child_path, indent + 2);
Packit ae235b
                    }
Packit ae235b
                  else
Packit ae235b
                    {
Packit ae235b
                      g_print ("Skipping path %s that is not enclosed by parent %s\n",
Packit ae235b
                               child_path, object_path);
Packit ae235b
                    }
Packit ae235b
                }
Packit ae235b
              else
Packit ae235b
                {
Packit ae235b
                  if (g_strcmp0 (object_path, "/") == 0)
Packit ae235b
                    child_path = g_strdup_printf ("/%s", o->nodes[n]->path);
Packit ae235b
                  else
Packit ae235b
                    child_path = g_strdup_printf ("%s/%s", object_path, o->nodes[n]->path);
Packit ae235b
                  introspect_do (c, child_path, indent + 2);
Packit ae235b
                }
Packit ae235b
              g_free (child_path);
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              dump_node (NULL, NULL, o->nodes[n], indent + 2, NULL, recurse);
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      g_print ("%*s};\n",
Packit ae235b
               indent, "");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_print ("\n");
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static const GOptionEntry introspect_entries[] =
Packit ae235b
{
Packit ae235b
  { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_introspect_dest, N_("Destination name to introspect"), NULL},
Packit ae235b
  { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_introspect_object_path, N_("Object path to introspect"), NULL},
Packit ae235b
  { "xml", 'x', 0, G_OPTION_ARG_NONE, &opt_introspect_xml, N_("Print XML"), NULL},
Packit ae235b
  { "recurse", 'r', 0, G_OPTION_ARG_NONE, &opt_introspect_recurse, N_("Introspect children"), NULL},
Packit ae235b
  { "only-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_introspect_only_properties, N_("Only print properties"), NULL},
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
introspect_do (GDBusConnection *c,
Packit ae235b
               const gchar     *object_path,
Packit ae235b
               guint            indent)
Packit ae235b
{
Packit ae235b
  GError *error;
Packit ae235b
  GVariant *result;
Packit ae235b
  GDBusNodeInfo *node;
Packit ae235b
  gboolean ret;
Packit ae235b
  const gchar *xml_data;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  node = NULL;
Packit ae235b
  result = NULL;
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  result = g_dbus_connection_call_sync (c,
Packit ae235b
                                        opt_introspect_dest,
Packit ae235b
                                        object_path,
Packit ae235b
                                        "org.freedesktop.DBus.Introspectable",
Packit ae235b
                                        "Introspect",
Packit ae235b
                                        NULL,
Packit ae235b
                                        G_VARIANT_TYPE ("(s)"),
Packit ae235b
                                        G_DBUS_CALL_FLAGS_NONE,
Packit ae235b
                                        3000, /* 3 sec */
Packit ae235b
                                        NULL,
Packit ae235b
                                        &error);
Packit ae235b
  if (result == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s\n"), error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  g_variant_get (result, "(&s)", &xml_data);
Packit ae235b
Packit ae235b
  if (opt_introspect_xml)
Packit ae235b
    {
Packit ae235b
      g_print ("%s", xml_data);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      node = g_dbus_node_info_new_for_xml (xml_data, &error);
Packit ae235b
      if (node == NULL)
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error parsing introspection XML: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      dump_node (c, opt_introspect_dest, node, indent, object_path, opt_introspect_recurse);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (node != NULL)
Packit ae235b
    g_dbus_node_info_unref (node);
Packit ae235b
  if (result != NULL)
Packit ae235b
    g_variant_unref (result);
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
handle_introspect (gint        *argc,
Packit ae235b
                   gchar      **argv[],
Packit ae235b
                   gboolean     request_completion,
Packit ae235b
                   const gchar *completion_cur,
Packit ae235b
                   const gchar *completion_prev)
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  GError *error;
Packit ae235b
  GDBusConnection *c;
Packit ae235b
  gboolean complete_names;
Packit ae235b
  gboolean complete_paths;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  c = NULL;
Packit ae235b
Packit ae235b
  modify_argv0_for_command (argc, argv, "introspect");
Packit ae235b
Packit ae235b
  o = command_option_context_new (NULL, _("Introspect a remote object."),
Packit ae235b
                                  introspect_entries, request_completion);
Packit ae235b
  g_option_context_add_group (o, connection_get_group ());
Packit ae235b
Packit ae235b
  complete_names = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
Packit ae235b
    {
Packit ae235b
      complete_names = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_paths = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
Packit ae235b
    {
Packit ae235b
      complete_paths = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_option_context_parse (o, argc, argv, NULL))
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        {
Packit ae235b
          s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
          g_printerr ("%s", s);
Packit ae235b
          g_free (s);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  c = connection_get_dbus_connection (&error);
Packit ae235b
  if (c == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 (completion_prev, "--address") == 0)
Packit ae235b
            {
Packit ae235b
              g_print ("unix:\n"
Packit ae235b
                       "tcp:\n"
Packit ae235b
                       "nonce-tcp:\n");
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              g_print ("--system \n--session \n--address \n");
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error connecting: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (complete_names)
Packit ae235b
    {
Packit ae235b
      print_names (c, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  /* this only makes sense on message bus connections */
Packit ae235b
  if (opt_introspect_dest == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--dest \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Destination is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (complete_paths)
Packit ae235b
    {
Packit ae235b
      print_paths (c, opt_introspect_dest, "/");
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (opt_introspect_object_path == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--object-path \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Object path is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      gchar *p;
Packit ae235b
      s = g_strdup (opt_introspect_object_path);
Packit ae235b
      p = strrchr (s, '/');
Packit ae235b
      if (p != NULL)
Packit ae235b
        {
Packit ae235b
          if (p == s)
Packit ae235b
            p++;
Packit ae235b
          *p = '\0';
Packit ae235b
        }
Packit ae235b
      print_paths (c, opt_introspect_dest, s);
Packit ae235b
      g_free (s);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (!request_completion && !g_variant_is_object_path (opt_introspect_object_path))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid object path\n"), opt_introspect_object_path);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_recurse)
Packit ae235b
    {
Packit ae235b
      g_print ("--recurse \n");
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (request_completion && opt_introspect_object_path != NULL && !opt_introspect_only_properties)
Packit ae235b
    {
Packit ae235b
      g_print ("--only-properties \n");
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* All done with completion now */
Packit ae235b
  if (request_completion)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (!introspect_do (c, opt_introspect_object_path, 0))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (c != NULL)
Packit ae235b
    g_object_unref (c);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gchar *opt_monitor_dest = NULL;
Packit ae235b
static gchar *opt_monitor_object_path = NULL;
Packit ae235b
Packit ae235b
static guint monitor_filter_id = 0;
Packit ae235b
Packit ae235b
static void
Packit ae235b
monitor_signal_cb (GDBusConnection *connection,
Packit ae235b
                   const gchar     *sender_name,
Packit ae235b
                   const gchar     *object_path,
Packit ae235b
                   const gchar     *interface_name,
Packit ae235b
                   const gchar     *signal_name,
Packit ae235b
                   GVariant        *parameters,
Packit ae235b
                   gpointer         user_data)
Packit ae235b
{
Packit ae235b
  gchar *s;
Packit ae235b
  s = g_variant_print (parameters, TRUE);
Packit ae235b
  g_print ("%s: %s.%s %s\n",
Packit ae235b
           object_path,
Packit ae235b
           interface_name,
Packit ae235b
           signal_name,
Packit ae235b
           s);
Packit ae235b
  g_free (s);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
monitor_on_name_appeared (GDBusConnection *connection,
Packit ae235b
                          const gchar *name,
Packit ae235b
                          const gchar *name_owner,
Packit ae235b
                          gpointer user_data)
Packit ae235b
{
Packit ae235b
  g_print ("The name %s is owned by %s\n", name, name_owner);
Packit ae235b
  g_assert (monitor_filter_id == 0);
Packit ae235b
  monitor_filter_id = g_dbus_connection_signal_subscribe (connection,
Packit ae235b
                                                          name_owner,
Packit ae235b
                                                          NULL,  /* any interface */
Packit ae235b
                                                          NULL,  /* any member */
Packit ae235b
                                                          opt_monitor_object_path,
Packit ae235b
                                                          NULL,  /* arg0 */
Packit ae235b
                                                          G_DBUS_SIGNAL_FLAGS_NONE,
Packit ae235b
                                                          monitor_signal_cb,
Packit ae235b
                                                          NULL,  /* user_data */
Packit ae235b
                                                          NULL); /* user_data destroy notify */
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
monitor_on_name_vanished (GDBusConnection *connection,
Packit ae235b
                          const gchar *name,
Packit ae235b
                          gpointer user_data)
Packit ae235b
{
Packit ae235b
  g_print ("The name %s does not have an owner\n", name);
Packit ae235b
Packit ae235b
  if (monitor_filter_id != 0)
Packit ae235b
    {
Packit ae235b
      g_dbus_connection_signal_unsubscribe (connection, monitor_filter_id);
Packit ae235b
      monitor_filter_id = 0;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static const GOptionEntry monitor_entries[] =
Packit ae235b
{
Packit ae235b
  { "dest", 'd', 0, G_OPTION_ARG_STRING, &opt_monitor_dest, N_("Destination name to monitor"), NULL},
Packit ae235b
  { "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_monitor_object_path, N_("Object path to monitor"), NULL},
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
handle_monitor (gint        *argc,
Packit ae235b
                gchar      **argv[],
Packit ae235b
                gboolean     request_completion,
Packit ae235b
                const gchar *completion_cur,
Packit ae235b
                const gchar *completion_prev)
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  GError *error;
Packit ae235b
  GDBusConnection *c;
Packit ae235b
  gboolean complete_names;
Packit ae235b
  gboolean complete_paths;
Packit ae235b
  GMainLoop *loop;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  c = NULL;
Packit ae235b
Packit ae235b
  modify_argv0_for_command (argc, argv, "monitor");
Packit ae235b
Packit ae235b
  o = command_option_context_new (NULL, _("Monitor a remote object."),
Packit ae235b
                                  monitor_entries, request_completion);
Packit ae235b
  g_option_context_add_group (o, connection_get_group ());
Packit ae235b
Packit ae235b
  complete_names = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
Packit ae235b
    {
Packit ae235b
      complete_names = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  complete_paths = FALSE;
Packit ae235b
  if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
Packit ae235b
    {
Packit ae235b
      complete_paths = TRUE;
Packit ae235b
      remove_arg ((*argc) - 1, argc, argv);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_option_context_parse (o, argc, argv, NULL))
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        {
Packit ae235b
          s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
          g_printerr ("%s", s);
Packit ae235b
          g_free (s);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  c = connection_get_dbus_connection (&error);
Packit ae235b
  if (c == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 (completion_prev, "--address") == 0)
Packit ae235b
            {
Packit ae235b
              g_print ("unix:\n"
Packit ae235b
                       "tcp:\n"
Packit ae235b
                       "nonce-tcp:\n");
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              g_print ("--system \n--session \n--address \n");
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error connecting: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Monitoring doesn’t make sense on a non-message-bus connection. */
Packit ae235b
  if (g_dbus_connection_get_unique_name (c) == NULL)
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (complete_names)
Packit ae235b
    {
Packit ae235b
      print_names (c, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  /* this only makes sense on message bus connections */
Packit ae235b
  if (opt_monitor_dest == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        g_print ("--dest \n");
Packit ae235b
      else
Packit ae235b
        g_printerr (_("Error: Destination is not specified\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid bus name\n"), opt_monitor_dest);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (complete_paths)
Packit ae235b
    {
Packit ae235b
      print_paths (c, opt_monitor_dest, "/");
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (opt_monitor_object_path == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          g_print ("--object-path \n");
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
      /* it's fine to not have an object path */
Packit ae235b
    }
Packit ae235b
  if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
Packit ae235b
    {
Packit ae235b
      gchar *p;
Packit ae235b
      s = g_strdup (opt_monitor_object_path);
Packit ae235b
      p = strrchr (s, '/');
Packit ae235b
      if (p != NULL)
Packit ae235b
        {
Packit ae235b
          if (p == s)
Packit ae235b
            p++;
Packit ae235b
          *p = '\0';
Packit ae235b
        }
Packit ae235b
      print_paths (c, opt_monitor_dest, s);
Packit ae235b
      g_free (s);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  if (!request_completion && (opt_monitor_object_path != NULL && !g_variant_is_object_path (opt_monitor_object_path)))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid object path\n"), opt_monitor_object_path);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* All done with completion now */
Packit ae235b
  if (request_completion)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (opt_monitor_object_path != NULL)
Packit ae235b
    g_print ("Monitoring signals on object %s owned by %s\n", opt_monitor_object_path, opt_monitor_dest);
Packit ae235b
  else
Packit ae235b
    g_print ("Monitoring signals from all objects owned by %s\n", opt_monitor_dest);
Packit ae235b
Packit ae235b
  loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
  g_bus_watch_name_on_connection (c,
Packit ae235b
                                  opt_monitor_dest,
Packit ae235b
                                  G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
Packit ae235b
                                  monitor_on_name_appeared,
Packit ae235b
                                  monitor_on_name_vanished,
Packit ae235b
                                  NULL,
Packit ae235b
                                  NULL);
Packit ae235b
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_main_loop_unref (loop);
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  if (c != NULL)
Packit ae235b
    g_object_unref (c);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gboolean opt_wait_activate_set = FALSE;
Packit ae235b
static gchar *opt_wait_activate_name = NULL;
Packit ae235b
static gint64 opt_wait_timeout = 0;  /* no timeout */
Packit ae235b
Packit ae235b
typedef enum {
Packit ae235b
  WAIT_STATE_RUNNING,  /* waiting to see the service */
Packit ae235b
  WAIT_STATE_SUCCESS,  /* seen it successfully */
Packit ae235b
  WAIT_STATE_TIMEOUT,  /* timed out before seeing it */
Packit ae235b
} WaitState;
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
opt_wait_activate_cb (const gchar  *option_name,
Packit ae235b
                      const gchar  *value,
Packit ae235b
                      gpointer      data,
Packit ae235b
                      GError      **error)
Packit ae235b
{
Packit ae235b
  /* @value may be NULL */
Packit ae235b
  opt_wait_activate_set = TRUE;
Packit ae235b
  opt_wait_activate_name = g_strdup (value);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static const GOptionEntry wait_entries[] =
Packit ae235b
{
Packit ae235b
  { "activate", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
Packit ae235b
    opt_wait_activate_cb,
Packit ae235b
    N_("Service to activate before waiting for the other one (well-known name)"),
Packit ae235b
    "[NAME]" },
Packit ae235b
  { "timeout", 't', 0, G_OPTION_ARG_INT64, &opt_wait_timeout,
Packit ae235b
    N_("Timeout to wait for before exiting with an error (seconds); 0 for "
Packit ae235b
       "no timeout (default)"), "SECS" },
Packit ae235b
  { NULL }
Packit ae235b
};
Packit ae235b
Packit ae235b
static void
Packit ae235b
wait_name_appeared_cb (GDBusConnection *connection,
Packit ae235b
                       const gchar     *name,
Packit ae235b
                       const gchar     *name_owner,
Packit ae235b
                       gpointer         user_data)
Packit ae235b
{
Packit ae235b
  WaitState *wait_state = user_data;
Packit ae235b
Packit ae235b
  *wait_state = WAIT_STATE_SUCCESS;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
wait_timeout_cb (gpointer user_data)
Packit ae235b
{
Packit ae235b
  WaitState *wait_state = user_data;
Packit ae235b
Packit ae235b
  *wait_state = WAIT_STATE_TIMEOUT;
Packit ae235b
Packit ae235b
  /* Removed in handle_wait(). */
Packit ae235b
  return G_SOURCE_CONTINUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
handle_wait (gint        *argc,
Packit ae235b
             gchar      **argv[],
Packit ae235b
             gboolean     request_completion,
Packit ae235b
             const gchar *completion_cur,
Packit ae235b
             const gchar *completion_prev)
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  GOptionContext *o;
Packit ae235b
  gchar *s;
Packit ae235b
  GError *error;
Packit ae235b
  GDBusConnection *c;
Packit ae235b
  guint watch_id, timer_id = 0, activate_watch_id;
Packit ae235b
  const gchar *activate_service, *wait_service;
Packit ae235b
  WaitState wait_state = WAIT_STATE_RUNNING;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  c = NULL;
Packit ae235b
Packit ae235b
  modify_argv0_for_command (argc, argv, "wait");
Packit ae235b
Packit ae235b
  o = command_option_context_new (_("[OPTION…] BUS-NAME"),
Packit ae235b
                                  _("Wait for a bus name to appear."),
Packit ae235b
                                  wait_entries, request_completion);
Packit ae235b
  g_option_context_add_group (o, connection_get_group ());
Packit ae235b
Packit ae235b
  if (!g_option_context_parse (o, argc, argv, NULL))
Packit ae235b
    {
Packit ae235b
      if (!request_completion)
Packit ae235b
        {
Packit ae235b
          s = g_option_context_get_help (o, FALSE, NULL);
Packit ae235b
          g_printerr ("%s", s);
Packit ae235b
          g_free (s);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  c = connection_get_dbus_connection (&error);
Packit ae235b
  if (c == NULL)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          if (g_strcmp0 (completion_prev, "--address") == 0)
Packit ae235b
            {
Packit ae235b
              g_print ("unix:\n"
Packit ae235b
                       "tcp:\n"
Packit ae235b
                       "nonce-tcp:\n");
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              g_print ("--system \n--session \n--address \n");
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr (_("Error connecting: %s\n"), error->message);
Packit ae235b
          g_error_free (error);
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* All done with completion now */
Packit ae235b
  if (request_completion)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  /*
Packit ae235b
   * Try and disentangle the command line arguments, with the aim of supporting:
Packit ae235b
   *    gdbus wait --session --activate ActivateName WaitName
Packit ae235b
   *    gdbus wait --session --activate ActivateAndWaitName
Packit ae235b
   *    gdbus wait --activate --session ActivateAndWaitName
Packit ae235b
   *    gdbus wait --session WaitName
Packit ae235b
   */
Packit ae235b
  if (*argc == 2 && opt_wait_activate_set && opt_wait_activate_name != NULL)
Packit ae235b
    {
Packit ae235b
      activate_service = opt_wait_activate_name;
Packit ae235b
      wait_service = (*argv)[1];
Packit ae235b
    }
Packit ae235b
  else if (*argc == 2 &&
Packit ae235b
           opt_wait_activate_set && opt_wait_activate_name == NULL)
Packit ae235b
    {
Packit ae235b
      activate_service = (*argv)[1];
Packit ae235b
      wait_service = (*argv)[1];
Packit ae235b
    }
Packit ae235b
  else if (*argc == 2 && !opt_wait_activate_set)
Packit ae235b
    {
Packit ae235b
      activate_service = NULL;  /* disabled */
Packit ae235b
      wait_service = (*argv)[1];
Packit ae235b
    }
Packit ae235b
  else if (*argc == 1 &&
Packit ae235b
           opt_wait_activate_set && opt_wait_activate_name != NULL)
Packit ae235b
    {
Packit ae235b
      activate_service = opt_wait_activate_name;
Packit ae235b
      wait_service = opt_wait_activate_name;
Packit ae235b
    }
Packit ae235b
  else if (*argc == 1 &&
Packit ae235b
           opt_wait_activate_set && opt_wait_activate_name == NULL)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: A service to activate for must be specified.\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (*argc == 1 && !opt_wait_activate_set)
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: A service to wait for must be specified.\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else /* if (*argc > 2) */
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: Too many arguments.\n"));
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (activate_service != NULL &&
Packit ae235b
      (!g_dbus_is_name (activate_service) ||
Packit ae235b
       g_dbus_is_unique_name (activate_service)))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
Packit ae235b
                  activate_service);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!g_dbus_is_name (wait_service) || g_dbus_is_unique_name (wait_service))
Packit ae235b
    {
Packit ae235b
      g_printerr (_("Error: %s is not a valid well-known bus name.\n"),
Packit ae235b
                  wait_service);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Start the prerequisite service if needed. */
Packit ae235b
  if (activate_service != NULL)
Packit ae235b
    {
Packit ae235b
      activate_watch_id = g_bus_watch_name_on_connection (c, activate_service,
Packit ae235b
                                                          G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
Packit ae235b
                                                          NULL, NULL,
Packit ae235b
                                                          NULL, NULL);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      activate_watch_id = 0;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Wait for the expected name to appear. */
Packit ae235b
  watch_id = g_bus_watch_name_on_connection (c,
Packit ae235b
                                             wait_service,
Packit ae235b
                                             G_BUS_NAME_WATCHER_FLAGS_NONE,
Packit ae235b
                                             wait_name_appeared_cb,
Packit ae235b
                                             NULL, &wait_state, NULL);
Packit ae235b
Packit ae235b
  /* Safety timeout. */
Packit ae235b
  if (opt_wait_timeout > 0)
Packit ae235b
    timer_id = g_timeout_add (opt_wait_timeout, wait_timeout_cb, &wait_state);
Packit ae235b
Packit ae235b
  while (wait_state == WAIT_STATE_RUNNING)
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
Packit ae235b
  g_bus_unwatch_name (watch_id);
Packit ae235b
  if (timer_id != 0)
Packit ae235b
      g_source_remove (timer_id);
Packit ae235b
  if (activate_watch_id != 0)
Packit ae235b
      g_bus_unwatch_name (activate_watch_id);
Packit ae235b
Packit ae235b
  ret = (wait_state == WAIT_STATE_SUCCESS);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  g_clear_object (&c);
Packit ae235b
  g_option_context_free (o);
Packit ae235b
  g_free (opt_wait_activate_name);
Packit ae235b
  opt_wait_activate_name = NULL;
Packit ae235b
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
static gchar *
Packit ae235b
pick_word_at (const gchar  *s,
Packit ae235b
              gint          cursor,
Packit ae235b
              gint         *out_word_begins_at)
Packit ae235b
{
Packit ae235b
  gint begin;
Packit ae235b
  gint end;
Packit ae235b
Packit ae235b
  if (s[0] == '\0')
Packit ae235b
    {
Packit ae235b
      if (out_word_begins_at != NULL)
Packit ae235b
        *out_word_begins_at = -1;
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (g_ascii_isspace (s[cursor]) && ((cursor > 0 && g_ascii_isspace(s[cursor-1])) || cursor == 0))
Packit ae235b
    {
Packit ae235b
      if (out_word_begins_at != NULL)
Packit ae235b
        *out_word_begins_at = cursor;
Packit ae235b
      return g_strdup ("");
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
Packit ae235b
    cursor--;
Packit ae235b
  begin = cursor;
Packit ae235b
Packit ae235b
  end = begin;
Packit ae235b
  while (!g_ascii_isspace (s[end]) && s[end] != '\0')
Packit ae235b
    end++;
Packit ae235b
Packit ae235b
  if (out_word_begins_at != NULL)
Packit ae235b
    *out_word_begins_at = begin;
Packit ae235b
Packit ae235b
  return g_strndup (s + begin, end - begin);
Packit ae235b
}
Packit ae235b
Packit ae235b
gint
Packit ae235b
main (gint argc, gchar *argv[])
Packit ae235b
{
Packit ae235b
  gint ret;
Packit ae235b
  const gchar *command;
Packit ae235b
  gboolean request_completion;
Packit ae235b
  gchar *completion_cur;
Packit ae235b
  gchar *completion_prev;
Packit ae235b
#ifdef G_OS_WIN32
Packit ae235b
  gchar *tmp;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  setlocale (LC_ALL, "");
Packit ae235b
  textdomain (GETTEXT_PACKAGE);
Packit ae235b
Packit ae235b
#ifdef G_OS_WIN32
Packit ae235b
  tmp = _glib_get_locale_dir ();
Packit ae235b
  bindtextdomain (GETTEXT_PACKAGE, tmp);
Packit ae235b
  g_free (tmp);
Packit ae235b
#else
Packit ae235b
  bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
Packit ae235b
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  ret = 1;
Packit ae235b
  completion_cur = NULL;
Packit ae235b
  completion_prev = NULL;
Packit ae235b
Packit ae235b
  if (argc < 2)
Packit ae235b
    {
Packit ae235b
      usage (&argc, &argv, FALSE);
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  request_completion = FALSE;
Packit ae235b
Packit ae235b
  //completion_debug ("---- argc=%d --------------------------------------------------------", argc);
Packit ae235b
Packit ae235b
 again:
Packit ae235b
  command = argv[1];
Packit ae235b
  if (g_strcmp0 (command, "help") == 0)
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          /* do nothing */
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          usage (&argc, &argv, TRUE);
Packit ae235b
          ret = 0;
Packit ae235b
        }
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "emit") == 0)
Packit ae235b
    {
Packit ae235b
      if (handle_emit (&argc,
Packit ae235b
                       &argv,
Packit ae235b
                       request_completion,
Packit ae235b
                       completion_cur,
Packit ae235b
                       completion_prev))
Packit ae235b
        ret = 0;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "call") == 0)
Packit ae235b
    {
Packit ae235b
      if (handle_call (&argc,
Packit ae235b
                       &argv,
Packit ae235b
                       request_completion,
Packit ae235b
                       completion_cur,
Packit ae235b
                       completion_prev))
Packit ae235b
        ret = 0;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "introspect") == 0)
Packit ae235b
    {
Packit ae235b
      if (handle_introspect (&argc,
Packit ae235b
                             &argv,
Packit ae235b
                             request_completion,
Packit ae235b
                             completion_cur,
Packit ae235b
                             completion_prev))
Packit ae235b
        ret = 0;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "monitor") == 0)
Packit ae235b
    {
Packit ae235b
      if (handle_monitor (&argc,
Packit ae235b
                          &argv,
Packit ae235b
                          request_completion,
Packit ae235b
                          completion_cur,
Packit ae235b
                          completion_prev))
Packit ae235b
        ret = 0;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "wait") == 0)
Packit ae235b
    {
Packit ae235b
      if (handle_wait (&argc,
Packit ae235b
                       &argv,
Packit ae235b
                       request_completion,
Packit ae235b
                       completion_cur,
Packit ae235b
                       completion_prev))
Packit ae235b
        ret = 0;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
Packit ae235b
    {
Packit ae235b
      const gchar *completion_line;
Packit ae235b
      gchar **completion_argv;
Packit ae235b
      gint completion_argc;
Packit ae235b
      gint completion_point;
Packit ae235b
      gchar *endp;
Packit ae235b
      gint cur_begin;
Packit ae235b
Packit ae235b
      request_completion = TRUE;
Packit ae235b
Packit ae235b
      completion_line = argv[2];
Packit ae235b
      completion_point = strtol (argv[3], &endp, 10);
Packit ae235b
      if (endp == argv[3] || *endp != '\0')
Packit ae235b
        goto out;
Packit ae235b
Packit ae235b
#if 0
Packit ae235b
      completion_debug ("completion_point=%d", completion_point);
Packit ae235b
      completion_debug ("----");
Packit ae235b
      completion_debug (" 0123456789012345678901234567890123456789012345678901234567890123456789");
Packit ae235b
      completion_debug ("'%s'", completion_line);
Packit ae235b
      completion_debug (" %*s^",
Packit ae235b
                         completion_point, "");
Packit ae235b
      completion_debug ("----");
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      if (!g_shell_parse_argv (completion_line,
Packit ae235b
                               &completion_argc,
Packit ae235b
                               &completion_argv,
Packit ae235b
                               NULL))
Packit ae235b
        {
Packit ae235b
          /* it's very possible the command line can't be parsed (for
Packit ae235b
           * example, missing quotes etc) - in that case, we just
Packit ae235b
           * don't autocomplete at all
Packit ae235b
           */
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      /* compute cur and prev */
Packit ae235b
      completion_prev = NULL;
Packit ae235b
      completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
Packit ae235b
      if (cur_begin > 0)
Packit ae235b
        {
Packit ae235b
          gint prev_end;
Packit ae235b
          for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
Packit ae235b
            {
Packit ae235b
              if (!g_ascii_isspace (completion_line[prev_end]))
Packit ae235b
                {
Packit ae235b
                  completion_prev = pick_word_at (completion_line, prev_end, NULL);
Packit ae235b
                  break;
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
#if 0
Packit ae235b
      completion_debug (" cur='%s'", completion_cur);
Packit ae235b
      completion_debug ("prev='%s'", completion_prev);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      argc = completion_argc;
Packit ae235b
      argv = completion_argv;
Packit ae235b
Packit ae235b
      ret = 0;
Packit ae235b
Packit ae235b
      goto again;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (request_completion)
Packit ae235b
        {
Packit ae235b
          g_print ("help \nemit \ncall \nintrospect \nmonitor \nwait \n");
Packit ae235b
          ret = 0;
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          g_printerr ("Unknown command '%s'\n", command);
Packit ae235b
          usage (&argc, &argv, FALSE);
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  g_free (completion_cur);
Packit ae235b
  g_free (completion_prev);
Packit ae235b
  return ret;
Packit ae235b
}