1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
/*
* Copyright (C) 2013-2015 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Charles Kerr <charles.kerr@canonical.com>
*
*/
#include "agent.h"
#include <cassert>
/***
****
***/
void Agent::cancel(QDBusMessage msg, const char *functionName)
{
QString name = "org.bluez.Error.Canceled";
QString text = QString("The request was canceled: %1").arg(functionName);
m_connection.send(msg.createErrorReply(name, text));
}
void Agent::reject(QDBusMessage msg, const char *functionName)
{
QString name = "org.bluez.Error.Rejected";
QString text = QString("The request was rejected: %1").arg(functionName);
m_connection.send(msg.createErrorReply(name, text));
}
QSharedPointer<Device> Agent::findOrCreateDevice(const QDBusObjectPath &path)
{
auto device = m_devices.getDeviceFromPath(path.path());
// If the device doesn't exist we just couldn't add it to our
// internal list as we didn't received the corresponding dbus
// signal for that yet. This normally happens when a remote device
// wants to pair with us but we didn't discovered that device yet.
// We simply create an entry for this new device then and will
// continue as normal.
if (!device)
device = m_devices.addDeviceFromPath(path);
return device;
}
/***
****
***/
/**
* This method gets called when the service daemon
* unregisters the agent. An agent can use it to do
* cleanup tasks. There is no need to unregister the
* agent, because when this method gets called it has
* already been unregistered.
*/
void Agent::Release()
{
Q_EMIT(releaseNeeded());
}
/***
****
***/
/**
* This method gets called when the service daemon
* needs to confirm a passkey for an authentication.
*
* To confirm the value it should return an empty reply
* or an error in case the passkey is invalid.
*
* Note that the passkey will always be a 6-digit number,
* so the display should be zero-padded at the start if
* the value contains less than 6 digits.
*
* Possible errors: org.bluez.Error.Rejected
* org.bluez.Error.Canceled
*/
void Agent::RequestConfirmation(const QDBusObjectPath &objectPath, uint passkey)
{
if (auto device = findOrCreateDevice(objectPath)) {
const uint tag = m_tag++;
setDelayedReply(true);
assert(!m_delayedReplies.contains(tag));
m_delayedReplies[tag] = message();
QString passkeyStr = QString("%1").arg(passkey, 6, 10, QChar('0'));
Q_EMIT(passkeyConfirmationNeeded(tag, device.data(), passkeyStr));
} else { // confirmation requested for an unknown device..?!
reject(message(), __func__);
}
}
/**
* Invoked by the user-facing code after it prompts the user to confirm/cancel
* the passkey passed from an Agent::passkeyConfirmationNeeded signal.
*
* @param tag: the tag from the Agent::passkeyConfirmationNeeded signal
* @param confirmed: true if user confirmed the passkey, false if they canceled
*/
void Agent::confirmPasskey(uint tag, bool confirmed)
{
if (m_delayedReplies.contains(tag)) {
QDBusMessage message = m_delayedReplies[tag];
if (confirmed)
m_connection.send(message.createReply());
else
cancel(message, __func__);
m_delayedReplies.remove(tag);
}
}
QString Agent::RequestPinCode(const QDBusObjectPath &objectPath)
{
if (auto device = findOrCreateDevice(objectPath)) {
const uint tag = m_tag++;
setDelayedReply(true);
assert(!m_delayedReplies.contains(tag));
m_delayedReplies[tag] = message();
Q_EMIT(pinCodeNeeded(tag, device.data()));
} else { // passkey requested for an unknown device..?!
reject(message(), __func__);
}
return 0;
}
/**
* This method gets called when the service daemon
* needs to get the passkey for an authentication.
*
* The return value should be a numeric value between 0-999999.
*
* Possible errors: org.bluez.Error.Rejected
* org.bluez.Error.Canceled
*/
unsigned int Agent::RequestPasskey(const QDBusObjectPath &objectPath)
{
if (auto device = findOrCreateDevice(objectPath)) {
const uint tag = m_tag++;
setDelayedReply(true);
assert(!m_delayedReplies.contains(tag));
m_delayedReplies[tag] = message();
Q_EMIT(passkeyNeeded(tag, device.data()));
} else { // passkey requested for an unknown device..?!
reject(message(), __func__);
}
return 0;
}
/**
* Invoked by the user-facing code after it prompts the user for a passkey
* as a result of an Agent::passkeyNeeded signal.
*
* @param tag: the tag from the Agent::passkeyNeeded signal
* @param provided: true if user provided the passkey, false if they canceled
* @param passkey: the passkey. Only valid if provided is true.
*/
void Agent::providePasskey(uint tag, bool provided, uint passkey)
{
if (m_delayedReplies.contains(tag)) {
if (provided)
m_connection.send(m_delayedReplies[tag].createReply(passkey));
else
cancel(m_delayedReplies[tag], __func__);
m_delayedReplies.remove(tag);
}
}
/***
****
***/
/**
* Invoked by the user-facing code after it prompts the user for a PIN code
* from an Agent::pinCodeNeeded() signal.
*
* @param tag: the tag from the Agent::passkeyConfirmationNeeded signal
* @param confirmed: true if user confirmed the passkey, false if they canceled
*/
void Agent::providePinCode(uint tag, bool confirmed, QString pinCode)
{
if (m_delayedReplies.contains(tag)) {
QDBusMessage message = m_delayedReplies[tag];
if (confirmed)
m_connection.send(message.createReply(qVariantFromValue(pinCode)));
else
cancel(message, __func__);
m_delayedReplies.remove(tag);
}
}
void Agent::DisplayPinCode(const QDBusObjectPath &objectPath, QString pincode)
{
if (auto device = findOrCreateDevice(objectPath)) {
Q_EMIT(displayPinCodeNeeded(device.data(), pincode));
} else {
reject(message(), __func__);
}
}
void Agent::DisplayPasskey(const QDBusObjectPath &objectPath, uint passkey, ushort entered)
{
if (auto device = findOrCreateDevice(objectPath)) {
QString passkeyStr = QString("%1").arg(passkey, 6, 10, QChar('0'));
Q_EMIT(displayPasskeyNeeded(device.data(), passkeyStr, entered));
} else {
reject(message(), __func__);
}
}
/**
* This method gets called to indicate that the agent
* request failed before a reply was returned.
*/
void Agent::Cancel()
{
qWarning() << "Cancel callback called";
Q_EMIT(cancelNeeded());
}
void Agent::RequestAuthorization(const QDBusObjectPath &objectPath)
{
qWarning() << "Authorization requested for device"
<< objectPath.path();
if (auto device = findOrCreateDevice(objectPath)) {
const uint tag = m_tag++;
setDelayedReply(true);
assert(!m_delayedReplies.contains(tag));
m_delayedReplies[tag] = message();
Q_EMIT(authorizationRequested(tag, device.data()));
}
else {
reject(message(), __func__);
}
}
void Agent::authorizationRequestCallback(uint tag, bool allow)
{
if (m_delayedReplies.contains(tag)) {
QDBusMessage message = m_delayedReplies[tag];
if (allow)
m_connection.send(message.createReply());
else
reject(message, __func__);
m_delayedReplies.remove(tag);
}
}
void Agent::displayPinCodeCallback(uint tag)
{
if (m_delayedReplies.contains(tag)) {
QDBusMessage message = m_delayedReplies[tag];
cancel(message, __func__);
m_delayedReplies.remove(tag);
}
}
/**
* Invoked by the user-facing code after it prompts the user to cancel
* the passkey passed from an Agent::displayPasskeyNeeded signal.
*
* @param tag: the tag from the Agent::displayPasskeyNeeded signal
*/
void Agent::displayPasskeyCallback(uint tag)
{
if (m_delayedReplies.contains(tag)) {
QDBusMessage message = m_delayedReplies[tag];
cancel(message, __func__);
m_delayedReplies.remove(tag);
}
}
|