BluezQt

pendingcall.cpp
1/*
2 * BluezQt - Asynchronous Bluez wrapper library
3 *
4 * SPDX-FileCopyrightText: 2014 David Rosca <nowrep@gmail.com>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9#include "pendingcall.h"
10#include "bluezqt_dbustypes.h"
11#include "debug.h"
12#include "obexfiletransferentry.h"
13#include "obextransfer.h"
14#include "obextransfer_p.h"
15
16#include <QDBusPendingCallWatcher>
17#include <QTimer>
18
19namespace BluezQt
20{
21static PendingCall::Error nameToError(const QString &name)
22{
23 if (name.startsWith(QLatin1String("org.freedesktop.DBus.Error"))) {
25 }
26
27 if (!name.startsWith(QLatin1String("org.bluez.Error"))) {
29 }
30
31#define FROM_BLUEZ_ERROR(string, value) \
32 if (errorName == QLatin1String(string)) { \
33 return value; \
34 }
35
36 const QString &errorName = name.mid(16);
37 FROM_BLUEZ_ERROR("NotReady", PendingCall::NotReady);
38 FROM_BLUEZ_ERROR("Failed", PendingCall::Failed);
39 FROM_BLUEZ_ERROR("Rejected", PendingCall::Rejected);
40 FROM_BLUEZ_ERROR("Canceled", PendingCall::Canceled);
41 FROM_BLUEZ_ERROR("InvalidArguments", PendingCall::InvalidArguments);
42 FROM_BLUEZ_ERROR("AlreadyExists", PendingCall::AlreadyExists);
43 FROM_BLUEZ_ERROR("DoesNotExist", PendingCall::DoesNotExist);
44 FROM_BLUEZ_ERROR("AlreadyConnected", PendingCall::AlreadyConnected);
45 FROM_BLUEZ_ERROR("ConnectFailed", PendingCall::ConnectFailed);
46 FROM_BLUEZ_ERROR("NotConnected", PendingCall::NotConnected);
47 FROM_BLUEZ_ERROR("NotSupported", PendingCall::NotSupported);
48 FROM_BLUEZ_ERROR("NotAuthorized", PendingCall::NotAuthorized);
49 FROM_BLUEZ_ERROR("AuthenticationCanceled", PendingCall::AuthenticationCanceled);
50 FROM_BLUEZ_ERROR("AuthenticationFailed", PendingCall::AuthenticationFailed);
51 FROM_BLUEZ_ERROR("AuthenticationRejected", PendingCall::AuthenticationRejected);
52 FROM_BLUEZ_ERROR("AuthenticationTimeout", PendingCall::AuthenticationTimeout);
53 FROM_BLUEZ_ERROR("ConnectionAttemptFailed", PendingCall::ConnectionAttemptFailed);
54 FROM_BLUEZ_ERROR("InvalidLength", PendingCall::InvalidLength);
55 FROM_BLUEZ_ERROR("NotPermitted", PendingCall::NotPermitted);
56#undef FROM_BLUEZ_ERROR
57
59}
60
61class PendingCallPrivate : public QObject
62{
63public:
64 explicit PendingCallPrivate(PendingCall *parent);
65
66 void processReply(QDBusPendingCallWatcher *call);
67 void processVoidReply(const QDBusPendingReply<> &reply);
68 void processUint32Reply(const QDBusPendingReply<quint32> &reply);
69 void processStringReply(const QDBusPendingReply<QString> &reply);
70 void processStringListReply(const QDBusPendingReply<QStringList> &reply);
71 void processObjectPathReply(const QDBusPendingReply<QDBusObjectPath> &reply);
72 void processFileTransferListReply(const QDBusPendingReply<QVariantMapList> &reply);
73 void processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply);
74 void processByteArrayReply(const QDBusPendingReply<QByteArray> &reply);
75 void processError(const QDBusError &m_error);
76
77 void emitFinished();
78 void emitDelayedFinished();
79 void emitInternalError(const QString &errorText);
80 void pendingCallFinished(QDBusPendingCallWatcher *m_watcher);
81
82 PendingCall *q;
83 int m_error;
84 QString m_errorText;
85 QVariant m_userData;
86 QVariantList m_value;
87 PendingCall::ReturnType m_type;
88 QDBusPendingCallWatcher *m_watcher;
89};
90
91PendingCallPrivate::PendingCallPrivate(PendingCall *parent)
92 : QObject(parent)
93 , q(parent)
94 , m_error(PendingCall::NoError)
95 , m_type(PendingCall::ReturnVoid)
96 , m_watcher(nullptr)
97{
98}
99
100void PendingCallPrivate::processReply(QDBusPendingCallWatcher *call)
101{
102 switch (m_type) {
103 case PendingCall::ReturnVoid:
104 processVoidReply(*call);
105 break;
106
107 case PendingCall::ReturnUint32:
108 processUint32Reply(*call);
109 break;
110
111 case PendingCall::ReturnString:
112 processStringReply(*call);
113 break;
114
115 case PendingCall::ReturnStringList:
116 processStringListReply(*call);
117 break;
118
119 case PendingCall::ReturnObjectPath:
120 processObjectPathReply(*call);
121 break;
122
123 case PendingCall::ReturnFileTransferList:
124 processFileTransferListReply(*call);
125 break;
126
127 case PendingCall::ReturnTransferWithProperties:
128 processTransferWithPropertiesReply(*call);
129 break;
130
131 case PendingCall::ReturnByteArray:
132 processByteArrayReply(*call);
133 break;
134
135 default:
136 break;
137 }
138}
139
140void PendingCallPrivate::processVoidReply(const QDBusPendingReply<> &reply)
141{
142 processError(reply.error());
143}
144
145void PendingCallPrivate::processUint32Reply(const QDBusPendingReply<quint32> &reply)
146{
147 processError(reply.error());
148 if (!reply.isError()) {
149 m_value.append(reply.value());
150 }
151}
152
153void PendingCallPrivate::processStringReply(const QDBusPendingReply<QString> &reply)
154{
155 processError(reply.error());
156 if (!reply.isError()) {
157 m_value.append(reply.value());
158 }
159}
160
161void PendingCallPrivate::processStringListReply(const QDBusPendingReply<QStringList> &reply)
162{
163 processError(reply.error());
164 if (!reply.isError()) {
165 m_value.append(reply.value());
166 }
167}
168
169void PendingCallPrivate::processObjectPathReply(const QDBusPendingReply<QDBusObjectPath> &reply)
170{
171 processError(reply.error());
172 if (!reply.isError()) {
173 m_value.append(QVariant::fromValue(reply.value()));
174 }
175}
176
177void PendingCallPrivate::processFileTransferListReply(const QDBusPendingReply<QVariantMapList> &reply)
178{
179 processError(reply.error());
180 if (!reply.isError()) {
182 items.reserve(reply.value().size());
183 const auto maps = reply.value();
184 for (const QVariantMap &map : maps) {
185 items.append(ObexFileTransferEntry(map));
186 }
187 m_value.append(QVariant::fromValue(items));
188 }
189}
190
191void PendingCallPrivate::processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply)
192{
193 processError(reply.error());
194 if (reply.isError()) {
195 return;
196 }
197
198 ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(reply.argumentAt<0>().path(), reply.argumentAt<1>()));
199 transfer->d->q = transfer.toWeakRef();
200 transfer->d->m_suspendable = true;
201 m_value.append(QVariant::fromValue(transfer));
202}
203
204void PendingCallPrivate::processByteArrayReply(const QDBusPendingReply<QByteArray> &reply)
205{
206 processError(reply.error());
207 if (!reply.isError()) {
208 m_value.append(QVariant::fromValue(reply.value()));
209 }
210}
211
212void PendingCallPrivate::processError(const QDBusError &error)
213{
214 if (error.isValid()) {
215 qCWarning(BLUEZQT) << "PendingCall Error:" << error.message();
216 m_error = nameToError(error.name());
217 m_errorText = error.message();
218 }
219}
220
221void PendingCallPrivate::emitFinished()
222{
223 m_watcher->deleteLater();
224 m_watcher = nullptr;
225 Q_EMIT q->finished(q);
226 q->deleteLater();
227}
228
229void PendingCallPrivate::emitDelayedFinished()
230{
231 Q_ASSERT(qobject_cast<QTimer *>(sender()));
232
233 Q_EMIT q->finished(q);
234 static_cast<QTimer *>(sender())->deleteLater();
235}
236
237void PendingCallPrivate::emitInternalError(const QString &errorText)
238{
239 qCWarning(BLUEZQT) << "PendingCall Internal error:" << errorText;
240 m_error = PendingCall::InternalError;
241 m_errorText = errorText;
242 emitFinished();
243}
244
245void PendingCallPrivate::pendingCallFinished(QDBusPendingCallWatcher *watcher)
246{
247 processReply(watcher);
248 emitFinished();
249}
250
251PendingCall::PendingCall(const QDBusPendingCall &call, ReturnType type, QObject *parent)
252 : QObject(parent)
253 , d(new PendingCallPrivate(this))
254{
255 qDBusRegisterMetaType<QVariantMapList>();
256
257 d->m_type = type;
258 d->m_watcher = new QDBusPendingCallWatcher(call, this);
259
260 connect(d->m_watcher, &QDBusPendingCallWatcher::finished, d.get(), &PendingCallPrivate::pendingCallFinished);
261}
262
263PendingCall::PendingCall(PendingCall::Error error, const QString &errorText, QObject *parent)
264 : QObject(parent)
265 , d(new PendingCallPrivate(this))
266{
267 d->m_error = error;
268 d->m_errorText = errorText;
269
270 QTimer *timer = new QTimer(this);
271 timer->setSingleShot(true);
272 timer->start(0);
273 connect(timer, &QTimer::timeout, d.get(), &PendingCallPrivate::emitDelayedFinished);
274}
275
276PendingCall::PendingCall(const QDBusPendingCall &call, ExternalProcessor externalProcessor, QObject *parent)
277 : QObject(parent)
278 , d(new PendingCallPrivate(this))
279{
280 qDBusRegisterMetaType<QVariantMapList>();
281
282 d->m_watcher = new QDBusPendingCallWatcher(call, this);
283 connect(d->m_watcher, &QDBusPendingCallWatcher::finished, [externalProcessor, this](QDBusPendingCallWatcher *watcher) {
284 externalProcessor(watcher, std::bind(&PendingCallPrivate::processError, d.get(), std::placeholders::_1), &d->m_value);
285 d->emitFinished();
286 });
287}
288
289PendingCall::~PendingCall() = default;
290
291QVariant PendingCall::value() const
292{
293 if (d->m_value.isEmpty()) {
294 return QVariant();
295 }
296 return d->m_value.first();
297}
298
299QVariantList PendingCall::values() const
300{
301 return d->m_value;
302}
303
304int PendingCall::error() const
305{
306 return d->m_error;
307}
308
309QString PendingCall::errorText() const
310{
311 return d->m_errorText;
312}
313
314bool PendingCall::isFinished() const
315{
316 if (d->m_watcher) {
317 return d->m_watcher->isFinished();
318 }
319 return true;
320}
321
322void PendingCall::waitForFinished()
323{
324 if (d->m_watcher) {
325 d->m_watcher->waitForFinished();
326 }
327}
328
329QVariant PendingCall::userData() const
330{
331 return d->m_userData;
332}
333
334void PendingCall::setUserData(const QVariant &userData)
335{
336 d->m_userData = userData;
337}
338
339} // namespace BluezQt
340
341#include "moc_pendingcall.cpp"
Error
Known error types.
Definition pendingcall.h:49
@ DoesNotExist
Indicates that an agent, service or pairing operation does not exists.
Definition pendingcall.h:65
@ AlreadyExists
Indicates that an agent or pairing record already exists.
Definition pendingcall.h:63
@ NotSupported
Indicates that the action is not supported.
Definition pendingcall.h:77
@ ConnectionAttemptFailed
Indicates that the connection attempt have failed.
Definition pendingcall.h:89
@ NotPermitted
Indicates that the action is not permitted (e.g.
Definition pendingcall.h:93
@ ConnectFailed
Indicates that the connection to the device have failed.
Definition pendingcall.h:73
@ NotReady
Indicates that the device is not ready.
Definition pendingcall.h:53
@ AuthenticationCanceled
Indicates that the authentication was canceled.
Definition pendingcall.h:81
@ AuthenticationTimeout
Indicates that the authentication timed out.
Definition pendingcall.h:87
@ InvalidLength
Indicates that the data provided generates a data packet which is too long.
Definition pendingcall.h:91
@ AuthenticationRejected
Indicates that the authentication was rejected.
Definition pendingcall.h:85
@ Failed
Indicates that the action have failed.
Definition pendingcall.h:55
@ InvalidArguments
Indicates that invalid arguments were passed.
Definition pendingcall.h:61
@ AlreadyConnected
Indicates that the device is already connected.
Definition pendingcall.h:71
@ UnknownError
Indicates an unknown error.
Definition pendingcall.h:99
@ DBusError
Indicates an error with D-Bus.
Definition pendingcall.h:95
@ NotAuthorized
Indicates that the caller is not authorized to do the action.
Definition pendingcall.h:79
@ Rejected
Indicates that the action was rejected.
Definition pendingcall.h:57
@ Canceled
Indicates that the action was canceled.
Definition pendingcall.h:59
@ NotConnected
Indicates that the device is not connected.
Definition pendingcall.h:75
@ AuthenticationFailed
Indicates that the authentication have failed.
Definition pendingcall.h:83
Type type(const QSqlDatabase &db)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString name(StandardShortcut id)
void finished(QDBusPendingCallWatcher *self)
QVariant argumentAt(int index) const const
QDBusError error() const const
bool isError() const const
typename Select< 0 >::Type value() const const
void append(QList< T > &&value)
void reserve(qsizetype size)
QObject * parent() const const
QString mid(qsizetype position, qsizetype n) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setSingleShot(bool singleShot)
void start()
void timeout()
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:52 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.