summaryrefslogtreecommitdiff
path: root/xmlrpcpendingcall.cpp
diff options
context:
space:
mode:
authorJavier S. Pedro <maemo@javispedro.com>2013-04-01 15:04:58 +0200
committerJavier S. Pedro <maemo@javispedro.com>2013-04-01 15:04:58 +0200
commit5ef8b38e55c1883224fe1f01f47aba45b7b42666 (patch)
tree67a873c6a7c5263d202793314c3b3a61543fbb40 /xmlrpcpendingcall.cpp
downloadtapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.tar.gz
tapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.zip
initial import
Diffstat (limited to 'xmlrpcpendingcall.cpp')
-rw-r--r--xmlrpcpendingcall.cpp187
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);
+}