summaryrefslogtreecommitdiff
path: root/src/lib/bluez/agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/bluez/agent.c')
-rw-r--r--src/lib/bluez/agent.c296
1 files changed, 227 insertions, 69 deletions
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;
}