Merge lp:~timchen119/ubuntu/utopic/gnome-bluetooth/lp1035431 into lp:ubuntu/utopic/gnome-bluetooth

Proposed by Tim Chen
Status: Merged
Approved by: Mathieu Trudel-Lapierre
Approved revision: 94
Merge reported by: Mathieu Trudel-Lapierre
Merged at revision: not available
Proposed branch: lp:~timchen119/ubuntu/utopic/gnome-bluetooth/lp1035431
Merge into: lp:ubuntu/utopic/gnome-bluetooth
Diff against target: 1854 lines (+1753/-12)
8 files modified
.pc/applied-patches (+1/-0)
.pc/ssp-parameter-fix.patch/lib/bluetooth-agent.c (+633/-0)
.pc/ssp-parameter-fix.patch/wizard/main.c (+1001/-0)
debian/changelog (+10/-0)
debian/patches/series (+1/-0)
debian/patches/ssp-parameter-fix.patch (+86/-0)
lib/bluetooth-agent.c (+4/-4)
wizard/main.c (+17/-8)
To merge this branch: bzr merge lp:~timchen119/ubuntu/utopic/gnome-bluetooth/lp1035431
Reviewer Review Type Date Requested Status
Mathieu Trudel-Lapierre Approve
Review via email: mp+219628@code.launchpad.net

Description of the change

This fixed the issue for the paring issue on Logitech K810 and HP bluetooth keyboard K4000 and should also fixed any ssp paired bluetooth keyboard.

gnome-bluetooth is being removed in recent gnome upstream, so we need to maintain a ubuntu distro patch here.

Another related merge is at
https://code.launchpad.net/~timchen119/ubuntu/utopic/bluez/lp1035431/+merge/219626

The root problem here is that in bluez4, the doc (agent-api.txt), specific that the
function

void DisplayPasskey(object device, uint32 passkey, uint8 entered)

however in bluez4's src/agent.c agent_display_passkey()
didn't pass the entered correct "enter" parameter,
and most of client implementation in linux (at least gnome-bluetooth, bluedevil, blueman) follows the specification in the api document so they never receive correct parameter.

This is already fixed in bluez5,
however due to the compatibility issue between bluez4 and bluez5
this never being backported in bluez4.

This request is from our OEM so please help to review these patch and see if there's things I can improve this patch. If the patch is accepted I'll send SRUs to trusty (OEM shipping image is LTS based, so it will be trusty right now).

To post a comment you must log in.
Revision history for this message
Mathieu Trudel-Lapierre (cyphermox) wrote :

