[gnome-shell/wip/hadess/import-gnome-bluetooth: 127/133] bluetooth: Import GnomeBluetoothClient into our C code
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/hadess/import-gnome-bluetooth: 127/133] bluetooth: Import GnomeBluetoothClient into our C code
- Date: Tue, 2 Nov 2021 14:28:25 +0000 (UTC)
commit 7e304b38bcb632f9876d770141541689a2ab8fb6
Author: Bastien Nocera <hadess hadess net>
Date: Tue Nov 2 14:55:09 2021 +0100
bluetooth: Import GnomeBluetoothClient into our C code
This is a minimal import that:
- namespaces the source files and headers
- namespaces the functions without caring about indentation
- hardcodes a libudev dependency that will soon be removed
src/meson.build | 14 +-
src/shell-bluetooth-client-private.h | 66 ++
src/shell-bluetooth-client.c | 1765 ++++++++++++++++++++++++++++++++++
src/shell-bluetooth-client.h | 80 ++
src/shell-bluetooth-client.xml | 60 ++
src/shell-bluetooth-enums.h | 182 ++++
src/shell-bluetooth-pin.c | 239 +++++
src/shell-bluetooth-pin.h | 36 +
src/shell-bluetooth-utils.c | 430 +++++++++
src/shell-bluetooth-utils.h | 68 ++
10 files changed, 2939 insertions(+), 1 deletion(-)
---
diff --git a/src/meson.build b/src/meson.build
index 53b8b527d5..95eb45fd35 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -48,6 +48,7 @@ gnome_shell_cflags = [
install_rpath = ':'.join([mutter_typelibdir, pkglibdir])
+libudev_dep = dependency('libudev')
gnome_shell_deps = [
gio_unix_dep,
libxml_dep,
@@ -61,7 +62,8 @@ gnome_shell_deps = [
gi_dep,
polkit_dep,
gcr_dep,
- libsystemd_dep
+ libsystemd_dep,
+ libudev_dep
]
gnome_shell_deps += nm_deps
@@ -95,6 +97,8 @@ libshell_public_headers = [
'shell-app.h',
'shell-app-system.h',
'shell-app-usage.h',
+ 'shell-bluetooth-client.h',
+ 'shell-bluetooth-enums.h',
'shell-blur-effect.h',
'shell-embedded-window.h',
'shell-glsl-effect.h',
@@ -134,6 +138,9 @@ libshell_sources = [
'shell-app.c',
'shell-app-system.c',
'shell-app-usage.c',
+ 'shell-bluetooth-client.c',
+ 'shell-bluetooth-utils.c',
+ 'shell-bluetooth-pin.c',
'shell-blur-effect.c',
'shell-embedded-window.c',
'shell-embedded-window-private.h',
@@ -195,6 +202,11 @@ dbus_generated += gnome.gdbus_codegen('switcheroo-control',
namespace: 'Shell'
)
+dbus_generated += gnome.gdbus_codegen('shell-bluetooth-client-glue',
+ 'shell-bluetooth-client.xml',
+ interface_prefix: 'org.bluez',
+)
+
libshell_no_gir_sources += dbus_generated
libshell = library('gnome-shell',
diff --git a/src/shell-bluetooth-client-private.h b/src/shell-bluetooth-client-private.h
new file mode 100644
index 0000000000..56f8bc44d7
--- /dev/null
+++ b/src/shell-bluetooth-client-private.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * BlueZ - ShellBluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel holtmann org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <shell-bluetooth-enums.h>
+
+typedef void (*ShellBluetoothClientSetupFunc) (ShellBluetoothClient *client,
+ const GError *error,
+ const char *device_path);
+
+void shell_bluetooth_client_setup_device (ShellBluetoothClient *client,
+ const char *path,
+ gboolean pair,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean shell_bluetooth_client_setup_device_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ char **path,
+ GError **error);
+
+void shell_bluetooth_client_cancel_setup_device (ShellBluetoothClient *client,
+ const char *path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean shell_bluetooth_client_cancel_setup_device_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ char **path,
+ GError **error);
+
+gboolean shell_bluetooth_client_set_trusted(ShellBluetoothClient *client,
+ const char *device, gboolean trusted);
+
+GDBusProxy *shell_bluetooth_client_get_device (ShellBluetoothClient *client,
+ const char *path);
+
+void shell_bluetooth_client_dump_device (GtkTreeModel *model,
+ GtkTreeIter *iter);
+
+gboolean shell_bluetooth_client_get_connectable(const char **uuids);
+
+GDBusProxy *_shell_bluetooth_client_get_default_adapter (ShellBluetoothClient *client);
diff --git a/src/shell-bluetooth-client.c b/src/shell-bluetooth-client.c
new file mode 100644
index 0000000000..d42e51dfd7
--- /dev/null
+++ b/src/shell-bluetooth-client.c
@@ -0,0 +1,1765 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel holtmann org>
+ * Copyright (C) 2010 Giovanni Campagna <scampa giovanni gmail com>
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/**
+ * SECTION:shell-bluetooth-client
+ * @short_description: ShellBluetooth client object
+ * @stability: Stable
+ * @include: shell-bluetooth-client.h
+ *
+ * The #ShellBluetoothClient object is used to query the state of Bluetooth
+ * devices and adapters.
+ **/
+
+#include <config.h>
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "shell-bluetooth-client.h"
+#include "shell-bluetooth-client-private.h"
+#include "shell-bluetooth-client-glue.h"
+#include "shell-bluetooth-utils.h"
+#include "shell-enum-types.h"
+#include "shell-bluetooth-pin.h"
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MANAGER_PATH "/"
+#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
+#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
+
+#define SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(obj) shell_bluetooth_client_get_instance_private (obj)
+
+typedef struct _ShellBluetoothClientPrivate ShellBluetoothClientPrivate;
+
+struct _ShellBluetoothClientPrivate {
+ GDBusObjectManager *manager;
+ GCancellable *cancellable;
+ GtkTreeStore *store;
+ GtkTreeRowReference *default_adapter;
+ /* Discoverable during discovery? */
+ gboolean disco_during_disco;
+ gboolean discovery_started;
+};
+
+enum {
+ PROP_0,
+ PROP_DEFAULT_ADAPTER,
+ PROP_DEFAULT_ADAPTER_POWERED,
+ PROP_DEFAULT_ADAPTER_DISCOVERABLE,
+ PROP_DEFAULT_ADAPTER_NAME,
+ PROP_DEFAULT_ADAPTER_DISCOVERING
+};
+
+enum {
+ DEVICE_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static const char *connectable_uuids[] = {
+ "HSP",
+ "AudioSource",
+ "AudioSink",
+ "A/V_RemoteControlTarget",
+ "A/V_RemoteControl",
+ "Headset_-_AG",
+ "Handsfree",
+ "HandsfreeAudioGateway",
+ "HumanInterfaceDeviceService",
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(ShellBluetoothClient, shell_bluetooth_client, G_TYPE_OBJECT)
+
+typedef gboolean (*IterSearchFunc) (GtkTreeStore *store,
+ GtkTreeIter *iter, gpointer user_data);
+
+static gboolean iter_search(GtkTreeStore *store,
+ GtkTreeIter *iter, GtkTreeIter *parent,
+ IterSearchFunc func, gpointer user_data)
+{
+ gboolean cont, found = FALSE;
+
+ if (parent == NULL)
+ cont = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),
+ iter);
+ else
+ cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(store),
+ iter, parent);
+
+ while (cont == TRUE) {
+ GtkTreeIter child;
+
+ found = func(store, iter, user_data);
+ if (found == TRUE)
+ break;
+
+ found = iter_search(store, &child, iter, func, user_data);
+ if (found == TRUE) {
+ *iter = child;
+ break;
+ }
+
+ cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);
+ }
+
+ return found;
+}
+
+static gboolean
+compare_path (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ const gchar *path = user_data;
+ g_autoptr(GDBusProxy) object = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(store), iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &object,
+ -1);
+
+ return (object != NULL &&
+ g_str_equal (path, g_dbus_proxy_get_object_path (object)));
+}
+
+static gboolean
+compare_address (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ const char *address = user_data;
+ g_autofree char *tmp_address = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(store), iter,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS, &tmp_address, -1);
+ return (g_strcmp0 (address, tmp_address) == 0);
+}
+
+static gboolean
+get_iter_from_path (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ const char *path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+ return iter_search(store, iter, NULL, compare_path, (gpointer) path);
+}
+
+static gboolean
+get_iter_from_proxy(GtkTreeStore *store,
+ GtkTreeIter *iter,
+ GDBusProxy *proxy)
+{
+ g_return_val_if_fail (proxy != NULL, FALSE);
+ return iter_search(store, iter, NULL, compare_path,
+ (gpointer) g_dbus_proxy_get_object_path (proxy));
+}
+
+static gboolean
+get_iter_from_address (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ const char *address,
+ GDBusProxy *adapter)
+{
+ GtkTreeIter parent_iter;
+
+ g_return_val_if_fail (address != NULL, FALSE);
+ g_return_val_if_fail (adapter != NULL, FALSE);
+
+ if (get_iter_from_proxy (store, &parent_iter, adapter) == FALSE)
+ return FALSE;
+
+ return iter_search (store, iter, &parent_iter, compare_address, (gpointer) address);
+}
+
+static char **
+device_list_uuids (const gchar * const *uuids)
+{
+ GPtrArray *ret;
+ guint i;
+
+ if (uuids == NULL)
+ return NULL;
+
+ ret = g_ptr_array_new ();
+
+ for (i = 0; uuids[i] != NULL; i++) {
+ const char *uuid;
+
+ uuid = shell_bluetooth_uuid_to_string (uuids[i]);
+ if (uuid == NULL)
+ continue;
+ g_ptr_array_add (ret, g_strdup (uuid));
+ }
+
+ if (ret->len == 0) {
+ g_ptr_array_free (ret, TRUE);
+ return NULL;
+ }
+
+ g_ptr_array_add (ret, NULL);
+
+ return (char **) g_ptr_array_free (ret, FALSE);
+}
+
+gboolean
+shell_bluetooth_client_get_connectable(const char **uuids)
+{
+ int i, j;
+
+ for (i = 0; uuids && uuids[i] != NULL; i++) {
+ for (j = 0; j < G_N_ELEMENTS (connectable_uuids); j++) {
+ if (g_str_equal (connectable_uuids[j], uuids[i]))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static const char *
+phone_oui_to_icon_name (const char *bdaddr)
+{
+ char *vendor;
+ const char *ret = NULL;
+
+ vendor = oui_to_vendor (bdaddr);
+ if (vendor == NULL)
+ return NULL;
+
+ if (strstr (vendor, "Apple") != NULL)
+ ret = "phone-apple-iphone";
+ else if (strstr (vendor, "Samsung") != NULL)
+ ret = "phone-samsung-galaxy-s";
+ else if (strstr (vendor, "Google") != NULL)
+ ret = "phone-google-nexus-one";
+ g_free (vendor);
+
+ return ret;
+}
+
+static const char *
+icon_override (const char *bdaddr,
+ ShellBluetoothType type)
+{
+ /* audio-card, you're ugly */
+ switch (type) {
+ case SHELL_BLUETOOTH_TYPE_HEADSET:
+ return "audio-headset";
+ case SHELL_BLUETOOTH_TYPE_HEADPHONES:
+ return "audio-headphones";
+ case SHELL_BLUETOOTH_TYPE_OTHER_AUDIO:
+ return "audio-speakers";
+ case SHELL_BLUETOOTH_TYPE_PHONE:
+ return phone_oui_to_icon_name (bdaddr);
+ case SHELL_BLUETOOTH_TYPE_DISPLAY:
+ return "video-display";
+ case SHELL_BLUETOOTH_TYPE_SCANNER:
+ return "scanner";
+ case SHELL_BLUETOOTH_TYPE_REMOTE_CONTROL:
+ case SHELL_BLUETOOTH_TYPE_WEARABLE:
+ case SHELL_BLUETOOTH_TYPE_TOY:
+ /* FIXME */
+ default:
+ return NULL;
+ }
+}
+
+static void
+device_resolve_type_and_icon (Device1 *device, ShellBluetoothType *type, const char **icon)
+{
+ g_return_if_fail (type);
+ g_return_if_fail (icon);
+
+ if (g_strcmp0 (device1_get_name (device), "ION iCade Game Controller") == 0 ||
+ g_strcmp0 (device1_get_name (device), "8Bitdo Zero GamePad") == 0) {
+ *type = SHELL_BLUETOOTH_TYPE_JOYPAD;
+ *icon = "input-gaming";
+ return;
+ }
+
+ if (*type == 0 || *type == SHELL_BLUETOOTH_TYPE_ANY)
+ *type = shell_bluetooth_appearance_to_type (device1_get_appearance (device));
+ if (*type == 0 || *type == SHELL_BLUETOOTH_TYPE_ANY)
+ *type = shell_bluetooth_class_to_type (device1_get_class (device));
+
+ *icon = icon_override (device1_get_address (device), *type);
+
+ if (!*icon)
+ *icon = device1_get_icon (device);
+
+ if (!*icon)
+ *icon = "bluetooth";
+}
+
+static void
+device_notify_cb (Device1 *device,
+ GParamSpec *pspec,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ const char *property = g_param_spec_get_name (pspec);
+ GtkTreeIter iter;
+
+ if (get_iter_from_proxy (priv->store, &iter, G_DBUS_PROXY (device)) == FALSE)
+ return;
+
+ if (g_strcmp0 (property, "name") == 0) {
+ const gchar *name = device1_get_name (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_NAME, name, -1);
+ } else if (g_strcmp0 (property, "alias") == 0) {
+ const gchar *alias = device1_get_alias (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, alias, -1);
+ } else if (g_strcmp0 (property, "paired") == 0) {
+ gboolean paired = device1_get_paired (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_PAIRED, paired, -1);
+ } else if (g_strcmp0 (property, "trusted") == 0) {
+ gboolean trusted = device1_get_trusted (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_TRUSTED, trusted, -1);
+ } else if (g_strcmp0 (property, "connected") == 0) {
+ gboolean connected = device1_get_connected (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_CONNECTED, connected, -1);
+ } else if (g_strcmp0 (property, "uuids") == 0) {
+ char **uuids;
+
+ uuids = device_list_uuids (device1_get_uuids (device));
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_UUIDS, uuids, -1);
+ g_strfreev (uuids);
+ } else if (g_strcmp0 (property, "legacy-pairing") == 0) {
+ gboolean legacypairing = device1_get_legacy_pairing (device);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
+ -1);
+ } else if (g_strcmp0 (property, "icon") == 0 ||
+ g_strcmp0 (property, "class") == 0 ||
+ g_strcmp0 (property, "appearance") == 0) {
+ ShellBluetoothType type = SHELL_BLUETOOTH_TYPE_ANY;
+ const char *icon = NULL;
+
+ device_resolve_type_and_icon (device, &type, &icon);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_TYPE, type,
+ SHELL_BLUETOOTH_COLUMN_ICON, icon,
+ -1);
+ } else {
+ g_debug ("Unhandled property: %s", property);
+ }
+}
+
+static void
+device_added (GDBusObjectManager *manager,
+ Device1 *device,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GDBusProxy *adapter;
+ const char *adapter_path, *address, *alias, *name, *icon;
+ char **uuids;
+ gboolean paired, trusted, connected;
+ int legacypairing;
+ ShellBluetoothType type = SHELL_BLUETOOTH_TYPE_ANY;
+ GtkTreeIter iter, parent;
+
+ g_signal_connect_object (G_OBJECT (device), "notify",
+ G_CALLBACK (device_notify_cb), client, 0);
+
+ adapter_path = device1_get_adapter (device);
+ address = device1_get_address (device);
+ alias = device1_get_alias (device);
+ name = device1_get_name (device);
+ paired = device1_get_paired (device);
+ trusted = device1_get_trusted (device);
+ connected = device1_get_connected (device);
+ uuids = device_list_uuids (device1_get_uuids (device));
+ legacypairing = device1_get_legacy_pairing (device);
+
+ device_resolve_type_and_icon (device, &type, &icon);
+
+ if (get_iter_from_path (priv->store, &parent, adapter_path) == FALSE)
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &parent,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &adapter, -1);
+
+ if (get_iter_from_address (priv->store, &iter, address, adapter) == FALSE) {
+ gtk_tree_store_insert_with_values (priv->store, &iter, &parent, -1,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS, address,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, alias,
+ SHELL_BLUETOOTH_COLUMN_NAME, name,
+ SHELL_BLUETOOTH_COLUMN_TYPE, type,
+ SHELL_BLUETOOTH_COLUMN_ICON, icon,
+ SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
+ SHELL_BLUETOOTH_COLUMN_UUIDS, uuids,
+ SHELL_BLUETOOTH_COLUMN_PAIRED, paired,
+ SHELL_BLUETOOTH_COLUMN_CONNECTED, connected,
+ SHELL_BLUETOOTH_COLUMN_TRUSTED, trusted,
+ SHELL_BLUETOOTH_COLUMN_PROXY, device,
+ -1);
+ } else {
+ gtk_tree_store_set(priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS, address,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, alias,
+ SHELL_BLUETOOTH_COLUMN_NAME, name,
+ SHELL_BLUETOOTH_COLUMN_TYPE, type,
+ SHELL_BLUETOOTH_COLUMN_ICON, icon,
+ SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
+ SHELL_BLUETOOTH_COLUMN_UUIDS, uuids,
+ SHELL_BLUETOOTH_COLUMN_PAIRED, paired,
+ SHELL_BLUETOOTH_COLUMN_CONNECTED, connected,
+ SHELL_BLUETOOTH_COLUMN_TRUSTED, trusted,
+ SHELL_BLUETOOTH_COLUMN_PROXY, device,
+ -1);
+ }
+ g_strfreev (uuids);
+ g_object_unref (adapter);
+}
+
+static void
+device_removed (const char *path,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter;
+
+ if (get_iter_from_path(priv->store, &iter, path) == TRUE) {
+ /* Note that removal can also happen from adapter_removed. */
+ g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path);
+ gtk_tree_store_remove(priv->store, &iter);
+ }
+}
+
+static void
+adapter_set_powered_cb (GDBusProxy *proxy,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) ret = NULL;
+
+ ret = g_dbus_proxy_call_finish (proxy, res, &error);
+ if (!ret) {
+ g_debug ("Error setting property 'Powered' on interface org.bluez.Adapter1: %s (%s, %d)",
+ error->message, g_quark_to_string (error->domain), error->code);
+ }
+}
+
+static void
+adapter_set_powered (ShellBluetoothClient *client,
+ const char *path,
+ gboolean powered)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ g_autoptr(GObject) adapter = NULL;
+ GtkTreeIter iter;
+ GVariant *variant;
+
+ g_return_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client));
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &adapter, -1);
+
+ if (adapter == NULL)
+ return;
+
+ variant = g_variant_new_boolean (powered);
+ g_dbus_proxy_call (G_DBUS_PROXY (adapter),
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)", "org.bluez.Adapter1", "Powered", variant),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, (GAsyncReadyCallback) adapter_set_powered_cb, client);
+}
+
+static void
+default_adapter_changed (GDBusObjectManager *manager,
+ const char *path,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter;
+ GtkTreePath *tree_path;
+ gboolean powered;
+
+ g_assert (!priv->default_adapter);
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
+ return;
+
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
+ priv->default_adapter = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->store), tree_path);
+ gtk_tree_path_free (tree_path);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT, TRUE, -1);
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_POWERED, &powered, -1);
+
+ if (powered) {
+ g_object_notify (G_OBJECT (client), "default-adapter");
+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
+ g_object_notify (G_OBJECT (client), "default-adapter-name");
+ return;
+ }
+
+ /*
+ * If the adapter is turn off (Powered = False in bluetooth) object
+ * notifications will be sent only when a Powered = True signal arrives
+ * from bluetoothd
+ */
+ adapter_set_powered (client, path, TRUE);
+}
+
+static void
+adapter_notify_cb (Adapter1 *adapter,
+ GParamSpec *pspec,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ const char *property = g_param_spec_get_name (pspec);
+ GtkTreeIter iter;
+ gboolean notify = TRUE;
+ gboolean is_default;
+
+ if (get_iter_from_proxy (priv->store, &iter, G_DBUS_PROXY (adapter)) == FALSE)
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
+
+ if (g_strcmp0 (property, "alias") == 0) {
+ const gchar *alias = adapter1_get_alias (adapter);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, alias, -1);
+
+ if (is_default) {
+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
+ g_object_notify (G_OBJECT (client), "default-adapter-name");
+ }
+ } else if (g_strcmp0 (property, "discovering") == 0) {
+ gboolean discovering = adapter1_get_discovering (adapter);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERING, discovering, -1);
+
+ if (is_default)
+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
+ } else if (g_strcmp0 (property, "powered") == 0) {
+ gboolean powered = adapter1_get_powered (adapter);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_POWERED, powered, -1);
+
+ if (is_default && powered) {
+ g_object_notify (G_OBJECT (client), "default-adapter");
+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
+ g_object_notify (G_OBJECT (client), "default-adapter-name");
+ }
+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
+ } else if (g_strcmp0 (property, "discoverable") == 0) {
+ gboolean discoverable = adapter1_get_discoverable (adapter);
+
+ gtk_tree_store_set (priv->store, &iter,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERABLE, discoverable, -1);
+
+ if (is_default)
+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
+ } else {
+ notify = FALSE;
+ }
+
+ if (notify != FALSE) {
+ GtkTreePath *path;
+
+ /* Tell the world */
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter);
+ gtk_tree_path_free (path);
+ }
+}
+
+static void
+adapter_added (GDBusObjectManager *manager,
+ Adapter1 *adapter,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter;
+ const gchar *address, *name, *alias;
+ gboolean discovering, discoverable, powered;
+
+ g_signal_connect_object (G_OBJECT (adapter), "notify",
+ G_CALLBACK (adapter_notify_cb), client, 0);
+
+ address = adapter1_get_address (adapter);
+ name = adapter1_get_name (adapter);
+ alias = adapter1_get_alias (adapter);
+ discovering = adapter1_get_discovering (adapter);
+ powered = adapter1_get_powered (adapter);
+ discoverable = adapter1_get_discoverable (adapter);
+
+ gtk_tree_store_insert_with_values(priv->store, &iter, NULL, -1,
+ SHELL_BLUETOOTH_COLUMN_PROXY, adapter,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS, address,
+ SHELL_BLUETOOTH_COLUMN_NAME, name,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, alias,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERING, discovering,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERABLE, discoverable,
+ SHELL_BLUETOOTH_COLUMN_POWERED, powered,
+ -1);
+
+ if (!priv->default_adapter) {
+ default_adapter_changed (manager,
+ g_dbus_object_get_object_path (g_dbus_interface_get_object
(G_DBUS_INTERFACE (adapter))),
+ client);
+ }
+}
+
+static void
+adapter_removed (GDBusObjectManager *manager,
+ const char *path,
+ ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter, childiter;
+ gboolean was_default;
+ gboolean have_child;
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT, &was_default, -1);
+
+ if (!was_default)
+ return;
+
+ /* Ensure that all devices are removed. This can happen if bluetoothd
+ * crashes as the "object-removed" signal is emitted in an undefined
+ * order. */
+ have_child = gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->store), &childiter, &iter);
+ while (have_child) {
+ GDBusProxy *object;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &childiter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &object, -1);
+
+ g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, g_dbus_proxy_get_object_path
(object));
+ g_object_unref (object);
+
+ have_child = gtk_tree_store_remove (priv->store, &childiter);
+ }
+
+ g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
+ gtk_tree_store_remove (priv->store, &iter);
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store),
+ &iter)) {
+ GDBusProxy *adapter;
+ const char *adapter_path;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &adapter, -1);
+
+ adapter_path = g_dbus_proxy_get_object_path (adapter);
+ default_adapter_changed (manager, adapter_path, client);
+
+ g_object_unref(adapter);
+ } else {
+ g_object_notify (G_OBJECT (client), "default-adapter");
+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
+ }
+}
+
+static GType
+object_manager_get_proxy_type_func (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *interface_name,
+ gpointer user_data)
+{
+ if (interface_name == NULL)
+ return G_TYPE_DBUS_OBJECT_PROXY;
+
+ if (g_str_equal (interface_name, BLUEZ_DEVICE_INTERFACE))
+ return TYPE_DEVICE1_PROXY;
+ if (g_str_equal (interface_name, BLUEZ_ADAPTER_INTERFACE))
+ return TYPE_ADAPTER1_PROXY;
+
+ return G_TYPE_DBUS_PROXY;
+}
+
+static void
+interface_added (GDBusObjectManager *manager,
+ GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ ShellBluetoothClient *client = user_data;
+
+ if (IS_ADAPTER1 (interface)) {
+ adapter_added (manager,
+ ADAPTER1 (interface),
+ client);
+ } else if (IS_DEVICE1 (interface)) {
+ device_added (manager,
+ DEVICE1 (interface),
+ client);
+ }
+}
+
+static void
+interface_removed (GDBusObjectManager *manager,
+ GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ ShellBluetoothClient *client = user_data;
+
+ if (IS_ADAPTER1 (interface)) {
+ adapter_removed (manager,
+ g_dbus_object_get_object_path (object),
+ client);
+ } else if (IS_DEVICE1 (interface)) {
+ device_removed (g_dbus_object_get_object_path (object),
+ client);
+ }
+}
+
+static void
+object_added (GDBusObjectManager *manager,
+ GDBusObject *object,
+ ShellBluetoothClient *client)
+{
+ GList *interfaces, *l;
+
+ interfaces = g_dbus_object_get_interfaces (object);
+
+ for (l = interfaces; l != NULL; l = l->next)
+ interface_added (manager, object, G_DBUS_INTERFACE (l->data), client);
+
+ g_list_free_full (interfaces, g_object_unref);
+}
+
+static void
+object_removed (GDBusObjectManager *manager,
+ GDBusObject *object,
+ ShellBluetoothClient *client)
+{
+ GList *interfaces, *l;
+
+ interfaces = g_dbus_object_get_interfaces (object);
+
+ for (l = interfaces; l != NULL; l = l->next)
+ interface_removed (manager, object, G_DBUS_INTERFACE (l->data), client);
+
+ g_list_free_full (interfaces, g_object_unref);
+}
+
+static void
+object_manager_new_callback(GObject *source_object,
+ GAsyncResult *res,
+ void *user_data)
+{
+ ShellBluetoothClient *client;
+ ShellBluetoothClientPrivate *priv;
+ GDBusObjectManager *manager;
+ GList *object_list, *l;
+ GError *error = NULL;
+
+ manager = g_dbus_object_manager_client_new_for_bus_finish (res, &error);
+ if (!manager) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Could not create bluez object manager: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ client = SHELL_BLUETOOTH_CLIENT (user_data);
+ priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ priv->manager = manager;
+
+ g_signal_connect_object (G_OBJECT (priv->manager), "interface-added", (GCallback) interface_added,
client, 0);
+ g_signal_connect_object (G_OBJECT (priv->manager), "interface-removed", (GCallback)
interface_removed, client, 0);
+
+ g_signal_connect_object (G_OBJECT (priv->manager), "object-added", (GCallback) object_added, client,
0);
+ g_signal_connect_object (G_OBJECT (priv->manager), "object-removed", (GCallback) object_removed,
client, 0);
+
+ object_list = g_dbus_object_manager_get_objects (priv->manager);
+
+ /* We need to add the adapters first, otherwise the devices will
+ * be dropped to the floor, as they wouldn't have a parent in
+ * the treestore */
+ for (l = object_list; l != NULL; l = l->next) {
+ GDBusObject *object = l->data;
+ GDBusInterface *iface;
+
+ iface = g_dbus_object_get_interface (object, BLUEZ_ADAPTER_INTERFACE);
+ if (!iface)
+ continue;
+
+ adapter_added (priv->manager,
+ ADAPTER1 (iface),
+ client);
+ }
+
+ for (l = object_list; l != NULL; l = l->next) {
+ GDBusObject *object = l->data;
+ GDBusInterface *iface;
+
+ iface = g_dbus_object_get_interface (object, BLUEZ_DEVICE_INTERFACE);
+ if (!iface)
+ continue;
+
+ device_added (priv->manager,
+ DEVICE1 (iface),
+ client);
+ }
+ g_list_free_full (object_list, g_object_unref);
+}
+
+static void shell_bluetooth_client_init(ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+
+ priv->cancellable = g_cancellable_new ();
+ priv->store = gtk_tree_store_new(_SHELL_BLUETOOTH_NUM_COLUMNS,
+ G_TYPE_OBJECT, /* SHELL_BLUETOOTH_COLUMN_PROXY */
+ G_TYPE_OBJECT, /* SHELL_BLUETOOTH_COLUMN_PROPERTIES */
+ G_TYPE_STRING, /* SHELL_BLUETOOTH_COLUMN_ADDRESS */
+ G_TYPE_STRING, /* SHELL_BLUETOOTH_COLUMN_ALIAS */
+ G_TYPE_STRING, /* SHELL_BLUETOOTH_COLUMN_NAME */
+ G_TYPE_UINT, /* SHELL_BLUETOOTH_COLUMN_TYPE */
+ G_TYPE_STRING, /* SHELL_BLUETOOTH_COLUMN_ICON */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_DEFAULT */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_PAIRED */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_TRUSTED */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_CONNECTED */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_DISCOVERABLE */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_DISCOVERING */
+ G_TYPE_INT, /* SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING */
+ G_TYPE_BOOLEAN, /* SHELL_BLUETOOTH_COLUMN_POWERED */
+ G_TYPE_HASH_TABLE, /* SHELL_BLUETOOTH_COLUMN_SERVICES */
+ G_TYPE_STRV); /* SHELL_BLUETOOTH_COLUMN_UUIDS */
+
+ g_dbus_object_manager_client_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
+ BLUEZ_SERVICE,
+ BLUEZ_MANAGER_PATH,
+ object_manager_get_proxy_type_func,
+ NULL, NULL,
+ priv->cancellable,
+ object_manager_new_callback, client);
+}
+
+GDBusProxy *
+_shell_bluetooth_client_get_default_adapter(ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GDBusProxy *adapter;
+
+ g_return_val_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client), NULL);
+
+ if (priv->default_adapter == NULL)
+ return NULL;
+
+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &adapter, -1);
+ gtk_tree_path_free (path);
+
+ return adapter;
+}
+
+static const char*
+_shell_bluetooth_client_get_default_adapter_path (ShellBluetoothClient *self)
+{
+ GDBusProxy *adapter = _shell_bluetooth_client_get_default_adapter (self);
+
+ if (adapter != NULL) {
+ const char *ret = g_dbus_proxy_get_object_path (adapter);
+ g_object_unref (adapter);
+ return ret;
+ }
+ return NULL;
+}
+
+static gboolean
+_shell_bluetooth_client_get_default_adapter_powered (ShellBluetoothClient *self)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (self);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean ret;
+
+ if (priv->default_adapter == NULL)
+ return FALSE;
+
+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, SHELL_BLUETOOTH_COLUMN_POWERED, &ret, -1);
+ gtk_tree_path_free (path);
+
+ return ret;
+}
+
+static char *
+_shell_bluetooth_client_get_default_adapter_name (ShellBluetoothClient *self)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (self);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ char *ret;
+
+ if (priv->default_adapter == NULL)
+ return NULL;
+
+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, SHELL_BLUETOOTH_COLUMN_ALIAS, &ret, -1);
+ gtk_tree_path_free (path);
+
+ return ret;
+}
+
+static void
+_shell_bluetooth_client_set_default_adapter_discovering (ShellBluetoothClient *client,
+ gboolean discovering,
+ gboolean discoverable)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (client);
+ g_autoptr(GDBusProxy) adapter = NULL;
+ GVariantBuilder builder;
+
+ adapter = _shell_bluetooth_client_get_default_adapter (client);
+ if (adapter == NULL)
+ return;
+
+ if (discovering) {
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&builder, "{sv}",
+ "Discoverable", g_variant_new_boolean (discoverable));
+ adapter1_call_set_discovery_filter_sync (ADAPTER1 (adapter),
+ g_variant_builder_end (&builder), NULL, NULL);
+ }
+
+ priv->discovery_started = discovering;
+ if (discovering)
+ adapter1_call_start_discovery (ADAPTER1 (adapter), NULL, NULL, NULL);
+ else
+ adapter1_call_stop_discovery (ADAPTER1 (adapter), NULL, NULL, NULL);
+}
+
+static gboolean
+_shell_bluetooth_client_get_default_adapter_discovering (ShellBluetoothClient *self)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (self);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean ret;
+
+ if (priv->default_adapter == NULL)
+ return FALSE;
+
+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, SHELL_BLUETOOTH_COLUMN_DISCOVERING, &ret,
-1);
+ gtk_tree_path_free (path);
+
+ return ret;
+}
+
+static void
+shell_bluetooth_client_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ShellBluetoothClient *self = SHELL_BLUETOOTH_CLIENT (object);
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DEFAULT_ADAPTER:
+ g_value_set_string (value, _shell_bluetooth_client_get_default_adapter_path (self));
+ break;
+ case PROP_DEFAULT_ADAPTER_POWERED:
+ g_value_set_boolean (value, _shell_bluetooth_client_get_default_adapter_powered (self));
+ break;
+ case PROP_DEFAULT_ADAPTER_NAME:
+ g_value_take_string (value, _shell_bluetooth_client_get_default_adapter_name (self));
+ break;
+ case PROP_DEFAULT_ADAPTER_DISCOVERABLE:
+ g_value_set_boolean (value, priv->disco_during_disco);
+ break;
+ case PROP_DEFAULT_ADAPTER_DISCOVERING:
+ g_value_set_boolean (value, _shell_bluetooth_client_get_default_adapter_discovering (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+shell_bluetooth_client_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ShellBluetoothClient *self = SHELL_BLUETOOTH_CLIENT (object);
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DEFAULT_ADAPTER_DISCOVERABLE:
+ priv->disco_during_disco = g_value_get_boolean (value);
+ _shell_bluetooth_client_set_default_adapter_discovering (self, priv->discovery_started,
priv->disco_during_disco);
+ break;
+ case PROP_DEFAULT_ADAPTER_DISCOVERING:
+ _shell_bluetooth_client_set_default_adapter_discovering (self, g_value_get_boolean (value),
priv->disco_during_disco);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void shell_bluetooth_client_finalize(GObject *object)
+{
+ ShellBluetoothClient *client = SHELL_BLUETOOTH_CLIENT (object);
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE (client);
+
+ if (priv->cancellable != NULL) {
+ g_cancellable_cancel (priv->cancellable);
+ g_clear_object (&priv->cancellable);
+ }
+ g_clear_object (&priv->manager);
+ g_object_unref (priv->store);
+
+ g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
+
+ G_OBJECT_CLASS(shell_bluetooth_client_parent_class)->finalize (object);
+}
+
+static void shell_bluetooth_client_class_init(ShellBluetoothClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = shell_bluetooth_client_finalize;
+ object_class->get_property = shell_bluetooth_client_get_property;
+ object_class->set_property = shell_bluetooth_client_set_property;
+
+ /**
+ * ShellBluetoothClient::device-removed:
+ * @client: a #ShellBluetoothClient object which received the signal
+ * @device: the D-Bus object path for the now-removed device
+ *
+ * The #ShellBluetoothClient::device-removed signal is launched when a
+ * device gets removed from the model.
+ **/
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ /**
+ * ShellBluetoothClient:default-adapter:
+ *
+ * The D-Bus path of the default ShellBluetooth adapter or %NULL.
+ */
+ g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER,
+ g_param_spec_string ("default-adapter", NULL,
+ "The D-Bus path of the default adapter",
+ NULL, G_PARAM_READABLE));
+ /**
+ * ShellBluetoothClient:default-adapter-powered:
+ *
+ * %TRUE if the default ShellBluetooth adapter is powered.
+ */
+ g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_POWERED,
+ g_param_spec_boolean ("default-adapter-powered", NULL,
+ "Whether the default adapter is powered",
+ FALSE, G_PARAM_READABLE));
+ /**
+ * ShellBluetoothClient:default-adapter-discoverable:
+ *
+ * %TRUE if the default ShellBluetooth adapter is discoverable during discovery.
+ */
+ g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_DISCOVERABLE,
+ g_param_spec_boolean ("default-adapter-discoverable", NULL,
+ "Whether the default adapter is visible by
other devices during discovery",
+ FALSE, G_PARAM_READWRITE));
+ /**
+ * ShellBluetoothClient:default-adapter-name:
+ *
+ * The name of the default ShellBluetooth adapter or %NULL.
+ */
+ g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_NAME,
+ g_param_spec_string ("default-adapter-name", NULL,
+ "The human readable name of the default
adapter",
+ NULL, G_PARAM_READABLE));
+ /**
+ * ShellBluetoothClient:default-adapter-discovering:
+ *
+ * %TRUE if the default ShellBluetooth adapter is discovering.
+ */
+ g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_DISCOVERING,
+ g_param_spec_boolean ("default-adapter-discovering", NULL,
+ "Whether the default adapter is searching for
devices",
+ FALSE, G_PARAM_READWRITE));
+}
+
+/**
+ * shell_bluetooth_client_new:
+ *
+ * Returns a reference to the #ShellBluetoothClient singleton. Use g_object_unref() when done with the
object.
+ *
+ * Return value: (transfer full): a #ShellBluetoothClient object.
+ **/
+ShellBluetoothClient *shell_bluetooth_client_new(void)
+{
+ static ShellBluetoothClient *shell_bluetooth_client = NULL;
+
+ if (shell_bluetooth_client != NULL)
+ return g_object_ref(shell_bluetooth_client);
+
+ shell_bluetooth_client = SHELL_BLUETOOTH_CLIENT (g_object_new (SHELL_BLUETOOTH_TYPE_CLIENT, NULL));
+ g_object_add_weak_pointer (G_OBJECT (shell_bluetooth_client),
+ (gpointer) &shell_bluetooth_client);
+
+ return shell_bluetooth_client;
+}
+
+/**
+ * shell_bluetooth_client_get_model:
+ * @client: a #ShellBluetoothClient object
+ *
+ * Returns an unfiltered #GtkTreeModel representing the adapter and devices available on the system.
+ *
+ * Return value: (transfer full): a #GtkTreeModel object.
+ **/
+GtkTreeModel *shell_bluetooth_client_get_model (ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv;
+ GtkTreeModel *model;
+
+ g_return_val_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client), NULL);
+
+ priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ model = GTK_TREE_MODEL (g_object_ref(priv->store));
+
+ return model;
+}
+
+/**
+ * shell_bluetooth_client_get_filter_model:
+ * @client: a #ShellBluetoothClient object
+ * @func: a #GtkTreeModelFilterVisibleFunc
+ * @data: user data to pass to gtk_tree_model_filter_set_visible_func()
+ * @destroy: a destroy function for gtk_tree_model_filter_set_visible_func()
+ *
+ * Returns a #GtkTreeModelFilter of devices filtered using the @func, @data and @destroy arguments to pass
to gtk_tree_model_filter_set_visible_func().
+ *
+ * Return value: (transfer full): a #GtkTreeModel object.
+ **/
+GtkTreeModel *shell_bluetooth_client_get_filter_model (ShellBluetoothClient *client,
+ GtkTreeModelFilterVisibleFunc func,
+ gpointer data, GDestroyNotify destroy)
+{
+ ShellBluetoothClientPrivate *priv;
+ GtkTreeModel *model;
+
+ g_return_val_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client), NULL);
+
+ priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ model = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
+
+ gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model),
+ func, data, destroy);
+
+ return model;
+}
+
+static gboolean adapter_filter(GtkTreeModel *model,
+ GtkTreeIter *iter, gpointer user_data)
+{
+ GDBusProxy *proxy;
+ gboolean active;
+
+ gtk_tree_model_get(model, iter, SHELL_BLUETOOTH_COLUMN_PROXY, &proxy, -1);
+
+ if (proxy == NULL)
+ return FALSE;
+
+ active = g_str_equal(BLUEZ_ADAPTER_INTERFACE,
+ g_dbus_proxy_get_interface_name(proxy));
+
+ g_object_unref(proxy);
+
+ return active;
+}
+
+/**
+ * shell_bluetooth_client_get_adapter_model:
+ * @client: a #ShellBluetoothClient object
+ *
+ * Returns a #GtkTreeModelFilter with only adapters present.
+ *
+ * Return value: (transfer full): a #GtkTreeModel object.
+ **/
+GtkTreeModel *shell_bluetooth_client_get_adapter_model (ShellBluetoothClient *client)
+{
+ return shell_bluetooth_client_get_filter_model (client, adapter_filter,
+ NULL, NULL);
+}
+
+/**
+ * shell_bluetooth_client_get_device_model:
+ * @client: a #ShellBluetoothClient object
+ *
+ * Returns a #GtkTreeModelFilter with only devices belonging to the default adapter listed.
+ * Note that the model will follow a specific adapter, and will not follow the default adapter.
+ * Also note that due to the way #GtkTreeModelFilter works, you will probably want to
+ * monitor signals on the "child-model" #GtkTreeModel to monitor for changes.
+ *
+ * Return value: (transfer full): a #GtkTreeModel object.
+ **/
+GtkTreeModel *shell_bluetooth_client_get_device_model (ShellBluetoothClient *client)
+{
+ ShellBluetoothClientPrivate *priv;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean cont, found = FALSE;
+
+ g_return_val_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client), NULL);
+
+ priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store), &iter);
+
+ while (cont == TRUE) {
+ gboolean is_default;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
+
+ if (is_default == TRUE) {
+ found = TRUE;
+ break;
+ }
+
+ cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(priv->store), &iter);
+ }
+
+ if (found == TRUE) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL(priv->store), &iter);
+ model = gtk_tree_model_filter_new (GTK_TREE_MODEL(priv->store), path);
+ gtk_tree_path_free (path);
+ } else
+ model = NULL;
+
+ return model;
+}
+
+typedef struct {
+ ShellBluetoothClientSetupFunc func;
+ ShellBluetoothClient *client;
+} CreateDeviceData;
+
+static void
+device_pair_callback (GDBusProxy *proxy,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (device1_call_pair_finish (DEVICE1(proxy), res, &error) == FALSE) {
+ g_debug ("Pair() failed for %s: %s",
+ g_dbus_proxy_get_object_path (proxy),
+ error->message);
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+/**
+ * shell_bluetooth_client_setup_device_finish:
+ * @client:
+ * @res:
+ * @path: (out):
+ * @error:
+ */
+gboolean
+shell_bluetooth_client_setup_device_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ char **path,
+ GError **error)
+{
+ GTask *task;
+ char *object_path;
+ gboolean ret;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ task = G_TASK (res);
+
+ g_warn_if_fail (g_task_get_source_tag (task) == shell_bluetooth_client_setup_device);
+
+ ret = g_task_propagate_boolean (task, error);
+ object_path = g_strdup (g_task_get_task_data (task));
+ *path = object_path;
+ g_debug ("shell_bluetooth_client_setup_device_finish() %s (path: %s)",
+ ret ? "success" : "failure", object_path);
+ return ret;
+}
+
+void
+shell_bluetooth_client_setup_device (ShellBluetoothClient *client,
+ const char *path,
+ gboolean pair,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GTask *task;
+ g_autoptr(GDBusProxy) device = NULL;
+ GtkTreeIter iter, adapter_iter;
+ gboolean paired;
+
+ g_return_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client));
+ g_return_if_fail (path != NULL);
+
+ task = g_task_new (G_OBJECT (client),
+ cancellable,
+ callback,
+ user_data);
+ g_task_set_source_tag (task, shell_bluetooth_client_setup_device);
+ g_task_set_task_data (task, g_strdup (path), (GDestroyNotify) g_free);
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Device with object path %s does not exist",
+ path);
+ g_object_unref (task);
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &device,
+ SHELL_BLUETOOTH_COLUMN_PAIRED, &paired, -1);
+
+ if (paired != FALSE &&
+ gtk_tree_model_iter_parent (GTK_TREE_MODEL(priv->store), &adapter_iter, &iter)) {
+ GDBusProxy *adapter;
+ g_autoptr(GError) err = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &adapter_iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &adapter,
+ -1);
+ adapter1_call_remove_device_sync (ADAPTER1 (adapter),
+ path,
+ NULL, &err);
+ if (err != NULL)
+ g_warning ("Failed to remove device: %s", err->message);
+ g_object_unref (adapter);
+ }
+
+ if (pair == TRUE) {
+ device1_call_pair (DEVICE1(device),
+ cancellable,
+ (GAsyncReadyCallback) device_pair_callback,
+ task);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+}
+
+/**
+ * shell_bluetooth_client_cancel_setup_device_finish:
+ * @client:
+ * @res:
+ * @path: (out):
+ * @error:
+ */
+gboolean
+shell_bluetooth_client_cancel_setup_device_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ char **path,
+ GError **error)
+{
+ GTask *task;
+ char *object_path;
+ gboolean ret;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ task = G_TASK (res);
+
+ g_warn_if_fail (g_task_get_source_tag (task) == shell_bluetooth_client_cancel_setup_device);
+
+ ret = g_task_propagate_boolean (task, error);
+ object_path = g_strdup (g_task_get_task_data (task));
+ *path = object_path;
+ g_debug ("shell_bluetooth_client_cancel_setup_device_finish() %s (path: %s)",
+ ret ? "success" : "failure", object_path);
+ return ret;
+}
+
+static void
+device_cancel_pairing_callback (GDBusProxy *proxy,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (device1_call_cancel_pairing_finish (DEVICE1(proxy), res, &error) == FALSE) {
+ g_debug ("CancelPairing() failed for %s: %s",
+ g_dbus_proxy_get_object_path (proxy),
+ error->message);
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+void
+shell_bluetooth_client_cancel_setup_device (ShellBluetoothClient *client,
+ const char *path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GTask *task;
+ g_autoptr(GDBusProxy) device = NULL;
+ GtkTreeIter iter;
+
+ g_return_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client));
+ g_return_if_fail (path != NULL);
+
+ task = g_task_new (G_OBJECT (client),
+ cancellable,
+ callback,
+ user_data);
+ g_task_set_source_tag (task, shell_bluetooth_client_cancel_setup_device);
+ g_task_set_task_data (task, g_strdup (path), (GDestroyNotify) g_free);
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Device with object path %s does not exist",
+ path);
+ g_object_unref (task);
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &device,
+ -1);
+
+ device1_call_cancel_pairing (DEVICE1(device),
+ cancellable,
+ (GAsyncReadyCallback) device_cancel_pairing_callback,
+ task);
+}
+
+gboolean
+shell_bluetooth_client_set_trusted (ShellBluetoothClient *client,
+ const char *device_path,
+ gboolean trusted)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GObject *device;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client), FALSE);
+ g_return_val_if_fail (device_path != NULL, FALSE);
+
+ if (get_iter_from_path (priv->store, &iter, device_path) == FALSE) {
+ g_debug ("Couldn't find device '%s' in tree to mark it as trusted", device_path);
+ return FALSE;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &device, -1);
+
+ if (device == NULL)
+ return FALSE;
+
+ g_object_set (device, "trusted", trusted, NULL);
+ g_object_unref (device);
+
+ return TRUE;
+}
+
+GDBusProxy *
+shell_bluetooth_client_get_device (ShellBluetoothClient *client,
+ const char *path)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter;
+ GDBusProxy *proxy;
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
+ return NULL;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &proxy,
+ -1);
+ return proxy;
+}
+
+static void
+connect_callback (GDBusProxy *proxy,
+ GAsyncResult *res,
+ GTask *task)
+{
+ gboolean retval;
+ GError *error = NULL;
+
+ retval = device1_call_connect_finish (DEVICE1 (proxy), res, &error);
+ if (retval == FALSE) {
+ g_debug ("Connect failed for %s: %s",
+ g_dbus_proxy_get_object_path (proxy), error->message);
+ g_task_return_error (task, error);
+ } else {
+ g_debug ("Connect succeeded for %s",
+ g_dbus_proxy_get_object_path (proxy));
+ g_task_return_boolean (task, retval);
+ }
+
+ g_object_unref (task);
+}
+
+static void
+disconnect_callback (GDBusProxy *proxy,
+ GAsyncResult *res,
+ GTask *task)
+{
+ gboolean retval;
+ GError *error = NULL;
+
+ retval = device1_call_disconnect_finish (DEVICE1 (proxy), res, &error);
+ if (retval == FALSE) {
+ g_debug ("Disconnect failed for %s: %s",
+ g_dbus_proxy_get_object_path (proxy),
+ error->message);
+ g_task_return_error (task, error);
+ } else {
+ g_debug ("Disconnect succeeded for %s",
+ g_dbus_proxy_get_object_path (proxy));
+ g_task_return_boolean (task, retval);
+ }
+
+ g_object_unref (task);
+}
+
+/**
+ * shell_bluetooth_client_connect_service:
+ * @client: a #ShellBluetoothClient
+ * @path: the object path on which to operate
+ * @connect: Whether try to connect or disconnect from services on a device
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the connection is complete
+ * @user_data: the data to pass to callback function
+ *
+ * When the connection operation is finished, @callback will be called. You can
+ * then call shell_bluetooth_client_connect_service_finish() to get the result of the
+ * operation.
+ **/
+void
+shell_bluetooth_client_connect_service (ShellBluetoothClient *client,
+ const char *path,
+ gboolean connect,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ShellBluetoothClientPrivate *priv = SHELL_BLUETOOTH_CLIENT_GET_PRIVATE(client);
+ GtkTreeIter iter;
+ GTask *task;
+ g_autoptr(GDBusProxy) device = NULL;
+
+ g_return_if_fail (SHELL_BLUETOOTH_IS_CLIENT (client));
+ g_return_if_fail (path != NULL);
+
+ task = g_task_new (G_OBJECT (client),
+ cancellable,
+ callback,
+ user_data);
+ g_task_set_source_tag (task, shell_bluetooth_client_connect_service);
+
+ if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Device with object path %s does not exist",
+ path);
+ g_object_unref (task);
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &device,
+ -1);
+
+ if (connect) {
+ device1_call_connect (DEVICE1(device),
+ cancellable,
+ (GAsyncReadyCallback) connect_callback,
+ task);
+ } else {
+ device1_call_disconnect (DEVICE1(device),
+ cancellable,
+ (GAsyncReadyCallback) disconnect_callback,
+ task);
+ }
+}
+
+/**
+ * shell_bluetooth_client_connect_service_finish:
+ * @client: a #ShellBluetoothClient
+ * @res: a #GAsyncResult
+ * @error: a #GError
+ *
+ * Finishes the connection operation. See shell_bluetooth_client_connect_service().
+ *
+ * Returns: %TRUE if the connection operation succeeded, %FALSE otherwise.
+ **/
+gboolean
+shell_bluetooth_client_connect_service_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ GError **error)
+{
+ GTask *task;
+
+ task = G_TASK (res);
+
+ g_warn_if_fail (g_task_get_source_tag (task) == shell_bluetooth_client_connect_service);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+#define BOOL_STR(x) (x ? "True" : "False")
+
+void
+shell_bluetooth_client_dump_device (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GDBusProxy *proxy;
+ char *address, *alias, *icon, **uuids;
+ gboolean is_default, paired, trusted, connected, discoverable, discovering, powered, is_adapter;
+ GtkTreeIter parent;
+ ShellBluetoothType type;
+
+ gtk_tree_model_get (model, iter,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS, &address,
+ SHELL_BLUETOOTH_COLUMN_ALIAS, &alias,
+ SHELL_BLUETOOTH_COLUMN_TYPE, &type,
+ SHELL_BLUETOOTH_COLUMN_ICON, &icon,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT, &is_default,
+ SHELL_BLUETOOTH_COLUMN_PAIRED, &paired,
+ SHELL_BLUETOOTH_COLUMN_TRUSTED, &trusted,
+ SHELL_BLUETOOTH_COLUMN_CONNECTED, &connected,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERABLE, &discoverable,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERING, &discovering,
+ SHELL_BLUETOOTH_COLUMN_POWERED, &powered,
+ SHELL_BLUETOOTH_COLUMN_UUIDS, &uuids,
+ SHELL_BLUETOOTH_COLUMN_PROXY, &proxy,
+ -1);
+ if (proxy) {
+ char *basename;
+ basename = g_path_get_basename(g_dbus_proxy_get_object_path(proxy));
+ is_adapter = !g_str_has_prefix (basename, "dev_");
+ g_free (basename);
+ } else {
+ is_adapter = !gtk_tree_model_iter_parent (model, &parent, iter);
+ }
+
+ if (is_adapter != FALSE) {
+ /* Adapter */
+ g_print ("Adapter: %s (%s)\n", alias, address);
+ if (is_default)
+ g_print ("\tDefault adapter\n");
+ g_print ("\tD-Bus Path: %s\n", proxy ? g_dbus_proxy_get_object_path (proxy) : "(none)");
+ g_print ("\tDiscoverable: %s\n", BOOL_STR (discoverable));
+ if (discovering)
+ g_print ("\tDiscovery in progress\n");
+ g_print ("\t%s\n", powered ? "Is powered" : "Is not powered");
+ } else {
+ /* Device */
+ g_print ("Device: %s (%s)\n", alias, address);
+ g_print ("\tD-Bus Path: %s\n", proxy ? g_dbus_proxy_get_object_path (proxy) : "(none)");
+ g_print ("\tType: %s Icon: %s\n", shell_bluetooth_type_to_string (type), icon);
+ g_print ("\tPaired: %s Trusted: %s Connected: %s\n", BOOL_STR(paired), BOOL_STR(trusted),
BOOL_STR(connected));
+ if (uuids != NULL) {
+ guint i;
+ g_print ("\tUUIDs: ");
+ for (i = 0; uuids[i] != NULL; i++)
+ g_print ("%s ", uuids[i]);
+ g_print ("\n");
+ }
+ }
+ g_print ("\n");
+
+ g_free (alias);
+ g_free (address);
+ g_free (icon);
+ g_clear_object (&proxy);
+ g_strfreev (uuids);
+}
+
diff --git a/src/shell-bluetooth-client.h b/src/shell-bluetooth-client.h
new file mode 100644
index 0000000000..c9bf012143
--- /dev/null
+++ b/src/shell-bluetooth-client.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * BlueZ - ShellBluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel holtmann org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <shell-bluetooth-enums.h>
+
+#define SHELL_BLUETOOTH_TYPE_CLIENT (shell_bluetooth_client_get_type())
+#define SHELL_BLUETOOTH_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ SHELL_BLUETOOTH_TYPE_CLIENT, ShellBluetoothClient))
+#define SHELL_BLUETOOTH_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ SHELL_BLUETOOTH_TYPE_CLIENT, ShellBluetoothClientClass))
+#define SHELL_BLUETOOTH_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ SHELL_BLUETOOTH_TYPE_CLIENT))
+#define SHELL_BLUETOOTH_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ SHELL_BLUETOOTH_TYPE_CLIENT))
+#define SHELL_BLUETOOTH_GET_CLIENT_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ SHELL_BLUETOOTH_TYPE_CLIENT, ShellBluetoothClientClass))
+
+/**
+ * ShellBluetoothClient:
+ *
+ * The <structname>ShellBluetoothClient</structname> struct contains
+ * only private fields and should not be directly accessed.
+ */
+typedef struct _ShellBluetoothClient ShellBluetoothClient;
+typedef struct _ShellBluetoothClientClass ShellBluetoothClientClass;
+
+struct _ShellBluetoothClient {
+ GObject parent;
+};
+
+struct _ShellBluetoothClientClass {
+ GObjectClass parent_class;
+};
+
+GType shell_bluetooth_client_get_type(void);
+
+ShellBluetoothClient *shell_bluetooth_client_new(void);
+
+GtkTreeModel *shell_bluetooth_client_get_model(ShellBluetoothClient *client);
+
+GtkTreeModel *shell_bluetooth_client_get_filter_model(ShellBluetoothClient *client,
+ GtkTreeModelFilterVisibleFunc func,
+ gpointer data, GDestroyNotify destroy);
+GtkTreeModel *shell_bluetooth_client_get_adapter_model(ShellBluetoothClient *client);
+GtkTreeModel *shell_bluetooth_client_get_device_model(ShellBluetoothClient *client);
+
+void shell_bluetooth_client_connect_service (ShellBluetoothClient *client,
+ const char *path,
+ gboolean connect,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean shell_bluetooth_client_connect_service_finish (ShellBluetoothClient *client,
+ GAsyncResult *res,
+ GError **error);
diff --git a/src/shell-bluetooth-client.xml b/src/shell-bluetooth-client.xml
new file mode 100644
index 0000000000..1324821402
--- /dev/null
+++ b/src/shell-bluetooth-client.xml
@@ -0,0 +1,60 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<node>
+ <interface name="org.bluez.Adapter1">
+ <method name="StartDiscovery"></method>
+ <method name="StopDiscovery"></method>
+ <method name="RemoveDevice"><arg name="device" type="o" direction="in"/></method>
+ <method name="SetDiscoveryFilter"><arg name="properties" type="a{sv}" direction="in"/></method>
+ <property name="Address" type="s" access="read"></property>
+ <property name="Name" type="s" access="read"></property>
+ <property name="Alias" type="s" access="readwrite"></property>
+ <property name="Class" type="u" access="read"></property>
+ <property name="Powered" type="b" access="readwrite"></property>
+ <property name="Discoverable" type="b" access="readwrite"></property>
+ <property name="DiscoverableTimeout" type="u" access="readwrite"></property>
+ <property name="Pairable" type="b" access="readwrite"></property>
+ <property name="PairableTimeout" type="u" access="readwrite"></property>
+ <property name="Discovering" type="b" access="read"></property>
+ <property name="UUIDs" type="as" access="read"></property>
+ <property name="Modalias" type="s" access="read"></property>
+ </interface>
+
+ <interface name="org.bluez.Device1">
+ <method name="Disconnect"></method>
+ <method name="Connect"></method>
+ <method name="ConnectProfile"><arg name="UUID" type="s" direction="in"/> </method>
+ <method name="DisconnectProfile"><arg name="UUID" type="s" direction="in"/> </method>
+ <method name="Pair"></method>
+ <method name="CancelPairing"></method>
+ <property name="Address" type="s" access="read"></property>
+ <property name="Name" type="s" access="read"></property>
+ <property name="Alias" type="s" access="readwrite"></property>
+ <property name="Class" type="u" access="read"></property>
+ <property name="Appearance" type="q" access="read"></property>
+ <property name="Icon" type="s" access="read"></property>
+ <property name="Paired" type="b" access="read"></property>
+ <property name="Trusted" type="b" access="readwrite"></property>
+ <property name="Blocked" type="b" access="readwrite"></property>
+ <property name="LegacyPairing" type="b" access="read"></property>
+ <property name="RSSI" type="n" access="read"></property>
+ <property name="Connected" type="b" access="read"></property>
+ <property name="UUIDs" type="as" access="read"></property>
+ <property name="Modalias" type="s" access="read"></property>
+ <property name="Adapter" type="o" access="read"></property>
+ </interface>
+
+ <interface name="org.bluez.AgentManager1">
+ <method name="RegisterAgent">
+ <arg name="agent" type="o" direction="in"/>
+ <arg name="capability" type="s" direction="in"/>
+ </method>
+ <method name="UnregisterAgent">
+ <arg name="agent" type="o" direction="in"/>
+ </method>
+ <method name="RequestDefaultAgent">
+ <arg name="agent" type="o" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/shell-bluetooth-enums.h b/src/shell-bluetooth-enums.h
new file mode 100644
index 0000000000..1ab8f7c15b
--- /dev/null
+++ b/src/shell-bluetooth-enums.h
@@ -0,0 +1,182 @@
+/*
+ *
+ * BlueZ - ShellBluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel holtmann org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#pragma once
+
+#include <glib.h>
+
+/**
+ * SECTION:shell-bluetooth-enums
+ * @short_description: ShellBluetooth related enumerations
+ * @stability: Stable
+ * @include: shell-bluetooth-enums.h
+ *
+ * Enumerations related to ShellBluetooth.
+ **/
+
+/**
+ * ShellBluetoothCategory:
+ * @SHELL_BLUETOOTH_CATEGORY_ALL: all devices
+ * @SHELL_BLUETOOTH_CATEGORY_PAIRED: paired devices
+ * @SHELL_BLUETOOTH_CATEGORY_TRUSTED: trusted devices
+ * @SHELL_BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED: neither paired, nor trusted devices
+ * @SHELL_BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED: paired and/or trusted devices
+ *
+ * The category of a ShellBluetooth devices.
+ **/
+typedef enum {
+ SHELL_BLUETOOTH_CATEGORY_ALL,
+ SHELL_BLUETOOTH_CATEGORY_PAIRED,
+ SHELL_BLUETOOTH_CATEGORY_TRUSTED,
+ SHELL_BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED,
+ SHELL_BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED,
+ /* < private > */
+ SHELL_BLUETOOTH_CATEGORY_NUM_CATEGORIES /*< skip >*/
+} ShellBluetoothCategory;
+
+/**
+ * ShellBluetoothType:
+ * @SHELL_BLUETOOTH_TYPE_ANY: any device, or a device of an unknown type
+ * @SHELL_BLUETOOTH_TYPE_PHONE: a telephone (usually a cell/mobile phone)
+ * @SHELL_BLUETOOTH_TYPE_MODEM: a modem
+ * @SHELL_BLUETOOTH_TYPE_COMPUTER: a computer, can be a laptop, a wearable computer, etc.
+ * @SHELL_BLUETOOTH_TYPE_NETWORK: a network device, such as a router
+ * @SHELL_BLUETOOTH_TYPE_HEADSET: a headset (usually a hands-free device)
+ * @SHELL_BLUETOOTH_TYPE_HEADPHONES: headphones (covers two ears)
+ * @SHELL_BLUETOOTH_TYPE_OTHER_AUDIO: another type of audio device
+ * @SHELL_BLUETOOTH_TYPE_KEYBOARD: a keyboard
+ * @SHELL_BLUETOOTH_TYPE_MOUSE: a mouse
+ * @SHELL_BLUETOOTH_TYPE_CAMERA: a camera (still or moving)
+ * @SHELL_BLUETOOTH_TYPE_PRINTER: a printer
+ * @SHELL_BLUETOOTH_TYPE_JOYPAD: a joypad, joystick, or other game controller
+ * @SHELL_BLUETOOTH_TYPE_TABLET: a drawing tablet
+ * @SHELL_BLUETOOTH_TYPE_VIDEO: a video device, such as a webcam
+ * @SHELL_BLUETOOTH_TYPE_REMOTE_CONTROL: a remote control
+ * @SHELL_BLUETOOTH_TYPE_SCANNER: a scanner
+ * @SHELL_BLUETOOTH_TYPE_DISPLAY: a display
+ * @SHELL_BLUETOOTH_TYPE_WEARABLE: a wearable computer
+ * @SHELL_BLUETOOTH_TYPE_TOY: a toy or game
+ * @SHELL_BLUETOOTH_TYPE_SPEAKERS: audio speaker or speakers
+ *
+ * The type of a ShellBluetooth device. See also %SHELL_BLUETOOTH_TYPE_INPUT and %SHELL_BLUETOOTH_TYPE_AUDIO
+ **/
+typedef enum {
+ SHELL_BLUETOOTH_TYPE_ANY = 1 << 0,
+ SHELL_BLUETOOTH_TYPE_PHONE = 1 << 1,
+ SHELL_BLUETOOTH_TYPE_MODEM = 1 << 2,
+ SHELL_BLUETOOTH_TYPE_COMPUTER = 1 << 3,
+ SHELL_BLUETOOTH_TYPE_NETWORK = 1 << 4,
+ SHELL_BLUETOOTH_TYPE_HEADSET = 1 << 5,
+ SHELL_BLUETOOTH_TYPE_HEADPHONES = 1 << 6,
+ SHELL_BLUETOOTH_TYPE_OTHER_AUDIO = 1 << 7,
+ SHELL_BLUETOOTH_TYPE_KEYBOARD = 1 << 8,
+ SHELL_BLUETOOTH_TYPE_MOUSE = 1 << 9,
+ SHELL_BLUETOOTH_TYPE_CAMERA = 1 << 10,
+ SHELL_BLUETOOTH_TYPE_PRINTER = 1 << 11,
+ SHELL_BLUETOOTH_TYPE_JOYPAD = 1 << 12,
+ SHELL_BLUETOOTH_TYPE_TABLET = 1 << 13,
+ SHELL_BLUETOOTH_TYPE_VIDEO = 1 << 14,
+ SHELL_BLUETOOTH_TYPE_REMOTE_CONTROL = 1 << 15,
+ SHELL_BLUETOOTH_TYPE_SCANNER = 1 << 16,
+ SHELL_BLUETOOTH_TYPE_DISPLAY = 1 << 17,
+ SHELL_BLUETOOTH_TYPE_WEARABLE = 1 << 18,
+ SHELL_BLUETOOTH_TYPE_TOY = 1 << 19,
+ SHELL_BLUETOOTH_TYPE_SPEAKERS = 1 << 20,
+} ShellBluetoothType;
+
+#define _SHELL_BLUETOOTH_TYPE_NUM_TYPES 21
+
+/**
+ * SHELL_BLUETOOTH_TYPE_INPUT:
+ *
+ * Use this value to select any ShellBluetooth input device where a #ShellBluetoothType enum is required.
+ */
+#define SHELL_BLUETOOTH_TYPE_INPUT (SHELL_BLUETOOTH_TYPE_KEYBOARD | SHELL_BLUETOOTH_TYPE_MOUSE |
SHELL_BLUETOOTH_TYPE_TABLET | SHELL_BLUETOOTH_TYPE_JOYPAD)
+/**
+ * SHELL_BLUETOOTH_TYPE_AUDIO:
+ *
+ * Use this value to select any ShellBluetooth audio device where a #ShellBluetoothType enum is required.
+ */
+#define SHELL_BLUETOOTH_TYPE_AUDIO (SHELL_BLUETOOTH_TYPE_HEADSET | SHELL_BLUETOOTH_TYPE_HEADPHONES |
SHELL_BLUETOOTH_TYPE_OTHER_AUDIO | SHELL_BLUETOOTH_TYPE_SPEAKERS)
+
+/**
+ * ShellBluetoothColumn:
+ * @SHELL_BLUETOOTH_COLUMN_PROXY: a #GDBusProxy object
+ * @SHELL_BLUETOOTH_COLUMN_PROPERTIES: Used to be #GDBusProxy object for DBus.Properties, now always %NULL
+ * @SHELL_BLUETOOTH_COLUMN_ADDRESS: a string representing a ShellBluetooth address
+ * @SHELL_BLUETOOTH_COLUMN_ALIAS: a string to use for display (the name of the device, or its address if the
name is not known). Only available for devices.
+ * @SHELL_BLUETOOTH_COLUMN_NAME: a string representing the device or adapter's name
+ * @SHELL_BLUETOOTH_COLUMN_TYPE: the #ShellBluetoothType of the device. Only available for devices.
+ * @SHELL_BLUETOOTH_COLUMN_ICON: a string representing the icon name for the device. Only available for
devices.
+ * @SHELL_BLUETOOTH_COLUMN_DEFAULT: whether the adapter is the default one. Only available for adapters.
+ * @SHELL_BLUETOOTH_COLUMN_PAIRED: whether the device is paired to its parent adapter. Only available for
devices.
+ * @SHELL_BLUETOOTH_COLUMN_TRUSTED: whether the device is trusted. Only available for devices.
+ * @SHELL_BLUETOOTH_COLUMN_CONNECTED: whether the device is connected. Only available for devices.
+ * @SHELL_BLUETOOTH_COLUMN_DISCOVERABLE: whether the adapter is discoverable/visible. Only available for
adapters.
+ * @SHELL_BLUETOOTH_COLUMN_DISCOVERING: whether the adapter is discovering. Only available for adapters.
+ * @SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING: whether the device does not support ShellBluetooth 2.1 Simple
Secure Pairing. Only available for devices.
+ * @SHELL_BLUETOOTH_COLUMN_POWERED: whether the adapter is powered. Only available for adapters.
+ * @SHELL_BLUETOOTH_COLUMN_SERVICES: an array of service names and #ShellBluetoothStatus connection statuses.
+ * @SHELL_BLUETOOTH_COLUMN_UUIDS: a string array of human-readable UUIDs.
+ *
+ * A column identifier to pass to shell_bluetooth_chooser_get_selected_device_info().
+ **/
+typedef enum {
+ SHELL_BLUETOOTH_COLUMN_PROXY,
+ SHELL_BLUETOOTH_COLUMN_PROPERTIES,
+ SHELL_BLUETOOTH_COLUMN_ADDRESS,
+ SHELL_BLUETOOTH_COLUMN_ALIAS,
+ SHELL_BLUETOOTH_COLUMN_NAME,
+ SHELL_BLUETOOTH_COLUMN_TYPE,
+ SHELL_BLUETOOTH_COLUMN_ICON,
+ SHELL_BLUETOOTH_COLUMN_DEFAULT,
+ SHELL_BLUETOOTH_COLUMN_PAIRED,
+ SHELL_BLUETOOTH_COLUMN_TRUSTED,
+ SHELL_BLUETOOTH_COLUMN_CONNECTED,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERABLE,
+ SHELL_BLUETOOTH_COLUMN_DISCOVERING,
+ SHELL_BLUETOOTH_COLUMN_LEGACYPAIRING,
+ SHELL_BLUETOOTH_COLUMN_POWERED,
+ SHELL_BLUETOOTH_COLUMN_SERVICES,
+ SHELL_BLUETOOTH_COLUMN_UUIDS,
+} ShellBluetoothColumn;
+
+#define _SHELL_BLUETOOTH_NUM_COLUMNS (SHELL_BLUETOOTH_COLUMN_UUIDS + 1)
+
+/**
+ * ShellBluetoothStatus:
+ * @SHELL_BLUETOOTH_STATUS_INVALID: whether the status has been set yet
+ * @SHELL_BLUETOOTH_STATUS_DISCONNECTED: whether the service is disconnected
+ * @SHELL_BLUETOOTH_STATUS_CONNECTED: whether the service is connected
+ * @SHELL_BLUETOOTH_STATUS_CONNECTING: whether the service is connecting
+ * @SHELL_BLUETOOTH_STATUS_PLAYING: whether the service is playing (only used by the audio service)
+ *
+ * The connection status of a service on a particular device. Note that @SHELL_BLUETOOTH_STATUS_CONNECTING
and @SHELL_BLUETOOTH_STATUS_PLAYING might not be available for all services.
+ **/
+typedef enum {
+ SHELL_BLUETOOTH_STATUS_INVALID = 0,
+ SHELL_BLUETOOTH_STATUS_DISCONNECTED,
+ SHELL_BLUETOOTH_STATUS_CONNECTED,
+ SHELL_BLUETOOTH_STATUS_CONNECTING,
+ SHELL_BLUETOOTH_STATUS_PLAYING
+} ShellBluetoothStatus;
diff --git a/src/shell-bluetooth-pin.c b/src/shell-bluetooth-pin.c
new file mode 100644
index 0000000000..3f134e74b9
--- /dev/null
+++ b/src/shell-bluetooth-pin.c
@@ -0,0 +1,239 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Bastien Nocera <hadess hadess net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <libudev.h>
+#include <shell-bluetooth-enums.h>
+#include <shell-bluetooth-utils.h>
+
+#include "shell-bluetooth-pin.h"
+
+#define PIN_CODE_DB "pin-code-database.xml"
+#define MAX_DIGITS_PIN_PREFIX "max:"
+
+char *
+oui_to_vendor (const char *oui)
+{
+ struct udev *udev = NULL;
+ struct udev_hwdb *hwdb = NULL;
+ struct udev_list_entry *list, *l;
+ char *modalias = NULL;
+ char *vendor = NULL;
+
+ if (oui == NULL ||
+ strlen (oui) < 8)
+ return NULL;
+
+ udev = udev_new ();
+ if (udev == NULL)
+ goto bail;
+
+ hwdb = udev_hwdb_new (udev);
+ if (hwdb == NULL)
+ goto bail;
+
+ modalias = g_strdup_printf ("OUI:%c%c%c%c%c%c",
+ g_ascii_toupper (oui[0]),
+ g_ascii_toupper (oui[1]),
+ g_ascii_toupper (oui[3]),
+ g_ascii_toupper (oui[4]),
+ g_ascii_toupper (oui[6]),
+ g_ascii_toupper (oui[7]));
+
+ list = udev_hwdb_get_properties_list_entry (hwdb, modalias, 0);
+
+ udev_list_entry_foreach (l, list) {
+ const char *name = udev_list_entry_get_name (l);
+
+ if (g_strcmp0 (name, "ID_OUI_FROM_DATABASE") == 0) {
+ vendor = g_strdup (udev_list_entry_get_value (l));
+ break;
+ }
+ }
+
+bail:
+ g_clear_pointer (&modalias, g_free);
+ g_clear_pointer (&hwdb, udev_hwdb_unref);
+ g_clear_pointer (&udev, udev_unref);
+
+ return vendor;
+}
+
+#define TYPE_IS(x, r) { \
+ if (g_str_equal(type, x)) return r; \
+}
+
+static guint string_to_type(const char *type)
+{
+ TYPE_IS ("any", SHELL_BLUETOOTH_TYPE_ANY);
+ TYPE_IS ("mouse", SHELL_BLUETOOTH_TYPE_MOUSE);
+ TYPE_IS ("tablet", SHELL_BLUETOOTH_TYPE_TABLET);
+ TYPE_IS ("keyboard", SHELL_BLUETOOTH_TYPE_KEYBOARD);
+ TYPE_IS ("headset", SHELL_BLUETOOTH_TYPE_HEADSET);
+ TYPE_IS ("headphones", SHELL_BLUETOOTH_TYPE_HEADPHONES);
+ TYPE_IS ("audio", SHELL_BLUETOOTH_TYPE_OTHER_AUDIO);
+ TYPE_IS ("printer", SHELL_BLUETOOTH_TYPE_PRINTER);
+ TYPE_IS ("network", SHELL_BLUETOOTH_TYPE_NETWORK);
+ TYPE_IS ("joypad", SHELL_BLUETOOTH_TYPE_JOYPAD);
+
+ g_warning ("unhandled type '%s'", type);
+ return SHELL_BLUETOOTH_TYPE_ANY;
+}
+
+typedef struct {
+ char *ret_pin;
+ guint max_digits;
+ guint type;
+ const char *address;
+ const char *name;
+ char *vendor;
+ gboolean confirm;
+} PinParseData;
+
+static void
+pin_db_parse_start_tag (GMarkupParseContext *ctx,
+ const gchar *element_name,
+ const gchar **attr_names,
+ const gchar **attr_values,
+ gpointer data,
+ GError **error)
+{
+ PinParseData *pdata = (PinParseData *) data;
+
+ if (pdata->ret_pin != NULL || pdata->max_digits != 0)
+ return;
+ if (g_str_equal (element_name, "device") == FALSE)
+ return;
+
+ while (*attr_names && *attr_values) {
+ if (g_str_equal (*attr_names, "type")) {
+ guint type;
+
+ type = string_to_type (*attr_values);
+ if (type != SHELL_BLUETOOTH_TYPE_ANY && type != pdata->type)
+ return;
+ } else if (g_str_equal (*attr_names, "oui")) {
+ if (g_str_has_prefix (pdata->address, *attr_values) == FALSE)
+ return;
+ } else if (g_str_equal (*attr_names, "vendor")) {
+ if (*attr_values == NULL || pdata->vendor == NULL)
+ return;
+ if (strstr (pdata->vendor, *attr_values) == NULL)
+ return;
+ } else if (g_str_equal (*attr_names, "name")) {
+ if (*attr_values == NULL || pdata->name == NULL)
+ return;
+ if (strstr (pdata->name, *attr_values) == NULL)
+ return;
+ pdata->confirm = FALSE;
+ } else if (g_str_equal (*attr_names, "pin")) {
+ if (g_str_has_prefix (*attr_values, MAX_DIGITS_PIN_PREFIX) != FALSE) {
+ pdata->max_digits = strtoul (*attr_values + strlen (MAX_DIGITS_PIN_PREFIX),
NULL, 0);
+ g_assert (pdata->max_digits > 0 && pdata->max_digits < PIN_NUM_DIGITS);
+ } else {
+ pdata->ret_pin = g_strdup (*attr_values);
+ }
+ return;
+ }
+
+ ++attr_names;
+ ++attr_values;
+ }
+}
+
+char *
+get_pincode_for_device (guint type,
+ const char *address,
+ const char *name,
+ guint *max_digits,
+ gboolean *confirm)
+{
+ GMarkupParseContext *ctx;
+ GMarkupParser parser = { pin_db_parse_start_tag, NULL, NULL, NULL, NULL };
+ PinParseData *data;
+ char *buf;
+ gsize buf_len;
+ GError *err = NULL;
+ char *tmp_vendor, *ret_pin;
+
+ g_return_val_if_fail (address != NULL, NULL);
+
+ g_debug ("Getting pincode for device '%s' (type: %s address: %s)",
+ name ? name : "", shell_bluetooth_type_to_string (type), address);
+
+ /* Load the PIN database and split it in lines */
+ if (!g_file_get_contents(PIN_CODE_DB, &buf, &buf_len, NULL)) {
+ char *filename;
+
+ filename = g_build_filename(GNOME_SHELL_DATADIR, PIN_CODE_DB, NULL);
+ if (!g_file_get_contents(filename, &buf, &buf_len, NULL)) {
+ g_warning("Could not load "PIN_CODE_DB);
+ g_free (filename);
+ return NULL;
+ }
+ g_free (filename);
+ }
+
+ data = g_new0 (PinParseData, 1);
+ data->type = type;
+ data->address = address;
+ data->name = name;
+ data->confirm = TRUE;
+
+ tmp_vendor = oui_to_vendor (address);
+ if (tmp_vendor)
+ data->vendor = g_ascii_strdown (tmp_vendor, -1);
+ g_free (tmp_vendor);
+
+ ctx = g_markup_parse_context_new (&parser, 0, data, NULL);
+
+ if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) {
+ g_warning ("Failed to parse '%s': %s\n", PIN_CODE_DB, err->message);
+ g_error_free (err);
+ }
+
+ g_markup_parse_context_free (ctx);
+ g_free (buf);
+
+ if (max_digits != NULL)
+ *max_digits = data->max_digits;
+ if (confirm != NULL)
+ *confirm = data->confirm;
+
+ g_debug ("Got pin '%s' (max digits: %d, confirm: %d) for device '%s' (type: %s address: %s, vendor:
%s)",
+ data->ret_pin, data->max_digits, data->confirm,
+ name ? name : "", shell_bluetooth_type_to_string (type), address, data->vendor);
+
+ g_free (data->vendor);
+ ret_pin = data->ret_pin;
+ g_free (data);
+
+ return ret_pin;
+}
+
diff --git a/src/shell-bluetooth-pin.h b/src/shell-bluetooth-pin.h
new file mode 100644
index 0000000000..31ddf909f7
--- /dev/null
+++ b/src/shell-bluetooth-pin.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Bastien Nocera <hadess hadess net>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#pragma once
+
+#include <glib.h>
+
+#define PIN_NUM_DIGITS 6
+
+char *oui_to_vendor (const char *oui);
+char *get_pincode_for_device (guint type,
+ const char *address,
+ const char *name,
+ guint *max_digits,
+ gboolean *confirm);
+
diff --git a/src/shell-bluetooth-utils.c b/src/shell-bluetooth-utils.c
new file mode 100644
index 0000000000..f979dcaacd
--- /dev/null
+++ b/src/shell-bluetooth-utils.c
@@ -0,0 +1,430 @@
+/*
+ *
+ * BlueZ - ShellBluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2011 Bastien Nocera <hadess hadess net>
+ * Copyright (C) 2010 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/**
+ * SECTION:bluetooth-utils
+ * @short_description: ShellBluetooth utility functions
+ * @stability: Stable
+ * @include: bluetooth-utils.h
+ *
+ * Those helper functions are used throughout the ShellBluetooth
+ * management utilities.
+ **/
+
+#include <config.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "shell-bluetooth-utils.h"
+#include "shell-enum-types.h"
+
+/**
+ * shell_bluetooth_type_to_string:
+ * @type: a #ShellBluetoothType
+ *
+ * Returns a human-readable string representation of @type usable for display to users. Do not free the
return value.
+ * The returned string is already translated with gettext().
+ *
+ * Return value: a string.
+ **/
+const gchar *
+shell_bluetooth_type_to_string (ShellBluetoothType type)
+{
+ switch (type) {
+ case SHELL_BLUETOOTH_TYPE_PHONE:
+ return _("Phone");
+ case SHELL_BLUETOOTH_TYPE_MODEM:
+ return _("Modem");
+ case SHELL_BLUETOOTH_TYPE_COMPUTER:
+ return _("Computer");
+ case SHELL_BLUETOOTH_TYPE_NETWORK:
+ return _("Network");
+ case SHELL_BLUETOOTH_TYPE_HEADSET:
+ /* translators: a hands-free headset, a combination of a single speaker with a microphone */
+ return _("Headset");
+ case SHELL_BLUETOOTH_TYPE_HEADPHONES:
+ return _("Headphones");
+ case SHELL_BLUETOOTH_TYPE_OTHER_AUDIO:
+ return _("Audio device");
+ case SHELL_BLUETOOTH_TYPE_KEYBOARD:
+ return _("Keyboard");
+ case SHELL_BLUETOOTH_TYPE_MOUSE:
+ return _("Mouse");
+ case SHELL_BLUETOOTH_TYPE_CAMERA:
+ return _("Camera");
+ case SHELL_BLUETOOTH_TYPE_PRINTER:
+ return _("Printer");
+ case SHELL_BLUETOOTH_TYPE_JOYPAD:
+ return _("Joypad");
+ case SHELL_BLUETOOTH_TYPE_TABLET:
+ return _("Tablet");
+ case SHELL_BLUETOOTH_TYPE_VIDEO:
+ return _("Video device");
+ case SHELL_BLUETOOTH_TYPE_REMOTE_CONTROL:
+ return _("Remote control");
+ case SHELL_BLUETOOTH_TYPE_SCANNER:
+ return _("Scanner");
+ case SHELL_BLUETOOTH_TYPE_DISPLAY:
+ return _("Display");
+ case SHELL_BLUETOOTH_TYPE_WEARABLE:
+ return _("Wearable");
+ case SHELL_BLUETOOTH_TYPE_TOY:
+ return _("Toy");
+ }
+
+ return _("Unknown");
+}
+
+/**
+ * shell_bluetooth_type_to_filter_string:
+ * @type: a #ShellBluetoothType
+ *
+ * Returns a human-readable string representation of @type usable for display to users,
+ * when type filters are displayed. Do not free the return value.
+ * The returned string is already translated with gettext().
+ *
+ * Return value: a string.
+ **/
+const gchar *
+shell_bluetooth_type_to_filter_string (ShellBluetoothType type)
+{
+ switch (type) {
+ case SHELL_BLUETOOTH_TYPE_ANY:
+ return _("All types");
+ default:
+ return shell_bluetooth_type_to_string (type);
+ }
+
+ g_assert_not_reached ();
+}
+
+/**
+ * shell_bluetooth_verify_address:
+ * @bdaddr: a string representing a ShellBluetooth address
+ *
+ * Returns whether the string is a valid ShellBluetooth address. This does not contact the device in any way.
+ *
+ * Return value: %TRUE if the address is valid, %FALSE if not.
+ **/
+gboolean
+shell_bluetooth_verify_address (const char *bdaddr)
+{
+ guint i;
+
+ g_return_val_if_fail (bdaddr != NULL, FALSE);
+
+ if (strlen (bdaddr) != 17)
+ return FALSE;
+
+ for (i = 0; i < 17; i++) {
+ if (((i + 1) % 3) == 0) {
+ if (bdaddr[i] != ':')
+ return FALSE;
+ continue;
+ }
+ if (g_ascii_isxdigit (bdaddr[i]) == FALSE)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * shell_bluetooth_class_to_type:
+ * @class: a ShellBluetooth device class
+ *
+ * Returns the type of device corresponding to the given @class value.
+ *
+ * Return value: a #ShellBluetoothType.
+ **/
+ShellBluetoothType
+shell_bluetooth_class_to_type (guint32 class)
+{
+ switch ((class & 0x1f00) >> 8) {
+ case 0x01:
+ return SHELL_BLUETOOTH_TYPE_COMPUTER;
+ case 0x02:
+ switch ((class & 0xfc) >> 2) {
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x05:
+ return SHELL_BLUETOOTH_TYPE_PHONE;
+ case 0x04:
+ return SHELL_BLUETOOTH_TYPE_MODEM;
+ }
+ break;
+ case 0x03:
+ return SHELL_BLUETOOTH_TYPE_NETWORK;
+ case 0x04:
+ switch ((class & 0xfc) >> 2) {
+ case 0x01:
+ case 0x02:
+ return SHELL_BLUETOOTH_TYPE_HEADSET;
+ case 0x05:
+ return SHELL_BLUETOOTH_TYPE_SPEAKERS;
+ case 0x06:
+ return SHELL_BLUETOOTH_TYPE_HEADPHONES;
+ case 0x0b: /* VCR */
+ case 0x0c: /* Video Camera */
+ case 0x0d: /* Camcorder */
+ return SHELL_BLUETOOTH_TYPE_VIDEO;
+ default:
+ return SHELL_BLUETOOTH_TYPE_OTHER_AUDIO;
+ }
+ break;
+ case 0x05:
+ switch ((class & 0xc0) >> 6) {
+ case 0x00:
+ switch ((class & 0x1e) >> 2) {
+ case 0x01:
+ case 0x02:
+ return SHELL_BLUETOOTH_TYPE_JOYPAD;
+ case 0x03:
+ return SHELL_BLUETOOTH_TYPE_REMOTE_CONTROL;
+ }
+ break;
+ case 0x01:
+ return SHELL_BLUETOOTH_TYPE_KEYBOARD;
+ case 0x02:
+ switch ((class & 0x1e) >> 2) {
+ case 0x05:
+ return SHELL_BLUETOOTH_TYPE_TABLET;
+ default:
+ return SHELL_BLUETOOTH_TYPE_MOUSE;
+ }
+ }
+ break;
+ case 0x06:
+ if (class & 0x80)
+ return SHELL_BLUETOOTH_TYPE_PRINTER;
+ if (class & 0x40)
+ return SHELL_BLUETOOTH_TYPE_SCANNER;
+ if (class & 0x20)
+ return SHELL_BLUETOOTH_TYPE_CAMERA;
+ if (class & 0x10)
+ return SHELL_BLUETOOTH_TYPE_DISPLAY;
+ break;
+ case 0x07:
+ return SHELL_BLUETOOTH_TYPE_WEARABLE;
+ case 0x08:
+ return SHELL_BLUETOOTH_TYPE_TOY;
+ }
+
+ return 0;
+}
+
+/**
+ * shell_bluetooth_appearance_to_type:
+ * @appearance: a ShellBluetooth device appearance
+ *
+ * Returns the type of device corresponding to the given @appearance value,
+ * as usually found in the GAP service.
+ *
+ * Return value: a #ShellBluetoothType.
+ **/
+ShellBluetoothType
+shell_bluetooth_appearance_to_type (guint16 appearance)
+{
+ switch ((appearance & 0xffc0) >> 6) {
+ case 0x01:
+ return SHELL_BLUETOOTH_TYPE_PHONE;
+ case 0x02:
+ return SHELL_BLUETOOTH_TYPE_COMPUTER;
+ case 0x05:
+ return SHELL_BLUETOOTH_TYPE_DISPLAY;
+ case 0x0a:
+ return SHELL_BLUETOOTH_TYPE_OTHER_AUDIO;
+ case 0x0b:
+ return SHELL_BLUETOOTH_TYPE_SCANNER;
+ case 0x0f: /* HID Generic */
+ switch (appearance & 0x3f) {
+ case 0x01:
+ return SHELL_BLUETOOTH_TYPE_KEYBOARD;
+ case 0x02:
+ return SHELL_BLUETOOTH_TYPE_MOUSE;
+ case 0x03:
+ case 0x04:
+ return SHELL_BLUETOOTH_TYPE_JOYPAD;
+ case 0x05:
+ return SHELL_BLUETOOTH_TYPE_TABLET;
+ case 0x08:
+ return SHELL_BLUETOOTH_TYPE_SCANNER;
+ }
+ break;
+ }
+
+ return 0;
+
+}
+
+static const char *
+uuid16_custom_to_string (guint uuid16, const char *uuid)
+{
+ switch (uuid16) {
+ case 0x2:
+ return "SyncMLClient";
+ case 0x5601:
+ return "Nokia SyncML Server";
+ default:
+ g_debug ("Unhandled custom UUID %s (0x%x)", uuid, uuid16);
+ return NULL;
+ }
+}
+
+/* Short names from Table 2 at:
+ * https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm */
+static const char *
+uuid16_to_string (guint uuid16, const char *uuid)
+{
+ switch (uuid16) {
+ case SHELL_BLUETOOTH_UUID_SPP:
+ return "SerialPort";
+ case SHELL_BLUETOOTH_UUID_DUN:
+ return "DialupNetworking";
+ case SHELL_BLUETOOTH_UUID_IRMC:
+ return "IrMCSync";
+ case SHELL_BLUETOOTH_UUID_OPP:
+ return "OBEXObjectPush";
+ case SHELL_BLUETOOTH_UUID_FTP:
+ return "OBEXFileTransfer";
+ case SHELL_BLUETOOTH_UUID_HSP:
+ return "HSP";
+ case SHELL_BLUETOOTH_UUID_A2DP_SOURCE:
+ return "AudioSource";
+ case SHELL_BLUETOOTH_UUID_A2DP_SINK:
+ return "AudioSink";
+ case SHELL_BLUETOOTH_UUID_AVRCP_TARGET:
+ return "A/V_RemoteControlTarget";
+ case SHELL_BLUETOOTH_UUID_A2DP:
+ return "AdvancedAudioDistribution";
+ case SHELL_BLUETOOTH_UUID_AVRCP_CONTROL:
+ return "A/V_RemoteControl";
+ case SHELL_BLUETOOTH_UUID_HSP_AG:
+ return "Headset_-_AG";
+ case SHELL_BLUETOOTH_UUID_PAN_PANU:
+ return "PANU";
+ case SHELL_BLUETOOTH_UUID_PAN_NAP:
+ return "NAP";
+ case SHELL_BLUETOOTH_UUID_PAN_GN:
+ return "GN";
+ case SHELL_BLUETOOTH_UUID_HFP_HF:
+ return "Handsfree";
+ case SHELL_BLUETOOTH_UUID_HFP_AG:
+ return "HandsfreeAudioGateway";
+ case SHELL_BLUETOOTH_UUID_HID:
+ case 0x1812:
+ return "HumanInterfaceDeviceService";
+ case SHELL_BLUETOOTH_UUID_SAP:
+ return "SIM_Access";
+ case SHELL_BLUETOOTH_UUID_PBAP:
+ return "Phonebook_Access_-_PSE";
+ case SHELL_BLUETOOTH_UUID_GENERIC_AUDIO:
+ return "GenericAudio";
+ case SHELL_BLUETOOTH_UUID_SDP: /* ServiceDiscoveryServerServiceClassID */
+ case SHELL_BLUETOOTH_UUID_PNP: /* PnPInformation */
+ /* Those are ignored */
+ return NULL;
+ case SHELL_BLUETOOTH_UUID_GENERIC_NET:
+ return "GenericNetworking";
+ case SHELL_BLUETOOTH_UUID_VDP_SOURCE:
+ return "VideoSource";
+ case 0x8e771303:
+ case 0x8e771301:
+ return "SEMC HLA";
+ case 0x8e771401:
+ return "SEMC Watch Phone";
+ default:
+ g_debug ("Unhandled UUID %s (0x%x)", uuid, uuid16);
+ return NULL;
+ }
+}
+
+/**
+ * shell_bluetooth_uuid_to_string:
+ * @uuid: a string representing a ShellBluetooth UUID
+ *
+ * Returns a string representing a human-readable (but not usable for display to users) version of the
@uuid. Do not free the return value.
+ *
+ * Return value: a string.
+ **/
+const char *
+shell_bluetooth_uuid_to_string (const char *uuid)
+{
+ char **parts;
+ guint uuid16;
+ gboolean is_custom = FALSE;
+
+ if (g_str_has_suffix (uuid, "-0000-1000-8000-0002ee000002") != FALSE)
+ is_custom = TRUE;
+
+ parts = g_strsplit (uuid, "-", -1);
+ if (parts == NULL || parts[0] == NULL) {
+ g_strfreev (parts);
+ return NULL;
+ }
+
+ uuid16 = g_ascii_strtoull (parts[0], NULL, 16);
+ g_strfreev (parts);
+ if (uuid16 == 0)
+ return NULL;
+
+ if (is_custom == FALSE)
+ return uuid16_to_string (uuid16, uuid);
+ return uuid16_custom_to_string (uuid16, uuid);
+}
+
+/**
+ * shell_bluetooth_send_to_address:
+ * @address: Remote device to use
+ * @alias: Remote device's name
+ *
+ * Start a GUI application for transfering files over ShellBluetooth.
+ **/
+void
+shell_bluetooth_send_to_address (const char *address,
+ const char *alias)
+{
+ GPtrArray *a;
+ GError *err = NULL;
+
+ a = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
+
+ g_ptr_array_add (a, g_strdup ("bluetooth-sendto"));
+ if (address != NULL)
+ g_ptr_array_add (a, g_strdup_printf ("--device=%s", address));
+ if (address != NULL && alias != NULL)
+ g_ptr_array_add (a, g_strdup_printf ("--name=%s", alias));
+ g_ptr_array_add (a, NULL);
+
+ if (g_spawn_async(NULL, (char **) a->pdata, NULL,
+ G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err) == FALSE) {
+ g_printerr("Couldn't execute command: %s\n", err->message);
+ g_error_free (err);
+ }
+
+ g_ptr_array_free (a, TRUE);
+}
+
diff --git a/src/shell-bluetooth-utils.h b/src/shell-bluetooth-utils.h
new file mode 100644
index 0000000000..4c9a88e877
--- /dev/null
+++ b/src/shell-bluetooth-utils.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * BlueZ - ShellBluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2011 Bastien Nocera <hadess hadess net>
+ * Copyright (C) 2010 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+#include <shell-bluetooth-enums.h>
+
+/*
+ * The profile UUID list is provided by the ShellBluetooth SIG:
+ * https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+ */
+#define SHELL_BLUETOOTH_UUID_SPP 0x1101
+#define SHELL_BLUETOOTH_UUID_DUN 0x1103
+#define SHELL_BLUETOOTH_UUID_IRMC 0x1104
+#define SHELL_BLUETOOTH_UUID_OPP 0x1105
+#define SHELL_BLUETOOTH_UUID_FTP 0x1106
+#define SHELL_BLUETOOTH_UUID_HSP 0x1108
+#define SHELL_BLUETOOTH_UUID_A2DP_SOURCE 0x110A
+#define SHELL_BLUETOOTH_UUID_A2DP_SINK 0x110B
+#define SHELL_BLUETOOTH_UUID_AVRCP_TARGET 0x110C
+#define SHELL_BLUETOOTH_UUID_A2DP 0x110D
+#define SHELL_BLUETOOTH_UUID_AVRCP_CONTROL 0x110E
+#define SHELL_BLUETOOTH_UUID_HSP_AG 0x1112
+#define SHELL_BLUETOOTH_UUID_PAN_PANU 0x1115
+#define SHELL_BLUETOOTH_UUID_PAN_NAP 0x1116
+#define SHELL_BLUETOOTH_UUID_PAN_GN 0x1117
+#define SHELL_BLUETOOTH_UUID_HFP_HF 0x111E
+#define SHELL_BLUETOOTH_UUID_HFP_AG 0x111F
+#define SHELL_BLUETOOTH_UUID_HID 0x1124
+#define SHELL_BLUETOOTH_UUID_SAP 0x112d
+#define SHELL_BLUETOOTH_UUID_PBAP 0x112F
+#define SHELL_BLUETOOTH_UUID_GENERIC_AUDIO 0x1203
+#define SHELL_BLUETOOTH_UUID_SDP 0x1000
+#define SHELL_BLUETOOTH_UUID_PNP 0x1200
+#define SHELL_BLUETOOTH_UUID_GENERIC_NET 0x1201
+#define SHELL_BLUETOOTH_UUID_VDP_SOURCE 0x1303
+
+ShellBluetoothType shell_bluetooth_class_to_type (guint32 class);
+ShellBluetoothType shell_bluetooth_appearance_to_type (guint16 appearance);
+const gchar *shell_bluetooth_type_to_string (guint type);
+const gchar *shell_bluetooth_type_to_filter_string (guint type);
+gboolean shell_bluetooth_verify_address (const char *bdaddr);
+const char *shell_bluetooth_uuid_to_string (const char *uuid);
+
+void shell_bluetooth_send_to_address (const char *address,
+ const char *alias);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]