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"