diff options
Diffstat (limited to 'Swiften/Parser')
45 files changed, 682 insertions, 109 deletions
diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h new file mode 100644 index 0000000..f1f9a83 --- /dev/null +++ b/Swiften/Parser/Attribute.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> + +namespace Swift { + class Attribute { + public: + Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { + } + + const std::string& getName() const { + return name; + } + + const std::string& getNamespace() const { + return ns; + } + + bool operator==(const Attribute& o) const { + return o.name == name && o.ns == ns; + } + + private: + std::string name; + std::string ns; + }; +} diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp new file mode 100644 index 0000000..1aeaf99 --- /dev/null +++ b/Swiften/Parser/AttributeMap.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/AttributeMap.h> + +#include <algorithm> +#include <boost/optional.hpp> + +using namespace Swift; + +namespace { + struct AttributeIs { + AttributeIs(const Attribute& attribute) : attribute(attribute) { + } + + bool operator()(const AttributeMap::Entry& o) const { + return o.getAttribute() == attribute; + } + + Attribute attribute; + }; +} + +AttributeMap::AttributeMap() { +} + +std::string AttributeMap::getAttribute(const std::string& attribute, const std::string& ns) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ns))); + if (i == attributes.end()) { + return ""; + } + else { + return i->getValue(); + } +} + +bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + if (i == attributes.end()) { + return defaultValue; + } + else { + return i->getValue() == "true" || i->getValue() == "1"; + } +} + +boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& attribute) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + if (i == attributes.end()) { + return boost::optional<std::string>(); + } + else { + return i->getValue(); + } +} + +void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { + attributes.push_back(Entry(Attribute(name, ns), value)); +} diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index c8b287b..31df606 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -4,38 +4,50 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef ATTRIBUTEMAP_H -#define ATTRIBUTEMAP_H +#pragma once +#include <vector> +#include <string> #include <map> +#include <boost/optional/optional_fwd.hpp> -#include <string> +#include <Swiften/Parser/Attribute.h> namespace Swift { - class AttributeMap : public std::map<std::string,std::string> { + class AttributeMap { public: - AttributeMap() {} - - std::string getAttribute(const std::string& attribute) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return ""; - } - else { - return i->second; - } - } + class Entry { + public: + Entry(const Attribute& attribute, const std::string& value) : attribute(attribute), value(value) { + } + + const Attribute& getAttribute() const { + return attribute; + } + + const std::string& getValue() const { + return value; + } + + private: + Attribute attribute; + std::string value; + }; - bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return defaultValue; - } - else { - return i->second == "true" || i->second == "1"; - } + AttributeMap(); + + std::string getAttribute(const std::string& attribute, const std::string& ns = "") const; + bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const; + boost::optional<std::string> getAttributeValue(const std::string&) const; + + void addAttribute(const std::string& name, const std::string& ns, const std::string& value); + + const std::vector<Entry>& getEntries() const { + return attributes; } + + private: + typedef std::vector<Entry> AttributeValueMap; + AttributeValueMap attributes; }; } - -#endif diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 88be752..448b199 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -30,7 +30,7 @@ static void handleStartElement(void* client, const XML_Char* name, const XML_Cha nsAttributePair.second = nsAttributePair.first; nsAttributePair.first = ""; } - attributeValues[nsAttributePair.second] = std::string(*(currentAttribute+1)); + attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); currentAttribute += 2; } diff --git a/Swiften/Parser/IQParser.cpp b/Swiften/Parser/IQParser.cpp index e0883f2..62d775f 100644 --- a/Swiften/Parser/IQParser.cpp +++ b/Swiften/Parser/IQParser.cpp @@ -5,8 +5,9 @@ */ #include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/IQParser.h" +#include <Swiften/Parser/IQParser.h> namespace Swift { @@ -15,22 +16,22 @@ IQParser::IQParser(PayloadParserFactoryCollection* factories) : } void IQParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "set") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "set") { getStanzaGeneric()->setType(IQ::Set); } - else if (type->second == "get") { + else if (*type == "get") { getStanzaGeneric()->setType(IQ::Get); } - else if (type->second == "result") { + else if (*type == "result") { getStanzaGeneric()->setType(IQ::Result); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(IQ::Error); } else { - std::cerr << "Unknown IQ type: " << type->second << std::endl; + std::cerr << "Unknown IQ type: " << *type << std::endl; getStanzaGeneric()->setType(IQ::Get); } } diff --git a/Swiften/Parser/IQParser.h b/Swiften/Parser/IQParser.h index e104dc4..35ab132 100644 --- a/Swiften/Parser/IQParser.h +++ b/Swiften/Parser/IQParser.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQParser_H -#define SWIFTEN_IQParser_H +#pragma once #include "Swiften/Parser/GenericStanzaParser.h" #include "Swiften/Elements/IQ.h" @@ -19,5 +18,3 @@ namespace Swift { virtual void handleStanzaAttributes(const AttributeMap&); }; } - -#endif diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index 34db4ca..0b15848 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -15,10 +15,18 @@ namespace Swift { -static void handleStartElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int, const xmlChar ** attributes) { +static void handleStartElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { AttributeMap attributeValues; + if (nbDefaulted != 0) { + // Just because i don't understand what this means yet :-) + std::cerr << "Unexpected nbDefaulted on XML element" << std::endl; + } for (int i = 0; i < nbAttributes*5; i += 5) { - attributeValues[std::string(reinterpret_cast<const char*>(attributes[i]))] = std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3]); + std::string attributeNS = ""; + if (attributes[i+2]) { + attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); + } + attributeValues.addAttribute(std::string(reinterpret_cast<const char*>(attributes[i])), attributeNS, std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3])); } static_cast<XMLParserClient*>(client)->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); } diff --git a/Swiften/Parser/MessageParser.cpp b/Swiften/Parser/MessageParser.cpp index 5f4d59c..7f5e6d4 100644 --- a/Swiften/Parser/MessageParser.cpp +++ b/Swiften/Parser/MessageParser.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/MessageParser.h" +#include <Swiften/Parser/MessageParser.h> namespace Swift { @@ -16,18 +16,18 @@ MessageParser::MessageParser(PayloadParserFactoryCollection* factories) : } void MessageParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "chat") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "chat") { getStanzaGeneric()->setType(Message::Chat); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Message::Error); } - else if (type->second == "groupchat") { + else if (*type == "groupchat") { getStanzaGeneric()->setType(Message::Groupchat); } - else if (type->second == "headline") { + else if (*type == "headline") { getStanzaGeneric()->setType(Message::Headline); } else { diff --git a/Swiften/Parser/PayloadParser.h b/Swiften/Parser/PayloadParser.h index 423a2bb..3dc04df 100644 --- a/Swiften/Parser/PayloadParser.h +++ b/Swiften/Parser/PayloadParser.h @@ -44,6 +44,6 @@ namespace Swift { /** * Retrieve a pointer to the payload. */ - virtual Payload::ref getPayload() const = 0; + virtual boost::shared_ptr<Payload> getPayload() const = 0; }; } diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp index 35db9ec..3de11ac 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -27,7 +27,7 @@ void BytestreamsParser::handleStartElement(const std::string& element, const std try { getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "streamhost-used") { diff --git a/Swiften/Parser/PayloadParsers/DelayParser.cpp b/Swiften/Parser/PayloadParsers/DelayParser.cpp index 3425b84..0ab2d7b 100644 --- a/Swiften/Parser/PayloadParsers/DelayParser.cpp +++ b/Swiften/Parser/PayloadParsers/DelayParser.cpp @@ -9,6 +9,7 @@ #include <locale> #include <boost/date_time/time_facet.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp b/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp index 19d0530..48841d2 100644 --- a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp +++ b/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp @@ -6,6 +6,7 @@ #include <Swiften/Parser/PayloadParsers/DelayParserFactory.h> +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/time_facet.hpp> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp index e1fcb20..2e9e87a 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp @@ -15,7 +15,7 @@ DiscoInfoParser::DiscoInfoParser() : level_(TopLevel), formParser_(NULL) { void DiscoInfoParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (level_ == PayloadLevel) { if (element == "identity") { - getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang"))); + getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"))); } else if (element == "feature") { getPayloadInternal()->addFeature(attributes.getAttribute("var")); diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp index f8e02a4..72449b8 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.cpp +++ b/Swiften/Parser/PayloadParsers/FormParser.cpp @@ -63,12 +63,9 @@ void FormParser::handleStartElement(const std::string& element, const std::strin else if (type == "text-private") { currentFieldParseHelper_ = TextPrivateFormFieldParseHelper::create(); } - else if (type == "text-single") { + else /*if (type == "text-single") || undefined */ { currentFieldParseHelper_ = TextSingleFormFieldParseHelper::create(); } - else { - currentFieldParseHelper_ = UntypedFormFieldParseHelper::create(); - } if (currentFieldParseHelper_) { currentFieldParseHelper_->getField()->setName(attributes.getAttribute("var")); currentFieldParseHelper_->getField()->setLabel(attributes.getAttribute("label")); diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h index 90a3550..e6e6ec0 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.h +++ b/Swiften/Parser/PayloadParsers/FormParser.h @@ -96,7 +96,6 @@ namespace Swift { SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDSingle, JID); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDMulti, JIDList); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListMulti, StringList); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Untyped, StringList); enum Level { TopLevel = 0, diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index e20c06d..55deafc 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -17,6 +17,7 @@ #include "Swiften/Parser/PayloadParsers/StartSessionParser.h" #include "Swiften/Parser/PayloadParsers/StatusParser.h" #include "Swiften/Parser/PayloadParsers/StatusShowParser.h" +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" #include "Swiften/Parser/PayloadParsers/RosterParser.h" #include "Swiften/Parser/PayloadParsers/SoftwareVersionParser.h" #include "Swiften/Parser/PayloadParsers/StorageParser.h" @@ -39,6 +40,7 @@ #include "Swiften/Parser/PayloadParsers/DelayParserFactory.h" #include "Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h" #include "Swiften/Parser/PayloadParsers/NicknameParserFactory.h" +#include "Swiften/Parser/PayloadParsers/ReplaceParser.h" using namespace boost; @@ -48,12 +50,14 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<IBBParser>("", "http://jabber.org/protocol/ibb"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusShowParser>("show"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusParser>("status"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ReplaceParser>("replace", "http://swift.im/protocol/replace"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BodyParser>("body"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SubjectParser>("subject"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<PriorityParser>("priority"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ErrorParser>("error"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SoftwareVersionParser>("query", "jabber:iq:version"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StorageParser>("storage", "storage:bookmarks"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterItemExchangeParser>("x", "http://jabber.org/protocol/rosterx"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterParser>("query", "jabber:iq:roster"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoInfoParser>("query", "http://jabber.org/protocol/disco#info"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoItemsParser>("query", "http://jabber.org/protocol/disco#items"))); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp index f36dc43..8196295 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.cpp +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -27,7 +27,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setSequenceNumber(boost::lexical_cast<int>(attributes.getAttribute("seq"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "open") { @@ -42,7 +42,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "close") { @@ -64,7 +64,7 @@ void IBBParser::handleEndElement(const std::string& element, const std::string&) data.push_back(c); } } - getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size()))); + getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size())).getDataVector()); } } } diff --git a/Swiften/Parser/PayloadParsers/PriorityParser.cpp b/Swiften/Parser/PayloadParsers/PriorityParser.cpp index bcbf67f..553a2b1 100644 --- a/Swiften/Parser/PayloadParsers/PriorityParser.cpp +++ b/Swiften/Parser/PayloadParsers/PriorityParser.cpp @@ -24,7 +24,7 @@ void PriorityParser::handleEndElement(const std::string&, const std::string&) { try { priority = boost::lexical_cast<int>(text_); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } getPayloadInternal()->setPriority(priority); } diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.cpp b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp new file mode 100644 index 0000000..8e5659f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/ReplaceParser.h" + +namespace Swift { + + ReplaceParser::ReplaceParser() : level_(0) { + } + + void ReplaceParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == 0) { + std::string id = attributes.getAttribute("id"); + getPayloadInternal()->setId(id); + } + level_++; + } + + void ReplaceParser::handleEndElement(const std::string&, const std::string&) { + --level_; + } + + void ReplaceParser::handleCharacterData(const std::string&) { + } + +} diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.h b/Swiften/Parser/PayloadParsers/ReplaceParser.h new file mode 100644 index 0000000..0789927 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Elements/Replace.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class ReplaceParser : public GenericPayloadParser<Replace> { + public: + ReplaceParser(); + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp new file mode 100644 index 0000000..ff2a73b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" +#include "Swiften/Parser/SerializingParser.h" + +namespace Swift { + +RosterItemExchangeParser::RosterItemExchangeParser() : level_(TopLevel), inItem_(false) { +} + +void RosterItemExchangeParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "item") { + inItem_ = true; + + currentItem_ = RosterItemExchangePayload::Item(); + + currentItem_.setJID(JID(attributes.getAttribute("jid"))); + currentItem_.setName(attributes.getAttribute("name")); + + std::string action = attributes.getAttribute("action"); + if (action == "add") { + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + else if (action == "modify") { + currentItem_.setAction(RosterItemExchangePayload::Item::Modify); + } + else if (action == "delete") { + currentItem_.setAction(RosterItemExchangePayload::Item::Delete); + } + else { + // Add is default action according to XEP + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentText_ = ""; + } + } + ++level_; +} + +void RosterItemExchangeParser::handleEndElement(const std::string& element, const std::string& /*ns*/) { + --level_; + if (level_ == PayloadLevel) { + if (inItem_) { + getPayloadInternal()->addItem(currentItem_); + inItem_ = false; + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentItem_.addGroup(currentText_); + } + } +} + +void RosterItemExchangeParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} + +} diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h new file mode 100644 index 0000000..3d6b8f4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class SerializingParser; + + class RosterItemExchangeParser : public GenericPayloadParser<RosterItemExchangePayload> { + public: + RosterItemExchangeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + ItemLevel = 2 + }; + int level_; + bool inItem_; + RosterItemExchangePayload::Item currentItem_; + std::string currentText_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RosterParser.cpp b/Swiften/Parser/PayloadParsers/RosterParser.cpp index ba19fbf..5fba30b 100644 --- a/Swiften/Parser/PayloadParsers/RosterParser.cpp +++ b/Swiften/Parser/PayloadParsers/RosterParser.cpp @@ -5,6 +5,9 @@ */ #include "Swiften/Parser/PayloadParsers/RosterParser.h" + +#include <boost/optional.hpp> + #include "Swiften/Parser/SerializingParser.h" namespace Swift { @@ -13,7 +16,13 @@ RosterParser::RosterParser() : level_(TopLevel), inItem_(false), unknownContentP } void RosterParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - if (level_ == PayloadLevel) { + if (level_ == TopLevel) { + boost::optional<std::string> ver = attributes.getAttributeValue("ver"); + if (ver) { + getPayloadInternal()->setVersion(*ver); + } + } + else if (level_ == PayloadLevel) { if (element == "item") { inItem_ = true; currentItem_ = RosterItemPayload(); diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp index 1cf7fcf..0d4a407 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp @@ -42,7 +42,7 @@ void StreamInitiationParser::handleStartElement(const std::string& element, cons try { currentFile.size = boost::lexical_cast<int>(attributes.getAttribute("size")); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "feature" && ns == FEATURE_NEG_NS) { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp index 6ec825b..7feada1 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp @@ -77,7 +77,6 @@ class FormParserTest : public CppUnit::TestFixture { "</field>" "<field var=\"untyped\">" "<value>foo</value>" - "<value>baz</value>" "</field>" "</x>")); @@ -114,8 +113,7 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[1]); CPPUNIT_ASSERT_EQUAL(std::string("Tell all your friends about your new bot!"), payload->getFields()[8]->getDescription()); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<UntypedFormField>(payload->getFields()[9])->getValue()[0]); - CPPUNIT_ASSERT_EQUAL(std::string("baz"), boost::dynamic_pointer_cast<UntypedFormField>(payload->getFields()[9])->getValue()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<TextSingleFormField>(payload->getFields()[9])->getValue()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp index b4229f2..2fc3e79 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp @@ -32,7 +32,7 @@ class IBBParserTest : public CppUnit::TestFixture { IBB::ref ibb = parser.getPayload<IBB>(); CPPUNIT_ASSERT(ibb->getAction() == IBB::Data); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a"), ibb->getData()); + CPPUNIT_ASSERT(ByteArray::create("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(4, ibb->getSequenceNumber()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp index 68a2e4f..e2b8be2 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp @@ -24,7 +24,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>-120</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(-120, payload->getPriority()); } @@ -33,7 +33,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>invalid</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(0, payload->getPriority()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp new file mode 100644 index 0000000..7c34eb1 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Parser/PayloadParsers/ReplaceParser.h" +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" + +using namespace Swift; + +class ReplaceParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ReplaceParserTest); + CPPUNIT_TEST(testParseTrivial); + CPPUNIT_TEST(testParseChild); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParseTrivial() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace'/>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getId()); + } + void testParseChild() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace' ><child xmlns='blah' id=\"hi\"/></replace>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getId()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ReplaceParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp new file mode 100644 index 0000000..9533e15 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" + +using namespace Swift; + +class RosterItemExchangeParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>")); + + RosterItemExchangePayload* payload = dynamic_cast<RosterItemExchangePayload*>(parser.getPayload().get()); + const RosterItemExchangePayload::RosterItemExchangePayloadItems& items = payload->getItems(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), items[0].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Foo @ Bar"), items[0].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Add, items[0].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items[0].getGroups().size()); + CPPUNIT_ASSERT_EQUAL(std::string("Group 1"), items[0].getGroups()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Group 2"), items[0].getGroups()[1]); + + CPPUNIT_ASSERT_EQUAL(JID("baz@blo.com"), items[1].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Baz"), items[1].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Modify, items[1].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), items[1].getGroups().size()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp index 1bcea0e..3102b74 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp @@ -17,6 +17,8 @@ class RosterParserTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(RosterParserTest); CPPUNIT_TEST(testParse); CPPUNIT_TEST(testParse_ItemWithUnknownContent); + CPPUNIT_TEST(testParse_WithVersion); + CPPUNIT_TEST(testParse_WithEmptyVersion); CPPUNIT_TEST_SUITE_END(); public: @@ -32,6 +34,8 @@ class RosterParserTest : public CppUnit::TestFixture "</query>")); RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + + CPPUNIT_ASSERT(!payload->getVersion()); const RosterPayload::RosterItemPayloads& items = payload->getItems(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); @@ -74,6 +78,24 @@ class RosterParserTest : public CppUnit::TestFixture "<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>" ), items[0].getUnknownContent()); } + + void testParse_WithVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver='ver10'/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("ver10"), *payload->getVersion()); + } + + void testParse_WithEmptyVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver=''/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *payload->getVersion()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterParserTest); diff --git a/Swiften/Parser/PresenceParser.cpp b/Swiften/Parser/PresenceParser.cpp index 845ccf0..867155f 100644 --- a/Swiften/Parser/PresenceParser.cpp +++ b/Swiften/Parser/PresenceParser.cpp @@ -5,6 +5,7 @@ */ #include <iostream> +#include <boost/optional.hpp> #include "Swiften/Parser/PresenceParser.h" @@ -15,31 +16,31 @@ PresenceParser::PresenceParser(PayloadParserFactoryCollection* factories) : } void PresenceParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "unavailable") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "unavailable") { getStanzaGeneric()->setType(Presence::Unavailable); } - else if (type->second == "probe") { + else if (*type == "probe") { getStanzaGeneric()->setType(Presence::Probe); } - else if (type->second == "subscribe") { + else if (*type == "subscribe") { getStanzaGeneric()->setType(Presence::Subscribe); } - else if (type->second == "subscribed") { + else if (*type == "subscribed") { getStanzaGeneric()->setType(Presence::Subscribed); } - else if (type->second == "unsubscribe") { + else if (*type == "unsubscribe") { getStanzaGeneric()->setType(Presence::Unsubscribe); } - else if (type->second == "unsubscribed") { + else if (*type == "unsubscribed") { getStanzaGeneric()->setType(Presence::Unsubscribed); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Presence::Error); } else { - std::cerr << "Unknown Presence type: " << type->second << std::endl; + std::cerr << "Unknown Presence type: " << *type << std::endl; getStanzaGeneric()->setType(Presence::Available); } } diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index cbb2190..d9915ed 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -6,6 +6,7 @@ myenv.MergeFlags(swiften_env.get("LIBXML_FLAGS", "")) myenv.MergeFlags(swiften_env.get("EXPAT_FLAGS", "")) sources = [ + "AttributeMap.cpp", "AuthRequestParser.cpp", "AuthChallengeParser.cpp", "AuthSuccessParser.cpp", @@ -37,6 +38,7 @@ sources = [ "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", + "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", "PayloadParsers/SecurityLabelParser.cpp", "PayloadParsers/SecurityLabelsCatalogParser.cpp", @@ -51,12 +53,15 @@ sources = [ "PayloadParsers/DelayParser.cpp", "PayloadParsers/MUCUserPayloadParser.cpp", "PayloadParsers/NicknameParser.cpp", + "PayloadParsers/ReplaceParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", "StanzaParser.cpp", "StreamErrorParser.cpp", "StreamFeaturesParser.cpp", + "StreamManagementEnabledParser.cpp", + "StreamResumeParser.cpp", "XMLParser.cpp", "XMLParserClient.cpp", "XMLParserFactory.cpp", diff --git a/Swiften/Parser/SerializingParser.cpp b/Swiften/Parser/SerializingParser.cpp index 43dfc51..03b9575 100644 --- a/Swiften/Parser/SerializingParser.cpp +++ b/Swiften/Parser/SerializingParser.cpp @@ -7,7 +7,6 @@ #include "Swiften/Parser/SerializingParser.h" #include "Swiften/Serializer/XML/XMLTextNode.h" #include "Swiften/Base/foreach.h" -#include <iostream> namespace Swift { @@ -16,8 +15,9 @@ SerializingParser::SerializingParser() { void SerializingParser::handleStartElement(const std::string& tag, const std::string& ns, const AttributeMap& attributes) { boost::shared_ptr<XMLElement> element(new XMLElement(tag, ns)); - for (AttributeMap::const_iterator i = attributes.begin(); i != attributes.end(); ++i) { - element->setAttribute((*i).first, (*i).second); + // FIXME: Ignoring attribute namespace + foreach (const AttributeMap::Entry& e, attributes.getEntries()) { + element->setAttribute(e.getAttribute().getName(), e.getValue()); } if (elementStack_.empty()) { diff --git a/Swiften/Parser/StanzaParser.cpp b/Swiften/Parser/StanzaParser.cpp index 64c4901..051f37e 100644 --- a/Swiften/Parser/StanzaParser.cpp +++ b/Swiften/Parser/StanzaParser.cpp @@ -7,6 +7,7 @@ #include "Swiften/Parser/StanzaParser.h" #include <iostream> +#include <boost/optional.hpp> #include <cassert> #include "Swiften/Parser/PayloadParser.h" @@ -39,17 +40,17 @@ void StanzaParser::handleStartElement(const std::string& element, const std::str currentPayloadParser_->handleStartElement(element, ns, attributes); } else { - AttributeMap::const_iterator from = attributes.find("from"); - if (from != attributes.end()) { - getStanza()->setFrom(JID(from->second)); + boost::optional<std::string> from = attributes.getAttributeValue("from"); + if (from) { + getStanza()->setFrom(JID(*from)); } - AttributeMap::const_iterator to = attributes.find("to"); - if (to != attributes.end()) { - getStanza()->setTo(JID(to->second)); + boost::optional<std::string> to = attributes.getAttributeValue("to"); + if (to) { + getStanza()->setTo(JID(*to)); } - AttributeMap::const_iterator id = attributes.find("id"); - if (id != attributes.end()) { - getStanza()->setID(id->second); + boost::optional<std::string> id = attributes.getAttributeValue("id"); + if (id) { + getStanza()->setID(*id); } handleStanzaAttributes(attributes); } diff --git a/Swiften/Parser/StreamFeaturesParser.cpp b/Swiften/Parser/StreamFeaturesParser.cpp index 377f215..1b3ad54 100644 --- a/Swiften/Parser/StreamFeaturesParser.cpp +++ b/Swiften/Parser/StreamFeaturesParser.cpp @@ -31,6 +31,9 @@ void StreamFeaturesParser::handleStartElement(const std::string& element, const else if (element == "compression" && ns == "http://jabber.org/features/compress") { inCompression_ = true; } + else if (element == "ver" && ns == "urn:xmpp:features:rosterver") { + getElementGeneric()->setHasRosterVersioning(); + } } else if (currentDepth_ == 2) { if (inCompression_ && element == "method") { diff --git a/Swiften/Parser/StreamManagementEnabledParser.cpp b/Swiften/Parser/StreamManagementEnabledParser.cpp new file mode 100644 index 0000000..906e071 --- /dev/null +++ b/Swiften/Parser/StreamManagementEnabledParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamManagementEnabledParser.h> + +using namespace Swift; + +StreamManagementEnabledParser::StreamManagementEnabledParser() : level(TopLevel) { +} + +StreamManagementEnabledParser::~StreamManagementEnabledParser() { +} + +void StreamManagementEnabledParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + if (attributes.getBoolAttribute("resume", false)) { + getElementGeneric()->setResumeSupported(); + } + getElementGeneric()->setResumeID(attributes.getAttribute("id")); + } + ++level; +} + +void StreamManagementEnabledParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamManagementEnabledParser.h b/Swiften/Parser/StreamManagementEnabledParser.h index adc45ab..db616af 100644 --- a/Swiften/Parser/StreamManagementEnabledParser.h +++ b/Swiften/Parser/StreamManagementEnabledParser.h @@ -1,17 +1,27 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StreamManagementEnabled.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamManagementEnabled.h> namespace Swift { class StreamManagementEnabledParser : public GenericElementParser<StreamManagementEnabled> { public: - StreamManagementEnabledParser() : GenericElementParser<StreamManagementEnabled>() {} + StreamManagementEnabledParser(); + ~StreamManagementEnabledParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; }; } diff --git a/Swiften/Parser/StreamResumeParser.cpp b/Swiften/Parser/StreamResumeParser.cpp new file mode 100644 index 0000000..f54dcf0 --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamResumeParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +StreamResumeParser::StreamResumeParser() : level(TopLevel) { +} + +StreamResumeParser::~StreamResumeParser() { +} + +void StreamResumeParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + boost::optional<std::string> handledStanzasCount = attributes.getAttributeValue("h"); + if (handledStanzasCount) { + try { + getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<int>(*handledStanzasCount)); + } + catch (const boost::bad_lexical_cast &) { + } + } + getElementGeneric()->setResumeID(attributes.getAttribute("previd")); + } + ++level; +} + +void StreamResumeParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamResumeParser.h b/Swiften/Parser/StreamResumeParser.h new file mode 100644 index 0000000..0ccd24c --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamResume.h> + +namespace Swift { + class StreamResumeParser : public GenericElementParser<StreamResume> { + public: + StreamResumeParser(); + ~StreamResumeParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; + }; +} diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp index fb68f29..8e2ccff 100644 --- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp +++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp @@ -14,6 +14,7 @@ using namespace Swift; class AttributeMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AttributeMapTest); + CPPUNIT_TEST(testGetAttribute_Namespaced); CPPUNIT_TEST(testGetBoolAttribute_True); CPPUNIT_TEST(testGetBoolAttribute_1); CPPUNIT_TEST(testGetBoolAttribute_False); @@ -24,39 +25,46 @@ class AttributeMapTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE_END(); public: - AttributeMapTest() {} + void testGetAttribute_Namespaced() { + AttributeMap testling; + testling.addAttribute("lang", "", "nl"); + testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "en"); + testling.addAttribute("lang", "", "fr"); + + CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); + } void testGetBoolAttribute_True() { AttributeMap testling; - testling["foo"] = "true"; + testling.addAttribute("foo", "", "true"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_1() { AttributeMap testling; - testling["foo"] = "1"; + testling.addAttribute("foo", "", "1"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_False() { AttributeMap testling; - testling["foo"] = "false"; + testling.addAttribute("foo", "", "false"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_0() { AttributeMap testling; - testling["foo"] = "0"; + testling.addAttribute("foo", "", "0"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_Invalid() { AttributeMap testling; - testling["foo"] = "bla"; + testling.addAttribute("foo", "", "bla"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } diff --git a/Swiften/Parser/UnitTest/StanzaParserTest.cpp b/Swiften/Parser/UnitTest/StanzaParserTest.cpp index d57f798..2657750 100644 --- a/Swiften/Parser/UnitTest/StanzaParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaParserTest.cpp @@ -40,8 +40,8 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["foo"] = "fum"; - attributes["bar"] = "baz"; + attributes.addAttribute("foo", "", "fum"); + attributes.addAttribute("bar", "", "baz"); testling.handleStartElement("mystanza", "", attributes); testling.handleStartElement("mypayload1", "", attributes); testling.handleStartElement("child", "", attributes); @@ -107,9 +107,9 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["to"] = "foo@example.com/blo"; - attributes["from"] = "bar@example.com/baz"; - attributes["id"] = "id-123"; + attributes.addAttribute("to", "", "foo@example.com/blo"); + attributes.addAttribute("from", "", "bar@example.com/baz"); + attributes.addAttribute("id", "", "id-123"); testling.handleStartElement("mystanza", "", attributes); testling.handleEndElement("mypayload1", ""); diff --git a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp index 1cdaf54..9fdea88 100644 --- a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp +++ b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp @@ -37,6 +37,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" "<sm xmlns='urn:xmpp:sm:2'/>" "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" + "<ver xmlns=\"urn:xmpp:features:rosterver\"/>" "</stream:features>")); StreamFeatures::ref element = boost::dynamic_pointer_cast<StreamFeatures>(testling.getElement()); @@ -49,6 +50,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(element->hasAuthenticationMechanism("DIGEST-MD5")); CPPUNIT_ASSERT(element->hasAuthenticationMechanism("PLAIN")); CPPUNIT_ASSERT(element->hasStreamManagement()); + CPPUNIT_ASSERT(element->hasRosterVersioning()); } void testParse_Empty() { diff --git a/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp new file mode 100644 index 0000000..07b7b31 --- /dev/null +++ b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/StreamManagementEnabledParser.h> +#include <Swiften/Parser/UnitTest/ElementParserTester.h> + +using namespace Swift; + +class StreamManagementEnabledParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(StreamManagementEnabledParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + StreamManagementEnabledParser testling; + ElementParserTester parser(&testling); + + CPPUNIT_ASSERT(parser.parse( + "<enabled xmlns=\"urn:xmpp:sm:3\" id=\"some-long-sm-id\" resume=\"true\"/>")); + + boost::shared_ptr<StreamManagementEnabled> element = boost::dynamic_pointer_cast<StreamManagementEnabled>(testling.getElement()); + CPPUNIT_ASSERT(element->getResumeSupported()); + CPPUNIT_ASSERT_EQUAL(std::string("some-long-sm-id"), element->getResumeID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(StreamManagementEnabledParserTest); diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 426b7a0..27534a1 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -31,6 +31,8 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_InErrorState); CPPUNIT_TEST(testParse_Incremental); CPPUNIT_TEST(testParse_WhitespaceInAttribute); + CPPUNIT_TEST(testParse_AttributeWithoutNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespace); CPPUNIT_TEST_SUITE_END(); public: @@ -46,13 +48,13 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes["type"]); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes.getAttribute("type")); CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); @@ -76,7 +78,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); @@ -205,6 +207,28 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data); } + + void testParse_AttributeWithoutNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } + + void testParse_AttributeWithNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' f:attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } private: class Client : public XMLParserClient { diff --git a/Swiften/Parser/XMPPParser.cpp b/Swiften/Parser/XMPPParser.cpp index 1fb7682..adcfdf5 100644 --- a/Swiften/Parser/XMPPParser.cpp +++ b/Swiften/Parser/XMPPParser.cpp @@ -29,6 +29,7 @@ #include "Swiften/Parser/EnableStreamManagementParser.h" #include "Swiften/Parser/StreamManagementEnabledParser.h" #include "Swiften/Parser/StreamManagementFailedParser.h" +#include "Swiften/Parser/StreamResumeParser.h" #include "Swiften/Parser/StanzaAckParser.h" #include "Swiften/Parser/StanzaAckRequestParser.h" #include "Swiften/Parser/StartTLSParser.h" @@ -182,6 +183,12 @@ ElementParser* XMPPParser::createElementParser(const std::string& element, const else if (element == "failed" && ns == "urn:xmpp:sm:2") { return new StreamManagementFailedParser(); } + else if (element == "resume" && ns == "urn:xmpp:sm:2") { + return new StreamResumeParser(); + } + else if (element == "resumed" && ns == "urn:xmpp:sm:2") { + return new StreamResumeParser(); + } else if (element == "a" && ns == "urn:xmpp:sm:2") { return new StanzaAckParser(); } |