client: Add gatt.clone command
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 11 Feb 2019 16:36:27 +0000 (18:36 +0200)
committerhimanshu <h.himanshu@samsung.com>
Tue, 11 Feb 2020 08:57:47 +0000 (14:27 +0530)
This adds clone command to gatt submenu which can be use to clone
services as follow:

Clone all services from the connected device:
> gatt.clone

Clone a given service
> gatt.select-attribute <attribute/uuid>
> gatt.clone

In either case there is a prompt to confirm since this may add a lot of
service the user must confim before proceding.

Then finally:

> gatt.register-application

Change-Id: Ia3298b1f1a52c04b0dad34a7b794c9f177c8978d
Signed-off-by: himanshu <h.himanshu@samsung.com>
client/gatt.c
client/gatt.h
client/main.c

index 6d30aa4..ebb2402 100755 (executable)
@@ -46,6 +46,7 @@
 #include "gatt.h"
 
 #define APP_PATH "/org/bluez/app"
+#define DEVICE_INTERFACE "org.bluez.Device1"
 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
 #define SERVICE_INTERFACE "org.bluez.GattService1"
 #define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
@@ -71,6 +72,7 @@ struct desc {
 
 struct chrc {
        struct service *service;
+       GDBusProxy *proxy;
        char *path;
        uint16_t handle;
        char *uuid;
@@ -88,6 +90,7 @@ struct chrc {
 
 struct service {
        DBusConnection *conn;
+       GDBusProxy *proxy;
        char *path;
        uint16_t handle;
        char *uuid;
@@ -2672,3 +2675,235 @@ void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
 
        return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
+
+static GDBusProxy *select_service(GDBusProxy *proxy)
+{
+       GList *l;
+
+       for (l = services; l; l = g_list_next(l)) {
+               GDBusProxy *p = l->data;
+
+               if (proxy == p || g_str_has_prefix(g_dbus_proxy_get_path(proxy),
+                                               g_dbus_proxy_get_path(p)))
+                       return p;
+       }
+
+       return NULL;
+}
+
+static void clone_chrc(struct GDBusProxy *proxy)
+{
+       struct service *service;
+       struct chrc *chrc;
+       DBusMessageIter iter;
+       DBusMessageIter array;
+       const char *uuid;
+       char **flags;
+       int i;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       if (g_dbus_proxy_get_property(proxy, "Flags", &iter) == FALSE)
+               return;
+
+       flags = g_new0(char *, dbus_message_iter_get_element_count(&iter) + 1);
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       for (i = 0; dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING;
+                                                                       i++) {
+               const char *flag;
+
+               dbus_message_iter_get_basic(&array, &flag);
+
+               flags[i] = g_strdup(flag);
+
+               dbus_message_iter_next(&array);
+       }
+
+       service = g_list_last(local_services)->data;
+
+       chrc = g_new0(struct chrc, 1);
+       chrc->service = service;
+       chrc->proxy = proxy;
+       chrc->uuid = g_strdup(uuid);
+       chrc->path = g_strdup_printf("%s/chrc%u", service->path,
+                                       g_list_length(service->chrcs));
+       chrc->flags = flags;
+
+       if (g_dbus_register_interface(service->conn, chrc->path, CHRC_INTERFACE,
+                                       chrc_methods, NULL, chrc_properties,
+                                       chrc, chrc_free) == FALSE) {
+               bt_shell_printf("Failed to register characteristic object\n");
+               chrc_free(chrc);
+               return bt_shell_noninteractive_quit(EXIT_FAILURE);
+       }
+
+       service->chrcs = g_list_append(service->chrcs, chrc);
+
+       print_chrc(chrc, COLORED_NEW);
+}
+
+static void clone_chrcs(struct GDBusProxy *proxy)
+{
+       GList *l;
+
+       for (l = characteristics; l; l = g_list_next(l)) {
+               GDBusProxy *p = l->data;
+
+               if (g_str_has_prefix(g_dbus_proxy_get_path(p),
+                                               g_dbus_proxy_get_path(proxy)))
+                       clone_chrc(p);
+       }
+}
+
+static void clone_service(struct GDBusProxy *proxy)
+{
+       struct service *service;
+       DBusMessageIter iter;
+       const char *uuid;
+       dbus_bool_t primary;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &primary);
+
+       if (!strcmp(uuid, "00001800-0000-1000-8000-00805f9b34fb") ||
+                       !strcmp(uuid, "00001801-0000-1000-8000-00805f9b34fb"))
+               return;
+
+       service = g_new0(struct service, 1);
+       service->conn = bt_shell_get_env("DBUS_CONNECTION");
+       service->proxy = proxy;
+       service->path = g_strdup_printf("%s/service%u", APP_PATH,
+                                       g_list_length(local_services));
+       service->uuid = g_strdup(uuid);
+       service->primary = primary;
+
+       if (g_dbus_register_interface(service->conn, service->path,
+                                       SERVICE_INTERFACE, NULL, NULL,
+                                       service_properties, service,
+                                       service_free) == FALSE) {
+               bt_shell_printf("Failed to register service object\n");
+               service_free(service);
+               return bt_shell_noninteractive_quit(EXIT_FAILURE);
+       }
+
+       print_service(service, COLORED_NEW);
+
+       local_services = g_list_append(local_services, service);
+
+       clone_chrcs(proxy);
+}
+
+static void clone_device(struct GDBusProxy *proxy)
+{
+       GList *l;
+
+       for (l = services; l; l = g_list_next(l)) {
+               struct GDBusProxy *p = l->data;
+
+               if (g_str_has_prefix(g_dbus_proxy_get_path(p),
+                                               g_dbus_proxy_get_path(proxy)))
+                       clone_service(p);
+       }
+}
+
+static void service_clone(const char *input, void *user_data)
+{
+       struct GDBusProxy *proxy = user_data;
+
+       if (!strcmp(input, "yes"))
+               return clone_service(proxy);
+       else if (!strcmp(input, "no"))
+               return bt_shell_noninteractive_quit(EXIT_FAILURE);
+       else if (!strcmp(input, "all"))
+               return clone_device(proxy);
+
+       bt_shell_printf("Invalid option: %s\n", input);
+
+       return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
+static void device_clone(const char *input, void *user_data)
+{
+       struct GDBusProxy *proxy = user_data;
+
+       if (!strcmp(input, "yes"))
+               return clone_device(proxy);
+       else if (!strcmp(input, "no"))
+               return bt_shell_noninteractive_quit(EXIT_FAILURE);
+
+       bt_shell_printf("Invalid option: %s\n", input);
+
+       return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
+static const char *proxy_get_name(struct GDBusProxy *proxy)
+{
+       DBusMessageIter iter;
+       const char *uuid;
+       const char *str;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return NULL;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       str = bt_uuidstr_to_str(uuid);
+
+       return str ? str : uuid;
+}
+
+static const char *proxy_get_alias(struct GDBusProxy *proxy)
+{
+       DBusMessageIter iter;
+       const char *alias;
+
+       if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE)
+               return NULL;
+
+       dbus_message_iter_get_basic(&iter, &alias);
+
+       return alias;
+}
+
+void gatt_clone_attribute(GDBusProxy *proxy, int argc, char *argv[])
+{
+       GDBusProxy *service = NULL;
+
+       if (argc > 1) {
+               proxy = gatt_select_attribute(proxy, argv[1]);
+               if (!proxy) {
+                       bt_shell_printf("Unable to find attribute %s\n",
+                                                               argv[1]);
+                       return bt_shell_noninteractive_quit(EXIT_FAILURE);
+               }
+       }
+
+       if (!strcmp(g_dbus_proxy_get_interface(proxy), DEVICE_INTERFACE)) {
+               bt_shell_prompt_input(proxy_get_alias(proxy),
+                                       "Clone (yes/no):",
+                                       device_clone, proxy);
+       }
+
+       /* Only clone services */
+       service = select_service(proxy);
+       if (service) {
+               bt_shell_prompt_input(proxy_get_name(proxy),
+                                       "Clone (yes/no/all):",
+                                       service_clone, service);
+               return;
+       }
+
+       return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
index d4d7bed..09ca618 100755 (executable)
@@ -37,6 +37,7 @@ char *gatt_attribute_generator(const char *text, int state);
 void gatt_read_attribute(GDBusProxy *proxy, int argc, char *argv[]);
 void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[]);
 void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
+void gatt_clone_attribute(GDBusProxy *proxy, int argc, char *argv[]);
 
 void gatt_acquire_write(GDBusProxy *proxy, const char *arg);
 void gatt_release_write(GDBusProxy *proxy, const char *arg);
index c17111c..def8552 100644 (file)
@@ -2110,6 +2110,19 @@ static void cmd_notify(int argc, char *argv[])
        gatt_notify_attribute(default_attr, enable ? true : false);
 }
 
+static void cmd_clone(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       proxy = default_attr ? default_attr : default_dev;
+       if (!proxy) {
+               bt_shell_printf("Not connected\n");
+               return bt_shell_noninteractive_quit(EXIT_FAILURE);
+       }
+
+       gatt_clone_attribute(proxy, argc, argv);
+}
+
 static void cmd_register_app(int argc, char *argv[])
 {
        if (check_default_ctrl() == FALSE)
@@ -2629,6 +2642,8 @@ static const struct bt_shell_menu gatt_menu = {
                                        "Release Notify file descriptor" },
        { "notify",       "<on/off>", cmd_notify, "Notify attribute value",
                                                        NULL },
+       { "clone",        "[dev/attribute/UUID]", cmd_clone,
+                                               "Clone a device or attribute" },
        { "register-application", "[UUID ...]", cmd_register_app,
                                                "Register profile to connect" },
        { "unregister-application", NULL, cmd_unregister_app,
@@ -2762,6 +2777,8 @@ int main(int argc, char *argv[])
        dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
        g_dbus_attach_object_manager(dbus_conn);
 
+       bt_shell_set_env("DBUS_CONNECTION", dbus_conn);
+
        client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
 
        g_dbus_client_set_connect_watch(client, connect_handler, NULL);