BluezQt

pendingcall.cpp
1 /*
2  * BluezQt - Asynchronous Bluez wrapper library
3  *
4  * SPDX-FileCopyrightText: 2014 David Rosca <[email protected]>
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 
19 namespace BluezQt
20 {
21 static 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 
61 class PendingCallPrivate : public QObject
62 {
63 public:
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 
91 PendingCallPrivate::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 
100 void 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 
140 void PendingCallPrivate::processVoidReply(const QDBusPendingReply<> &reply)
141 {
142  processError(reply.error());
143 }
144 
145 void PendingCallPrivate::processUint32Reply(const QDBusPendingReply<quint32> &reply)
146 {
147  processError(reply.error());
148  if (!reply.isError()) {
149  m_value.append(reply.value());
150  }
151 }
152 
153 void PendingCallPrivate::processStringReply(const QDBusPendingReply<QString> &reply)
154 {
155  processError(reply.error());
156  if (!reply.isError()) {
157  m_value.append(reply.value());
158  }
159 }
160 
161 void PendingCallPrivate::processStringListReply(const QDBusPendingReply<QStringList> &reply)
162 {
163  processError(reply.error());
164  if (!reply.isError()) {
165  m_value.append(reply.value());
166  }
167 }
168 
169 void 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 
177 void 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 
191 void 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 
204 void 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 
212 void 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 
221 void PendingCallPrivate::emitFinished()
222 {
223  m_watcher->deleteLater();
224  m_watcher = nullptr;
225  Q_EMIT q->finished(q);
226  q->deleteLater();
227 }
228 
229 void 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 
237 void 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 
245 void PendingCallPrivate::pendingCallFinished(QDBusPendingCallWatcher *watcher)
246 {
247  processReply(watcher);
248  emitFinished();
249 }
250 
251 PendingCall::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, &PendingCallPrivate::pendingCallFinished);
261 }
262 
263 PendingCall::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, &PendingCallPrivate::emitDelayedFinished);
274 }
275 
276 PendingCall::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, std::placeholders::_1), &d->m_value);
285  d->emitFinished();
286  });
287 }
288 
290 {
291  delete d;
292 }
293 
294 QVariant PendingCall::value() const
295 {
296  if (d->m_value.isEmpty()) {
297  return QVariant();
298  }
299  return d->m_value.first();
300 }
301 
302 QVariantList PendingCall::values() const
303 {
304  return d->m_value;
305 }
306 
307 int PendingCall::error() const
308 {
309  return d->m_error;
310 }
311 
312 QString PendingCall::errorText() const
313 {
314  return d->m_errorText;
315 }
316 
317 bool PendingCall::isFinished() const
318 {
319  if (d->m_watcher) {
320  return d->m_watcher->isFinished();
321  }
322  return true;
323 }
324 
326 {
327  if (d->m_watcher) {
328  d->m_watcher->waitForFinished();
329  }
330 }
331 
332 QVariant PendingCall::userData() const
333 {
334  return d->m_userData;
335 }
336 
337 void PendingCall::setUserData(const QVariant &userData)
338 {
339  d->m_userData = userData;
340 }
341 
342 } // namespace BluezQt
void append(const T &value)
@ NotReady
Indicates that the device is not ready.
Definition: pendingcall.h:51
void finished(QDBusPendingCallWatcher *self)
@ NotAuthorized
Indicates that the caller is not authorized to do the action.
Definition: pendingcall.h:77
void waitForFinished()
Waits for the call to finish.
@ DoesNotExist
Indicates that an agent, service or pairing operation does not exists.
Definition: pendingcall.h:63
QVariant fromValue(const T &value)
@ AlreadyConnected
Indicates that the device is already connected.
Definition: pendingcall.h:69
@ Failed
Indicates that the action have failed.
Definition: pendingcall.h:53
@ InternalError
Indicates an internal error.
Definition: pendingcall.h:95
@ ConnectionAttemptFailed
Indicates that the connection attempt have failed.
Definition: pendingcall.h:87
void setSingleShot(bool singleShot)
@ InvalidArguments
Indicates that invalid arguments were passed.
Definition: pendingcall.h:59
@ ConnectFailed
Indicates that the connection to the device have failed.
Definition: pendingcall.h:71
@ AuthenticationTimeout
Indicates that the authentication timed out.
Definition: pendingcall.h:85
bool isError() const const
@ AuthenticationFailed
Indicates that the authentication have failed.
Definition: pendingcall.h:81
@ Canceled
Indicates that the action was canceled.
Definition: pendingcall.h:57
Error
Known error types.
Definition: pendingcall.h:47
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void reserve(int alloc)
@ NotConnected
Indicates that the device is not connected.
Definition: pendingcall.h:73
@ AlreadyExists
Indicates that an agent or pairing record already exists.
Definition: pendingcall.h:61
void start(int msec)
@ DBusError
Indicates an error with D-Bus.
Definition: pendingcall.h:93
@ Rejected
Indicates that the action was rejected.
Definition: pendingcall.h:55
void timeout()
void setUserData(const QVariant &userData)
Sets the user data of the call.
T1 value() const const
QDBusError error() const const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
@ UnknownError
Indicates an unknown error.
Definition: pendingcall.h:97
@ InvalidLength
Indicates that the data provided generates a data packet which is too long.
Definition: pendingcall.h:89
QString name(StandardShortcut id)
@ NotSupported
Indicates that the action is not supported.
Definition: pendingcall.h:75
~PendingCall() override
Destroys a PendingCall object.
QVariant argumentAt(int index) const const
@ AuthenticationCanceled
Indicates that the authentication was canceled.
Definition: pendingcall.h:79
@ NotPermitted
Indicates that the action is not permitted (e.g.
Definition: pendingcall.h:91
QString mid(int position, int n) const const
@ AuthenticationRejected
Indicates that the authentication was rejected.
Definition: pendingcall.h:83
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sun Sep 25 2022 04:19:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.