File indexing completed on 2024-04-21 04:44:13
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 "upnpeventsubscriber.h" 0008 0009 #include "upnplogging.h" 0010 0011 #include "upnpabstractservice.h" 0012 #include "upnpbasictypes.h" 0013 0014 #include "upnpstatevariabledescription.h" 0015 0016 #include <QBuffer> 0017 #include <QPointer> 0018 #include <QUuid> 0019 #include <QXmlStreamWriter> 0020 0021 #include <QNetworkReply> 0022 #include <QNetworkRequest> 0023 0024 #include <QLoggingCategory> 0025 0026 class UpnpEventSubscriberPrivate 0027 { 0028 public: 0029 int mSecondTimeout = 1800; 0030 0031 QUrl mCallback; 0032 0033 QString mUuid; 0034 0035 quint32 mSequenceCounter = 0; 0036 0037 QNetworkAccessManager mNetworkAccess; 0038 0039 UpnpAbstractService *mUpnpService = nullptr; 0040 0041 QPointer<QBuffer> mSentBuffer; 0042 }; 0043 0044 UpnpEventSubscriber::UpnpEventSubscriber(QObject *parent) 0045 : QObject(parent) 0046 , d(std::make_unique<UpnpEventSubscriberPrivate>()) 0047 { 0048 const QString &uuidString(QUuid::createUuid().toString()); 0049 d->mUuid = uuidString.mid(1, uuidString.length() - 2); 0050 } 0051 0052 UpnpEventSubscriber::~UpnpEventSubscriber() = default; 0053 0054 void UpnpEventSubscriber::setSecondTimeout(int newValue) 0055 { 0056 d->mSecondTimeout = newValue; 0057 } 0058 0059 int UpnpEventSubscriber::secondTimeout() const 0060 { 0061 return d->mSecondTimeout; 0062 } 0063 0064 void UpnpEventSubscriber::setCallback(const QUrl &callbackAddress) 0065 { 0066 d->mCallback = callbackAddress; 0067 } 0068 0069 const QUrl &UpnpEventSubscriber::callback() const 0070 { 0071 return d->mCallback; 0072 } 0073 0074 const QString &UpnpEventSubscriber::uuid() const 0075 { 0076 return d->mUuid; 0077 } 0078 0079 void UpnpEventSubscriber::setUpnpService(UpnpAbstractService *service) 0080 { 0081 d->mUpnpService = service; 0082 } 0083 0084 void UpnpEventSubscriber::sendEventNotification() 0085 { 0086 QNetworkRequest newRequest(d->mCallback); 0087 newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArray("text/xml")); 0088 newRequest.setRawHeader("NT", "upnp:event"); 0089 newRequest.setRawHeader("NTS", "upnp:propchange"); 0090 QString sidHeader = QStringLiteral("uuid:") + d->mUuid; 0091 newRequest.setRawHeader("SID", sidHeader.toLatin1()); 0092 newRequest.setRawHeader("SEQ", QByteArray::number(d->mSequenceCounter)); 0093 0094 QPointer<QBuffer> requestBody(new QBuffer); 0095 requestBody->open(QIODevice::ReadWrite); 0096 0097 QXmlStreamWriter insertStream(requestBody.data()); 0098 insertStream.setAutoFormatting(true); 0099 0100 insertStream.writeStartDocument(QStringLiteral("1.0")); 0101 insertStream.writeNamespace(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("e")); 0102 insertStream.writeStartElement(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("propertyset")); 0103 const auto &allStateVariables(d->mUpnpService->stateVariables()); 0104 for (const QString &itVariable : allStateVariables) { 0105 const UpnpStateVariableDescription ¤tStateVariable(d->mUpnpService->stateVariable(itVariable)); 0106 if (currentStateVariable.mEvented) { 0107 insertStream.writeStartElement(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("property")); 0108 0109 const QVariant &propertyValue(d->mUpnpService->property(currentStateVariable.mPropertyName.constData())); 0110 if (propertyValue.canConvert<bool>()) { 0111 insertStream.writeTextElement(itVariable, propertyValue.toBool() ? QStringLiteral("1") : QStringLiteral("0")); 0112 } else { 0113 insertStream.writeTextElement(itVariable, propertyValue.toString()); 0114 } 0115 0116 insertStream.writeEndElement(); 0117 } 0118 } 0119 insertStream.writeEndElement(); 0120 insertStream.writeEndDocument(); 0121 requestBody->seek(0); 0122 0123 QNetworkReply *replyHandler = d->mNetworkAccess.sendCustomRequest(newRequest, "NOTIFY", requestBody.data()); 0124 connect(replyHandler, &QNetworkReply::finished, this, &UpnpEventSubscriber::eventingFinished); 0125 connect(replyHandler, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::errorOccurred), this, &UpnpEventSubscriber::eventingInErrorFinished); 0126 0127 d->mSentBuffer = requestBody; 0128 } 0129 0130 void UpnpEventSubscriber::notifyPropertyChange(const QString &serviceId, const QByteArray &propertyName) 0131 { 0132 Q_UNUSED(serviceId) 0133 0134 QNetworkRequest newRequest(d->mCallback); 0135 newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArray("text/xml")); 0136 newRequest.setRawHeader("NT", "upnp:event"); 0137 newRequest.setRawHeader("NTS", "upnp:propchange"); 0138 QString sidHeader = QStringLiteral("uuid:") + d->mUuid; 0139 newRequest.setRawHeader("SID", sidHeader.toLatin1()); 0140 newRequest.setRawHeader("SEQ", QByteArray::number(d->mSequenceCounter)); 0141 0142 QPointer<QBuffer> requestBody(new QBuffer); 0143 requestBody->open(QIODevice::ReadWrite); 0144 0145 QXmlStreamWriter insertStream(requestBody.data()); 0146 insertStream.setAutoFormatting(true); 0147 0148 insertStream.writeStartDocument(QStringLiteral("1.0")); 0149 insertStream.writeNamespace(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("e")); 0150 insertStream.writeStartElement(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("propertyset")); 0151 const auto &allStateVariables(d->mUpnpService->stateVariables()); 0152 for (const QString &itVariable : allStateVariables) { 0153 const UpnpStateVariableDescription ¤tStateVariable(d->mUpnpService->stateVariable(itVariable)); 0154 if (currentStateVariable.mEvented && currentStateVariable.mPropertyName == propertyName) { 0155 insertStream.writeStartElement(QStringLiteral("urn:schemas-upnp-org:event-1-0"), QStringLiteral("property")); 0156 0157 const QVariant &propertyValue(d->mUpnpService->property(currentStateVariable.mPropertyName.constData())); 0158 if (propertyValue.canConvert<bool>()) { 0159 insertStream.writeTextElement(itVariable, propertyValue.toBool() ? QStringLiteral("1") : QStringLiteral("0")); 0160 } else { 0161 insertStream.writeTextElement(itVariable, propertyValue.toString()); 0162 } 0163 0164 insertStream.writeEndElement(); 0165 } 0166 } 0167 insertStream.writeEndElement(); 0168 insertStream.writeEndDocument(); 0169 requestBody->seek(0); 0170 0171 QNetworkReply *replyHandler = d->mNetworkAccess.sendCustomRequest(newRequest, "NOTIFY", requestBody.data()); 0172 0173 connect(replyHandler, &QNetworkReply::finished, this, &UpnpEventSubscriber::eventingFinished); 0174 0175 d->mSentBuffer = requestBody; 0176 d->mSentBuffer->seek(0); 0177 qCDebug(orgKdeUpnpLibQtUpnp()) << "UpnpEventSubscriber::notifyPropertyChange" << d->mSentBuffer->data(); 0178 } 0179 0180 void UpnpEventSubscriber::eventingFinished() 0181 { 0182 d->mSentBuffer.clear(); 0183 } 0184 0185 void UpnpEventSubscriber::eventingInErrorFinished(QNetworkReply::NetworkError code) 0186 { 0187 Q_UNUSED(code) 0188 0189 d->mSentBuffer.clear(); 0190 } 0191 0192 #include "moc_upnpeventsubscriber.cpp"