The new Bluetooth plugin will be responsible for handle DBus for the
Bluetooth profiles implemented by oFono. Each Bluetooth profile can
register callbacks to create a modem, remove all modems and set alias. The
idea is to have here soon code the handle Bluetooth Agent stuff too.
---
plugins/bluetooth.c | 482 +++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/hfp.c | 458 ++++--------------------------------------------
2 files changed, 518 insertions(+), 422 deletions(-)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index b4fe676..fc89579 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -40,13 +40,478 @@ static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static int send_method_call_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ DBusPendingCallNotifyFunction cb,
+ void *user_data, DBusFreeFunction free_func,
+ int timeout, int type, ...)
+{
+ DBusMessage *msg;
+ DBusPendingCall *call;
+ va_list args;
+ int err;
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ ofono_error("Unable to allocate new D-Bus %s message", method);
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ va_start(args, type);
+
+ if (!dbus_message_append_args_valist(msg, type, args)) {
+ va_end(args);
+ err = -EIO;
+ goto fail;
+ }
+
+ va_end(args);
+
+ if (timeout > 0)
+ timeout *=1000;
+
+ if (!dbus_connection_send_with_reply(connection, msg, &call, timeout)) {
+ ofono_error("Sending %s failed", method);
+ err = -EIO;
+ goto fail;
+ }
+
+ dbus_pending_call_set_notify(call, cb, user_data, free_func);
+ dbus_pending_call_unref(call);
+ dbus_message_unref(msg);
+
+ return 0;
+
+fail:
+ if (free_func && user_data)
+ free_func(user_data);
+
+ if (msg)
+ dbus_message_unref(msg);
+
+ return err;
+}
+
+typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data);
+
+struct property_handler {
+ const char *property;
+ PropertyHandler callback;
+ gpointer user_data;
+};
+
+static gint property_handler_compare(gconstpointer a, gconstpointer b)
+{
+ const struct property_handler *handler = a;
+ const char *property = b;
+
+ return strcmp(handler->property, property);
+}
+
+static void parse_properties_reply(DBusMessage *reply,
+ const char *property, ...)
+{
+ va_list args;
+ GSList *prop_handlers = NULL;
+ DBusMessageIter array, dict;
+
+ va_start(args, property);
+
+ while (property != NULL) {
+ struct property_handler *handler =
+ g_new0(struct property_handler, 1);
+
+ handler->property = property;
+ handler->callback = va_arg(args, PropertyHandler);
+ handler->user_data = va_arg(args, gpointer);
+
+ property = va_arg(args, const char *);
+
+ prop_handlers = g_slist_prepend(prop_handlers, handler);
+ }
+
+ va_end(args);
+
+ if (dbus_message_iter_init(reply, &array) == FALSE)
+ goto done;
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ goto done;
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+ GSList *l;
+
+ dbus_message_iter_recurse(&dict, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ goto done;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ goto done;
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ l = g_slist_find_custom(prop_handlers, key,
+ property_handler_compare);
+
+ if (l) {
+ struct property_handler *handler = l->data;
+
+ handler->callback(&value, handler->user_data);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+done:
+ g_slist_foreach(prop_handlers, (GFunc)g_free, NULL);
+ g_slist_free(prop_handlers);
+}
+
+static void has_uuid(DBusMessageIter *array, gpointer user_data)
+{
+ gboolean *profiles = user_data;
+ DBusMessageIter value;
+
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(array, &value);
+
+ while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
+ const char *uuid;
+
+ dbus_message_iter_get_basic(&value, &uuid);
+
+ if (!strcasecmp(uuid, HFP_AG_UUID))
+ *profiles |= HFP_AG;
+
+ if (!strcasecmp(uuid, DUN_GW_UUID))
+ *profiles |= DUN_GW;
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static void parse_string(DBusMessageIter *iter, gpointer user_data)
+{
+ char **str = user_data;
+ int arg_type = dbus_message_iter_get_arg_type(iter);
+
+ if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING)
+ return;
+
+ dbus_message_iter_get_basic(iter, str);
+}
+
+static void device_properties_cb(DBusPendingCall *call, gpointer user_data)
+{
+ DBusMessage *reply;
+ int have_uuid = 0;
+ const char *path = user_data;
+ const char *adapter = NULL;
+ const char *adapter_addr = NULL;
+ const char *device_addr = NULL;
+ const char *alias = NULL;
+ struct bluetooth_profile *profile;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
+ DBG("Bluetooth daemon is apparently not available.");
+ goto done;
+ }
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+ if (!dbus_message_is_error(reply, DBUS_ERROR_UNKNOWN_METHOD))
+ ofono_info("Error from GetProperties reply: %s",
+ dbus_message_get_error_name(reply));
+
+ goto done;
+ }
+
+ parse_properties_reply(reply, "UUIDs", has_uuid, &have_uuid,
+ "Adapter", parse_string, &adapter,
+ "Address", parse_string, &device_addr,
+ "Alias", parse_string, &alias, NULL);
+
+ if (adapter)
+ adapter_addr = g_hash_table_lookup(adapter_address_hash,
+ adapter);
+
+ if ((have_uuid & HFP_AG) && device_addr && adapter_addr) {
+ profile = g_hash_table_lookup(uuid_hash, HFP_AG_UUID);
+ profile->create(path, device_addr, adapter_addr, alias);
+ }
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void parse_devices(DBusMessageIter *array, gpointer user_data)
+{
+ DBusMessageIter value;
+ GSList **device_list = user_data;
+
+ DBG("");
+
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(array, &value);
+
+ while (dbus_message_iter_get_arg_type(&value)
+ == DBUS_TYPE_OBJECT_PATH) {
+ const char *path;
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ *device_list = g_slist_prepend(*device_list, (gpointer) path);
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
+ void *user_data)
+{
+ const char *property;
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+ if (g_str_equal(property, "UUIDs") == TRUE) {
+ int profiles = 0;
+ const char *path = dbus_message_get_path(msg);
+ DBusMessageIter variant;
+
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(&iter, &variant);
+
+ has_uuid(&variant, &profiles);
+
+ /* We need the full set of properties to be able to create
+ * the modem properly, including Adapter and Alias, so
+ * refetch everything again
+ */
+ if (profiles)
+ send_method_call_with_reply(BLUEZ_SERVICE, path,
+ BLUEZ_DEVICE_INTERFACE, "GetProperties",
+ device_properties_cb, g_strdup(path), g_free,
+ -1, DBUS_TYPE_INVALID);
+ } else if (g_str_equal(property, "Alias") == TRUE) {
+ const char *path = dbus_message_get_path(msg);
+ struct bluetooth_profile *profile;
+ const char *alias = NULL;
+ DBusMessageIter variant;
+ GHashTableIter hash_iter;
+ gpointer key, value;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(&iter, &variant);
+
+ parse_string(&variant, &alias);
+
+ g_hash_table_iter_init (&hash_iter, uuid_hash);
+ while (g_hash_table_iter_next(&hash_iter, &key, &value))
+ {
+ profile = value;
+ profile->set_alias(path, alias);
+ }
+ }
+
+ return TRUE;
+}
+
+static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
+{
+ const char *path = user_data;
+ DBusMessage *reply;
+ GSList *device_list = NULL;
+ GSList *l;
+ const char *addr;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
+ DBG("Bluetooth daemon is apparently not available.");
+ goto done;
+ }
+
+ parse_properties_reply(reply, "Devices", parse_devices, &device_list,
+ "Address", parse_string, &addr, NULL);
+
+ DBG("Adapter Address: %s, Path: %s", addr, path);
+ g_hash_table_insert(adapter_address_hash,
+ g_strdup(path), g_strdup(addr));
+
+ for (l = device_list; l; l = l->next) {
+ const char *device = l->data;
+
+ send_method_call_with_reply(BLUEZ_SERVICE, device,
+ BLUEZ_DEVICE_INTERFACE, "GetProperties",
+ device_properties_cb, g_strdup(device), g_free,
+ -1, DBUS_TYPE_INVALID);
+ }
+
+done:
+ g_slist_free(device_list);
+ dbus_message_unref(reply);
+}
+
+static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
+{
+ const char *path;
+ int ret;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ ret = send_method_call_with_reply(BLUEZ_SERVICE, path,
+ BLUEZ_ADAPTER_INTERFACE, "GetProperties",
+ adapter_properties_cb, g_strdup(path), g_free,
+ -1, DBUS_TYPE_INVALID);
+
+ return TRUE;
+}
+
+static gboolean adapter_removed(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ const char *path;
+
+ if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == TRUE)
+ g_hash_table_remove(adapter_address_hash, path);
+
+ return TRUE;
+}
+
+static void parse_adapters(DBusMessageIter *array, gpointer user_data)
+{
+ DBusMessageIter value;
+
+ DBG("");
+
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(array, &value);
+
+ while (dbus_message_iter_get_arg_type(&value)
+ == DBUS_TYPE_OBJECT_PATH) {
+ const char *path;
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ DBG("Calling GetProperties on %s", path);
+
+ send_method_call_with_reply(BLUEZ_SERVICE, path,
+ BLUEZ_ADAPTER_INTERFACE, "GetProperties",
+ adapter_properties_cb, g_strdup(path), g_free,
+ -1, DBUS_TYPE_INVALID);
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static void manager_properties_cb(DBusPendingCall *call, gpointer user_data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
+ DBG("Bluetooth daemon is apparently not available.");
+ goto done;
+ }
+
+ DBG("");
+
+ parse_properties_reply(reply, "Adapters", parse_adapters, NULL, NULL);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void bluetooth_remove_all_modem(gpointer key, gpointer value, gpointer user_data)
+{
+ struct bluetooth_profile *profile = value;
+
+ profile->remove_all();
+}
+
+static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
+{
+ if (!uuid_hash)
+ return;
+
+ g_hash_table_foreach(uuid_hash, bluetooth_remove_all_modem, NULL);
+}
+
+static guint bluetooth_watch;
+static guint adapter_added_watch;
+static guint adapter_removed_watch;
+static guint property_watch;
+
int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
{
+ int err;
+
if (uuid_hash)
goto done;
connection = ofono_dbus_get_connection();
+ bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
+ NULL, bluetooth_disconnect, NULL, NULL);
+
+ adapter_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ BLUEZ_MANAGER_INTERFACE,
+ "AdapterAdded",
+ adapter_added, NULL, NULL);
+
+ adapter_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ BLUEZ_MANAGER_INTERFACE,
+ "AdapterRemoved",
+ adapter_removed, NULL, NULL);
+
+ property_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ BLUEZ_DEVICE_INTERFACE,
+ "PropertyChanged",
+ property_changed, NULL, NULL);
+
+ if (bluetooth_watch == 0 || adapter_added_watch == 0 ||
+ adapter_removed_watch == 0 || property_watch == 0) {
+ err = -EIO;
+ goto remove;
+ }
+
uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
@@ -56,7 +521,19 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile
*profile)
done:
g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
+ send_method_call_with_reply(BLUEZ_SERVICE, "/",
+ BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+
return 0;
+
+remove:
+ g_dbus_remove_watch(connection, bluetooth_watch);
+ g_dbus_remove_watch(connection, adapter_added_watch);
+ g_dbus_remove_watch(connection, adapter_removed_watch);
+ g_dbus_remove_watch(connection, property_watch);
+ return err;
}
void bluetooth_unregister_uuid(const char *uuid)
@@ -66,6 +543,11 @@ void bluetooth_unregister_uuid(const char *uuid)
if (g_hash_table_size(uuid_hash))
return;
+ g_dbus_remove_watch(connection, bluetooth_watch);
+ g_dbus_remove_watch(connection, adapter_added_watch);
+ g_dbus_remove_watch(connection, adapter_removed_watch);
+ g_dbus_remove_watch(connection, property_watch);
+
g_hash_table_destroy(uuid_hash);
g_hash_table_destroy(adapter_address_hash);
uuid_hash = NULL;
diff --git a/plugins/hfp.c b/plugins/hfp.c
index a49e4af..01d56fa 100644
--- a/plugins/hfp.c
+++ b/plugins/hfp.c
@@ -62,8 +62,7 @@ static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *chld_prefix[] = { "+CHLD:", NULL };
static DBusConnection *connection;
-static GHashTable *uuid_hash = NULL;
-static GHashTable *adapter_address_hash;
+static GHashTable *modem_hash = NULL;
static void hfp_debug(const char *str, void *user_data)
{
@@ -259,101 +258,6 @@ fail:
return err;
}
-typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data);
-
-struct property_handler {
- const char *property;
- PropertyHandler callback;
- gpointer user_data;
-};
-
-static gint property_handler_compare(gconstpointer a, gconstpointer b)
-{
- const struct property_handler *handler = a;
- const char *property = b;
-
- return strcmp(handler->property, property);
-}
-
-static void parse_properties_reply(DBusMessage *reply,
- const char *property, ...)
-{
- va_list args;
- GSList *prop_handlers = NULL;
- DBusMessageIter array, dict;
-
- va_start(args, property);
-
- while (property != NULL) {
- struct property_handler *handler =
- g_new0(struct property_handler, 1);
-
- handler->property = property;
- handler->callback = va_arg(args, PropertyHandler);
- handler->user_data = va_arg(args, gpointer);
-
- property = va_arg(args, const char *);
-
- prop_handlers = g_slist_prepend(prop_handlers, handler);
- }
-
- va_end(args);
-
- if (dbus_message_iter_init(reply, &array) == FALSE)
- goto done;
-
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- goto done;
-
- dbus_message_iter_recurse(&array, &dict);
-
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry, value;
- const char *key;
- GSList *l;
-
- dbus_message_iter_recurse(&dict, &entry);
-
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
- goto done;
-
- dbus_message_iter_get_basic(&entry, &key);
-
- dbus_message_iter_next(&entry);
-
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
- goto done;
-
- dbus_message_iter_recurse(&entry, &value);
-
- l = g_slist_find_custom(prop_handlers, key,
- property_handler_compare);
-
- if (l) {
- struct property_handler *handler = l->data;
-
- handler->callback(&value, handler->user_data);
- }
-
- dbus_message_iter_next(&dict);
- }
-
-done:
- g_slist_foreach(prop_handlers, (GFunc)g_free, NULL);
- g_slist_free(prop_handlers);
-}
-
-static void parse_string(DBusMessageIter *iter, gpointer user_data)
-{
- char **str = user_data;
- int arg_type = dbus_message_iter_get_arg_type(iter);
-
- if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING)
- return;
-
- dbus_message_iter_get_basic(iter, str);
-}
-
static void cind_status_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
@@ -596,6 +500,10 @@ static int hfp_create_modem(const char *device, const char
*dev_addr,
struct hfp_data *data;
char buf[256];
+ /* We already have this device in our hash, ignore */
+ if (g_hash_table_lookup(modem_hash, device) != NULL)
+ return -EALREADY;
+
ofono_info("Using device: %s, devaddr: %s, adapter: %s",
device, dev_addr, adapter_addr);
@@ -624,7 +532,7 @@ static int hfp_create_modem(const char *device, const char *dev_addr,
ofono_modem_set_name(modem, alias);
ofono_modem_register(modem);
- g_hash_table_insert(uuid_hash, g_strdup(device), modem);
+ g_hash_table_insert(modem_hash, g_strdup(device), modem);
return 0;
@@ -635,286 +543,35 @@ free:
return -ENOMEM;
}
-static void has_hfp_uuid(DBusMessageIter *array, gpointer user_data)
-{
- gboolean *hfp = user_data;
- DBusMessageIter value;
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
- const char *uuid;
-
- dbus_message_iter_get_basic(&value, &uuid);
-
- if (!strcasecmp(uuid, HFP_AG_UUID)) {
- *hfp = TRUE;
- return;
- }
-
- dbus_message_iter_next(&value);
- }
-}
-
-static void device_properties_cb(DBusPendingCall *call, gpointer user_data)
-{
- DBusMessage *reply;
- char *path = user_data;
- gboolean have_hfp = FALSE;
- const char *adapter = NULL;
- const char *adapter_addr = NULL;
- const char *device_addr = NULL;
- const char *alias = NULL;
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
- DBG("Bluetooth daemon is apparently not available.");
- goto done;
- }
-
- if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
- if (!dbus_message_is_error(reply, DBUS_ERROR_UNKNOWN_METHOD))
- ofono_info("Error from GetProperties reply: %s",
- dbus_message_get_error_name(reply));
-
- goto done;
- }
-
- parse_properties_reply(reply, "UUIDs", has_hfp_uuid, &have_hfp,
- "Adapter", parse_string, &adapter,
- "Address", parse_string, &device_addr,
- "Alias", parse_string, &alias, NULL);
-
- if (adapter)
- adapter_addr = g_hash_table_lookup(adapter_address_hash,
- adapter);
-
- if (have_hfp && device_addr && adapter_addr)
- hfp_create_modem(path, device_addr, adapter_addr, alias);
-
-done:
- dbus_message_unref(reply);
-}
-
-static void parse_devices(DBusMessageIter *array, gpointer user_data)
-{
- DBusMessageIter value;
- GSList **device_list = user_data;
-
- DBG("");
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value)
- == DBUS_TYPE_OBJECT_PATH) {
- const char *path;
-
- dbus_message_iter_get_basic(&value, &path);
-
- *device_list = g_slist_prepend(*device_list, (gpointer) path);
-
- dbus_message_iter_next(&value);
- }
-}
-
-static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
-{
- const char *path = user_data;
- DBusMessage *reply;
- GSList *device_list = NULL;
- GSList *l;
- const char *addr;
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
- DBG("Bluetooth daemon is apparently not available.");
- goto done;
- }
-
- parse_properties_reply(reply, "Devices", parse_devices, &device_list,
- "Address", parse_string, &addr, NULL);
-
- DBG("Adapter Address: %s, Path: %s", addr, path);
- g_hash_table_insert(adapter_address_hash,
- g_strdup(path), g_strdup(addr));
-
- for (l = device_list; l; l = l->next) {
- const char *device = l->data;
-
- send_method_call_with_reply(BLUEZ_SERVICE, device,
- BLUEZ_DEVICE_INTERFACE, "GetProperties",
- device_properties_cb, g_strdup(device), g_free,
- -1, DBUS_TYPE_INVALID);
- }
-
-done:
- g_slist_free(device_list);
- dbus_message_unref(reply);
-}
-
-static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
- void *user_data)
-{
- const char *path;
- int ret;
-
- dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-
- ret = send_method_call_with_reply(BLUEZ_SERVICE, path,
- BLUEZ_ADAPTER_INTERFACE, "GetProperties",
- adapter_properties_cb, g_strdup(path), g_free,
- -1, DBUS_TYPE_INVALID);
-
- return TRUE;
-}
-
-static gboolean adapter_removed(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- const char *path;
-
- if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID) == TRUE)
- g_hash_table_remove(adapter_address_hash, path);
-
- return TRUE;
-}
-
-static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
- void *user_data)
+static gboolean hfp_remove_each_modem(gpointer key, gpointer value, gpointer user_data)
{
- const char *property;
- DBusMessageIter iter;
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return FALSE;
-
- dbus_message_iter_get_basic(&iter, &property);
- if (g_str_equal(property, "UUIDs") == TRUE) {
- gboolean have_hfp = FALSE;
- const char *path = dbus_message_get_path(msg);
- DBusMessageIter variant;
-
- /* We already have this device in our hash, ignore */
- if (g_hash_table_lookup(uuid_hash, path) != NULL)
- return TRUE;
-
- if (!dbus_message_iter_next(&iter))
- return FALSE;
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return FALSE;
-
- dbus_message_iter_recurse(&iter, &variant);
-
- has_hfp_uuid(&variant, &have_hfp);
-
- /* We need the full set of properties to be able to create
- * the modem properly, including Adapter and Alias, so
- * refetch everything again
- */
- if (have_hfp)
- send_method_call_with_reply(BLUEZ_SERVICE, path,
- BLUEZ_DEVICE_INTERFACE, "GetProperties",
- device_properties_cb, g_strdup(path), g_free,
- -1, DBUS_TYPE_INVALID);
- } else if (g_str_equal(property, "Alias") == TRUE) {
- const char *path = dbus_message_get_path(msg);
- struct ofono_modem *modem =
- g_hash_table_lookup(uuid_hash, path);
- const char *alias = NULL;
- DBusMessageIter variant;
-
- if (modem == NULL)
- return TRUE;
-
- if (!dbus_message_iter_next(&iter))
- return FALSE;
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return FALSE;
-
- dbus_message_iter_recurse(&iter, &variant);
-
- parse_string(&variant, &alias);
+ struct ofono_modem *modem = value;
- ofono_modem_set_name(modem, alias);
- }
+ ofono_modem_remove(modem);
return TRUE;
}
-static void parse_adapters(DBusMessageIter *array, gpointer user_data)
+static void hfp_remove_all_modem()
{
- DBusMessageIter value;
-
- DBG("");
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ if (modem_hash == NULL)
return;
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value)
- == DBUS_TYPE_OBJECT_PATH) {
- const char *path;
-
- dbus_message_iter_get_basic(&value, &path);
-
- DBG("Calling GetProperties on %s", path);
-
- send_method_call_with_reply(BLUEZ_SERVICE, path,
- BLUEZ_ADAPTER_INTERFACE, "GetProperties",
- adapter_properties_cb, g_strdup(path), g_free,
- -1, DBUS_TYPE_INVALID);
-
- dbus_message_iter_next(&value);
- }
-}
-
-static void manager_properties_cb(DBusPendingCall *call, gpointer user_data)
-{
- DBusMessage *reply;
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
- DBG("Bluetooth daemon is apparently not available.");
- goto done;
- }
-
- parse_properties_reply(reply, "Adapters", parse_adapters, NULL, NULL);
-
-done:
- dbus_message_unref(reply);
+ g_hash_table_foreach_remove(modem_hash, hfp_remove_each_modem, NULL);
}
-static gboolean hfp_remove_each_modem(gpointer key, gpointer value, gpointer user_data)
+static void hfp_set_alias(const char *device, const char *alias)
{
- struct ofono_modem *modem = value;
-
- ofono_modem_remove(modem);
+ struct ofono_modem *modem;
- return TRUE;
-}
+ if (!device || !alias)
+ return;
-static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
-{
- if (uuid_hash == NULL)
+ modem = g_hash_table_lookup(modem_hash, device);
+ if (!modem)
return;
- g_hash_table_foreach_remove(uuid_hash, hfp_remove_each_modem, NULL);
+ ofono_modem_set_name(modem, alias);
}
static int hfp_register_ofono_handsfree(struct ofono_modem *modem)
@@ -971,7 +628,7 @@ static void hfp_remove(struct ofono_modem *modem)
HFP_AGENT_INTERFACE))
hfp_unregister_ofono_handsfree(modem);
- g_hash_table_remove(uuid_hash, data->handsfree_path);
+ g_hash_table_remove(modem_hash, data->handsfree_path);
g_free(data->handsfree_path);
g_free(data);
@@ -1104,10 +761,12 @@ static struct ofono_modem_driver hfp_driver = {
.post_sim = hfp_post_sim,
};
-static guint bluetooth_exit_watch;
-static guint adapter_added_watch;
-static guint adapter_removed_watch;
-static guint uuid_watch;
+static struct bluetooth_profile hfp_profile = {
+ .name = "hfp",
+ .create = hfp_create_modem,
+ .remove_all = hfp_remove_all_modem,
+ .set_alias = hfp_set_alias,
+};
static int hfp_init()
{
@@ -1118,73 +777,28 @@ static int hfp_init()
connection = ofono_dbus_get_connection();
- bluetooth_exit_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
- NULL, bluetooth_disconnect, NULL, NULL);
-
- adapter_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- BLUEZ_MANAGER_INTERFACE,
- "AdapterAdded",
- adapter_added, NULL, NULL);
-
- adapter_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- BLUEZ_MANAGER_INTERFACE,
- "AdapterRemoved",
- adapter_removed, NULL, NULL);
-
- uuid_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- BLUEZ_DEVICE_INTERFACE,
- "PropertyChanged",
- property_changed, NULL, NULL);
+ err = ofono_modem_driver_register(&hfp_driver);
+ if (err < 0)
+ return err;
- if (bluetooth_exit_watch == 0 || adapter_added_watch == 0 ||
- adapter_removed_watch == 0|| uuid_watch == 0) {
- err = -EIO;
- goto remove;
+ err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_profile);
+ if (err < 0) {
+ ofono_modem_driver_unregister(&hfp_driver);
+ return err;
}
- uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
- adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, g_free);
-
- err = ofono_modem_driver_register(&hfp_driver);
- if (err < 0)
- goto remove;
-
- send_method_call_with_reply(BLUEZ_SERVICE, "/",
- BLUEZ_MANAGER_INTERFACE, "GetProperties",
- manager_properties_cb, NULL, NULL, -1,
- DBUS_TYPE_INVALID);
-
return 0;
-
-remove:
- g_dbus_remove_watch(connection, bluetooth_exit_watch);
- g_dbus_remove_watch(connection, adapter_added_watch);
- g_dbus_remove_watch(connection, adapter_removed_watch);
- g_dbus_remove_watch(connection, uuid_watch);
-
- if (uuid_hash)
- g_hash_table_destroy(uuid_hash);
-
- if (adapter_address_hash)
- g_hash_table_destroy(adapter_address_hash);
-
- return err;
}
static void hfp_exit()
{
- g_dbus_remove_watch(connection, bluetooth_exit_watch);
- g_dbus_remove_watch(connection, adapter_added_watch);
- g_dbus_remove_watch(connection, adapter_removed_watch);
- g_dbus_remove_watch(connection, uuid_watch);
-
+ bluetooth_unregister_uuid(HFP_AG_UUID);
ofono_modem_driver_unregister(&hfp_driver);
- g_hash_table_destroy(uuid_hash);
- g_hash_table_destroy(adapter_address_hash);
+ g_hash_table_destroy(modem_hash);
}
OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION,
--
1.7.1