diff options
author | Javier S. Pedro <maemo@javispedro.com> | 2013-04-01 15:04:58 +0200 |
---|---|---|
committer | Javier S. Pedro <maemo@javispedro.com> | 2013-04-01 15:04:58 +0200 |
commit | 5ef8b38e55c1883224fe1f01f47aba45b7b42666 (patch) | |
tree | 67a873c6a7c5263d202793314c3b3a61543fbb40 /xmlrpcpendingcall.cpp | |
download | tapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.tar.gz tapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.zip |
initial import
Diffstat (limited to 'xmlrpcpendingcall.cpp')
-rw-r--r-- | xmlrpcpendingcall.cpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/xmlrpcpendingcall.cpp b/xmlrpcpendingcall.cpp new file mode 100644 index 0000000..d94b76d --- /dev/null +++ b/xmlrpcpendingcall.cpp @@ -0,0 +1,187 @@ +#include <QtCore/QDateTime> +#include <QtCore/QEventLoop> +#include <QtCore/QDebug> + +#include "xmlrpcinterface.h" +#include "xmlrpcpendingcall.h" + +XmlRpcPendingCall::XmlRpcPendingCall(QNetworkReply *reply, XmlRpcInterface *parent) + : QObject(parent), _reply(reply), _state(StateWaitingReply) +{ + connect(_reply, SIGNAL(finished()), SLOT(handleRequestFinished())); + _reply->setParent(this); +} + +void XmlRpcPendingCall::waitForFinished() +{ + if (_state == StateWaitingReply) { + QEventLoop loop; + connect(this, SIGNAL(finished(XmlRpcPendingCall*)), &loop, SLOT(quit())); + loop.exec(); + } +} + +bool XmlRpcPendingCall::decodeMethodResponse(QXmlStreamReader *r) +{ + if (r->readNextStartElement()) { + if (r->name() == "fault") { + _state = StateFaultReceived; + if (r->readNextStartElement()) { + if (r->name() != "value") return false; + _value = decodeValue(r); + if (!_value.isValid()) return false; + } + return true; + } else if (r->name() == "params") { + _state = StateReplyReceived; + if (r->readNextStartElement()) { + if (r->name() != "param") return false; + if (r->readNextStartElement()) { + if (r->name() != "value") return false; + _value = decodeValue(r); + if (!_value.isValid()) return false; + } else { + return false; + } + } + return true; + } + } + + return false; +} + +QVariant XmlRpcPendingCall::decodeValue(QXmlStreamReader *r) +{ + Q_ASSERT(r->isStartElement() && r->name() == "value"); + QVariant value; + + if (r->readNextStartElement()) { + if (r->name() == "string") { + value = QVariant::fromValue(r->readElementText()); + } else if (r->name() == "int") { + bool ok; + value = QVariant::fromValue(r->readElementText().toInt(&ok)); + if (!ok) value.clear(); + } else if (r->name() == "boolean") { + bool ok; + value = QVariant::fromValue<bool>(r->readElementText().toInt(&ok)); + if (!ok) value.clear(); + } else if (r->name() == "double") { + bool ok; + value = QVariant::fromValue(r->readElementText().toDouble(&ok)); + if (!ok) value.clear(); + } else if (r->name() == "dateTime.iso8601") { + QString text = r->readElementText(); + QDateTime dateTime = QDateTime::fromString(text, Qt::ISODate); + if (!dateTime.isValid()) { + // Qt seems not be happy without dashes + text.insert(4, '-'); + text.insert(7, '-'); + dateTime = QDateTime::fromString(text, Qt::ISODate); + if (!dateTime.isValid()) { + qWarning() << "Invalid dateTime format" << text; + return QVariant(); + } + } + value = QVariant::fromValue(dateTime); + } else if (r->name() == "base64") { + QByteArray data = r->readElementText().toAscii(); + value = QVariant::fromValue(QByteArray::fromBase64(data)); + } else if (r->name() == "array") { + QList<QVariant> list; + if (!r->readNextStartElement() || r->name() != "data") { + qWarning() << "Unexpected element inside <array>:" << r->name(); + return QVariant(); + } + while (r->readNextStartElement()) { + if (r->name() != "value") return QVariant(); + QVariant value = decodeValue(r); + if (!value.isValid()) return QVariant(); + list.append(value); + } + if (r->readNextStartElement()) { + // No other elements + qWarning() << "Unexpected element inside <array>:" << r->name(); + return QVariant(); + } + value = QVariant::fromValue(list); + } else if (r->name() == "struct") { + QMap<QString, QVariant> map; + while (r->readNextStartElement()) { + if (r->name() != "member") return QVariant(); + QString name; + if (r->readNextStartElement() && r->name() == "name") { + name = r->readElementText(); + } else { + qWarning() << "Malformed struct"; + return QVariant(); + } + if (r->readNextStartElement() && r->name() == "value") { + QVariant value = decodeValue(r); + if (!value.isValid()) return QVariant(); + map.insert(name, value); + } else { + qWarning() << "Malformed struct"; + return QVariant(); + } + if (r->readNextStartElement()) { + // No other elements + qWarning() << "Unexpected element inside <member>" << r->name(); + return false; + } + } + value = QVariant::fromValue(map); + } else { + qWarning() << "Unknown value type:" << r->name(); + } + } + + if (r->readNextStartElement()) { + // There is more than one element inside this <value> + qWarning() << "More than element inside <value>"; + return QVariant(); + } else if (r->isEndElement() && r->name() == "value") { + // Everything OK + return value; + } else { + qWarning() << "Expected </value> instead of" << r->name(); + return QVariant(); + } +} + +void XmlRpcPendingCall::handleRequestFinished() +{ + Q_ASSERT(_state == StateWaitingReply); + + QNetworkReply::NetworkError error = _reply->error(); + if (error == QNetworkReply::NoError) { + QByteArray data = _reply->readAll(); + QXmlStreamReader reader(data); + bool parse_ok = false; + if (reader.readNextStartElement()) { + if (reader.name() == "methodResponse") { + parse_ok = decodeMethodResponse(&reader); + } + } + if (parse_ok) { + Q_ASSERT(_state == StateReplyReceived || _state == StateFaultReceived); + } else { + qWarning() << "Parse error!"; + QVariantMap obj; + obj.insert("code", QVariant(reader.error())); + obj.insert("message", QVariant(reader.errorString())); + _value = obj; + _state = StateParseError; + } + } else { + qWarning() << "Network error!" << error; + QVariantMap obj; + obj.insert("code", QVariant(error)); + obj.insert("message", QVariant(_reply->errorString())); + _value = obj; + _state = StateNetworkError; + } + + emit finished(this); +} |