2
* Copyright (C) 2010, 2011 Tuomo Penttinen, all rights reserved.
4
* Author: Tuomo Penttinen <tp@herqq.org>
6
* This file is part of Herqq UPnP (HUPnP) library.
8
* Herqq UPnP is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU Lesser General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
13
* Herqq UPnP is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with Herqq UPnP. If not, see <http://www.gnu.org/licenses/>.
22
#include "hevent_messages_p.h"
24
#include "../../general/hlogger_p.h"
26
#include <QtXml/QDomDocument>
28
#include <QtCore/QRegExp>
29
#include <QtCore/QStringList>
31
#include <QtNetwork/QHostAddress>
39
/*******************************************************************************
41
*******************************************************************************/
44
inline bool isValidCallback(const QUrl& callback)
46
return callback.isValid() && !callback.isEmpty() &&
47
callback.scheme() == "http" && !(QHostAddress(callback.host()).isNull());
50
inline bool isValidEventUrl(const QUrl& eventUrl)
52
return eventUrl.isValid() && !eventUrl.isEmpty() &&
53
!(QHostAddress(eventUrl.host()).isNull());
57
HSubscribeRequest::HSubscribeRequest() :
58
m_callbacks(), m_timeout(), m_sid(), m_eventUrl(), m_userAgent()
62
HSubscribeRequest::HSubscribeRequest(
63
const QUrl& eventUrl, const HSid& sid, const HTimeout& timeout) :
64
m_callbacks(), m_timeout(), m_sid(), m_eventUrl(), m_userAgent()
68
if (!isValidEventUrl(eventUrl))
70
HLOG_WARN(QString("Invalid eventURL: [%1]").arg(eventUrl.toString()));
73
else if (sid.isEmpty())
75
HLOG_WARN("Empty SID");
80
m_eventUrl = eventUrl;
84
HSubscribeRequest::HSubscribeRequest(
85
const QUrl& eventUrl, const HProductTokens& userAgent, const QUrl& callback,
86
const HTimeout& timeout) :
87
m_callbacks (), m_timeout(), m_sid(), m_eventUrl(), m_userAgent()
91
if (!isValidEventUrl(eventUrl))
93
HLOG_WARN(QString("Invalid eventURL: [%1]").arg(eventUrl.toString()));
96
else if (!isValidCallback(callback))
98
HLOG_WARN(QString("Invalid callback: [%1]").arg(callback.toString()));
102
m_callbacks.push_back(callback);
105
m_eventUrl = eventUrl;
106
m_userAgent = userAgent;
109
HSubscribeRequest::HSubscribeRequest(
110
const QUrl& eventUrl, const HProductTokens& userAgent,
111
const QList<QUrl>& callbacks, const HTimeout& timeout) :
112
m_callbacks(), m_timeout(), m_sid(), m_eventUrl(), m_userAgent()
116
if (!isValidEventUrl(eventUrl))
118
HLOG_WARN(QString("Invalid eventURL: [%1]").arg(eventUrl.toString()));
122
foreach(const QUrl& callback, callbacks)
124
if (!isValidCallback(callback))
126
HLOG_WARN(QString("Invalid callback: [%1]").arg(callback.toString()));
132
m_eventUrl = eventUrl;
133
m_userAgent = userAgent;
134
m_callbacks = callbacks;
137
HSubscribeRequest::~HSubscribeRequest()
143
QList<QUrl> parseCallbacks(const QString& arg)
147
QStringList callbacks =
148
arg.split(QRegExp("<[.]*>"), QString::SkipEmptyParts);
150
foreach(QString callbackStr, callbacks)
152
QUrl callback(callbackStr.remove('<').remove('>'));
153
if (!callback.isValid() || callback.isEmpty() || callback.scheme() != "http")
155
return QList<QUrl>();
158
retVal.push_back(callback);
165
HSubscribeRequest::RetVal HSubscribeRequest::setContents(
166
const QString& nt, const QUrl& eventUrl, const QString& sid,
167
const QString& callback, const QString& timeout, const QString& userAgent)
171
// this has to be properly defined no matter what
172
if (!isValidEventUrl(eventUrl))
174
HLOG_WARN(QString("Invalid eventURL: [%1]").arg(eventUrl.toString()));
178
HSubscribeRequest tmp;
180
// these fields are the same regardless of message type
181
tmp.m_eventUrl = eventUrl;
182
tmp.m_timeout = timeout;
184
if (!HSid(sid).isEmpty())
186
// this appears to be a renewal, confirm.
187
if (!callback.isEmpty() || !nt.isEmpty())
189
return IncompatibleHeaders;
198
// this appears to be an initial subscription
200
if (nt.simplified().compare("upnp:event", Qt::CaseInsensitive) != 0)
202
return PreConditionFailed;
205
tmp.m_callbacks = parseCallbacks(callback);
206
if (tmp.m_callbacks.isEmpty())
208
return PreConditionFailed;
211
tmp.m_userAgent = HProductTokens(userAgent);
217
/*******************************************************************************
219
*******************************************************************************/
220
HSubscribeResponse::HSubscribeResponse() :
221
m_sid(), m_timeout(), m_server(), m_responseGenerated()
225
HSubscribeResponse::HSubscribeResponse(
226
const HSid& sid, const HProductTokens& server, const HTimeout& timeout,
227
const QDateTime& responseGenerated) :
228
m_sid(sid), m_timeout(timeout), m_server(server),
229
m_responseGenerated(responseGenerated)
233
*this = HSubscribeResponse();
237
HSubscribeResponse::~HSubscribeResponse()
241
/*******************************************************************************
242
* HUnsubscribeRequest
243
*******************************************************************************/
244
HUnsubscribeRequest::HUnsubscribeRequest() :
245
m_eventUrl(), m_sid()
249
HUnsubscribeRequest::HUnsubscribeRequest(const QUrl& eventUrl, const HSid& sid) :
250
m_eventUrl(), m_sid()
252
if (sid.isEmpty() || !isValidEventUrl(eventUrl))
257
m_eventUrl = eventUrl;
261
HUnsubscribeRequest::~HUnsubscribeRequest()
265
HUnsubscribeRequest::RetVal HUnsubscribeRequest::setContents(
266
const QUrl& eventUrl, const QString& sid)
268
HUnsubscribeRequest tmp;
271
tmp.m_eventUrl = eventUrl;
273
if (tmp.m_sid.isEmpty())
275
return PreConditionFailed;
277
else if (!isValidEventUrl(tmp.m_eventUrl))
286
/*******************************************************************************
288
*******************************************************************************/
291
HNotifyRequest::RetVal parseData(
292
const QByteArray& data, QList<QPair<QString, QString> >& parsedData)
297
if (!dd.setContent(data, true))
299
return HNotifyRequest::InvalidContents;
302
//QDomNodeList propertySetNodes =
303
// dd.elementsByTagNameNS("urn:schemas-upnp.org:event-1-0", "propertyset");
305
QDomElement propertySetElement = dd.firstChildElement("propertyset");
307
if (propertySetElement.isNull())
309
return HNotifyRequest::InvalidContents;
312
QDomElement propertyElement =
313
propertySetElement.firstChildElement("property");
314
//propertySetNodes.at(0).toElement().elementsByTagNameNS(
315
// "urn:schemas-upnp.org:event-1-0", "property");
317
QList<QPair<QString, QString> > tmp;
318
while(!propertyElement.isNull())
320
QDomElement variableElement = propertyElement.firstChildElement();
321
if (variableElement.isNull())
323
return HNotifyRequest::InvalidContents;
326
QDomText variableValue = variableElement.firstChild().toText();
328
qMakePair(variableElement.localName(), variableValue.data()));
330
propertyElement = propertyElement.nextSiblingElement("property");
334
return HNotifyRequest::Success;
338
HNotifyRequest::HNotifyRequest() :
339
m_callback(), m_sid(), m_seq(0), m_dataAsVariables(), m_data()
343
HNotifyRequest::HNotifyRequest(
344
const QUrl& callback, const HSid& sid,
345
quint32 seq, const QByteArray& contents) :
346
m_callback(), m_sid(), m_seq(0), m_dataAsVariables(),
351
if (!isValidCallback(callback) || sid.isEmpty() || contents.isEmpty())
356
if (parseData(contents, m_dataAsVariables) != Success)
361
m_callback = callback;
367
HNotifyRequest::~HNotifyRequest()
371
HNotifyRequest::RetVal HNotifyRequest::setContents(
372
const QUrl& callback,
373
const QString& nt, const QString& nts, const QString& sid,
374
const QString& seq, const QString& contents)
379
if (tmpNt.type () != HNt::Type_UpnpEvent ||
380
tmpNt.subType() != HNt::SubType_UpnpPropChange)
382
return PreConditionFailed;
387
tmp.m_callback = callback;
388
if (!isValidCallback(tmp.m_callback))
394
if (tmp.m_sid.isEmpty())
396
return PreConditionFailed;
399
QString tmpSeq = seq.trimmed();
402
tmp.m_seq = tmpSeq.toUInt(&ok);
405
return InvalidSequenceNr;
408
tmp.m_data = contents.toUtf8();
410
RetVal rv = parseData(tmp.m_data, tmp.m_dataAsVariables);