/* * Copyright (C) 2008-2012 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * http://code.google.com/p/qxmpp * * This file is a part of QXmpp library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * */ #include #include #include #include #include #include "QXmppConstants.h" #include "QXmppRpcIq.h" #include "QXmppUtils.h" void QXmppRpcMarshaller::marshall(QXmlStreamWriter *writer, const QVariant &value) { writer->writeStartElement("value"); switch( value.type() ) { case QVariant::Int: case QVariant::UInt: case QVariant::LongLong: case QVariant::ULongLong: writer->writeTextElement("i4", value.toString()); break; case QVariant::Double: writer->writeTextElement("double", value.toString()); break; case QVariant::Bool: writer->writeTextElement("boolean", value.toBool() ? "1" : "0"); break; case QVariant::Date: writer->writeTextElement("dateTime.iso8601", value.toDate().toString( Qt::ISODate ) ); break; case QVariant::DateTime: writer->writeTextElement("dateTime.iso8601", value.toDateTime().toString( Qt::ISODate ) ); break; case QVariant::Time: writer->writeTextElement("dateTime.iso8601", value.toTime().toString( Qt::ISODate ) ); break; case QVariant::StringList: case QVariant::List: { writer->writeStartElement("array"); writer->writeStartElement("data"); foreach(const QVariant &item, value.toList()) marshall(writer, item); writer->writeEndElement(); writer->writeEndElement(); break; } case QVariant::Map: { writer->writeStartElement("struct"); QMap map = value.toMap(); QMap::ConstIterator index = map.begin(); while( index != map.end() ) { writer->writeStartElement("member"); writer->writeTextElement("name", index.key()); marshall( writer, *index ); writer->writeEndElement(); ++index; } writer->writeEndElement(); break; } case QVariant::ByteArray: { writer->writeTextElement("base64", value.toByteArray().toBase64() ); break; } default: { if (value.isNull()) writer->writeEmptyElement("nil"); else if( value.canConvert(QVariant::String) ) { writer->writeTextElement("string", value.toString() ); } break; } } writer->writeEndElement(); } QVariant QXmppRpcMarshaller::demarshall(const QDomElement &elem, QStringList &errors) { if ( elem.tagName().toLower() != "value" ) { errors << "Bad param value"; return QVariant(); } if ( !elem.firstChild().isElement() ) { return QVariant( elem.text() ); } const QDomElement typeData = elem.firstChild().toElement(); const QString typeName = typeData.tagName().toLower(); if (typeName == "nil") { return QVariant(); } if ( typeName == "string" ) { return QVariant( typeData.text() ); } else if (typeName == "int" || typeName == "i4" ) { bool ok = false; QVariant val( typeData.text().toInt( &ok ) ); if (ok) return val; errors << "I was looking for an integer but data was courupt"; return QVariant(); } else if( typeName == "double" ) { bool ok = false; QVariant val( typeData.text().toDouble( &ok ) ); if (ok) return val; errors << "I was looking for an double but data was corrupt"; } else if( typeName == "boolean" ) return QVariant( typeData.text() == "1" || typeData.text().toLower() == "true" ); else if( typeName == "datetime" || typeName == "datetime.iso8601" ) return QVariant( QDateTime::fromString( typeData.text(), Qt::ISODate ) ); else if( typeName == "array" ) { QVariantList arr; QDomElement valueNode = typeData.firstChildElement("data").firstChildElement(); while (!valueNode.isNull() && errors.isEmpty()) { arr.append(demarshall(valueNode, errors)); valueNode = valueNode.nextSiblingElement(); } return QVariant( arr ); } else if( typeName == "struct" ) { QMap stct; QDomNode valueNode = typeData.firstChild(); while(!valueNode.isNull() && errors.isEmpty()) { const QDomElement memberNode = valueNode.toElement().elementsByTagName("name").item(0).toElement(); const QDomElement dataNode = valueNode.toElement().elementsByTagName("value").item(0).toElement(); stct[ memberNode.text() ] = demarshall(dataNode, errors); valueNode = valueNode.nextSibling(); } return QVariant(stct); } else if( typeName == "base64" ) { QVariant returnVariant; QByteArray dest; QByteArray src = typeData.text().toLatin1(); return QVariant(QByteArray::fromBase64(src)); } errors << QString( "Cannot handle type %1").arg(typeName); return QVariant(); } QXmppRpcErrorIq::QXmppRpcErrorIq() : QXmppIq( QXmppIq::Error ) { } QXmppRpcInvokeIq QXmppRpcErrorIq::query() const { return m_query; } void QXmppRpcErrorIq::setQuery(const QXmppRpcInvokeIq &query) { m_query = query; } /// \cond bool QXmppRpcErrorIq::isRpcErrorIq(const QDomElement &element) { QString type = element.attribute("type"); QDomElement errorElement = element.firstChildElement("error"); QDomElement queryElement = element.firstChildElement("query"); return (type == "error") && !errorElement.isNull() && queryElement.namespaceURI() == ns_rpc; } void QXmppRpcErrorIq::parseElementFromChild(const QDomElement &element) { m_query.parseElementFromChild(element); } void QXmppRpcErrorIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { m_query.toXmlElementFromChild(writer); } /// \endcond QXmppRpcResponseIq::QXmppRpcResponseIq() : QXmppIq(QXmppIq::Result), m_faultCode(0) { } /// Returns the fault code. /// int QXmppRpcResponseIq::faultCode() const { return m_faultCode; } /// Sets the fault code. /// /// \param faultCode void QXmppRpcResponseIq::setFaultCode(int faultCode) { m_faultCode = faultCode; } /// Returns the fault string. /// QString QXmppRpcResponseIq::faultString() const { return m_faultString; } /// Sets the fault string. /// /// \param faultString void QXmppRpcResponseIq::setFaultString(const QString& faultString) { m_faultString = faultString; } /// Returns the response values. /// QVariantList QXmppRpcResponseIq::values() const { return m_values; } /// Sets the response values. /// /// \param values void QXmppRpcResponseIq::setValues(const QVariantList &values) { m_values = values; } /// \cond bool QXmppRpcResponseIq::isRpcResponseIq(const QDomElement &element) { QString type = element.attribute("type"); QDomElement dataElement = element.firstChildElement("query"); return dataElement.namespaceURI() == ns_rpc && type == "result"; } void QXmppRpcResponseIq::parseElementFromChild(const QDomElement &element) { QDomElement queryElement = element.firstChildElement("query"); QDomElement methodElement = queryElement.firstChildElement("methodResponse"); const QDomElement contents = methodElement.firstChildElement(); if( contents.tagName().toLower() == "params") { QDomNode param = contents.firstChildElement("param"); while (!param.isNull()) { QStringList errors; const QVariant value = QXmppRpcMarshaller::demarshall(param.firstChildElement("value"), errors); if (!errors.isEmpty()) break; m_values << value; param = param.nextSiblingElement("param"); } } else if( contents.tagName().toLower() == "fault") { QStringList errors; const QDomElement errElement = contents.firstChildElement("value"); const QVariant error = QXmppRpcMarshaller::demarshall(errElement, errors); if (!errors.isEmpty()) return; m_faultCode = error.toMap()["faultCode"].toInt(); m_faultString = error.toMap()["faultString"].toString(); } } void QXmppRpcResponseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("query"); writer->writeAttribute("xmlns", ns_rpc); writer->writeStartElement("methodResponse"); if (m_faultCode) { writer->writeStartElement("fault"); QMap fault; fault["faultCode"] = m_faultCode; fault["faultString"] = m_faultString; QXmppRpcMarshaller::marshall(writer, fault); writer->writeEndElement(); } else if (!m_values.isEmpty()) { writer->writeStartElement("params"); foreach (const QVariant &arg, m_values) { writer->writeStartElement("param"); QXmppRpcMarshaller::marshall(writer, arg); writer->writeEndElement(); } writer->writeEndElement(); } writer->writeEndElement(); writer->writeEndElement(); } /// \endcond QXmppRpcInvokeIq::QXmppRpcInvokeIq() : QXmppIq(QXmppIq::Set) { } /// Returns the method arguments. /// QVariantList QXmppRpcInvokeIq::arguments() const { return m_arguments; } /// Sets the method arguments. /// /// \param arguments void QXmppRpcInvokeIq::setArguments(const QVariantList &arguments) { m_arguments = arguments; } /// Returns the method name. /// QString QXmppRpcInvokeIq::method() const { return m_method; } /// Sets the method name. /// /// \param method void QXmppRpcInvokeIq::setMethod(const QString &method) { m_method = method; } /// \cond bool QXmppRpcInvokeIq::isRpcInvokeIq(const QDomElement &element) { QString type = element.attribute("type"); QDomElement dataElement = element.firstChildElement("query"); return dataElement.namespaceURI() == ns_rpc && type == "set"; } void QXmppRpcInvokeIq::parseElementFromChild(const QDomElement &element) { QDomElement queryElement = element.firstChildElement("query"); QDomElement methodElement = queryElement.firstChildElement("methodCall"); m_method = methodElement.firstChildElement("methodName").text(); const QDomElement methodParams = methodElement.firstChildElement("params"); m_arguments.clear(); if( !methodParams.isNull() ) { QDomNode param = methodParams.firstChildElement("param"); while (!param.isNull()) { QStringList errors; QVariant arg = QXmppRpcMarshaller::demarshall(param.firstChildElement("value"), errors); if (!errors.isEmpty()) break; m_arguments << arg; param = param.nextSiblingElement("param"); } } } void QXmppRpcInvokeIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("query"); writer->writeAttribute("xmlns", ns_rpc); writer->writeStartElement("methodCall"); writer->writeTextElement("methodName", m_method); if (!m_arguments.isEmpty()) { writer->writeStartElement("params"); foreach(const QVariant &arg, m_arguments) { writer->writeStartElement("param"); QXmppRpcMarshaller::marshall(writer, arg); writer->writeEndElement(); } writer->writeEndElement(); } writer->writeEndElement(); writer->writeEndElement(); } /// \endcond