3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <readline/readline.h>
32 #include "gdbus/gdbus.h"
36 #define AGENT_PATH "/org/bluez/agent"
37 #define AGENT_INTERFACE "org.bluez.Agent1"
39 #define AGENT_PROMPT COLOR_RED "[agent]" COLOR_OFF " "
41 static gboolean agent_registered = FALSE;
42 static const char *agent_capability = NULL;
43 static DBusMessage *pending_message = NULL;
44 static char *agent_saved_prompt = NULL;
45 static int agent_saved_point = 0;
47 static void agent_prompt(const char *msg)
51 /* Normal use should not prompt for user input to the agent a second
52 * time before it releases the prompt, but we take a safe action. */
53 if (agent_saved_prompt)
56 agent_saved_point = rl_point;
57 agent_saved_prompt = g_strdup(rl_prompt);
62 prompt = g_strdup_printf(AGENT_PROMPT "%s", msg);
63 rl_set_prompt(prompt);
66 rl_replace_line("", 0);
70 static void agent_release_prompt(void)
72 if (!agent_saved_prompt)
75 /* This will cause rl_expand_prompt to re-run over the last prompt, but
76 * our prompt doesn't expand anyway. */
77 rl_set_prompt(agent_saved_prompt);
78 rl_replace_line("", 0);
79 rl_point = agent_saved_point;
82 g_free(agent_saved_prompt);
83 agent_saved_prompt = NULL;
86 dbus_bool_t agent_completion(void)
94 static void pincode_response(DBusConnection *conn, const char *input)
96 g_dbus_send_reply(conn, pending_message, DBUS_TYPE_STRING, &input,
100 static void passkey_response(DBusConnection *conn, const char *input)
102 dbus_uint32_t passkey;
103 if (sscanf(input, "%u", &passkey) == 1)
104 g_dbus_send_reply(conn, pending_message, DBUS_TYPE_UINT32,
105 &passkey, DBUS_TYPE_INVALID);
106 else if (!strcmp(input, "no"))
107 g_dbus_send_error(conn, pending_message,
108 "org.bluez.Error.Rejected", NULL);
110 g_dbus_send_error(conn, pending_message,
111 "org.bluez.Error.Canceled", NULL);
114 static void confirm_response(DBusConnection *conn, const char *input)
116 if (!strcmp(input, "yes"))
117 g_dbus_send_reply(conn, pending_message, DBUS_TYPE_INVALID);
118 else if (!strcmp(input, "no"))
119 g_dbus_send_error(conn, pending_message,
120 "org.bluez.Error.Rejected", NULL);
122 g_dbus_send_error(conn, pending_message,
123 "org.bluez.Error.Canceled", NULL);
126 dbus_bool_t agent_input(DBusConnection *conn, const char *input)
130 if (!pending_message)
133 agent_release_prompt();
135 member = dbus_message_get_member(pending_message);
137 if (!strcmp(member, "RequestPinCode"))
138 pincode_response(conn, input);
139 else if (!strcmp(member, "RequestPasskey"))
140 passkey_response(conn, input);
141 else if (!strcmp(member, "RequestConfirmation"))
142 confirm_response(conn, input);
143 else if (!strcmp(member, "RequestAuthorization"))
144 confirm_response(conn, input);
145 else if (!strcmp(member, "AuthorizeService"))
146 confirm_response(conn, input);
148 g_dbus_send_error(conn, pending_message,
149 "org.bluez.Error.Canceled", NULL);
151 dbus_message_unref(pending_message);
152 pending_message = NULL;
157 static void agent_release(DBusConnection *conn)
159 agent_registered = FALSE;
160 agent_capability = NULL;
162 if (pending_message) {
163 dbus_message_unref(pending_message);
164 pending_message = NULL;
167 agent_release_prompt();
169 g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
172 static DBusMessage *release_agent(DBusConnection *conn,
173 DBusMessage *msg, void *user_data)
175 rl_printf("Agent released\n");
179 return dbus_message_new_method_return(msg);
182 static DBusMessage *request_pincode(DBusConnection *conn,
183 DBusMessage *msg, void *user_data)
187 rl_printf("Request PIN code\n");
189 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
192 agent_prompt("Enter PIN code: ");
194 pending_message = dbus_message_ref(msg);
199 static DBusMessage *display_pincode(DBusConnection *conn,
200 DBusMessage *msg, void *user_data)
205 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
206 DBUS_TYPE_STRING, &pincode, DBUS_TYPE_INVALID);
208 rl_printf(AGENT_PROMPT "PIN code: %s\n", pincode);
210 return dbus_message_new_method_return(msg);
213 static DBusMessage *request_passkey(DBusConnection *conn,
214 DBusMessage *msg, void *user_data)
218 rl_printf("Request passkey\n");
220 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
223 agent_prompt("Enter passkey (number in 0-999999): ");
225 pending_message = dbus_message_ref(msg);
230 static DBusMessage *display_passkey(DBusConnection *conn,
231 DBusMessage *msg, void *user_data)
234 dbus_uint32_t passkey;
235 dbus_uint16_t entered;
236 char passkey_full[7];
238 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
239 DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_UINT16, &entered,
242 snprintf(passkey_full, sizeof(passkey_full), "%.6u", passkey);
243 passkey_full[6] = '\0';
245 if (entered > strlen(passkey_full))
246 entered = strlen(passkey_full);
248 rl_printf(AGENT_PROMPT "Passkey: "
249 COLOR_BOLDGRAY "%.*s" COLOR_BOLDWHITE "%s\n" COLOR_OFF,
250 entered, passkey_full, passkey_full + entered);
252 return dbus_message_new_method_return(msg);
255 static DBusMessage *request_confirmation(DBusConnection *conn,
256 DBusMessage *msg, void *user_data)
259 dbus_uint32_t passkey;
262 rl_printf("Request confirmation\n");
264 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
265 DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID);
267 str = g_strdup_printf("Confirm passkey %06u (yes/no): ", passkey);
271 pending_message = dbus_message_ref(msg);
276 static DBusMessage *request_authorization(DBusConnection *conn,
277 DBusMessage *msg, void *user_data)
281 rl_printf("Request authorization\n");
283 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
286 agent_prompt("Accept pairing (yes/no): ");
288 pending_message = dbus_message_ref(msg);
293 static DBusMessage *authorize_service(DBusConnection *conn,
294 DBusMessage *msg, void *user_data)
296 const char *device, *uuid;
299 rl_printf("Authorize service\n");
301 dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
302 DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
304 str = g_strdup_printf("Authorize service %s (yes/no): ", uuid);
308 pending_message = dbus_message_ref(msg);
313 static DBusMessage *cancel_request(DBusConnection *conn,
314 DBusMessage *msg, void *user_data)
316 rl_printf("Request canceled\n");
318 agent_release_prompt();
319 dbus_message_unref(pending_message);
320 pending_message = NULL;
322 return dbus_message_new_method_return(msg);
325 static const GDBusMethodTable methods[] = {
326 { GDBUS_METHOD("Release", NULL, NULL, release_agent) },
327 { GDBUS_ASYNC_METHOD("RequestPinCode",
328 GDBUS_ARGS({ "device", "o" }),
329 GDBUS_ARGS({ "pincode", "s" }), request_pincode) },
330 { GDBUS_METHOD("DisplayPinCode",
331 GDBUS_ARGS({ "device", "o" }, { "pincode", "s" }),
332 NULL, display_pincode) },
333 { GDBUS_ASYNC_METHOD("RequestPasskey",
334 GDBUS_ARGS({ "device", "o" }),
335 GDBUS_ARGS({ "passkey", "u" }), request_passkey) },
336 { GDBUS_METHOD("DisplayPasskey",
337 GDBUS_ARGS({ "device", "o" }, { "passkey", "u" },
339 NULL, display_passkey) },
340 { GDBUS_ASYNC_METHOD("RequestConfirmation",
341 GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }),
342 NULL, request_confirmation) },
343 { GDBUS_ASYNC_METHOD("RequestAuthorization",
344 GDBUS_ARGS({ "device", "o" }),
345 NULL, request_authorization) },
346 { GDBUS_ASYNC_METHOD("AuthorizeService",
347 GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
348 NULL, authorize_service) },
349 { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
353 static void register_agent_setup(DBusMessageIter *iter, void *user_data)
355 const char *path = AGENT_PATH;
356 const char *capability = agent_capability;
358 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
359 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &capability);
362 static void register_agent_reply(DBusMessage *message, void *user_data)
364 DBusConnection *conn = user_data;
367 dbus_error_init(&error);
369 if (dbus_set_error_from_message(&error, message) == FALSE) {
370 agent_registered = TRUE;
371 rl_printf("Agent registered\n");
373 rl_printf("Failed to register agent: %s\n", error.name);
374 dbus_error_free(&error);
376 if (g_dbus_unregister_interface(conn, AGENT_PATH,
377 AGENT_INTERFACE) == FALSE)
378 rl_printf("Failed to unregister agent object\n");
382 void agent_register(DBusConnection *conn, GDBusProxy *manager,
383 const char *capability)
386 if (agent_registered == TRUE) {
387 rl_printf("Agent is already registered\n");
391 agent_capability = capability;
393 if (g_dbus_register_interface(conn, AGENT_PATH,
394 AGENT_INTERFACE, methods,
395 NULL, NULL, NULL, NULL) == FALSE) {
396 rl_printf("Failed to register agent object\n");
400 if (g_dbus_proxy_method_call(manager, "RegisterAgent",
401 register_agent_setup,
402 register_agent_reply,
403 conn, NULL) == FALSE) {
404 rl_printf("Failed to call register agent method\n");
408 agent_capability = NULL;
411 static void unregister_agent_setup(DBusMessageIter *iter, void *user_data)
413 const char *path = AGENT_PATH;
415 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
418 static void unregister_agent_reply(DBusMessage *message, void *user_data)
420 DBusConnection *conn = user_data;
423 dbus_error_init(&error);
425 if (dbus_set_error_from_message(&error, message) == FALSE) {
426 rl_printf("Agent unregistered\n");
429 rl_printf("Failed to unregister agent: %s\n", error.name);
430 dbus_error_free(&error);
434 void agent_unregister(DBusConnection *conn, GDBusProxy *manager)
436 if (agent_registered == FALSE) {
437 rl_printf("No agent is registered\n");
442 rl_printf("Agent unregistered\n");
447 if (g_dbus_proxy_method_call(manager, "UnregisterAgent",
448 unregister_agent_setup,
449 unregister_agent_reply,
450 conn, NULL) == FALSE) {
451 rl_printf("Failed to call unregister agent method\n");
456 static void request_default_setup(DBusMessageIter *iter, void *user_data)
458 const char *path = AGENT_PATH;
460 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
463 static void request_default_reply(DBusMessage *message, void *user_data)
467 dbus_error_init(&error);
469 if (dbus_set_error_from_message(&error, message) == TRUE) {
470 rl_printf("Failed to request default agent: %s\n", error.name);
471 dbus_error_free(&error);
475 rl_printf("Default agent request successful\n");
478 void agent_default(DBusConnection *conn, GDBusProxy *manager)
480 if (agent_registered == FALSE) {
481 rl_printf("No agent is registered\n");
485 if (g_dbus_proxy_method_call(manager, "RequestDefaultAgent",
486 request_default_setup,
487 request_default_reply,
488 NULL, NULL) == FALSE) {
489 rl_printf("Failed to call request default agent method\n");