File indexing completed on 2024-12-08 12:15:36
0001 /* 0002 * BluezQt - Asynchronous Bluez wrapper library 0003 * 0004 * SPDX-FileCopyrightText: 2014 David Rosca <nowrep@gmail.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "pendingcall.h" 0010 #include "bluezqt_dbustypes.h" 0011 #include "debug.h" 0012 #include "obexfiletransferentry.h" 0013 #include "obextransfer.h" 0014 #include "obextransfer_p.h" 0015 0016 #include <QDBusPendingCallWatcher> 0017 #include <QTimer> 0018 0019 namespace BluezQt 0020 { 0021 static PendingCall::Error nameToError(const QString &name) 0022 { 0023 if (name.startsWith(QLatin1String("org.freedesktop.DBus.Error"))) { 0024 return PendingCall::DBusError; 0025 } 0026 0027 if (!name.startsWith(QLatin1String("org.bluez.Error"))) { 0028 return PendingCall::UnknownError; 0029 } 0030 0031 #define FROM_BLUEZ_ERROR(string, value) \ 0032 if (errorName == QLatin1String(string)) { \ 0033 return value; \ 0034 } 0035 0036 const QString &errorName = name.mid(16); 0037 FROM_BLUEZ_ERROR("NotReady", PendingCall::NotReady); 0038 FROM_BLUEZ_ERROR("Failed", PendingCall::Failed); 0039 FROM_BLUEZ_ERROR("Rejected", PendingCall::Rejected); 0040 FROM_BLUEZ_ERROR("Canceled", PendingCall::Canceled); 0041 FROM_BLUEZ_ERROR("InvalidArguments", PendingCall::InvalidArguments); 0042 FROM_BLUEZ_ERROR("AlreadyExists", PendingCall::AlreadyExists); 0043 FROM_BLUEZ_ERROR("DoesNotExist", PendingCall::DoesNotExist); 0044 FROM_BLUEZ_ERROR("AlreadyConnected", PendingCall::AlreadyConnected); 0045 FROM_BLUEZ_ERROR("ConnectFailed", PendingCall::ConnectFailed); 0046 FROM_BLUEZ_ERROR("NotConnected", PendingCall::NotConnected); 0047 FROM_BLUEZ_ERROR("NotSupported", PendingCall::NotSupported); 0048 FROM_BLUEZ_ERROR("NotAuthorized", PendingCall::NotAuthorized); 0049 FROM_BLUEZ_ERROR("AuthenticationCanceled", PendingCall::AuthenticationCanceled); 0050 FROM_BLUEZ_ERROR("AuthenticationFailed", PendingCall::AuthenticationFailed); 0051 FROM_BLUEZ_ERROR("AuthenticationRejected", PendingCall::AuthenticationRejected); 0052 FROM_BLUEZ_ERROR("AuthenticationTimeout", PendingCall::AuthenticationTimeout); 0053 FROM_BLUEZ_ERROR("ConnectionAttemptFailed", PendingCall::ConnectionAttemptFailed); 0054 FROM_BLUEZ_ERROR("InvalidLength", PendingCall::InvalidLength); 0055 FROM_BLUEZ_ERROR("NotPermitted", PendingCall::NotPermitted); 0056 #undef FROM_BLUEZ_ERROR 0057 0058 return PendingCall::UnknownError; 0059 } 0060 0061 class PendingCallPrivate : public QObject 0062 { 0063 public: 0064 explicit PendingCallPrivate(PendingCall *parent); 0065 0066 void processReply(QDBusPendingCallWatcher *call); 0067 void processVoidReply(const QDBusPendingReply<> &reply); 0068 void processUint32Reply(const QDBusPendingReply<quint32> &reply); 0069 void processStringReply(const QDBusPendingReply<QString> &reply); 0070 void processStringListReply(const QDBusPendingReply<QStringList> &reply); 0071 void processObjectPathReply(const QDBusPendingReply<QDBusObjectPath> &reply); 0072 void processFileTransferListReply(const QDBusPendingReply<QVariantMapList> &reply); 0073 void processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply); 0074 void processByteArrayReply(const QDBusPendingReply<QByteArray> &reply); 0075 void processError(const QDBusError &m_error); 0076 0077 void emitFinished(); 0078 void emitDelayedFinished(); 0079 void emitInternalError(const QString &errorText); 0080 void pendingCallFinished(QDBusPendingCallWatcher *m_watcher); 0081 0082 PendingCall *q; 0083 int m_error; 0084 QString m_errorText; 0085 QVariant m_userData; 0086 QVariantList m_value; 0087 PendingCall::ReturnType m_type; 0088 QDBusPendingCallWatcher *m_watcher; 0089 }; 0090 0091 PendingCallPrivate::PendingCallPrivate(PendingCall *parent) 0092 : QObject(parent) 0093 , q(parent) 0094 , m_error(PendingCall::NoError) 0095 , m_type(PendingCall::ReturnVoid) 0096 , m_watcher(nullptr) 0097 { 0098 } 0099 0100 void PendingCallPrivate::processReply(QDBusPendingCallWatcher *call) 0101 { 0102 switch (m_type) { 0103 case PendingCall::ReturnVoid: 0104 processVoidReply(*call); 0105 break; 0106 0107 case PendingCall::ReturnUint32: 0108 processUint32Reply(*call); 0109 break; 0110 0111 case PendingCall::ReturnString: 0112 processStringReply(*call); 0113 break; 0114 0115 case PendingCall::ReturnStringList: 0116 processStringListReply(*call); 0117 break; 0118 0119 case PendingCall::ReturnObjectPath: 0120 processObjectPathReply(*call); 0121 break; 0122 0123 case PendingCall::ReturnFileTransferList: 0124 processFileTransferListReply(*call); 0125 break; 0126 0127 case PendingCall::ReturnTransferWithProperties: 0128 processTransferWithPropertiesReply(*call); 0129 break; 0130 0131 case PendingCall::ReturnByteArray: 0132 processByteArrayReply(*call); 0133 break; 0134 0135 default: 0136 break; 0137 } 0138 } 0139 0140 void PendingCallPrivate::processVoidReply(const QDBusPendingReply<> &reply) 0141 { 0142 processError(reply.error()); 0143 } 0144 0145 void PendingCallPrivate::processUint32Reply(const QDBusPendingReply<quint32> &reply) 0146 { 0147 processError(reply.error()); 0148 if (!reply.isError()) { 0149 m_value.append(reply.value()); 0150 } 0151 } 0152 0153 void PendingCallPrivate::processStringReply(const QDBusPendingReply<QString> &reply) 0154 { 0155 processError(reply.error()); 0156 if (!reply.isError()) { 0157 m_value.append(reply.value()); 0158 } 0159 } 0160 0161 void PendingCallPrivate::processStringListReply(const QDBusPendingReply<QStringList> &reply) 0162 { 0163 processError(reply.error()); 0164 if (!reply.isError()) { 0165 m_value.append(reply.value()); 0166 } 0167 } 0168 0169 void PendingCallPrivate::processObjectPathReply(const QDBusPendingReply<QDBusObjectPath> &reply) 0170 { 0171 processError(reply.error()); 0172 if (!reply.isError()) { 0173 m_value.append(QVariant::fromValue(reply.value())); 0174 } 0175 } 0176 0177 void PendingCallPrivate::processFileTransferListReply(const QDBusPendingReply<QVariantMapList> &reply) 0178 { 0179 processError(reply.error()); 0180 if (!reply.isError()) { 0181 QList<ObexFileTransferEntry> items; 0182 items.reserve(reply.value().size()); 0183 const auto maps = reply.value(); 0184 for (const QVariantMap &map : maps) { 0185 items.append(ObexFileTransferEntry(map)); 0186 } 0187 m_value.append(QVariant::fromValue(items)); 0188 } 0189 } 0190 0191 void PendingCallPrivate::processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply) 0192 { 0193 processError(reply.error()); 0194 if (reply.isError()) { 0195 return; 0196 } 0197 0198 ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(reply.argumentAt<0>().path(), reply.argumentAt<1>())); 0199 transfer->d->q = transfer.toWeakRef(); 0200 transfer->d->m_suspendable = true; 0201 m_value.append(QVariant::fromValue(transfer)); 0202 } 0203 0204 void PendingCallPrivate::processByteArrayReply(const QDBusPendingReply<QByteArray> &reply) 0205 { 0206 processError(reply.error()); 0207 if (!reply.isError()) { 0208 m_value.append(QVariant::fromValue(reply.value())); 0209 } 0210 } 0211 0212 void PendingCallPrivate::processError(const QDBusError &error) 0213 { 0214 if (error.isValid()) { 0215 qCWarning(BLUEZQT) << "PendingCall Error:" << error.message(); 0216 m_error = nameToError(error.name()); 0217 m_errorText = error.message(); 0218 } 0219 } 0220 0221 void PendingCallPrivate::emitFinished() 0222 { 0223 m_watcher->deleteLater(); 0224 m_watcher = nullptr; 0225 Q_EMIT q->finished(q); 0226 q->deleteLater(); 0227 } 0228 0229 void PendingCallPrivate::emitDelayedFinished() 0230 { 0231 Q_ASSERT(qobject_cast<QTimer *>(sender())); 0232 0233 Q_EMIT q->finished(q); 0234 static_cast<QTimer *>(sender())->deleteLater(); 0235 } 0236 0237 void PendingCallPrivate::emitInternalError(const QString &errorText) 0238 { 0239 qCWarning(BLUEZQT) << "PendingCall Internal error:" << errorText; 0240 m_error = PendingCall::InternalError; 0241 m_errorText = errorText; 0242 emitFinished(); 0243 } 0244 0245 void PendingCallPrivate::pendingCallFinished(QDBusPendingCallWatcher *watcher) 0246 { 0247 processReply(watcher); 0248 emitFinished(); 0249 } 0250 0251 PendingCall::PendingCall(const QDBusPendingCall &call, ReturnType type, QObject *parent) 0252 : QObject(parent) 0253 , d(new PendingCallPrivate(this)) 0254 { 0255 qDBusRegisterMetaType<QVariantMapList>(); 0256 0257 d->m_type = type; 0258 d->m_watcher = new QDBusPendingCallWatcher(call, this); 0259 0260 connect(d->m_watcher, &QDBusPendingCallWatcher::finished, d, &PendingCallPrivate::pendingCallFinished); 0261 } 0262 0263 PendingCall::PendingCall(PendingCall::Error error, const QString &errorText, QObject *parent) 0264 : QObject(parent) 0265 , d(new PendingCallPrivate(this)) 0266 { 0267 d->m_error = error; 0268 d->m_errorText = errorText; 0269 0270 QTimer *timer = new QTimer(this); 0271 timer->setSingleShot(true); 0272 timer->start(0); 0273 connect(timer, &QTimer::timeout, d, &PendingCallPrivate::emitDelayedFinished); 0274 } 0275 0276 PendingCall::PendingCall(const QDBusPendingCall &call, ExternalProcessor externalProcessor, QObject *parent) 0277 : QObject(parent) 0278 , d(new PendingCallPrivate(this)) 0279 { 0280 qDBusRegisterMetaType<QVariantMapList>(); 0281 0282 d->m_watcher = new QDBusPendingCallWatcher(call, this); 0283 connect(d->m_watcher, &QDBusPendingCallWatcher::finished, [externalProcessor, this](QDBusPendingCallWatcher *watcher) { 0284 externalProcessor(watcher, std::bind(&PendingCallPrivate::processError, d, std::placeholders::_1), &d->m_value); 0285 d->emitFinished(); 0286 }); 0287 } 0288 0289 PendingCall::~PendingCall() 0290 { 0291 delete d; 0292 } 0293 0294 QVariant PendingCall::value() const 0295 { 0296 if (d->m_value.isEmpty()) { 0297 return QVariant(); 0298 } 0299 return d->m_value.first(); 0300 } 0301 0302 QVariantList PendingCall::values() const 0303 { 0304 return d->m_value; 0305 } 0306 0307 int PendingCall::error() const 0308 { 0309 return d->m_error; 0310 } 0311 0312 QString PendingCall::errorText() const 0313 { 0314 return d->m_errorText; 0315 } 0316 0317 bool PendingCall::isFinished() const 0318 { 0319 if (d->m_watcher) { 0320 return d->m_watcher->isFinished(); 0321 } 0322 return true; 0323 } 0324 0325 void PendingCall::waitForFinished() 0326 { 0327 if (d->m_watcher) { 0328 d->m_watcher->waitForFinished(); 0329 } 0330 } 0331 0332 QVariant PendingCall::userData() const 0333 { 0334 return d->m_userData; 0335 } 0336 0337 void PendingCall::setUserData(const QVariant &userData) 0338 { 0339 d->m_userData = userData; 0340 } 0341 0342 } // namespace BluezQt 0343 0344 #include "moc_pendingcall.cpp"