Looks fine to me. If it fixes the issues let's land it.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2014-02-25 16:32:43 +0000
+++ .pc/applied-patches 2014-05-15 03:31:21 +0000
@@ -7,3 +7,4 @@
7git_leak_fixes.patch7git_leak_fixes.patch
8git_disconnect_callbacks.patch8git_disconnect_callbacks.patch
9git_reference_handling.patch9git_reference_handling.patch
10ssp-parameter-fix.patch
1011
=== added directory '.pc/ssp-parameter-fix.patch'
=== added directory '.pc/ssp-parameter-fix.patch/lib'
=== added file '.pc/ssp-parameter-fix.patch/lib/bluetooth-agent.c'
--- .pc/ssp-parameter-fix.patch/lib/bluetooth-agent.c 1970-01-01 00:00:00 +0000
+++ .pc/ssp-parameter-fix.patch/lib/bluetooth-agent.c 2014-05-15 03:31:21 +0000
@@ -0,0 +1,633 @@
1/*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library 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 GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <stdio.h>
29#include <gio/gio.h>
30
31#include "bluetooth-client-glue.h"
32#include "bluetooth-agent.h"
33
34#define BLUEZ_SERVICE "org.bluez"
35
36#define BLUEZ_MANAGER_PATH "/"
37#define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager"
38#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device"
39
40static const gchar introspection_xml[] =
41"<node name='/'>"
42" <interface name='org.bluez.Agent'>"
43" <method name='Release'/>"
44" <method name='RequestPinCode'>"
45" <arg type='o' name='device' direction='in'/>"
46" <arg type='s' name='pincode' direction='out'/>"
47" </method>"
48" <method name='RequestPasskey'>"
49" <arg type='o' name='device' direction='in'/>"
50" <arg type='u' name='passkey' direction='out'/>"
51" </method>"
52" <method name='DisplayPasskey'>"
53" <arg type='o' name='device' direction='in'/>"
54" <arg type='u' name='passkey' direction='in'/>"
55" <arg type='y' name='entered' direction='in'/>"
56" </method>"
57" <method name='RequestConfirmation'>"
58" <arg type='o' name='device' direction='in'/>"
59" <arg type='u' name='passkey' direction='in'/>"
60" </method>"
61" <method name='Authorize'>"
62" <arg type='o' name='device' direction='in'/>"
63" <arg type='s' name='uuid' direction='in'/>"
64" </method>"
65" <method name='ConfirmMode'>"
66" <arg type='s' name='mode'/>"
67" </method>"
68" <method name='Cancel'/>"
69" </interface>"
70"</node>";
71
72#define BLUETOOTH_AGENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
73 BLUETOOTH_TYPE_AGENT, BluetoothAgentPrivate))
74
75typedef struct _BluetoothAgentPrivate BluetoothAgentPrivate;
76
77struct _BluetoothAgentPrivate {
78 GDBusConnection *conn;
79 gchar *busname;
80 gchar *path;
81 GDBusProxy *adapter;
82 GDBusNodeInfo *introspection_data;
83 guint reg_id;
84 guint watch_id;
85
86 BluetoothAgentPasskeyFunc pincode_func;
87 gpointer pincode_data;
88
89 BluetoothAgentDisplayFunc display_func;
90 gpointer display_data;
91
92 BluetoothAgentPasskeyFunc passkey_func;
93 gpointer passkey_data;
94
95 BluetoothAgentConfirmFunc confirm_func;
96 gpointer confirm_data;
97
98 BluetoothAgentAuthorizeFunc authorize_func;
99 gpointer authorize_data;
100
101 BluetoothAgentCancelFunc cancel_func;
102 gpointer cancel_data;
103};
104
105G_DEFINE_TYPE(BluetoothAgent, bluetooth_agent, G_TYPE_OBJECT)
106
107static GDBusProxy *
108get_device_from_adapter (BluetoothAgent *agent,
109 const char *path)
110{
111 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
112
113 if (priv->adapter == NULL)
114 return NULL;
115
116 return g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
117 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
118 NULL,
119 g_dbus_proxy_get_name (priv->adapter),
120 path,
121 BLUEZ_DEVICE_INTERFACE,
122 NULL,
123 NULL);
124}
125
126static gboolean bluetooth_agent_request_pin_code(BluetoothAgent *agent,
127 const char *path, GDBusMethodInvocation *invocation)
128{
129 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
130 GDBusProxy *device;
131 gboolean result = FALSE;
132
133 if (priv->pincode_func) {
134 device = get_device_from_adapter (agent, path);
135
136 result = priv->pincode_func(invocation, device,
137 priv->pincode_data);
138
139 if (device != NULL)
140 g_object_unref(device);
141 }
142
143 return result;
144}
145
146static gboolean bluetooth_agent_request_passkey(BluetoothAgent *agent,
147 const char *path, GDBusMethodInvocation *invocation)
148{
149 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
150 GDBusProxy *device;
151 gboolean result = FALSE;
152
153 if (priv->passkey_func) {
154 device = get_device_from_adapter (agent, path);
155
156 result = priv->passkey_func(invocation, device,
157 priv->passkey_data);
158
159 if (device != NULL)
160 g_object_unref(device);
161 }
162
163 return result;
164}
165
166static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent,
167 const char *path, guint passkey, guint8 entered,
168 GDBusMethodInvocation *invocation)
169{
170 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
171 GDBusProxy *device;
172 gboolean result = FALSE;
173
174 if (priv->display_func) {
175 device = get_device_from_adapter (agent, path);
176
177 result = priv->display_func(invocation, device, passkey, entered,
178 priv->display_data);
179
180 if (device != NULL)
181 g_object_unref(device);
182 }
183
184 return result;
185}
186
187static gboolean bluetooth_agent_request_confirmation(BluetoothAgent *agent,
188 const char *path, guint passkey,
189 GDBusMethodInvocation *invocation)
190{
191 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
192 GDBusProxy *device;
193 gboolean result = FALSE;
194
195 if (priv->confirm_func) {
196 device = get_device_from_adapter (agent, path);
197
198 result = priv->confirm_func(invocation, device, passkey,
199 priv->confirm_data);
200
201 if (device != NULL)
202 g_object_unref(device);
203 }
204
205 return result;
206}
207
208static gboolean bluetooth_agent_authorize(BluetoothAgent *agent,
209 const char *path, const char *uuid,
210 GDBusMethodInvocation *invocation)
211{
212 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
213 GDBusProxy *device;
214 gboolean result = FALSE;
215
216 if (priv->authorize_func) {
217 device = get_device_from_adapter (agent, path);
218
219 result = priv->authorize_func(invocation, device, uuid,
220 priv->authorize_data);
221
222 if (device != NULL)
223 g_object_unref(device);
224 }
225
226 return result;
227}
228
229static gboolean bluetooth_agent_cancel(BluetoothAgent *agent,
230 GDBusMethodInvocation *invocation)
231{
232 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
233 gboolean result = FALSE;
234
235 if (priv->cancel_func)
236 result = priv->cancel_func(invocation, priv->cancel_data);
237
238 return result;
239}
240
241static void
242name_appeared_cb (GDBusConnection *connection,
243 const gchar *name,
244 const gchar *name_owner,
245 BluetoothAgent *agent)
246{
247 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
248
249 g_free (priv->busname);
250 priv->busname = g_strdup (name_owner);
251}
252
253static void
254name_vanished_cb (GDBusConnection *connection,
255 const gchar *name,
256 BluetoothAgent *agent)
257{
258 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
259
260 g_free (priv->busname);
261 priv->busname = NULL;
262}
263
264static void bluetooth_agent_init(BluetoothAgent *agent)
265{
266 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
267
268 priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
269 g_assert (priv->introspection_data);
270 priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
271 priv->watch_id = g_bus_watch_name_on_connection (priv->conn,
272 BLUEZ_SERVICE,
273 G_BUS_NAME_WATCHER_FLAGS_NONE,
274 (GBusNameAppearedCallback) name_appeared_cb,
275 (GBusNameVanishedCallback) name_vanished_cb,
276 agent,
277 NULL);
278}
279
280static void bluetooth_agent_finalize(GObject *agent)
281{
282 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
283
284 bluetooth_agent_unregister (BLUETOOTH_AGENT (agent));
285
286 g_bus_unwatch_name (priv->watch_id);
287 g_free (priv->busname);
288 g_dbus_node_info_unref (priv->introspection_data);
289 g_object_unref (priv->conn);
290
291 G_OBJECT_CLASS(bluetooth_agent_parent_class)->finalize(agent);
292}
293
294static void bluetooth_agent_class_init(BluetoothAgentClass *klass)
295{
296 GObjectClass *object_class = (GObjectClass *) klass;
297
298 g_type_class_add_private(klass, sizeof(BluetoothAgentPrivate));
299
300 object_class->finalize = bluetooth_agent_finalize;
301}
302
303BluetoothAgent *
304bluetooth_agent_new (void)
305{
306 return BLUETOOTH_AGENT (g_object_new (BLUETOOTH_TYPE_AGENT, NULL));
307}
308
309static void
310handle_method_call (GDBusConnection *connection,
311 const gchar *sender,
312 const gchar *object_path,
313 const gchar *interface_name,
314 const gchar *method_name,
315 GVariant *parameters,
316 GDBusMethodInvocation *invocation,
317 gpointer user_data)
318{
319 BluetoothAgent *agent = (BluetoothAgent *) user_data;
320 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
321
322 if (g_str_equal (sender, priv->busname) == FALSE) {
323 g_assert_not_reached ();
324 /* FIXME, should this just be a D-Bus Error instead? */
325 }
326
327 if (g_strcmp0 (method_name, "Release") == 0) {
328 g_dbus_method_invocation_return_value (invocation, NULL);
329 } else if (g_strcmp0 (method_name, "RequestPinCode") == 0) {
330 char *path;
331 g_variant_get (parameters, "(o)", &path);
332 bluetooth_agent_request_pin_code (agent, path, invocation);
333 g_free (path);
334 } else if (g_strcmp0 (method_name, "RequestPasskey") == 0) {
335 char *path;
336 g_variant_get (parameters, "(o)", &path);
337 bluetooth_agent_request_passkey (agent, path, invocation);
338 g_free (path);
339 } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) {
340 char *path;
341 guint32 passkey;
342 guint8 entered;
343
344 g_variant_get (parameters, "(ouy)", &path, &passkey, &entered);
345 bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation);
346 g_free (path);
347 } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) {
348 char *path;
349 guint32 passkey;
350
351 g_variant_get (parameters, "(ou)", &path, &passkey);
352 bluetooth_agent_request_confirmation (agent, path, passkey, invocation);
353 g_free (path);
354 } else if (g_strcmp0 (method_name, "Authorize") == 0) {
355 char *path, *uuid;
356 g_variant_get (parameters, "(os)", &path, &uuid);
357 bluetooth_agent_authorize (agent, path, uuid, invocation);
358 g_free (path);
359 g_free (uuid);
360 } else if (g_strcmp0 (method_name, "Cancel") == 0) {
361 bluetooth_agent_cancel (agent, invocation);
362 } else if (g_strcmp0 (method_name, "ConfirmMode") == 0) {
363 g_dbus_method_invocation_return_value (invocation, NULL);
364 }
365}
366
367static const GDBusInterfaceVTable interface_vtable =
368{
369 handle_method_call,
370 NULL, /* GetProperty */
371 NULL, /* SetProperty */
372};
373
374gboolean bluetooth_agent_setup(BluetoothAgent *agent, const char *path)
375{
376 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
377 GError *error = NULL;
378
379 if (priv->path != NULL) {
380 g_warning ("Agent already setup on '%s'", priv->path);
381 return FALSE;
382 }
383
384 priv->path = g_strdup(path);
385
386 priv->reg_id = g_dbus_connection_register_object (priv->conn,
387 priv->path,
388 priv->introspection_data->interfaces[0],
389 &interface_vtable,
390 agent,
391 NULL,
392 &error);
393 if (priv->reg_id == 0) {
394 g_warning ("Failed to register object: %s", error->message);
395 g_error_free (error);
396 }
397
398 return TRUE;
399}
400
401#define BLUEZ_SERVICE "org.bluez"
402#define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager"
403
404static GDBusProxy *
405get_default_adapter (void)
406{
407 Manager *manager;
408 char *adapter_path;
409 Adapter *adapter;
410
411 manager = manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
412 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
413 BLUEZ_SERVICE,
414 BLUEZ_MANAGER_PATH,
415 NULL,
416 NULL);
417 if (manager == NULL)
418 return NULL;
419 if (manager_call_default_adapter_sync (manager, &adapter_path, NULL, NULL) == FALSE) {
420 g_object_unref (manager);
421 return NULL;
422 }
423 adapter = adapter_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
424 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
425 BLUEZ_SERVICE,
426 adapter_path,
427 NULL,
428 NULL);
429 g_object_unref (manager);
430 g_free (adapter_path);
431
432 return G_DBUS_PROXY (adapter);
433}
434
435gboolean bluetooth_agent_register(BluetoothAgent *agent)
436{
437 BluetoothAgentPrivate *priv;
438 GError *error = NULL;
439 char *path;
440 GVariant *r;
441
442 g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE);
443
444 priv = BLUETOOTH_AGENT_GET_PRIVATE (agent);
445
446 priv->adapter = get_default_adapter ();
447
448 if (priv->adapter == NULL)
449 return FALSE;
450
451 if (priv->path != NULL) {
452 g_warning ("Agent already setup on '%s'", priv->path);
453 return FALSE;
454 }
455
456 path = g_path_get_basename(g_dbus_proxy_get_object_path(priv->adapter));
457 priv->path = g_strdup_printf("/org/bluez/agent/%s", path);
458 g_free(path);
459
460 priv->reg_id = g_dbus_connection_register_object (priv->conn,
461 priv->path,
462 priv->introspection_data->interfaces[0],
463 &interface_vtable,
464 agent,
465 NULL,
466 &error);
467 if (priv->reg_id == 0) {
468 g_warning ("Failed to register object: %s", error->message);
469 g_error_free (error);
470 error = NULL;
471 return FALSE;
472 }
473
474 r = g_dbus_proxy_call_sync (priv->adapter, "RegisterAgent",
475 g_variant_new ("(os)", priv->path, "DisplayYesNo"),
476 G_DBUS_CALL_FLAGS_NONE,
477 -1, NULL, &error);
478 if (r == NULL) {
479 g_printerr ("Agent registration failed: %s\n", error->message);
480 g_error_free (error);
481 return FALSE;
482 }
483 g_variant_unref (r);
484
485 return TRUE;
486}
487
488gboolean bluetooth_agent_unregister(BluetoothAgent *agent)
489{
490 BluetoothAgentPrivate *priv;
491 GError *error = NULL;
492
493 g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE);
494
495 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
496
497 if (priv->adapter == NULL)
498 return FALSE;
499
500 if (g_dbus_proxy_call_sync (priv->adapter, "UnregisterAgent",
501 g_variant_new ("(o)", priv->path),
502 G_DBUS_CALL_FLAGS_NONE,
503 -1, NULL, &error) == FALSE) {
504 /* Ignore errors if the adapter is gone */
505 if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD) == FALSE) {
506 g_printerr ("Agent unregistration failed: %s '%s'\n",
507 error->message,
508 g_quark_to_string (error->domain));
509 }
510 g_error_free(error);
511 }
512
513 g_object_unref(priv->adapter);
514 priv->adapter = NULL;
515
516 g_free(priv->path);
517 priv->path = NULL;
518
519 g_free(priv->busname);
520 priv->busname = NULL;
521
522 if (priv->reg_id > 0) {
523 g_dbus_connection_unregister_object (priv->conn, priv->reg_id);
524 priv->reg_id = 0;
525 }
526
527 return TRUE;
528}
529
530void bluetooth_agent_set_pincode_func(BluetoothAgent *agent,
531 BluetoothAgentPasskeyFunc func, gpointer data)
532{
533 BluetoothAgentPrivate *priv;
534
535 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
536
537 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
538
539 priv->pincode_func = func;
540 priv->pincode_data = data;
541}
542
543void bluetooth_agent_set_passkey_func(BluetoothAgent *agent,
544 BluetoothAgentPasskeyFunc func, gpointer data)
545{
546 BluetoothAgentPrivate *priv;
547
548 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
549
550 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
551
552 priv->passkey_func = func;
553 priv->passkey_data = data;
554}
555
556void bluetooth_agent_set_display_func(BluetoothAgent *agent,
557 BluetoothAgentDisplayFunc func, gpointer data)
558{
559 BluetoothAgentPrivate *priv;
560
561 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
562
563 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
564
565 priv->display_func = func;
566 priv->display_data = data;
567}
568
569void bluetooth_agent_set_confirm_func(BluetoothAgent *agent,
570 BluetoothAgentConfirmFunc func, gpointer data)
571{
572 BluetoothAgentPrivate *priv;
573
574 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
575
576 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
577
578 priv->confirm_func = func;
579 priv->confirm_data = data;
580}
581
582void bluetooth_agent_set_authorize_func(BluetoothAgent *agent,
583 BluetoothAgentAuthorizeFunc func, gpointer data)
584{
585 BluetoothAgentPrivate *priv;
586
587 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
588
589 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
590
591 priv->authorize_func = func;
592 priv->authorize_data = data;
593}
594
595void bluetooth_agent_set_cancel_func(BluetoothAgent *agent,
596 BluetoothAgentCancelFunc func, gpointer data)
597{
598 BluetoothAgentPrivate *priv;
599
600 g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
601
602 priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
603
604 priv->cancel_func = func;
605 priv->cancel_data = data;
606}
607
608GQuark bluetooth_agent_error_quark(void)
609{
610 static GQuark quark = 0;
611 if (!quark)
612 quark = g_quark_from_static_string("agent");
613
614 return quark;
615}
616
617#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
618
619GType bluetooth_agent_error_get_type(void)
620{
621 static GType etype = 0;
622 if (etype == 0) {
623 static const GEnumValue values[] = {
624 ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"),
625 { 0, 0, 0 }
626 };
627
628 etype = g_enum_register_static("agent", values);
629 }
630
631 return etype;
632}
633
0634
=== added directory '.pc/ssp-parameter-fix.patch/wizard'
=== added file '.pc/ssp-parameter-fix.patch/wizard/main.c'
--- .pc/ssp-parameter-fix.patch/wizard/main.c 1970-01-01 00:00:00 +0000
+++ .pc/ssp-parameter-fix.patch/wizard/main.c 2014-05-15 03:31:21 +0000
@@ -0,0 +1,1001 @@
1/*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
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.
12 *
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.
17 *
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
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <math.h>
29#include <glib/gi18n.h>
30#include <gtk/gtk.h>
31#include <gdk/gdkkeysyms.h>
32
33#include <bluetooth-client.h>
34#include <bluetooth-client-private.h>
35#include <bluetooth-chooser.h>
36#include <bluetooth-agent.h>
37#include <bluetooth-plugin-manager.h>
38
39#include "pin.h"
40
41#define AGENT_PATH "/org/bluez/agent/wizard"
42
43/* We'll try to connect to the device repeatedly for that
44 * amount of time before we bail out */
45#define CONNECT_TIMEOUT 3.0
46
47#define W(x) GTK_WIDGET(gtk_builder_get_object(builder, x))
48
49enum {
50 PAGE_SEARCH,
51 PAGE_CONNECTING,
52 PAGE_SETUP,
53 PAGE_SSP_SETUP,
54 PAGE_FINISHING,
55 PAGE_SUMMARY
56};
57
58typedef enum {
59 PAIRING_UI_NORMAL,
60 PAIRING_UI_KEYBOARD,
61 PAIRING_UI_ICADE
62} PairingUIBehaviour;
63
64static gboolean set_page_search_complete(void);
65
66static BluetoothClient *client;
67static BluetoothAgent *agent;
68
69static gchar *target_address = NULL;
70static gchar *target_name = NULL;
71static guint target_max_digits = 0;
72static PairingUIBehaviour target_ui_behaviour = PAIRING_UI_NORMAL;
73static gboolean target_ssp = FALSE;
74static gboolean create_started = FALSE;
75static gboolean display_called = FALSE;
76
77/* NULL means automatic, anything else is a pincode specified by the user */
78static gchar *user_pincode = NULL;
79/* If TRUE, then we won't display the PIN code to the user when pairing */
80static gboolean automatic_pincode = FALSE;
81static char *pincode = NULL;
82
83static GtkBuilder *builder = NULL;
84
85static GtkAssistant *window_assistant = NULL;
86static GtkWidget *button_quit = NULL;
87static GtkWidget *button_cancel = NULL;
88static GtkWidget *page_search = NULL;
89static GtkWidget *page_connecting = NULL;
90static GtkWidget *page_setup = NULL;
91static GtkWidget *page_ssp_setup = NULL;
92static GtkWidget *page_finishing = NULL;
93static GtkWidget *page_summary = NULL;
94
95static GtkWidget *label_connecting = NULL;
96static GtkWidget *spinner_connecting = NULL;
97
98static GtkWidget *label_pin = NULL;
99static GtkWidget *label_pin_help = NULL;
100
101static GtkWidget *label_ssp_pin_help = NULL;
102static GtkWidget *label_ssp_pin = NULL;
103static GtkWidget *does_not_match_button = NULL;
104static GtkWidget *matches_button = NULL;
105
106static GtkWidget *label_finishing = NULL;
107static GtkWidget *spinner_finishing = NULL;
108
109static gboolean summary_failure = FALSE;
110static GtkWidget *label_summary = NULL;
111static GtkWidget *extra_config_vbox = NULL;
112
113static BluetoothChooser *selector = NULL;
114
115static GtkWidget *pin_dialog = NULL;
116static GtkWidget *radio_auto = NULL;
117static GtkWidget *radio_0000 = NULL;
118static GtkWidget *radio_1111 = NULL;
119static GtkWidget *radio_1234 = NULL;
120static GtkWidget *radio_none = NULL;
121static GtkWidget *radio_custom = NULL;
122static GtkWidget *entry_custom = NULL;
123
124/* Signals */
125void quit_callback(GtkWidget *assistant, gpointer data);
126void prepare_callback(GtkWidget *assistant, GtkWidget *page, gpointer data);
127void select_device_changed(BluetoothChooser *selector, const char *address, gpointer user_data);
128gboolean entry_custom_event(GtkWidget *entry, GdkEventKey *event);
129void set_user_pincode(GtkWidget *button);
130void toggle_set_sensitive(GtkWidget *button, gpointer data);
131void pin_option_button_clicked (GtkButton *button, gpointer data);
132void entry_custom_changed(GtkWidget *entry);
133void restart_button_clicked (GtkButton *button, gpointer user_data);
134void does_not_match_cb (GtkButton *button, gpointer user_data);
135void matches_cb (GtkButton *button, gpointer user_data);
136
137static void
138set_large_label (GtkLabel *label, const char *text)
139{
140 char *str;
141
142 str = g_strdup_printf("<span font_desc=\"50\"> %s </span>", text);
143 gtk_label_set_markup(GTK_LABEL(label), str);
144 g_free(str);
145}
146
147static char *
148get_random_pincode (guint num_digits)
149{
150 if (num_digits == 0)
151 num_digits = PIN_NUM_DIGITS;
152 return g_strdup_printf ("%d", g_random_int_range (pow (10, num_digits - 1),
153 pow (10, num_digits)));
154}
155
156static char *
157get_icade_pincode (char **pin_display_str)
158{
159 GString *pin, *pin_display;
160 guint i;
161 static char *arrows[] = {
162 NULL,
163 "⬆", /* up = 1 */
164 "⬇", /* down = 2 */
165 "⬅", /* left = 3 */
166 "➡" /* right = 4 */
167 };
168
169 pin = g_string_new (NULL);
170 pin_display = g_string_new (NULL);
171
172 for (i = 0; i < PIN_NUM_DIGITS; i++) {
173 int r;
174 char *c;
175
176 r = g_random_int_range (1, 4);
177
178 c = g_strdup_printf ("%d", r);
179 g_string_append (pin, c);
180 g_free (c);
181
182 g_string_append (pin_display, arrows[r]);
183 }
184 g_string_append (pin_display, "❍");
185
186 *pin_display_str = g_string_free (pin_display, FALSE);
187 return g_string_free (pin, FALSE);
188}
189
190static gboolean
191pincode_callback (GDBusMethodInvocation *invocation,
192 GDBusProxy *device,
193 gpointer user_data)
194{
195 target_ssp = FALSE;
196
197 /* Only show the pincode page if the pincode isn't automatic */
198 if (automatic_pincode == FALSE)
199 gtk_assistant_set_current_page (window_assistant, PAGE_SETUP);
200 g_debug ("Using pincode \"%s\"", pincode);
201 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", pincode));
202
203 return TRUE;
204}
205
206void
207restart_button_clicked (GtkButton *button,
208 gpointer user_data)
209{
210 /* Clean up old state */
211 target_ssp = FALSE;
212 display_called = FALSE;
213 g_free (target_address);
214 target_address = NULL;
215 g_free (target_name);
216 target_name = NULL;
217 summary_failure = FALSE;
218 target_ui_behaviour = PAIRING_UI_NORMAL;
219
220 g_object_set (selector,
221 "device-category-filter", BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED,
222 NULL);
223
224 gtk_assistant_set_current_page (window_assistant, PAGE_SEARCH);
225}
226
227void
228does_not_match_cb (GtkButton *button,
229 gpointer user_data)
230{
231 GDBusMethodInvocation *invocation;
232 GError *error = NULL;
233 char *text;
234
235 summary_failure = TRUE;
236 gtk_assistant_set_current_page (window_assistant, PAGE_SUMMARY);
237
238 /* translators:
239 * The '%s' is the device name, for example:
240 * Pairing with 'Sony Bluetooth Headset' cancelled
241 */
242 text = g_strdup_printf(_("Pairing with '%s' cancelled"), target_name);
243 gtk_label_set_text(GTK_LABEL(label_summary), text);
244 g_free(text);
245
246 invocation = g_object_get_data (G_OBJECT (button), "invocation");
247 error = g_error_new (AGENT_ERROR, AGENT_ERROR_REJECT,
248 "Agent callback cancelled");
249 g_dbus_method_invocation_return_gerror (invocation, error);
250 g_error_free (error);
251
252 g_object_set_data (G_OBJECT(does_not_match_button), "invocation", NULL);
253 g_object_set_data (G_OBJECT(matches_button), "invocation", NULL);
254}
255
256void
257matches_cb (GtkButton *button,
258 gpointer user_data)
259{
260 GDBusMethodInvocation *invocation;
261
262 invocation = g_object_get_data (G_OBJECT (button), "invocation");
263 gtk_widget_set_sensitive (does_not_match_button, FALSE);
264 gtk_widget_set_sensitive (matches_button, FALSE);
265 g_dbus_method_invocation_return_value (invocation, NULL);
266
267 g_object_set_data (G_OBJECT(does_not_match_button), "invocation", NULL);
268 g_object_set_data (G_OBJECT(matches_button), "invocation", NULL);
269}
270
271static gboolean
272confirm_callback (GDBusMethodInvocation *invocation,
273 GDBusProxy *device,
274 guint pin,
275 gpointer user_data)
276{
277 char *str, *label;
278
279 target_ssp = TRUE;
280 gtk_assistant_set_current_page (window_assistant, PAGE_SSP_SETUP);
281
282 gtk_widget_show (label_ssp_pin_help);
283 label = g_strdup_printf (_("Please confirm that the PIN displayed on '%s' matches this one."),
284 target_name);
285 gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), label);
286 g_free (label);
287
288 gtk_widget_show (label_ssp_pin);
289 str = g_strdup_printf ("%06d", pin);
290 set_large_label (GTK_LABEL (label_ssp_pin), str);
291 g_free (str);
292
293 g_object_set_data (G_OBJECT(does_not_match_button), "invocation", invocation);
294 g_object_set_data (G_OBJECT(matches_button), "invocation", invocation);
295
296 return TRUE;
297}
298
299static gboolean
300display_callback (GDBusMethodInvocation *invocation,
301 GDBusProxy *device,
302 guint pin,
303 guint entered,
304 gpointer user_data)
305{
306 gchar *text, *done, *code;
307
308 display_called = TRUE;
309 target_ssp = TRUE;
310 gtk_assistant_set_current_page (window_assistant, PAGE_SSP_SETUP);
311
312 code = g_strdup_printf("%06d", pin);
313
314 if (entered > 0) {
315 GtkEntry *entry;
316 gunichar invisible;
317 GString *str;
318 guint i;
319
320 entry = GTK_ENTRY (gtk_entry_new ());
321 invisible = gtk_entry_get_invisible_char (entry);
322 g_object_unref (entry);
323
324 str = g_string_new (NULL);
325 for (i = 0; i < entered; i++)
326 g_string_append_unichar (str, invisible);
327 if (entered < strlen (code))
328 g_string_append (str, code + entered);
329
330 done = g_string_free (str, FALSE);
331 } else {
332 done = g_strdup ("");
333 }
334
335 gtk_widget_show (label_pin_help);
336
337 gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), _("Please enter the following PIN:"));
338 text = g_strdup_printf("%s%s", done, code + entered);
339 set_large_label (GTK_LABEL (label_ssp_pin), text);
340 g_free(text);
341
342 g_free(done);
343 g_free(code);
344
345 g_dbus_method_invocation_return_value (invocation, NULL);
346
347 return TRUE;
348}
349
350static gboolean
351cancel_callback (GDBusMethodInvocation *invocation,
352 gpointer user_data)
353{
354 gchar *text;
355
356 create_started = FALSE;
357
358 summary_failure = TRUE;
359 gtk_assistant_set_current_page (window_assistant, PAGE_SUMMARY);
360
361 /* translators:
362 * The '%s' is the device name, for example:
363 * Pairing with 'Sony Bluetooth Headset' cancelled
364 */
365 text = g_strdup_printf(_("Pairing with '%s' cancelled"), target_name);
366 gtk_label_set_text(GTK_LABEL(label_summary), text);
367 g_free(text);
368
369 g_dbus_method_invocation_return_value (invocation, NULL);
370
371 return TRUE;
372}
373
374typedef struct {
375 char *path;
376 GTimer *timer;
377} ConnectData;
378
379static void
380connect_callback (GObject *source_object,
381 GAsyncResult *res,
382 gpointer user_data)
383{
384 ConnectData *data = (ConnectData *) user_data;
385 gboolean success;
386
387 success = bluetooth_client_connect_service_finish (client, res, NULL);
388
389 if (success == FALSE && g_timer_elapsed (data->timer, NULL) < CONNECT_TIMEOUT) {
390 bluetooth_client_connect_service (client, data->path, TRUE, NULL, connect_callback, data);
391 return;
392 }
393
394 if (success == FALSE)
395 g_debug ("Failed to connect to device %s", data->path);
396
397 g_timer_destroy (data->timer);
398 g_free (data->path);
399 g_free (data);
400
401 gtk_assistant_set_current_page (window_assistant, PAGE_SUMMARY);
402}
403
404static void
405create_callback (BluetoothClient *_client,
406 const char *path,
407 const GError *error,
408 gpointer user_data)
409{
410 ConnectData *data;
411
412 create_started = FALSE;
413
414 /* Create failed */
415 if (path == NULL) {
416 char *text;
417
418 summary_failure = TRUE;
419 gtk_assistant_set_current_page (window_assistant, PAGE_SUMMARY);
420
421 /* translators:
422 * The '%s' is the device name, for example:
423 * Setting up 'Sony Bluetooth Headset' failed
424 */
425 text = g_strdup_printf(_("Setting up '%s' failed"), target_name);
426
427 g_warning ("Setting up '%s' failed: %s", target_name, error->message);
428
429 gtk_label_set_markup(GTK_LABEL(label_summary), text);
430 g_free (text);
431
432 return;
433 }
434
435 bluetooth_client_set_trusted(client, path, TRUE);
436
437 data = g_new0 (ConnectData, 1);
438 data->path = g_strdup (path);
439 data->timer = g_timer_new ();
440
441 bluetooth_client_connect_service (client, path, TRUE, NULL, connect_callback, data);
442 gtk_assistant_set_current_page (window_assistant, PAGE_FINISHING);
443}
444
445void
446quit_callback (GtkWidget *widget,
447 gpointer data)
448{
449 gtk_widget_destroy(GTK_WIDGET (window_assistant));
450}
451
452void prepare_callback (GtkWidget *assistant,
453 GtkWidget *page,
454 gpointer data)
455{
456 gboolean complete = TRUE;
457
458 gtk_widget_hide (button_quit);
459 gtk_widget_hide (button_cancel);
460
461 if (page == page_search) {
462 complete = set_page_search_complete ();
463 bluetooth_chooser_start_discovery(selector);
464 } else {
465 bluetooth_chooser_stop_discovery(selector);
466 }
467
468 if (page == page_connecting) {
469 char *text;
470
471 complete = FALSE;
472
473 gtk_spinner_start (GTK_SPINNER (spinner_connecting));
474
475 /* translators:
476 * The '%s' is the device name, for example:
477 * Connecting to 'Sony Bluetooth Headset'...
478 */
479 text = g_strdup_printf (_("Connecting to '%s'..."), target_name);
480 gtk_label_set_text (GTK_LABEL (label_connecting), text);
481 g_free (text);
482
483 gtk_widget_show (button_cancel);
484 } else {
485 gtk_spinner_stop (GTK_SPINNER (spinner_connecting));
486 }
487
488 if ((page == page_setup || page == page_connecting) && (create_started == FALSE)) {
489 const char *path = AGENT_PATH;
490
491 /* Set the filter on the selector, so we can use it to get more
492 * info later, in page_summary */
493 g_object_set (selector,
494 "device-category-filter", BLUETOOTH_CATEGORY_ALL,
495 NULL);
496
497 /* Do we pair, or don't we? */
498 if (automatic_pincode && pincode == NULL) {
499 g_debug ("Not pairing as %s", automatic_pincode ? "pincode is NULL" : "automatic_pincode is FALSE");
500 path = NULL;
501 }
502
503 g_object_ref(agent);
504 bluetooth_client_create_device (client, target_address,
505 path, create_callback, assistant);
506 create_started = TRUE;
507 }
508
509 if (page == page_setup) {
510 complete = FALSE;
511
512 if (automatic_pincode == FALSE && target_ssp == FALSE) {
513 char *help, *pincode_display;
514
515 g_free (pincode);
516 pincode = NULL;
517 pincode_display = NULL;
518
519 switch (target_ui_behaviour) {
520 case PAIRING_UI_NORMAL:
521 help = g_strdup_printf (_("Please enter the following PIN on '%s':"), target_name);
522 break;
523 case PAIRING_UI_KEYBOARD:
524 help = g_strdup_printf (_("Please enter the following PIN on '%s' and press “Enter” on the keyboard:"), target_name);
525 pincode = get_random_pincode (target_max_digits);
526 pincode_display = g_strdup_printf ("%s⏎", pincode);
527 break;
528 case PAIRING_UI_ICADE:
529 help = g_strdup (_("Please move the joystick of your iCade in the following directions:"));
530 pincode = get_icade_pincode (&pincode_display);
531 break;
532 default:
533 g_assert_not_reached ();
534 }
535
536 if (pincode == NULL)
537 pincode = get_random_pincode (target_max_digits);
538
539 gtk_label_set_markup(GTK_LABEL(label_pin_help), help);
540 g_free (help);
541 set_large_label (GTK_LABEL (label_pin), pincode_display ? pincode_display : pincode);
542 g_free (pincode_display);
543 } else {
544 g_assert_not_reached ();
545 }
546
547 gtk_widget_show (button_cancel);
548 }
549
550 if (page == page_finishing) {
551 char *text;
552
553 complete = FALSE;
554
555 gtk_spinner_start (GTK_SPINNER (spinner_finishing));
556
557 /* translators:
558 * The '%s' is the device name, for example:
559 * Please wait while finishing setup on 'Sony Bluetooth Headset'...
560 */
561 text = g_strdup_printf (_("Please wait while finishing setup on device '%s'..."), target_name);
562 gtk_label_set_text (GTK_LABEL (label_finishing), text);
563 g_free (text);
564
565 gtk_widget_show (button_quit);
566 } else {
567 gtk_spinner_stop (GTK_SPINNER (spinner_finishing));
568 }
569
570 if (page == page_summary && summary_failure == FALSE) {
571 GList *widgets = NULL;
572 GValue value = { 0, };
573 char **uuids, *text;
574
575 /* FIXME remove this code when bluetoothd has pair/unpair code */
576 g_object_set (G_OBJECT (selector), "device-selected", target_address, NULL);
577
578 bluetooth_chooser_get_selected_device_info (selector, "name", &value);
579 text = g_strdup_printf (_("Successfully set up new device '%s'"), g_value_get_string (&value));
580 g_value_unset (&value);
581 gtk_label_set_text (GTK_LABEL (label_summary), text);
582 g_free (text);
583
584 if (bluetooth_chooser_get_selected_device_info (selector, "uuids", &value) != FALSE) {
585 uuids = g_value_get_boxed (&value);
586 widgets = bluetooth_plugin_manager_get_widgets (target_address,
587 (const char **) uuids);
588 g_value_unset (&value);
589 }
590 if (widgets != NULL) {
591 GList *l;
592
593 for (l = widgets; l != NULL; l = l->next) {
594 GtkWidget *widget = l->data;
595 gtk_box_pack_start (GTK_BOX (extra_config_vbox),
596 widget,
597 FALSE,
598 TRUE,
599 0);
600 }
601 g_list_free (widgets);
602 gtk_widget_show_all (extra_config_vbox);
603 }
604 gtk_widget_show (button_quit);
605 }
606
607 /* Setup the buttons some */
608 if (page == page_summary && summary_failure) {
609 complete = FALSE;
610 gtk_assistant_add_action_widget (GTK_ASSISTANT (assistant), W("restart_button"));
611 gtk_widget_show (button_quit);
612 } else {
613 if (gtk_widget_get_parent (W("restart_button")) != NULL)
614 gtk_assistant_remove_action_widget (GTK_ASSISTANT (assistant), W("restart_button"));
615 }
616
617 if (page == page_ssp_setup) {
618 if (display_called == FALSE) {
619 complete = FALSE;
620 gtk_assistant_add_action_widget (GTK_ASSISTANT (assistant), W("matches_button"));
621 gtk_assistant_add_action_widget (GTK_ASSISTANT (assistant), W("does_not_match_button"));
622 } else {
623 gtk_widget_show (button_cancel);
624 }
625 } else {
626 if (gtk_widget_get_parent (W("does_not_match_button")) != NULL)
627 gtk_assistant_remove_action_widget (GTK_ASSISTANT (assistant), W("does_not_match_button"));
628 if (gtk_widget_get_parent (W("matches_button")) != NULL)
629 gtk_assistant_remove_action_widget (GTK_ASSISTANT (assistant), W("matches_button"));
630 }
631
632 gtk_assistant_set_page_complete (GTK_ASSISTANT(assistant),
633 page, complete);
634}
635
636static gboolean
637set_page_search_complete (void)
638{
639 char *name, *address;
640 gboolean complete = FALSE;
641
642 address = bluetooth_chooser_get_selected_device (selector);
643 name = bluetooth_chooser_get_selected_device_name (selector);
644
645 if (address == NULL)
646 complete = FALSE;
647 else if (name == NULL)
648 complete = (user_pincode != NULL && strlen(user_pincode) >= 4);
649 else
650 complete = (user_pincode == NULL || strlen(user_pincode) >= 4);
651
652 g_free (address);
653 g_free (name);
654
655 gtk_assistant_set_page_complete (GTK_ASSISTANT (window_assistant),
656 page_search, complete);
657
658 return complete;
659}
660
661gboolean
662entry_custom_event (GtkWidget *entry, GdkEventKey *event)
663{
664 gunichar c;
665
666 if (event->length == 0)
667 return FALSE;
668
669 /* Not a printable character? */
670 c = gdk_keyval_to_unicode (event->keyval);
671 if (c == 0 ||
672 g_unichar_iscntrl (c) ||
673 g_unichar_isdigit (c))
674 return FALSE;
675
676 return TRUE;
677}
678
679void
680entry_custom_changed (GtkWidget *entry)
681{
682 g_free (user_pincode);
683 user_pincode = g_strdup (gtk_entry_get_text(GTK_ENTRY(entry)));
684 gtk_dialog_set_response_sensitive (GTK_DIALOG (pin_dialog),
685 GTK_RESPONSE_ACCEPT,
686 gtk_entry_get_text_length (GTK_ENTRY (entry)) >= 1);
687}
688
689void
690toggle_set_sensitive (GtkWidget *button,
691 gpointer data)
692{
693 gboolean active;
694
695 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
696 gtk_widget_set_sensitive(entry_custom, active);
697 /* When selecting another PIN, make sure the "Close" button is sensitive */
698 if (!active)
699 gtk_dialog_set_response_sensitive (GTK_DIALOG (pin_dialog),
700 GTK_RESPONSE_ACCEPT, TRUE);
701 else
702 entry_custom_changed (entry_custom);
703}
704
705void
706set_user_pincode (GtkWidget *button)
707{
708 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
709 return;
710
711 g_free (user_pincode);
712 user_pincode = g_strdup (g_object_get_data (G_OBJECT (button), "pin"));
713}
714
715void
716select_device_changed (BluetoothChooser *selector,
717 const char *address,
718 gpointer user_data)
719{
720 GValue value = { 0, };
721 guint target_type = BLUETOOTH_TYPE_ANY;
722 gboolean is_custom_pin = FALSE;
723 int legacypairing;
724
725 if (gtk_assistant_get_current_page (GTK_ASSISTANT (window_assistant)) != PAGE_SEARCH)
726 return;
727
728 set_page_search_complete ();
729
730 /* Device was deselected */
731 if (address == NULL)
732 return;
733
734 if (bluetooth_chooser_get_selected_device_info (selector, "legacypairing", &value) != FALSE) {
735 legacypairing = g_value_get_int (&value);
736 if (legacypairing == -1)
737 legacypairing = TRUE;
738 } else {
739 legacypairing = TRUE;
740 }
741
742 g_free(target_address);
743 target_address = g_strdup (address);
744
745 g_free(target_name);
746 target_name = bluetooth_chooser_get_selected_device_name (selector);
747
748 target_type = bluetooth_chooser_get_selected_device_type (selector);
749 target_ssp = !legacypairing;
750 automatic_pincode = FALSE;
751 target_ui_behaviour = PAIRING_UI_NORMAL;
752
753 g_free (pincode);
754 pincode = NULL;
755
756 g_free (user_pincode);
757 user_pincode = get_pincode_for_device (target_type, target_address, target_name, &target_max_digits);
758 if (user_pincode != NULL &&
759 g_str_equal (user_pincode, "NULL") == FALSE) {
760 if (g_str_equal (user_pincode, "KEYBOARD")) {
761 target_ui_behaviour = PAIRING_UI_KEYBOARD;
762 is_custom_pin = TRUE;
763 } else if (g_str_equal (user_pincode, "ICADE")) {
764 target_ui_behaviour = PAIRING_UI_ICADE;
765 is_custom_pin = TRUE;
766 } else {
767 pincode = g_strdup (user_pincode);
768 }
769 }
770
771 if (is_custom_pin)
772 automatic_pincode = FALSE;
773 else
774 automatic_pincode = user_pincode != NULL;
775
776 g_free (user_pincode);
777 user_pincode = NULL;
778
779 gtk_entry_set_max_length (GTK_ENTRY (entry_custom), target_max_digits);
780}
781
782void
783pin_option_button_clicked (GtkButton *button,
784 gpointer data)
785{
786 GtkWidget *radio;
787
788 gtk_window_set_transient_for (GTK_WINDOW (pin_dialog),
789 GTK_WINDOW (window_assistant));
790 gtk_window_present (GTK_WINDOW (pin_dialog));
791
792 /* When reopening, try to guess where the pincode was set */
793 if (user_pincode == NULL)
794 radio = radio_auto;
795 else if (g_str_equal (user_pincode, "0000"))
796 radio = radio_0000;
797 else if (g_str_equal (user_pincode, "1111"))
798 radio = radio_1111;
799 else if (g_str_equal (user_pincode, "1234"))
800 radio = radio_1234;
801 else if (g_str_equal (user_pincode, "NULL"))
802 radio = radio_none;
803 else {
804 radio = radio_custom;
805 gtk_entry_set_text (GTK_ENTRY (entry_custom), user_pincode);
806 }
807 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
808
809 gtk_dialog_run (GTK_DIALOG (pin_dialog));
810 gtk_widget_hide (pin_dialog);
811 g_free (pincode);
812 pincode = g_strdup (user_pincode);
813 automatic_pincode = user_pincode != NULL;
814}
815
816static int
817page_func (gint current_page,
818 gpointer data)
819{
820 if (current_page == PAGE_SEARCH) {
821 if (target_ssp != FALSE || automatic_pincode != FALSE)
822 return PAGE_CONNECTING;
823 else
824 return PAGE_SETUP;
825 }
826 if (current_page == PAGE_SETUP)
827 return PAGE_SUMMARY;
828 return current_page + 1;
829}
830
831static gboolean
832create_wizard (void)
833{
834 GtkAssistant *assistant;
835 GError *err = NULL;
836
837 builder = gtk_builder_new ();
838 if (gtk_builder_add_from_file (builder, "wizard.ui", NULL) == 0) {
839 if (gtk_builder_add_from_file (builder, PKGDATADIR "/wizard.ui", &err) == 0) {
840 g_warning ("Could not load UI from %s: %s", PKGDATADIR "/wizard.ui", err->message);
841 g_error_free(err);
842 return FALSE;
843 }
844 }
845
846 window_assistant = GTK_ASSISTANT(gtk_builder_get_object(builder, "assistant"));
847 assistant = window_assistant;
848
849 gtk_assistant_set_forward_page_func (assistant, page_func, NULL, NULL);
850
851 /* The 2 custom buttons */
852 button_quit = W("quit_button");
853 button_cancel = W("cancel_button");
854 gtk_assistant_add_action_widget (assistant, button_quit);
855 gtk_assistant_add_action_widget (assistant, button_cancel);
856 gtk_widget_hide (button_quit);
857 gtk_widget_hide (button_cancel);
858
859 /* Intro page, nothing to do */
860
861 /* Search page */
862 page_search = W("page_search");
863 selector = BLUETOOTH_CHOOSER (gtk_builder_get_object (builder, "selector"));
864
865 /* Connecting page */
866 page_connecting = W("page_connecting");
867 label_connecting = W("label_connecting");
868 spinner_connecting = W("spinner_connecting");
869
870 /* Setup page */
871 page_setup = W("page_setup");
872 label_pin_help = W("label_pin_help");
873 label_pin = W("label_pin");
874
875 /* SSP Setup page */
876 page_ssp_setup = W("page_ssp_setup");
877 gtk_assistant_set_page_complete(assistant, page_ssp_setup, FALSE);
878 label_ssp_pin_help = W("label_ssp_pin_help");
879 label_ssp_pin = W("label_ssp_pin");
880 does_not_match_button = W("does_not_match_button");
881 matches_button = W("matches_button");
882
883 /* Finishing page */
884 page_finishing = W("page_finishing");
885 label_finishing = W("label_finishing");
886 spinner_finishing = W("spinner_finishing");
887
888 /* Summary page */
889 page_summary = W("page_summary");
890 label_summary = W("label_summary");
891 extra_config_vbox = W("extra_config_vbox");
892
893 /* PIN dialog */
894 pin_dialog = W("pin_dialog");
895 radio_auto = W("radio_auto");
896 radio_0000 = W("radio_0000");
897 radio_1111 = W("radio_1111");
898 radio_1234 = W("radio_1234");
899 radio_none = W("radio_none");
900 radio_custom = W("radio_custom");
901 entry_custom = W("entry_custom");
902
903 g_object_set_data (G_OBJECT (radio_auto), "pin", NULL);
904 g_object_set_data (G_OBJECT (radio_0000), "pin", "0000");
905 g_object_set_data (G_OBJECT (radio_1111), "pin", "1111");
906 g_object_set_data (G_OBJECT (radio_1234), "pin", "1234");
907 g_object_set_data (G_OBJECT (radio_none), "pin", "NULL");
908 g_object_set_data (G_OBJECT (radio_custom), "pin", "");
909 g_object_set_data (G_OBJECT (radio_custom), "entry", entry_custom);
910
911 gtk_builder_connect_signals(builder, NULL);
912
913 gtk_widget_show (GTK_WIDGET(assistant));
914
915 gtk_assistant_update_buttons_state(GTK_ASSISTANT(assistant));
916
917 return TRUE;
918}
919
920static void
921activate_cb (GApplication *app,
922 gpointer user_data)
923{
924 gtk_window_present_with_time (GTK_WINDOW (user_data), GDK_CURRENT_TIME);
925}
926
927static GOptionEntry options[] = {
928 { NULL },
929};
930
931int main (int argc, char **argv)
932{
933 GtkApplication *app;
934 GError *error = NULL;
935
936 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
937 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
938 textdomain(GETTEXT_PACKAGE);
939
940 if (gtk_init_with_args(&argc, &argv, NULL,
941 options, GETTEXT_PACKAGE, &error) == FALSE) {
942 if (error) {
943 g_printerr("%s\n", error->message);
944 g_error_free(error);
945 } else
946 g_printerr("An unknown error occurred\n");
947
948 return 1;
949 }
950
951 app = gtk_application_new ("org.gnome.Bluetooth.wizard", G_APPLICATION_FLAGS_NONE);
952 if (g_application_register (G_APPLICATION (app), NULL, &error) == FALSE) {
953 g_warning ("Could not register application: %s", error->message);
954 g_error_free (error);
955 return 1;
956 }
957
958 if (g_application_get_is_remote (G_APPLICATION (app))) {
959 g_application_activate (G_APPLICATION (app));
960 gdk_notify_startup_complete ();
961 return 0;
962 }
963
964 gtk_window_set_default_icon_name("bluetooth");
965
966 client = bluetooth_client_new();
967
968 agent = bluetooth_agent_new();
969 g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *) (&agent));
970
971 bluetooth_agent_set_pincode_func(agent, pincode_callback, NULL);
972 bluetooth_agent_set_display_func(agent, display_callback, NULL);
973 bluetooth_agent_set_cancel_func(agent, cancel_callback, NULL);
974 bluetooth_agent_set_confirm_func(agent, confirm_callback, NULL);
975
976 bluetooth_agent_setup(agent, AGENT_PATH);
977
978 bluetooth_plugin_manager_init ();
979
980 if (create_wizard() == FALSE)
981 return 1;
982 gtk_application_add_window (app,
983 GTK_WINDOW (window_assistant));
984
985 g_signal_connect (app, "activate",
986 G_CALLBACK (activate_cb), window_assistant);
987
988 g_application_run (G_APPLICATION (app), argc, argv);
989
990 bluetooth_plugin_manager_cleanup ();
991
992 if (agent != NULL)
993 g_object_unref (agent);
994
995 g_object_unref(client);
996
997 g_object_unref(app);
998
999 return 0;
1000}
1001
01002
=== modified file 'debian/changelog'
--- debian/changelog 2014-04-25 02:00:56 +0000
+++ debian/changelog 2014-05-15 03:31:21 +0000
@@ -1,3 +1,13 @@
1gnome-bluetooth (3.8.2.1-0ubuntu6~test1) utopic; urgency=medium
2
3 * Add ssp parameter fix, fix the parameter entered in agent dbus API,
4 also fix the wizard's UI to show the pin code correctly.
5 Fixed Logitech Bluetooth Keyboard K760, Logitech Bluetooth Keyboard K810,
6 HP Bluetooth Keyboard K4000 secure simple pairing failed issue.
7 (LP: #1035431, #1291756)
8
9 -- Jian-Ding Chen (timchen119) <tim.chen119@canonical.com> Fri, 02 May 2014 16:50:57 +0800
10
1gnome-bluetooth (3.8.2.1-0ubuntu5) utopic; urgency=low11gnome-bluetooth (3.8.2.1-0ubuntu5) utopic; urgency=low
212
3 * debian/patches/99_add_microsoft_mice.patch: fix the problem that13 * debian/patches/99_add_microsoft_mice.patch: fix the problem that
414
=== modified file 'debian/patches/series'
--- debian/patches/series 2014-02-25 16:32:43 +0000
+++ debian/patches/series 2014-05-15 03:31:21 +0000
@@ -7,3 +7,4 @@
7git_leak_fixes.patch7git_leak_fixes.patch
8git_disconnect_callbacks.patch8git_disconnect_callbacks.patch
9git_reference_handling.patch9git_reference_handling.patch
10ssp-parameter-fix.patch
1011
=== added file 'debian/patches/ssp-parameter-fix.patch'
--- debian/patches/ssp-parameter-fix.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/ssp-parameter-fix.patch 2014-05-15 03:31:21 +0000
@@ -0,0 +1,86 @@
1Description: ssp parameter fix
2 * Add ssp parameter fix, fix the parameter entered in agent dbus API,
3 also fix the wizard's UI to show the pin code correctly.
4 Fixed Logitech Bluetooth Keyboard K760, Logitech Bluetooth Keyboard K810,
5 HP Bluetooth Keyboard K4000 secure simple pairing failed issue.
6 (LP: #1035431, #1291756)
7Author: Jian-Ding Chen (timchen119) <tim.chen119@canonical.com>
8Bug-Ubuntu: https://bugs.launchpad.net/bugs/1035431
9Bug-Ubuntu: https://bugs.launchpad.net/bugs/1291756
10Last-Update: 2014-04-29
11
12--- gnome-bluetooth-3.8.2.1.orig/lib/bluetooth-agent.c
13+++ gnome-bluetooth-3.8.2.1/lib/bluetooth-agent.c
14@@ -52,7 +52,7 @@ static const gchar introspection_xml[] =
15 " <method name='DisplayPasskey'>"
16 " <arg type='o' name='device' direction='in'/>"
17 " <arg type='u' name='passkey' direction='in'/>"
18-" <arg type='y' name='entered' direction='in'/>"
19+" <arg type='q' name='entered' direction='in'/>"
20 " </method>"
21 " <method name='RequestConfirmation'>"
22 " <arg type='o' name='device' direction='in'/>"
23@@ -164,7 +164,7 @@ static gboolean bluetooth_agent_request_
24 }
25
26 static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent,
27- const char *path, guint passkey, guint8 entered,
28+ const char *path, guint passkey, guint16 entered,
29 GDBusMethodInvocation *invocation)
30 {
31 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
32@@ -339,9 +339,9 @@ handle_method_call (GDBusConnection
33 } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) {
34 char *path;
35 guint32 passkey;
36- guint8 entered;
37+ guint16 entered;
38
39- g_variant_get (parameters, "(ouy)", &path, &passkey, &entered);
40+ g_variant_get (parameters, "(ouq)", &path, &passkey, &entered);
41 bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation);
42 g_free (path);
43 } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) {
44--- gnome-bluetooth-3.8.2.1.orig/wizard/main.c
45+++ gnome-bluetooth-3.8.2.1/wizard/main.c
46@@ -303,7 +303,7 @@ display_callback (GDBusMethodInvocation
47 guint entered,
48 gpointer user_data)
49 {
50- gchar *text, *done, *code;
51+ gchar *text, *done, *code, *label;
52
53 display_called = TRUE;
54 target_ssp = TRUE;
55@@ -329,18 +329,27 @@ display_callback (GDBusMethodInvocation
56
57 done = g_string_free (str, FALSE);
58 } else {
59- done = g_strdup ("");
60+ done = g_strdup_printf("%s", code);
61 }
62
63- gtk_widget_show (label_pin_help);
64+ gtk_widget_show (label_ssp_pin);
65
66- gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), _("Please enter the following PIN:"));
67- text = g_strdup_printf("%s%s", done, code + entered);
68+ if (target_ui_behaviour == PAIRING_UI_KEYBOARD) {
69+ label = g_strdup_printf (_("Please enter the following PIN on '%s' and press “Enter” on the keyboard:"), target_name);
70+ text = g_strdup_printf("%s⏎", done);
71+ }
72+ else {
73+ label = g_strdup_printf (_("Please enter the following PIN on '%s':"), target_name);
74+ text = g_strdup_printf("%s", done);
75+ }
76+
77+ gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), label);
78 set_large_label (GTK_LABEL (label_ssp_pin), text);
79 g_free(text);
80
81 g_free(done);
82 g_free(code);
83+ g_free(label);
84
85 g_dbus_method_invocation_return_value (invocation, NULL);
86
087
=== modified file 'lib/bluetooth-agent.c'
--- lib/bluetooth-agent.c 2013-07-03 16:07:57 +0000
+++ lib/bluetooth-agent.c 2014-05-15 03:31:21 +0000
@@ -52,7 +52,7 @@
52" <method name='DisplayPasskey'>"52" <method name='DisplayPasskey'>"
53" <arg type='o' name='device' direction='in'/>"53" <arg type='o' name='device' direction='in'/>"
54" <arg type='u' name='passkey' direction='in'/>"54" <arg type='u' name='passkey' direction='in'/>"
55" <arg type='y' name='entered' direction='in'/>"55" <arg type='q' name='entered' direction='in'/>"
56" </method>"56" </method>"
57" <method name='RequestConfirmation'>"57" <method name='RequestConfirmation'>"
58" <arg type='o' name='device' direction='in'/>"58" <arg type='o' name='device' direction='in'/>"
@@ -164,7 +164,7 @@
164}164}
165165
166static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent,166static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent,
167 const char *path, guint passkey, guint8 entered,167 const char *path, guint passkey, guint16 entered,
168 GDBusMethodInvocation *invocation)168 GDBusMethodInvocation *invocation)
169{169{
170 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);170 BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
@@ -339,9 +339,9 @@
339 } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) {339 } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) {
340 char *path;340 char *path;
341 guint32 passkey;341 guint32 passkey;
342 guint8 entered;342 guint16 entered;
343343
344 g_variant_get (parameters, "(ouy)", &path, &passkey, &entered);344 g_variant_get (parameters, "(ouq)", &path, &passkey, &entered);
345 bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation);345 bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation);
346 g_free (path);346 g_free (path);
347 } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) {347 } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) {
348348
=== modified file 'wizard/main.c'
--- wizard/main.c 2013-07-03 16:07:57 +0000
+++ wizard/main.c 2014-05-15 03:31:21 +0000
@@ -303,7 +303,7 @@
303 guint entered,303 guint entered,
304 gpointer user_data)304 gpointer user_data)
305{305{
306 gchar *text, *done, *code;306 gchar *text, *done, *code, *label;
307307
308 display_called = TRUE;308 display_called = TRUE;
309 target_ssp = TRUE;309 target_ssp = TRUE;
@@ -329,18 +329,27 @@
329329
330 done = g_string_free (str, FALSE);330 done = g_string_free (str, FALSE);
331 } else {331 } else {
332 done = g_strdup ("");332 done = g_strdup_printf("%s", code);
333 }333 }
334334
335 gtk_widget_show (label_pin_help);335 gtk_widget_show (label_ssp_pin);
336336
337 gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), _("Please enter the following PIN:"));337 if (target_ui_behaviour == PAIRING_UI_KEYBOARD) {
338 text = g_strdup_printf("%s%s", done, code + entered);338 label = g_strdup_printf (_("Please enter the following PIN on '%s' and press “Enter” on the keyboard:"), target_name);
339 text = g_strdup_printf("%s⏎", done);
340 }
341 else {
342 label = g_strdup_printf (_("Please enter the following PIN on '%s':"), target_name);
343 text = g_strdup_printf("%s", done);
344 }
345
346 gtk_label_set_markup(GTK_LABEL(label_ssp_pin_help), label);
339 set_large_label (GTK_LABEL (label_ssp_pin), text);347 set_large_label (GTK_LABEL (label_ssp_pin), text);
340 g_free(text);348 g_free(text);
341349
342 g_free(done);350 g_free(done);
343 g_free(code);351 g_free(code);
352 g_free(label);
344353
345 g_dbus_method_invocation_return_value (invocation, NULL);354 g_dbus_method_invocation_return_value (invocation, NULL);
346355

Subscribers

People subscribed via source and target branches

to all changes: