summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Orlenko <zxteam@gmail.com>2011-01-09 00:32:59 +1000
committerAlexander Orlenko <zxteam@gmail.com>2011-01-09 00:32:59 +1000
commit81d7b6c8eecfdbafab4381e1f1e5d294d33b0e06 (patch)
treede26bacb301cddb721f03edaa99439ef3a18ef20
parent7b92b49e82d3b6616ca4b4fef4b369c1208c4328 (diff)
downloadbluez-tools-81d7b6c8eecfdbafab4381e1f1e5d294d33b0e06.tar.gz
Updated .gitignore
Added capability/pin/daemon options to bt-agent Added support of PIN Hash Table to lib/bluez/agent.c Added support of Interactive Mode to lib/bluez/agent.c
-rw-r--r--.gitignore1
-rw-r--r--src/bt-agent.c166
-rw-r--r--src/lib/bluez/agent.c296
3 files changed, 385 insertions, 78 deletions
diff --git a/.gitignore b/.gitignore
index 5795628..80994da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,4 @@ src/bt-network
src/bt-obex
src/bt-serial
stamp-h1
+test_*
diff --git a/src/bt-agent.c b/src/bt-agent.c
index 6093b8e..ce791ef 100644
--- a/src/bt-agent.c
+++ b/src/bt-agent.c
@@ -2,7 +2,7 @@
*
* bluez-tools - a set of tools to manage bluetooth devices for linux
*
- * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com>
+ * Copyright (C) 2010-2011 Alexander Orlenko <zxteam@gmail.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -29,8 +29,11 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
#include <glib.h>
+#include <glib/gstdio.h>
#include "lib/dbus-common.h"
#include "lib/helpers.h"
@@ -39,12 +42,100 @@
static gboolean need_unregister = TRUE;
static GMainLoop *mainloop = NULL;
-static void sigterm_handler(int sig)
+static GHashTable *pin_hash_table = NULL;
+static gchar *pin_arg = NULL;
+
+static void read_pin_file(const gchar *filename, GHashTable *pin_hash_table, gboolean first_run) {
+ g_assert(filename != NULL && strlen(filename) > 0);
+ g_assert(pin_hash_table != NULL);
+
+ GStatBuf sbuf;
+ memset(&sbuf, 0, sizeof(sbuf));
+ if (g_stat(filename, &sbuf) != 0) {
+ if (first_run) {
+ g_printerr("%s: %s\n", filename, strerror(errno));
+ exit(EXIT_FAILURE);
+ } else {
+ return;
+ }
+ }
+ if (!S_ISREG(sbuf.st_mode)) {
+ if (first_run) {
+ g_printerr("%s: It's not a regular file\n", filename);
+ exit(EXIT_FAILURE);
+ } else {
+ return;
+ }
+ }
+ if (sbuf.st_mode & S_IROTH) {
+ if (first_run)
+ g_print("Warning! %s is world readable!\n", filename);
+ }
+
+ FILE *fp = g_fopen(filename, "r");
+ if (!fp) {
+ if (first_run) {
+ g_printerr("%s: %s\n", filename, strerror(errno));
+ exit(EXIT_FAILURE);
+ } else {
+ return;
+ }
+ }
+
+ g_hash_table_remove_all(pin_hash_table);
+
+ gchar *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ guint n = 0;
+ GRegex *regex = g_regex_new("^(\\S+)\\s+(\\S+)$", 0, 0, NULL);
+
+ while ((read = getline(&line, &len, fp)) != -1) {
+ n++;
+
+ if (g_regex_match_simple("^\\s*(#|$)", line, 0, 0))
+ continue;
+
+ GMatchInfo *match_info;
+ if (g_regex_match(regex, line, 0, &match_info)) {
+ gchar **t = g_match_info_fetch_all(match_info);
+ /* Convert MAC to upper case */
+ if (g_regex_match_simple("^([0-9a-fA-F]{2}(:|$)){6}$", t[1], 0, 0))
+ g_hash_table_insert(pin_hash_table, g_ascii_strup(t[1], -1), g_strdup(t[2]));
+ else
+ g_hash_table_insert(pin_hash_table, g_strdup(t[1]), g_strdup(t[2]));
+ g_strfreev(t);
+ } else {
+ if (first_run)
+ g_print("%d: Invalid line (ignored)\n", n);
+ }
+ g_match_info_free(match_info);
+ }
+
+ g_regex_unref(regex);
+ if (line)
+ g_free(line);
+ fclose(fp);
+
+ first_run = FALSE;
+
+ return;
+}
+
+static void signal_handler(int sig)
{
- g_message("%s received", sig == SIGTERM ? "SIGTERM" : "SIGINT");
+ g_message("%s received", sig == SIGTERM ? "SIGTERM" : (sig == SIGUSR1 ? "SIGUSR1" : "SIGINT"));
- if (g_main_loop_is_running(mainloop))
- g_main_loop_quit(mainloop);
+ if (sig == SIGUSR1 && pin_arg) {
+ /* Re-read PIN's file */
+ g_print("Re-reading PIN's file\n");
+ read_pin_file(pin_arg, pin_hash_table, FALSE);
+ } else if (sig == SIGTERM || sig == SIGINT) {
+
+
+ if (g_main_loop_is_running(mainloop))
+ g_main_loop_quit(mainloop);
+ }
}
static void agent_released(Agent *agent, gpointer data)
@@ -56,12 +147,19 @@ static void agent_released(Agent *agent, gpointer data)
if (g_main_loop_is_running(mainloop))
g_main_loop_quit(mainloop);
+
+ g_print("Agent released\n");
}
static gchar *adapter_arg = NULL;
+static gchar *capability_arg = NULL;
+static gchar *daemon_arg = FALSE;
static GOptionEntry entries[] = {
{"adapter", 'a', 0, G_OPTION_ARG_STRING, &adapter_arg, "Adapter Name or MAC", "<name|mac>"},
+ {"capability", 'c', 0, G_OPTION_ARG_STRING, &capability_arg, "Agent capability", "<capability>"},
+ {"pin", 'p', 0, G_OPTION_ARG_STRING, &pin_arg, "Path to the PIN's file"},
+ {"daemon", 'd', 0, G_OPTION_ARG_NONE, &daemon_arg, "Run in background (as daemon)"},
{NULL}
};
@@ -80,6 +178,11 @@ int main(int argc, char *argv[])
g_option_context_add_main_entries(context, entries, NULL);
g_option_context_set_summary(context, "Version "PACKAGE_VERSION);
g_option_context_set_description(context,
+ "`capability` can be one of:\n"
+ " DisplayOnly\n"
+ " DisplayYesNo (default)\n"
+ " KeyboardOnly\n"
+ " NoInputNoOutput\n\n"
//"Report bugs to <"PACKAGE_BUGREPORT">."
"Project home page <"PACKAGE_URL">."
);
@@ -90,6 +193,21 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ if (capability_arg) {
+ if (
+ g_strcmp0(capability_arg, "DisplayOnly") != 0 &&
+ g_strcmp0(capability_arg, "DisplayYesNo") != 0 &&
+ g_strcmp0(capability_arg, "KeyboardOnly") != 0 &&
+ g_strcmp0(capability_arg, "NoInputNoOutput") != 0
+ ) {
+ g_print("%s: Invalid capability: %s\n", g_get_prgname(), capability_arg);
+ g_print("Try `%s --help` for more information.\n", g_get_prgname());
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ capability_arg = "DisplayYesNo"; // default value
+ }
+
g_option_context_free(context);
if (!dbus_system_connect(&error)) {
@@ -104,6 +222,12 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ /* Read PIN's file */
+ if (pin_arg) {
+ pin_hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ read_pin_file(pin_arg, pin_hash_table, TRUE);
+ }
+
mainloop = g_main_loop_new(NULL, FALSE);
Manager *manager = g_object_new(MANAGER_TYPE, NULL);
@@ -111,19 +235,43 @@ int main(int argc, char *argv[])
Adapter *adapter = find_adapter(adapter_arg, &error);
exit_if_error(error);
- Agent *agent = g_object_new(AGENT_TYPE, NULL);
+ Agent *agent = g_object_new(AGENT_TYPE, "PinHashTable", pin_hash_table, "Interactive", !daemon_arg, NULL);
- adapter_register_agent(adapter, AGENT_DBUS_PATH, "DisplayYesNo", &error);
+ adapter_register_agent(adapter, AGENT_DBUS_PATH, capability_arg, &error);
exit_if_error(error);
+ g_print("Agent registered\n");
g_signal_connect(agent, "AgentReleased", G_CALLBACK(agent_released), mainloop);
- /* Add SIGTERM && SIGINT handlers */
+ if (daemon_arg) {
+ pid_t pid, sid;
+
+ /* Fork off the parent process */
+ pid = fork();
+ if (pid < 0)
+ exit(EXIT_FAILURE);
+ /* Ok, terminate parent proccess */
+ if (pid > 0)
+ exit(EXIT_SUCCESS);
+
+ /* Create a new SID for the child process */
+ sid = setsid();
+ if (sid < 0)
+ exit(EXIT_FAILURE);
+
+ /* Close out the standard file descriptors */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ }
+
+ /* Add SIGTERM/SIGINT/SIGUSR1 handlers */
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
- sa.sa_handler = sigterm_handler;
+ sa.sa_handler = signal_handler;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
g_main_loop_run(mainloop);
diff --git a/src/lib/bluez/agent.c b/src/lib/bluez/agent.c
index bff75c0..dc29706 100644
--- a/src/lib/bluez/agent.c
+++ b/src/lib/bluez/agent.c
@@ -2,7 +2,7 @@
*
* bluez-tools - a set of tools to manage bluetooth devices for linux
*
- * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com>
+ * Copyright (C) 2010-2011 Alexander Orlenko <zxteam@gmail.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -41,13 +41,24 @@
#define AGENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), AGENT_TYPE, AgentPrivate))
struct _AgentPrivate {
- /* Unused */
- DBusGProxy *proxy;
+ /* Properties */
+ GHashTable *pin_hash_table; /* (extern) name|mac -> pin hash table */
+ gboolean interactive; /* Interactive mode */
};
G_DEFINE_TYPE(Agent, agent, G_TYPE_OBJECT);
enum {
+ PROP_0,
+
+ PROP_PIN_HASH_TABLE, /* write, construct only */
+ PROP_INTERACTIVE /* write, construct only */
+};
+
+static void _agent_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static void _agent_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+
+enum {
AGENT_RELEASED,
LAST_SIGNAL
@@ -61,9 +72,6 @@ static void agent_dispose(GObject *gobject)
dbus_g_connection_unregister_g_object(system_conn, gobject);
- /* Proxy free */
- //g_object_unref(self->priv->proxy);
-
/* Chain up to the parent class */
G_OBJECT_CLASS(agent_parent_class)->dispose(gobject);
}
@@ -76,6 +84,20 @@ static void agent_class_init(AgentClass *klass)
g_type_class_add_private(klass, sizeof(AgentPrivate));
+ /* Properties registration */
+ GParamSpec *pspec;
+
+ gobject_class->get_property = _agent_get_property;
+ gobject_class->set_property = _agent_set_property;
+
+ /* object PinHashTable [write, construct only] */
+ pspec = g_param_spec_boxed("PinHashTable", "pin_hash_table", "Name|MAC -> PIN hash table", G_TYPE_HASH_TABLE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(gobject_class, PROP_PIN_HASH_TABLE, pspec);
+
+ /* boolean Interactive [write, construct only] */
+ pspec = g_param_spec_boolean("Interactive", "interactive", "Interactive mode", TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(gobject_class, PROP_INTERACTIVE, pspec);
+
/* Signals registation */
signals[AGENT_RELEASED] = g_signal_new("AgentReleased",
G_TYPE_FROM_CLASS(gobject_class),
@@ -91,16 +113,65 @@ static void agent_init(Agent *self)
g_assert(system_conn != NULL);
+ /* Properties init */
+ self->priv->pin_hash_table = NULL;
+ self->priv->interactive = TRUE;
+
dbus_g_connection_register_g_object(system_conn, AGENT_DBUS_PATH, G_OBJECT(self));
- g_print("Agent registered\n");
+}
+
+static void _agent_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ Agent *self = AGENT(object);
+
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void _agent_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ Agent *self = AGENT(object);
+
+ switch (property_id) {
+ case PROP_PIN_HASH_TABLE:
+ self->priv->pin_hash_table = g_value_get_boxed(value);
+ break;
+
+ case PROP_INTERACTIVE:
+ self->priv->interactive = g_value_get_boolean(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
}
/* Methods */
-gboolean agent_release(Agent *self, GError **error)
+static const gchar *find_device_pin(Agent *self, Device *device_obj)
{
- g_print("Agent released\n");
+ if (self->priv->pin_hash_table) {
+ const gchar *pin_by_addr = g_hash_table_lookup(self->priv->pin_hash_table, device_get_address(device_obj));
+ const gchar *pin_by_alias = g_hash_table_lookup(self->priv->pin_hash_table, device_get_alias(device_obj));
+ const gchar *pin_all = g_hash_table_lookup(self->priv->pin_hash_table, "*");
+
+ if (pin_by_addr)
+ return pin_by_addr;
+ else if (pin_by_alias)
+ return pin_by_alias;
+ else if (pin_all)
+ return pin_all;
+ }
+
+ return NULL;
+}
+gboolean agent_release(Agent *self, GError **error)
+{
g_signal_emit(self, signals[AGENT_RELEASED], 0);
return TRUE;
@@ -109,113 +180,200 @@ gboolean agent_release(Agent *self, GError **error)
gboolean agent_request_pin_code(Agent *self, const gchar *device, gchar **ret, GError **error)
{
Device *device_obj = g_object_new(DEVICE_TYPE, "DBusObjectPath", device, NULL);
- g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+ const gchar *pin = find_device_pin(self, device_obj);
+
+ if (self->priv->interactive)
+ g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+
g_object_unref(device_obj);
- *ret = g_new0(gchar, 17);
- g_print("Enter PIN code: ");
- errno = 0;
- if (scanf("%16s", *ret) == EOF && errno) {
- g_warning("%s\n", strerror(errno));
+ /* Try to use found PIN */
+ if (pin != NULL) {
+ if (self->priv->interactive)
+ g_print("PIN found\n");
+
+ *ret = g_new0(gchar, 17);
+ sscanf(pin, "%16s", *ret);
+
+ return TRUE;
+ } else if (self->priv->interactive) {
+ g_print("Enter PIN code: ");
+ *ret = g_new0(gchar, 17);
+ errno = 0;
+ if (scanf("%16s", *ret) == EOF && errno) {
+ g_warning("%s\n", strerror(errno));
+ }
+
+ return TRUE;
}
- return TRUE;
+
+ return FALSE; // Request rejected
}
gboolean agent_request_passkey(Agent *self, const gchar *device, guint *ret, GError **error)
{
Device *device_obj = g_object_new(DEVICE_TYPE, "DBusObjectPath", device, NULL);
- g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+ const gchar *pin = find_device_pin(self, device_obj);
+
+ if (self->priv->interactive)
+ g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+
g_object_unref(device_obj);
- g_print("Enter passkey: ");
- errno = 0;
- if (scanf("%u", ret) == EOF && errno) {
- g_warning("%s\n", strerror(errno));
+ /* Try to use found PIN */
+ if (pin != NULL) {
+ if (self->priv->interactive)
+ g_print("Passkey found\n");
+
+ sscanf(pin, "%u", ret);
+
+ return TRUE;
+ } else if (self->priv->interactive) {
+ g_print("Enter passkey: ");
+ errno = 0;
+ if (scanf("%u", ret) == EOF && errno) {
+ g_warning("%s\n", strerror(errno));
+ }
+
+ return TRUE;
}
- return TRUE;
+
+ return FALSE; // Request rejected
}
gboolean agent_display_passkey(Agent *self, const gchar *device, guint passkey, guint8 entered, GError **error)
{
Device *device_obj = g_object_new(DEVICE_TYPE, "DBusObjectPath", device, NULL);
- g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+ const gchar *pin = find_device_pin(self, device_obj);
+
+ if (self->priv->interactive)
+ g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+
g_object_unref(device_obj);
- g_print("Passkey: %u, entered: %u\n", passkey, entered);
- return TRUE;
+ if (self->priv->interactive) {
+ g_print("Passkey: %u, entered: %u\n", passkey, entered);
+
+ return TRUE;
+ } else if (pin != NULL) {
+ /* OK, device found */
+ return TRUE;
+ }
+
+ return FALSE; // Request rejected
}
gboolean agent_request_confirmation(Agent *self, const gchar *device, guint passkey, GError **error)
{
Device *device_obj = g_object_new(DEVICE_TYPE, "DBusObjectPath", device, NULL);
- g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+ const gchar *pin = find_device_pin(self, device_obj);
+
+ if (self->priv->interactive)
+ g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+
g_object_unref(device_obj);
- gchar yn[4] = {0,};
- g_print("Confirm passkey: %u (yes/no)? ", passkey);
- errno = 0;
- if (scanf("%3s", yn) == EOF && errno) {
- g_warning("%s\n", strerror(errno));
- }
- if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
- return TRUE;
- } else {
- // TODO: Fix error code
- if (error)
- *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Passkey doesn't match");
- return FALSE;
+ /* Try to use found PIN */
+ if (pin != NULL) {
+ guint passkey_t;
+ sscanf(pin, "%u", &passkey_t);
+
+ if (g_strcmp0(pin, "*") == 0 || passkey_t == passkey) {
+ if (self->priv->interactive)
+ g_print("Passkey confirmed\n");
+
+ return TRUE;
+ } else {
+ if (self->priv->interactive)
+ g_print("Passkey rejected\n");
+
+ // TODO: Fix error code
+ if (error)
+ *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Passkey doesn't match");
+ return FALSE;
+ }
+ } else if (self->priv->interactive) {
+ g_print("Confirm passkey: %u (yes/no)? ", passkey);
+ gchar yn[4] = {0,};
+ errno = 0;
+ if (scanf("%3s", yn) == EOF && errno) {
+ g_warning("%s\n", strerror(errno));
+ }
+ if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
+ return TRUE;
+ } else {
+ // TODO: Fix error code
+ if (error)
+ *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Passkey doesn't match");
+ return FALSE;
+ }
}
- return TRUE;
+ return FALSE; // Request rejected
}
gboolean agent_authorize(Agent *self, const gchar *device, const gchar *uuid, GError **error)
{
Device *device_obj = g_object_new(DEVICE_TYPE, "DBusObjectPath", device, NULL);
- g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+ const gchar *pin = find_device_pin(self, device_obj);
+
+ if (self->priv->interactive)
+ g_print("Device: %s (%s)\n", device_get_alias(device_obj), device_get_address(device_obj));
+
g_object_unref(device_obj);
- gchar yn[4] = {0,};
- g_print("Authorize a connection to: %s (yes/no)? ", uuid2name(uuid));
- errno = 0;
- if (scanf("%3s", yn) == EOF && errno) {
- g_warning("%s\n", strerror(errno));
- }
- if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
+ if (pin != NULL) {
+ if (self->priv->interactive)
+ g_print("Connection to %s authorized\n", uuid2name(uuid));
+
return TRUE;
- } else {
- // TODO: Fix error code
- if (error)
- *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Connection rejected by user");
- return FALSE;
+ } else if (self->priv->interactive) {
+ g_print("Authorize a connection to: %s (yes/no)? ", uuid2name(uuid));
+ gchar yn[4] = {0,};
+ errno = 0;
+ if (scanf("%3s", yn) == EOF && errno) {
+ g_warning("%s\n", strerror(errno));
+ }
+ if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
+ return TRUE;
+ } else {
+ // TODO: Fix error code
+ if (error)
+ *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Connection rejected by user");
+ return FALSE;
+ }
}
- return TRUE;
+ return FALSE; // Request rejected
}
gboolean agent_confirm_mode_change(Agent *self, const gchar *mode, GError **error)
{
- gchar yn[4] = {0,};
- g_print("Confirm mode change: %s (yes/no)? ", mode);
- errno = 0;
- if (scanf("%3s", yn) == EOF && errno) {
- g_warning("%s\n", strerror(errno));
- }
- if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
- return TRUE;
- } else {
- // TODO: Fix error code
- if (error)
- *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Confirmation rejected by user");
- return FALSE;
+ if (self->priv->interactive) {
+ g_print("Confirm mode change: %s (yes/no)? ", mode);
+ gchar yn[4] = {0,};
+ errno = 0;
+ if (scanf("%3s", yn) == EOF && errno) {
+ g_warning("%s\n", strerror(errno));
+ }
+ if (g_strcmp0(yn, "y") == 0 || g_strcmp0(yn, "yes") == 0) {
+ return TRUE;
+ } else {
+ // TODO: Fix error code
+ if (error)
+ *error = g_error_new(g_quark_from_static_string("org.bluez.Error.Rejected"), 0, "Confirmation rejected by user");
+ return FALSE;
+ }
}
- return TRUE;
+ return TRUE; // Request accepted
}
gboolean agent_cancel(Agent *self, GError **error)
{
- g_print("Request cancelled\n");
+ if (self->priv->interactive)
+ g_print("Request cancelled\n");
+
return TRUE;
}