Warning, file /libraries/upnp-lib-qt/src/upnpabstractservice.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002    SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003 
0004    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "upnpabstractservice.h"
0008 
0009 #include "upnplogging.h"
0010 
0011 #include "upnpbasictypes.h"
0012 #include "upnpeventsubscriber.h"
0013 
0014 #include "upnpactiondescription.h"
0015 #include "upnpservicedescription.h"
0016 #include "upnpstatevariabledescription.h"
0017 
0018 #include <QBuffer>
0019 #include <QIODevice>
0020 #include <QMetaObject>
0021 #include <QMetaProperty>
0022 #include <QPointer>
0023 #include <QTimer>
0024 #include <QXmlStreamWriter>
0025 
0026 #include <QLoggingCategory>
0027 
0028 class UpnpAbstractServicePrivate
0029 {
0030 public:
0031     UpnpAbstractServicePrivate()
0032         : mService()
0033         , mXmlDescription()
0034         , mSubscribers()
0035     {
0036     }
0037 
0038     UpnpServiceDescription mService;
0039 
0040     QPointer<QIODevice> mXmlDescription;
0041 
0042     QVector<QPointer<UpnpEventSubscriber>> mSubscribers;
0043 };
0044 
0045 UpnpAbstractService::UpnpAbstractService(QObject *parent)
0046     : QObject(parent)
0047     , d(std::make_unique<UpnpAbstractServicePrivate>())
0048 {
0049 }
0050 
0051 UpnpAbstractService::~UpnpAbstractService() = default;
0052 
0053 QIODevice *UpnpAbstractService::buildAndGetXmlDescription()
0054 {
0055     if (!d->mXmlDescription) {
0056         QPointer<QBuffer> newDescription(new QBuffer);
0057 
0058         newDescription->open(QIODevice::ReadWrite);
0059 
0060         QXmlStreamWriter insertStream(newDescription.data());
0061         insertStream.setAutoFormatting(true);
0062 
0063         insertStream.writeStartDocument();
0064         insertStream.writeStartElement(QStringLiteral("scpd"));
0065         insertStream.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("urn:schemas-upnp-org:service-1-0"));
0066         insertStream.writeStartElement(QStringLiteral("specVersion"));
0067         insertStream.writeTextElement(QStringLiteral("major"), QStringLiteral("1"));
0068         insertStream.writeTextElement(QStringLiteral("minor"), QStringLiteral("0"));
0069         insertStream.writeEndElement();
0070 
0071         insertStream.writeStartElement(QStringLiteral("actionList"));
0072         const auto &allActions = description().actions();
0073         for (const auto &itAction : allActions) {
0074             insertStream.writeStartElement(QStringLiteral("action"));
0075             insertStream.writeTextElement(QStringLiteral("name"), itAction.mName);
0076             insertStream.writeStartElement(QStringLiteral("argumentList"));
0077             for (const auto &itArgument : itAction.mArguments) {
0078                 insertStream.writeStartElement(QStringLiteral("argument"));
0079                 insertStream.writeTextElement(QStringLiteral("name"), itArgument.mName);
0080                 insertStream.writeTextElement(QStringLiteral("direction"), (itArgument.mDirection == UpnpArgumentDirection::In) ? QStringLiteral("in") : QStringLiteral("out"));
0081                 if (itArgument.mIsReturnValue) {
0082                     insertStream.writeEmptyElement(QStringLiteral("retval"));
0083                 }
0084                 insertStream.writeTextElement(QStringLiteral("relatedStateVariable"), itArgument.mRelatedStateVariable);
0085                 insertStream.writeEndElement();
0086             }
0087             insertStream.writeEndElement();
0088             insertStream.writeEndElement();
0089         }
0090         insertStream.writeEndElement();
0091 
0092         insertStream.writeStartElement(QStringLiteral("serviceStateTable"));
0093 
0094         const auto &allStateVariables = description().stateVariables();
0095         for (const auto &itStateVariable : allStateVariables) {
0096             insertStream.writeStartElement(QStringLiteral("stateVariable"));
0097             if (itStateVariable.mEvented) {
0098                 insertStream.writeAttribute(QStringLiteral("sendEvents"), QStringLiteral("yes"));
0099             } else {
0100                 insertStream.writeAttribute(QStringLiteral("sendEvents"), QStringLiteral("no"));
0101             }
0102             insertStream.writeTextElement(QStringLiteral("name"), itStateVariable.mUpnpName);
0103             insertStream.writeTextElement(QStringLiteral("dataType"), itStateVariable.mDataType);
0104             if (itStateVariable.mDefaultValue.isValid()) {
0105                 insertStream.writeTextElement(QStringLiteral("defaultValue"), itStateVariable.mDefaultValue.toString());
0106             }
0107             if (itStateVariable.mMinimumValue.isValid() && itStateVariable.mMaximumValue.isValid()
0108                 && itStateVariable.mStep.isValid()) {
0109                 insertStream.writeStartElement(QStringLiteral("allowedValueRange"));
0110                 if (itStateVariable.mMinimumValue.isValid()) {
0111                     insertStream.writeTextElement(QStringLiteral("minimum"), itStateVariable.mMinimumValue.toString());
0112                 }
0113                 if (itStateVariable.mMaximumValue.isValid()) {
0114                     insertStream.writeTextElement(QStringLiteral("maximum"), itStateVariable.mMaximumValue.toString());
0115                 }
0116                 if (itStateVariable.mStep.isValid()) {
0117                     insertStream.writeTextElement(QStringLiteral("step"), itStateVariable.mStep.toString());
0118                 }
0119                 insertStream.writeEndElement();
0120             }
0121             if (!itStateVariable.mValueList.isEmpty()) {
0122                 insertStream.writeStartElement(QStringLiteral("allowedValueList"));
0123                 for (const auto &itValue : itStateVariable.mValueList) {
0124                     insertStream.writeTextElement(QStringLiteral("allowedValue"), itValue);
0125                 }
0126                 insertStream.writeEndElement();
0127             }
0128             insertStream.writeEndElement();
0129         }
0130         insertStream.writeEndElement();
0131         insertStream.writeEndElement();
0132         insertStream.writeEndDocument();
0133 
0134         d->mXmlDescription = newDescription;
0135     }
0136 
0137     d->mXmlDescription->seek(0);
0138 
0139     return d->mXmlDescription;
0140 }
0141 
0142 QPointer<UpnpEventSubscriber> UpnpAbstractService::subscribeToEvents(const QByteArray &requestData, const QMap<QByteArray, QByteArray> &headers)
0143 {
0144     Q_UNUSED(requestData)
0145 
0146     QPointer<UpnpEventSubscriber> newSubscriber(new UpnpEventSubscriber);
0147 
0148     const QByteArray &rawCallBackAddress = headers["callback"];
0149     newSubscriber->setCallback(QUrl(QString::fromLatin1(rawCallBackAddress.mid(1, rawCallBackAddress.length() - 2))));
0150 
0151     const QByteArray &rawTimeout = headers["timeout"];
0152     bool conversionIsOk = false;
0153     newSubscriber->setSecondTimeout(rawTimeout.right(rawTimeout.length() - 7).toInt(&conversionIsOk));
0154     if (!conversionIsOk || rawTimeout == "Second-infinite") {
0155         newSubscriber->setSecondTimeout(description().maximumSubscriptionDuration());
0156     }
0157 
0158     int signalIndex = -1;
0159     for (int i = 0; i < newSubscriber->metaObject()->methodCount(); ++i) {
0160         if (newSubscriber->metaObject()->method(i).name() == "notifyPropertyChange") {
0161             signalIndex = i;
0162             break;
0163         }
0164     }
0165 
0166     if (signalIndex != -1) {
0167         newSubscriber->setUpnpService(this);
0168         d->mSubscribers.push_back(newSubscriber);
0169 
0170         const auto &allStateVariables = description().stateVariables();
0171         for (const auto &currentStateVariable : allStateVariables) {
0172             if (currentStateVariable.mEvented) {
0173                 connect(this, metaObject()->property(currentStateVariable.mPropertyIndex).notifySignal(), newSubscriber, newSubscriber->metaObject()->method(signalIndex));
0174             }
0175         }
0176     }
0177 
0178     sendEventNotification(newSubscriber);
0179 
0180     return newSubscriber;
0181 }
0182 
0183 void UpnpAbstractService::unsubscribeToEvents(const QByteArray &requestData, const QMap<QByteArray, QByteArray> &headers)
0184 {
0185     Q_UNUSED(headers);
0186 
0187     qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpAbstractService::unsubscribeToEvents" << requestData;
0188 }
0189 
0190 void UpnpAbstractService::addAction(const UpnpActionDescription &newAction)
0191 {
0192     description().actions()[newAction.mName] = newAction;
0193 }
0194 
0195 const UpnpActionDescription &UpnpAbstractService::action(const QString &name) const
0196 {
0197     return description().action(name);
0198 }
0199 
0200 QList<QString> UpnpAbstractService::actions() const
0201 {
0202     return description().actions().keys();
0203 }
0204 
0205 void UpnpAbstractService::addStateVariable(const UpnpStateVariableDescription &newVariable)
0206 {
0207     description().stateVariables()[newVariable.mUpnpName] = newVariable;
0208 }
0209 
0210 const UpnpStateVariableDescription &UpnpAbstractService::stateVariable(const QString &name) const
0211 {
0212     return description().stateVariable(name);
0213 }
0214 
0215 QList<QString> UpnpAbstractService::stateVariables() const
0216 {
0217     return description().stateVariables().keys();
0218 }
0219 
0220 QVector<QPair<QString, QVariant>> UpnpAbstractService::invokeAction(const QString &actionName, const QVector<QVariant> &arguments, bool &isInError)
0221 {
0222     Q_UNUSED(actionName)
0223     Q_UNUSED(arguments)
0224     Q_UNUSED(isInError)
0225 
0226     return {};
0227 }
0228 
0229 void UpnpAbstractService::setDescription(const UpnpServiceDescription &value)
0230 {
0231     d->mService = value;
0232     Q_EMIT descriptionChanged();
0233 }
0234 
0235 UpnpServiceDescription &UpnpAbstractService::description()
0236 {
0237     return d->mService;
0238 }
0239 
0240 const UpnpServiceDescription &UpnpAbstractService::description() const
0241 {
0242     return d->mService;
0243 }
0244 void UpnpAbstractService::sendEventNotification(const QPointer<UpnpEventSubscriber> &currentSubscriber)
0245 {
0246     QTimer::singleShot(0, currentSubscriber.data(), &UpnpEventSubscriber::sendEventNotification);
0247 }
0248 
0249 #include "moc_upnpabstractservice.cpp"