Hi Arkadiusz, On Sun, Mar 2, 2025 at 11:47 AM Arkadiusz Bokowy <arkadiusz.bokowy@xxxxxxxxx> wrote: > > --- > client/main.c | 93 ++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 80 insertions(+), 13 deletions(-) > > diff --git a/client/main.c b/client/main.c > index feb21a116..e4ed692ec 100644 > --- a/client/main.c > +++ b/client/main.c > @@ -1969,13 +1969,44 @@ static void cmd_remove(int argc, char *argv[]) > remove_device(proxy); > } > > +struct connection_data { > + GDBusProxy *proxy; > + char *uuid; > +}; > + > +static void connection_setup(DBusMessageIter *iter, void *user_data) > +{ > + struct connection_data *data = user_data; > + > + if (!data->uuid) > + return; > + > + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->uuid); > +} > + > +static void format_connection_profile(char *output, size_t size, > + const char *uuid) > +{ > + const char *text; > + > + text = bt_uuidstr_to_str(uuid); > + if (!text) > + text = uuid; > + > + snprintf(output, size, " profile \"%s\"", text); > +} > + > static void connect_reply(DBusMessage *message, void *user_data) > { > - GDBusProxy *proxy = user_data; > + struct connection_data *data = user_data; > + GDBusProxy *proxy = data->proxy; > DBusError error; > > dbus_error_init(&error); > > + g_free(data->uuid); > + g_free(data); > + > if (dbus_set_error_from_message(&error, message) == TRUE) { > bt_shell_printf("Failed to connect: %s %s\n", error.name, > error.message); > @@ -1991,6 +2022,9 @@ static void connect_reply(DBusMessage *message, void *user_data) > > static void cmd_connect(int argc, char *argv[]) > { > + struct connection_data *data; > + const char *method = "Connect"; > + char profile[128] = ""; > GDBusProxy *proxy; > > if (check_default_ctrl() == FALSE) > @@ -2002,31 +2036,49 @@ static void cmd_connect(int argc, char *argv[]) > return bt_shell_noninteractive_quit(EXIT_FAILURE); > } > > - if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply, > - proxy, NULL) == FALSE) { > + data = new0(struct connection_data, 1); > + data->proxy = proxy; > + > + if (argc == 3) { > + method = "ConnectProfile"; > + data->uuid = g_strdup(argv[2]); > + format_connection_profile(profile, sizeof(profile), argv[2]); > + } > + > + if (g_dbus_proxy_method_call(proxy, method, connection_setup, > + connect_reply, data, NULL) == FALSE) { > bt_shell_printf("Failed to connect\n"); > return bt_shell_noninteractive_quit(EXIT_FAILURE); > } > > - bt_shell_printf("Attempting to connect to %s\n", argv[1]); > + bt_shell_printf("Attempting to connect%s to %s\n", profile, argv[1]); > } > > static void disconn_reply(DBusMessage *message, void *user_data) > { > - GDBusProxy *proxy = user_data; > + struct connection_data *data = user_data; > + const bool profile_disconnected = data->uuid != NULL; > + GDBusProxy *proxy = data->proxy; > DBusError error; > > dbus_error_init(&error); > > + g_free(data->uuid); > + g_free(data); > + > if (dbus_set_error_from_message(&error, message) == TRUE) { > bt_shell_printf("Failed to disconnect: %s\n", error.name); > dbus_error_free(&error); > return bt_shell_noninteractive_quit(EXIT_FAILURE); > } > > - bt_shell_printf("Successful disconnected\n"); > + bt_shell_printf("Disconnection successful\n"); > > - if (proxy == default_dev) > + /* If only a single profile was disconnected, the device itself might > + * still be connected. In that case, let the property change handler > + * take care of setting the default device to NULL. > + */ > + if (proxy == default_dev && !profile_disconnected) > set_default_device(NULL, NULL); > > return bt_shell_noninteractive_quit(EXIT_SUCCESS); > @@ -2034,19 +2086,31 @@ static void disconn_reply(DBusMessage *message, void *user_data) > > static void cmd_disconn(int argc, char *argv[]) > { > + struct connection_data *data; > + const char *method = "Disconnect"; > + char profile[128] = ""; > GDBusProxy *proxy; > > proxy = find_device(argc, argv); > if (!proxy) > return bt_shell_noninteractive_quit(EXIT_FAILURE); > > - if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply, > - proxy, NULL) == FALSE) { > + data = new0(struct connection_data, 1); > + data->proxy = proxy; > + > + if (argc == 3) { > + method = "DisconnectProfile"; > + data->uuid = g_strdup(argv[2]); > + format_connection_profile(profile, sizeof(profile), argv[2]); > + } > + > + if (g_dbus_proxy_method_call(proxy, method, connection_setup, > + disconn_reply, data, NULL) == FALSE) { > bt_shell_printf("Failed to disconnect\n"); > return bt_shell_noninteractive_quit(EXIT_FAILURE); > } > > - bt_shell_printf("Attempting to disconnect from %s\n", > + bt_shell_printf("Attempting to disconnect%s from %s\n", profile, > proxy_address(proxy)); > } > > @@ -3241,10 +3305,13 @@ static const struct bt_shell_menu main_menu = { > dev_generator }, > { "remove", "<dev>", cmd_remove, "Remove device", > dev_generator }, > - { "connect", "<dev>", cmd_connect, "Connect device", > - dev_generator }, > - { "disconnect", "[dev]", cmd_disconn, "Disconnect device", > + { "connect", "<dev> [uuid]", cmd_connect, > + "Connect a device and all its profiles or " > + "optionally connect a single profile only", > dev_generator }, > + { "disconnect", "[dev] [uuid]", cmd_disconn, > + "Disconnect a device or optionally disconnect " > + "a single profile only", dev_generator }, Great idea, but let's update the documentation as well so it reflects this change (client/bluetoothctl.rst), also it is probably worth adding a few examples like connect/disconnect all/hfp/a2dp, etc. > { "wake", "[dev] [on/off]", cmd_wake, "Get/Set wake support", > dev_generator }, > { } }, > -- > 2.39.5 > > -- Luiz Augusto von Dentz