From e4704555946626980014d936dcfe6ede2710501b Mon Sep 17 00:00:00 2001 From: Richard Maudsley <richard.maudsley@isode.com> Date: Tue, 25 Feb 2014 13:19:11 +0000 Subject: Added MAM parsers, serializers and tests. Change-Id: I589a7c65664bfecfd0ac34240600dcccb4cbd40e diff --git a/Swiften/Elements/Forwarded.cpp b/Swiften/Elements/Forwarded.cpp new file mode 100644 index 0000000..590c1ca --- /dev/null +++ b/Swiften/Elements/Forwarded.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/Forwarded.h> + +using namespace Swift; + +Forwarded::~Forwarded() { +} diff --git a/Swiften/Elements/Forwarded.h b/Swiften/Elements/Forwarded.h new file mode 100644 index 0000000..f1a718c --- /dev/null +++ b/Swiften/Elements/Forwarded.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class Delay; + class Stanza; + + class SWIFTEN_API Forwarded : public Payload { + public: + virtual ~Forwarded(); + + void setDelay(boost::shared_ptr<Delay> delay) { delay_ = delay; } + const boost::shared_ptr<Delay>& getDelay() const { return delay_; } + + void setStanza(boost::shared_ptr<Stanza> stanza) { stanza_ = stanza; } + const boost::shared_ptr<Stanza>& getStanza() const { return stanza_; } + + private: + boost::shared_ptr<Delay> delay_; + boost::shared_ptr<Stanza> stanza_; + }; +} diff --git a/Swiften/Elements/MAMArchived.cpp b/Swiften/Elements/MAMArchived.cpp new file mode 100644 index 0000000..4ec5750 --- /dev/null +++ b/Swiften/Elements/MAMArchived.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMArchived.h> + +using namespace Swift; + +MAMArchived::~MAMArchived() { +} diff --git a/Swiften/Elements/MAMArchived.h b/Swiften/Elements/MAMArchived.h new file mode 100644 index 0000000..df83427 --- /dev/null +++ b/Swiften/Elements/MAMArchived.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API MAMArchived : public Payload { + public: + virtual ~MAMArchived(); + + void setBy(const JID& by) { by_ = by; } + const JID& getBy() const { return by_; } + + void setID(const std::string& id) { id_ = id; } + const std::string& getID() const { return id_; } + + private: + JID by_; + std::string id_; + }; +} diff --git a/Swiften/Elements/MAMQuery.cpp b/Swiften/Elements/MAMQuery.cpp new file mode 100644 index 0000000..ff71bcc --- /dev/null +++ b/Swiften/Elements/MAMQuery.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMQuery.h> + +using namespace Swift; + +MAMQuery::~MAMQuery() { +} diff --git a/Swiften/Elements/MAMQuery.h b/Swiften/Elements/MAMQuery.h new file mode 100644 index 0000000..3f3724e --- /dev/null +++ b/Swiften/Elements/MAMQuery.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/ResultSet.h> + +namespace Swift { + class SWIFTEN_API MAMQuery : public Payload { + public: + virtual ~MAMQuery(); + + void setQueryID(const boost::optional<std::string>& queryID) { queryID_ = queryID; } + const boost::optional<std::string>& getQueryID() const { return queryID_; } + + void setForm(boost::shared_ptr<Form> form) { form_ = form; } + const boost::shared_ptr<Form>& getForm() const { return form_; } + + void setResultSet(boost::shared_ptr<ResultSet> resultSet) { resultSet_ = resultSet; } + const boost::shared_ptr<ResultSet>& getResultSet() const { return resultSet_; } + + private: + boost::optional<std::string> queryID_; + boost::shared_ptr<Form> form_; + boost::shared_ptr<ResultSet> resultSet_; + }; +} diff --git a/Swiften/Elements/MAMResult.cpp b/Swiften/Elements/MAMResult.cpp new file mode 100644 index 0000000..79913d3 --- /dev/null +++ b/Swiften/Elements/MAMResult.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMResult.h> + +using namespace Swift; + +MAMResult::~MAMResult() { +} diff --git a/Swiften/Elements/MAMResult.h b/Swiften/Elements/MAMResult.h new file mode 100644 index 0000000..7d43902 --- /dev/null +++ b/Swiften/Elements/MAMResult.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ContainerPayload.h> +#include <Swiften/Elements/Forwarded.h> + +namespace Swift { + class SWIFTEN_API MAMResult : public ContainerPayload<Forwarded> { + public: + virtual ~MAMResult(); + + void setID(const std::string& id) { id_ = id; } + const std::string& getID() const { return id_; } + + void setQueryID(const boost::optional<std::string>& queryID) { queryID_ = queryID; } + const boost::optional<std::string>& getQueryID() const { return queryID_; } + + private: + std::string id_; + boost::optional<std::string> queryID_; + }; +} diff --git a/Swiften/Elements/ResultSet.cpp b/Swiften/Elements/ResultSet.cpp new file mode 100644 index 0000000..2565bbb --- /dev/null +++ b/Swiften/Elements/ResultSet.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/ResultSet.h> + +using namespace Swift; + +ResultSet::~ResultSet() { +} diff --git a/Swiften/Elements/ResultSet.h b/Swiften/Elements/ResultSet.h new file mode 100644 index 0000000..871b699 --- /dev/null +++ b/Swiften/Elements/ResultSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API ResultSet : public Payload { + public: + virtual ~ResultSet(); + + void setMaxItems(const boost::optional<int>& maxItems) { maxItems_ = maxItems; } + const boost::optional<int>& getMaxItems() const { return maxItems_; } + + void setCount(const boost::optional<int>& count) { count_ = count; } + const boost::optional<int>& getCount() const { return count_; } + + void setFirstIDIndex(const boost::optional<int>& firstIndex) { firstIndex_ = firstIndex; } + const boost::optional<int>& getFirstIDIndex() const { return firstIndex_; } + + void setFirstID(const boost::optional<std::string>& firstID) { firstID_ = firstID; } + const boost::optional<std::string>& getFirstID() const { return firstID_; } + + void setLastID(const boost::optional<std::string>& lastID) { lastID_ = lastID; } + const boost::optional<std::string>& getLastID() const { return lastID_; } + + void setAfter(const boost::optional<std::string>& after) { after_ = after; } + const boost::optional<std::string>& getAfter() const { return after_; } + + private: + boost::optional<int> maxItems_; + boost::optional<int> count_; + boost::optional<int> firstIndex_; + boost::optional<std::string> firstID_; + boost::optional<std::string> lastID_; + boost::optional<std::string> after_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/ForwardedParser.cpp b/Swiften/Parser/PayloadParsers/ForwardedParser.cpp new file mode 100644 index 0000000..6625e77 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ForwardedParser.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/IQParser.h> +#include <Swiften/Parser/MessageParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/DelayParser.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PresenceParser.h> + + +using namespace Swift; + +ForwardedParser::ForwardedParser(PayloadParserFactoryCollection* factories) : factories_(factories), level_(TopLevel) { +} + +void ForwardedParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "iq" && ns == "jabber:client") { /* begin parsing a nested stanza? */ + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<IQParser>(factories_)); + } else if (element == "message" && ns == "jabber:client") { + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<MessageParser>(factories_)); + } else if (element == "presence" && ns == "jabber:client") { + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<PresenceParser>(factories_)); + } else if (element == "delay" && ns == "urn:xmpp:delay") { /* nested delay payload */ + delayParser_ = boost::make_shared<DelayParser>(); + } + } + if (childParser_) { /* parsing a nested stanza? */ + childParser_->handleStartElement(element, ns, attributes); + } + if (delayParser_) { /* parsing a nested delay payload? */ + delayParser_->handleStartElement(element, ns, attributes); + } + ++level_; +} + +void ForwardedParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (childParser_ && level_ >= PayloadLevel) { + childParser_->handleEndElement(element, ns); + } + if (childParser_ && level_ == PayloadLevel) { + /* done parsing nested stanza */ + getPayloadInternal()->setStanza(childParser_->getStanza()); + childParser_.reset(); + } + if (delayParser_ && level_ >= PayloadLevel) { + delayParser_->handleEndElement(element, ns); + } + if (delayParser_ && level_ == PayloadLevel) { + /* done parsing nested delay payload */ + getPayloadInternal()->setDelay(boost::dynamic_pointer_cast<Delay>(delayParser_->getPayload())); + delayParser_.reset(); + } +} + +void ForwardedParser::handleCharacterData(const std::string& data) { + if (childParser_) { + childParser_->handleCharacterData(data); + } + if (delayParser_) { + delayParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/ForwardedParser.h b/Swiften/Parser/PayloadParsers/ForwardedParser.h new file mode 100644 index 0000000..14117ae --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ForwardedParser.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class StanzaParser; + class DelayParser; + + class SWIFTEN_API ForwardedParser : public GenericPayloadParser<Forwarded> { + public: + ForwardedParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + PayloadParserFactoryCollection* factories_; + boost::shared_ptr<StanzaParser> childParser_; + boost::shared_ptr<DelayParser> delayParser_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 22019b4..4541b3b 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -76,6 +76,11 @@ #include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h> #include <Swiften/Parser/PayloadParsers/UserLocationParser.h> #include <Swiften/Parser/PayloadParsers/UserTuneParser.h> +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> using namespace boost; @@ -144,6 +149,11 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubOwnerPubSubParser> >("pubsub", "http://jabber.org/protocol/pubsub#owner", this)); factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubEventParser> >("event", "http://jabber.org/protocol/pubsub#event", this)); factories_.push_back(boost::make_shared<PubSubErrorParserFactory>()); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<ResultSetParser> >("set", "http://jabber.org/protocol/rsm")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<ForwardedParser> >("forwarded", "urn:xmpp:forward:0", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<MAMResultParser> >("result", "urn:xmpp:mam:0", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<MAMQueryParser> >("query", "urn:xmpp:mam:0")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<MAMArchivedParser> >("archived", "urn:xmpp:mam:0")); foreach(shared_ptr<PayloadParserFactory> factory, factories_) { addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp b/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp new file mode 100644 index 0000000..616d41a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> + +using namespace Swift; + +MAMArchivedParser::MAMArchivedParser() : level_(TopLevel) { +} + +void MAMArchivedParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("by"))) { + getPayloadInternal()->setBy(*attributeValue); + } + if ((attributeValue = attributes.getAttributeValue("id"))) { + getPayloadInternal()->setID(*attributeValue); + } + } + + ++level_; +} + +void MAMArchivedParser::handleEndElement(const std::string&, const std::string&) { + --level_; +} + +void MAMArchivedParser::handleCharacterData(const std::string&) { +} diff --git a/Swiften/Parser/PayloadParsers/MAMArchivedParser.h b/Swiften/Parser/PayloadParsers/MAMArchivedParser.h new file mode 100644 index 0000000..b92b41a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMArchivedParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMArchived.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class SWIFTEN_API MAMArchivedParser : public GenericPayloadParser<MAMArchived> { + public: + MAMArchivedParser(); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0 + }; + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp b/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp new file mode 100644 index 0000000..9ae8e41 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> + +using namespace Swift; + +MAMQueryParser::MAMQueryParser() : level_(TopLevel) { +} + +void MAMQueryParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("queryid"))) { + getPayloadInternal()->setQueryID(*attributeValue); + } + } else if (level_ == PayloadLevel) { + if (element == "x" && ns == "jabber:x:data") { + formParser_ = boost::make_shared<FormParser>(); + } else if (element == "set" && ns == "http://jabber.org/protocol/rsm") { + resultSetParser_ = boost::make_shared<ResultSetParser>(); + } + } + + if (formParser_) { /* parsing a nested Form */ + formParser_->handleStartElement(element, ns, attributes); + } + + if (resultSetParser_) { /* parsing a nested ResultSet */ + resultSetParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void MAMQueryParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + + if (formParser_ && level_ >= PayloadLevel) { + formParser_->handleEndElement(element, ns); + } + if (formParser_ && level_ == PayloadLevel) { + /* done parsing nested Form */ + getPayloadInternal()->setForm(boost::dynamic_pointer_cast<Form>(formParser_->getPayload())); + formParser_.reset(); + } + + if (resultSetParser_ && level_ >= PayloadLevel) { + resultSetParser_->handleEndElement(element, ns); + } + if (resultSetParser_ && level_ == PayloadLevel) { + /* done parsing nested ResultSet */ + getPayloadInternal()->setResultSet(boost::dynamic_pointer_cast<ResultSet>(resultSetParser_->getPayload())); + resultSetParser_.reset(); + } +} + +void MAMQueryParser::handleCharacterData(const std::string& data) { + if (formParser_) { + formParser_->handleCharacterData(data); + } + if (resultSetParser_) { + resultSetParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/MAMQueryParser.h b/Swiften/Parser/PayloadParsers/MAMQueryParser.h new file mode 100644 index 0000000..7bbdacb --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMQueryParser.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMQuery.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class ResultSetParser; + class FormParser; + + class SWIFTEN_API MAMQueryParser : public GenericPayloadParser<MAMQuery> { + public: + MAMQueryParser(); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + boost::shared_ptr<FormParser> formParser_; + boost::shared_ptr<ResultSetParser> resultSetParser_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MAMResultParser.cpp b/Swiften/Parser/PayloadParsers/MAMResultParser.cpp new file mode 100644 index 0000000..e4eec3b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMResultParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> + +using namespace Swift; + +MAMResultParser::MAMResultParser(PayloadParserFactoryCollection* factories) : factories_(factories), level_(TopLevel) { +} + +void MAMResultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("id"))) { + getPayloadInternal()->setID(*attributeValue); + } + if ((attributeValue = attributes.getAttributeValue("queryid"))) { + getPayloadInternal()->setQueryID(*attributeValue); + } + } else if (level_ == PayloadLevel) { + if (element == "forwarded" && ns == "urn:xmpp:forward:0") { + payloadParser_ = boost::make_shared<ForwardedParser>(factories_); + } + } + + if (payloadParser_) { + /* parsing a nested payload */ + payloadParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void MAMResultParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (payloadParser_ && level_ >= PayloadLevel) { + payloadParser_->handleEndElement(element, ns); + } + if (payloadParser_ && level_ == PayloadLevel) { + /* done parsing nested stanza */ + getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<Forwarded>(payloadParser_->getPayload())); + payloadParser_.reset(); + } +} + +void MAMResultParser::handleCharacterData(const std::string& data) { + if (payloadParser_) { + payloadParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/MAMResultParser.h b/Swiften/Parser/PayloadParsers/MAMResultParser.h new file mode 100644 index 0000000..39ff20a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMResultParser.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class ForwardedParser; + + class SWIFTEN_API MAMResultParser : public GenericPayloadParser<MAMResult> { + public: + MAMResultParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + boost::shared_ptr<ForwardedParser> payloadParser_; + PayloadParserFactoryCollection* factories_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/ResultSetParser.cpp b/Swiften/Parser/PayloadParsers/ResultSetParser.cpp new file mode 100644 index 0000000..95960d7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ResultSetParser.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> + +using namespace Swift; + +ResultSetParser::ResultSetParser() : level_(TopLevel) { +} + +void ResultSetParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + currentText_ = ""; + if (level_ == PayloadLevel) { + if (element == "first" && ns == "http://jabber.org/protocol/rsm") { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("index")) { + try { + getPayloadInternal()->setFirstIDIndex(boost::lexical_cast<int>(*attributeValue)); + } catch(boost::bad_lexical_cast&) { + } + } + } + } + ++level_; +} + +void ResultSetParser::handleEndElement(const std::string& element, const std::string&) { + --level_; + if (level_ == PayloadLevel) { + if (element == "max") { + try { + getPayloadInternal()->setMaxItems(boost::lexical_cast<int>(currentText_)); + } catch(boost::bad_lexical_cast&) { + } + } else if (element == "count") { + try { + getPayloadInternal()->setCount(boost::lexical_cast<int>(currentText_)); + } catch(boost::bad_lexical_cast&) { + } + } else if (element == "first") { + getPayloadInternal()->setFirstID(currentText_); + } else if (element == "last") { + getPayloadInternal()->setLastID(currentText_); + } else if (element == "after") { + getPayloadInternal()->setAfter(currentText_); + } + } +} + +void ResultSetParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} diff --git a/Swiften/Parser/PayloadParsers/ResultSetParser.h b/Swiften/Parser/PayloadParsers/ResultSetParser.h new file mode 100644 index 0000000..55399ef --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ResultSetParser.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ResultSet.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class SWIFTEN_API ResultSetParser : public GenericPayloadParser<ResultSet> { + public: + ResultSetParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + std::string currentText_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp new file mode 100644 index 0000000..a950fa4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> + +using namespace Swift; + +class ForwardedParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ForwardedParserTest); + CPPUNIT_TEST(testParseIQ); + CPPUNIT_TEST(testParseMessage); + CPPUNIT_TEST(testParseMessageNoDelay); + CPPUNIT_TEST(testParsePresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParseIQ() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<iq xmlns=\"jabber:client\" type=\"get\" from=\"kindanormal@example.com/IM\" to=\"stupidnewbie@example.com\" id=\"id0\"/>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<IQ> iq = boost::dynamic_pointer_cast<IQ>(payload->getStanza()); + CPPUNIT_ASSERT(!!iq); + CPPUNIT_ASSERT_EQUAL(JID("stupidnewbie@example.com"), iq->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("kindanormal@example.com/IM"), iq->getFrom()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), iq->getID()); + CPPUNIT_ASSERT_EQUAL(IQ::Get, iq->getType()); + } + + void testParseMessage() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<message xmlns=\"jabber:client\" to=\"juliet@capulet.lit/balcony\" from=\"romeo@montague.lit/orchard\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(payload->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } + + void testParseMessageNoDelay() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<message xmlns=\"jabber:client\" to=\"juliet@capulet.lit/balcony\" from=\"romeo@montague.lit/orchard\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(!payload->getDelay()); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(payload->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } + + void testParsePresence() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<presence xmlns=\"jabber:client\" from=\"alice@wonderland.lit/rabbithole\" to=\"madhatter@wonderland.lit\" type=\"unavailable\"/>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(payload->getStanza()); + CPPUNIT_ASSERT(!!presence); + CPPUNIT_ASSERT_EQUAL(JID("madhatter@wonderland.lit"), presence->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/rabbithole"), presence->getFrom()); + CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, presence->getType()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ForwardedParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp new file mode 100644 index 0000000..3e65cc6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MAMArchivedParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMArchivedParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<archived by=\"juliet@capulet.lit\" id=\"28482-98726-73623\" xmlns=\"urn:xmpp:mam:0\"/>")); + + boost::shared_ptr<MAMArchived> payload = parser.getPayload<MAMArchived>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit"), payload->getBy()); + CPPUNIT_ASSERT_EQUAL(std::string("28482-98726-73623"), payload->getID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMArchivedParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp new file mode 100644 index 0000000..ddcd7c4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MAMQueryParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMQueryParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseEmpty); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "<x type=\"form\" xmlns=\"jabber:x:data\">" + "<field type=\"text-single\" var=\"FORM_TYPE\">" + "<value>urn:xmpp:mam:0</value>" + "</field>" + "<field type=\"text-single\" var=\"start\">" + "<value>2010-08-07T00:00:00Z</value>" + "</field>" + "</x>" + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>10</max>" + "</set>" + "</query>")); + + + boost::shared_ptr<MAMQuery> payload = parser.getPayload<MAMQuery>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), *payload->getQueryID()); + + CPPUNIT_ASSERT(payload->getForm()); + boost::shared_ptr<FormField> fieldType = payload->getForm()->getField("FORM_TYPE"); + CPPUNIT_ASSERT(fieldType); + CPPUNIT_ASSERT_EQUAL(std::string("urn:xmpp:mam:0"), fieldType->getTextSingleValue()); + boost::shared_ptr<FormField> fieldStart = payload->getForm()->getField("start"); + CPPUNIT_ASSERT(fieldStart); + CPPUNIT_ASSERT_EQUAL(std::string("2010-08-07T00:00:00Z"), fieldStart->getTextSingleValue()); + + CPPUNIT_ASSERT(payload->getResultSet()); + boost::shared_ptr<ResultSet> resultSet = payload->getResultSet(); + CPPUNIT_ASSERT(resultSet->getMaxItems()); + CPPUNIT_ASSERT_EQUAL(*resultSet->getMaxItems(), 10); + } + + void testParseEmpty() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "</query>")); + + boost::shared_ptr<MAMQuery> payload = parser.getPayload<MAMQuery>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), *payload->getQueryID()); + CPPUNIT_ASSERT(!payload->getForm()); + CPPUNIT_ASSERT(!payload->getResultSet()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMQueryParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp new file mode 100644 index 0000000..e62db9b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/Message.h> + +using namespace Swift; + +class MAMResultParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMResultParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<result id=\"28482-98726-73623\" queryid=\"f27\" xmlns=\"urn:xmpp:mam:0\">" + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message xmlns=\"jabber:client\" from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>" + "</result>")); + + boost::shared_ptr<MAMResult> payload = parser.getPayload<MAMResult>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT_EQUAL(std::string("28482-98726-73623"), payload->getID()); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("f27"), *payload->getQueryID()); + + boost::shared_ptr<Forwarded> forwarded = payload->getPayload(); + CPPUNIT_ASSERT(forwarded->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(forwarded->getDelay()->getStamp())); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(forwarded->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMResultParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp new file mode 100644 index 0000000..68df71b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/PayloadParsers/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class ResultSetParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ResultSetParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseFirstNoIndex); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "<count>800</count>" + "<first index=\"123\">stpeter@jabber.org</first>" + "<last>peterpan@neverland.lit</last>" + "<after>09af3-cc343-b409f</after>" + "</set>")); + + boost::shared_ptr<ResultSet> payload = parser.getPayload<ResultSet>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getMaxItems()); + CPPUNIT_ASSERT_EQUAL(100, *payload->getMaxItems()); + CPPUNIT_ASSERT(payload->getCount()); + CPPUNIT_ASSERT_EQUAL(800, *payload->getCount()); + CPPUNIT_ASSERT(payload->getFirstID()); + CPPUNIT_ASSERT_EQUAL(std::string("stpeter@jabber.org"), *payload->getFirstID()); + CPPUNIT_ASSERT(payload->getFirstIDIndex()); + CPPUNIT_ASSERT_EQUAL(123, *payload->getFirstIDIndex()); + CPPUNIT_ASSERT(payload->getLastID()); + CPPUNIT_ASSERT_EQUAL(std::string("peterpan@neverland.lit"), *payload->getLastID()); + CPPUNIT_ASSERT(payload->getAfter()); + CPPUNIT_ASSERT_EQUAL(std::string("09af3-cc343-b409f"), *payload->getAfter()); + } + + void testParseFirstNoIndex() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first>stpeter@jabber.org</first>" + "</set>")); + + boost::shared_ptr<ResultSet> payload = parser.getPayload<ResultSet>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getFirstID()); + CPPUNIT_ASSERT_EQUAL(std::string("stpeter@jabber.org"), *payload->getFirstID()); + CPPUNIT_ASSERT(!payload->getFirstIDIndex()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ResultSetParserTest); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 4d6db11..056862f 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -77,6 +77,11 @@ sources = [ "PayloadParsers/UserTuneParser.cpp", "PayloadParsers/WhiteboardParser.cpp", "PayloadParsers/PubSubErrorParserFactory.cpp", + "PayloadParsers/ResultSetParser.cpp", + "PayloadParsers/ForwardedParser.cpp", + "PayloadParsers/MAMResultParser.cpp", + "PayloadParsers/MAMQueryParser.cpp", + "PayloadParsers/MAMArchivedParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index 80db7da..574b7d8 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -141,6 +141,11 @@ if env["SCONS_STAGE"] == "build" : "Elements/UserTune.cpp", "Elements/VCard.cpp", "Elements/MUCOccupant.cpp", + "Elements/ResultSet.cpp", + "Elements/Forwarded.cpp", + "Elements/MAMResult.cpp", + "Elements/MAMQuery.cpp", + "Elements/MAMArchived.cpp", "Entity/Entity.cpp", "Entity/PayloadPersister.cpp", "MUC/MUC.cpp", @@ -219,6 +224,11 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/UserLocationSerializer.cpp", "Serializer/PayloadSerializers/UserTuneSerializer.cpp", "Serializer/PayloadSerializers/WhiteboardSerializer.cpp", + "Serializer/PayloadSerializers/ResultSetSerializer.cpp", + "Serializer/PayloadSerializers/ForwardedSerializer.cpp", + "Serializer/PayloadSerializers/MAMResultSerializer.cpp", + "Serializer/PayloadSerializers/MAMQuerySerializer.cpp", + "Serializer/PayloadSerializers/MAMArchivedSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", "Serializer/StreamErrorSerializer.cpp", @@ -407,6 +417,11 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DeliveryReceiptParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/IdleParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp"), File("Parser/UnitTest/BOSHBodyExtractorTest.cpp"), File("Parser/UnitTest/AttributeMapTest.cpp"), File("Parser/UnitTest/EnumParserTest.cpp"), @@ -459,6 +474,11 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/DeliveryReceiptSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/IdleSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp"), File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"), File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"), File("Serializer/UnitTest/AuthChallengeSerializerTest.cpp"), diff --git a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp index 6148632..f809798 100644 --- a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp @@ -20,7 +20,7 @@ DelaySerializer::DelaySerializer() : GenericPayloadSerializer<Delay>() { std::string DelaySerializer::serializePayload(boost::shared_ptr<Delay> delay) const { XMLElement delayElement("delay", "urn:xmpp:delay"); - if (delay->getFrom()) { + if (delay->getFrom() && delay->getFrom()->isValid()) { delayElement.setAttribute("from", delay->getFrom()->toString()); } delayElement.setAttribute("stamp", dateTimeToString(delay->getStamp())); diff --git a/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp new file mode 100644 index 0000000..767d9de --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/GenericStanzaSerializer.h> +#include <Swiften/Serializer/IQSerializer.h> +#include <Swiften/Serializer/MessageSerializer.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PresenceSerializer.h> + + +using namespace Swift; + +ForwardedSerializer::ForwardedSerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +ForwardedSerializer::~ForwardedSerializer() { +} + +std::string ForwardedSerializer::serializePayload(boost::shared_ptr<Forwarded> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("forwarded", "urn:xmpp:forward:0"); + + if (payload->getDelay()) { + element.addNode(boost::make_shared<XMLRawTextNode>(DelaySerializer().serialize(payload->getDelay()))); + } + + if (payload->getStanza()) { /* find out what type of stanza we are dealing with and branch into the correct serializer*/ + boost::shared_ptr<IQ> iq; + boost::shared_ptr<Message> message; + boost::shared_ptr<Presence> presence; + const std::string ns = "jabber:client"; + if ((iq = boost::dynamic_pointer_cast<IQ>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(IQSerializer(serializers_).serialize(iq, ns)))); + } else if ((message = boost::dynamic_pointer_cast<Message>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(MessageSerializer(serializers_).serialize(message, ns)))); + } else if ((presence = boost::dynamic_pointer_cast<Presence>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(PresenceSerializer(serializers_).serialize(presence, ns)))); + } + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h new file mode 100644 index 0000000..4b283e2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ForwardedSerializer : public GenericPayloadSerializer<Forwarded> { + public: + ForwardedSerializer(PayloadSerializerCollection* serializers); + virtual ~ForwardedSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<Forwarded>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp new file mode 100644 index 0000000..04a6584 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h> + +using namespace Swift; + +MAMArchivedSerializer::MAMArchivedSerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +MAMArchivedSerializer::~MAMArchivedSerializer() { +} + +std::string MAMArchivedSerializer::serializePayload(boost::shared_ptr<MAMArchived> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("archived", "urn:xmpp:mam:0"); + element.setAttribute("by", payload->getBy()); + element.setAttribute("id", payload->getID()); + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h new file mode 100644 index 0000000..7c60798 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMArchived.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMArchivedSerializer : public GenericPayloadSerializer<MAMArchived> { + public: + MAMArchivedSerializer(PayloadSerializerCollection* serializers); + virtual ~MAMArchivedSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMArchived>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp new file mode 100644 index 0000000..1151fba --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> + +using namespace Swift; + +MAMQuerySerializer::MAMQuerySerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +MAMQuerySerializer::~MAMQuerySerializer() { +} + +std::string MAMQuerySerializer::serializePayload(boost::shared_ptr<MAMQuery> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("query", "urn:xmpp:mam:0"); + + if (payload->getQueryID()) { + element.setAttribute("queryid", *payload->getQueryID()); + } + + if (payload->getForm()) { + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getForm()))); + } + + if (payload->getResultSet()) { + element.addNode(boost::make_shared<XMLRawTextNode>(ResultSetSerializer().serialize(payload->getResultSet()))); + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h new file mode 100644 index 0000000..a6d1339 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMQuery.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMQuerySerializer : public GenericPayloadSerializer<MAMQuery> { + public: + MAMQuerySerializer(PayloadSerializerCollection* serializers); + virtual ~MAMQuerySerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMQuery>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp new file mode 100644 index 0000000..c4fd4a5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h> + +using namespace Swift; + +MAMResultSerializer::MAMResultSerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +MAMResultSerializer::~MAMResultSerializer() { +} + +std::string MAMResultSerializer::serializePayload(boost::shared_ptr<MAMResult> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("result", "urn:xmpp:mam:0"); + + element.setAttribute("id", payload->getID()); + + if (payload->getQueryID()) { + element.setAttribute("queryid", *payload->getQueryID()); + } + + element.addNode(boost::make_shared<XMLRawTextNode>(ForwardedSerializer(serializers_).serialize(payload->getPayload()))); + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h new file mode 100644 index 0000000..bb0c326 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMResultSerializer : public GenericPayloadSerializer<MAMResult> { + public: + MAMResultSerializer(PayloadSerializerCollection* serializers); + virtual ~MAMResultSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMResult>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp new file mode 100644 index 0000000..86d8830 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> + +using namespace Swift; + +ResultSetSerializer::ResultSetSerializer() { +} + +ResultSetSerializer::~ResultSetSerializer() { +} + +std::string ResultSetSerializer::serializePayload(boost::shared_ptr<ResultSet> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("set", "http://jabber.org/protocol/rsm"); + + if (payload->getMaxItems()) { + element.addNode(boost::make_shared<XMLElement>("max", "", boost::lexical_cast<std::string>(*payload->getMaxItems()))); + } + + if (payload->getCount()) { + element.addNode(boost::make_shared<XMLElement>("count", "", boost::lexical_cast<std::string>(*payload->getCount()))); + } + + if (payload->getFirstID()) { + boost::shared_ptr<XMLElement> firstElement = boost::make_shared<XMLElement>("first", "", *payload->getFirstID()); + if (payload->getFirstIDIndex()) { + firstElement->setAttribute("index", boost::lexical_cast<std::string>(*payload->getFirstIDIndex())); + } + element.addNode(firstElement); + } + + if (payload->getLastID()) { + element.addNode(boost::make_shared<XMLElement>("last", "", *payload->getLastID())); + } + + if (payload->getAfter()) { + element.addNode(boost::make_shared<XMLElement>("after", "", *payload->getAfter())); + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h new file mode 100644 index 0000000..1d476e2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ResultSet.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ResultSetSerializer : public GenericPayloadSerializer<ResultSet> { + public: + ResultSetSerializer(); + virtual ~ResultSetSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<ResultSet>) const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp new file mode 100644 index 0000000..8af1672 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class ForwardedSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ForwardedSerializerTest); + CPPUNIT_TEST(testSerializeIQ); + CPPUNIT_TEST(testSerializeMessage); + CPPUNIT_TEST(testSerializeMessageNoDelay); + CPPUNIT_TEST(testSerializePresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerializeIQ() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<IQ> iq = IQ::createResult(JID("juliet@capulet.lit/balcony"), JID("romeo@montague.lit/orchard"), "id0"); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(iq); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<iq from=\"romeo@montague.lit/orchard\" id=\"id0\" to=\"juliet@capulet.lit/balcony\" type=\"result\" xmlns=\"jabber:client\"/>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializeMessage() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializeMessageNoDelay() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializePresence() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Presence> presence(boost::make_shared<Presence>()); + presence->setType(Presence::Subscribe); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(presence); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<presence type=\"subscribe\" xmlns=\"jabber:client\"/>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ForwardedSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp new file mode 100644 index 0000000..b174d32 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMArchivedSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMArchivedSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMArchivedSerializer serializer(&serializers); + + boost::shared_ptr<MAMArchived> archived(boost::make_shared<MAMArchived>()); + archived->setBy("juliet@capulet.lit"); + archived->setID("28482-98726-73623"); + + std::string expectedResult = + "<archived by=\"juliet@capulet.lit\" id=\"28482-98726-73623\" xmlns=\"urn:xmpp:mam:0\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(archived)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMArchivedSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp new file mode 100644 index 0000000..cc49be1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMQuerySerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMQuerySerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMQuerySerializer serializer(&serializers); + + boost::shared_ptr<Form> parameters(boost::make_shared<Form>()); + + boost::shared_ptr<FormField> fieldType = boost::make_shared<FormField>(FormField::TextSingleType); + fieldType->setName("FORM_TYPE"); + fieldType->addValue("urn:xmpp:mam:0"); + parameters->addField(fieldType); + + boost::shared_ptr<FormField> fieldStart = boost::make_shared<FormField>(FormField::TextSingleType); + fieldStart->setName("start"); + fieldStart->addValue("2010-08-07T00:00:00Z"); + parameters->addField(fieldStart); + + boost::shared_ptr<ResultSet> set = boost::make_shared<ResultSet>(); + set->setMaxItems(10); + + boost::shared_ptr<MAMQuery> query(boost::make_shared<MAMQuery>()); + query->setQueryID(std::string("id0")); + query->setForm(parameters); + query->setResultSet(set); + + std::string expectedResult = + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "<x type=\"form\" xmlns=\"jabber:x:data\">" + "<field type=\"text-single\" var=\"FORM_TYPE\">" + "<value>urn:xmpp:mam:0</value>" + "</field>" + "<field type=\"text-single\" var=\"start\">" + "<value>2010-08-07T00:00:00Z</value>" + "</field>" + "</x>" + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>10</max>" + "</set>" + "</query>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(query)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMQuerySerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp new file mode 100644 index 0000000..2060c97 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMResultSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMResultSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMResultSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + boost::shared_ptr<MAMResult> result(boost::make_shared<MAMResult>()); + result->setID("28482-98726-73623"); + result->setQueryID(std::string("f27")); + result->setPayload(forwarded); + + std::string expectedResult = + "<result id=\"28482-98726-73623\" queryid=\"f27\" xmlns=\"urn:xmpp:mam:0\">" + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>" + "</result>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(result)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMResultSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp new file mode 100644 index 0000000..641b856 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Elements/ResultSet.h> + +using namespace Swift; + +class ResultSetSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ResultSetSerializerTest); + CPPUNIT_TEST(testSerializeFull); + CPPUNIT_TEST(testSerializeMaxItems); + CPPUNIT_TEST(testSerializeFirst); + CPPUNIT_TEST(testSerializeFirstWithIndex); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerializeFull() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setMaxItems(100); + resultSet->setCount(800); + resultSet->setFirstIDIndex(123); + resultSet->setFirstID(std::string("stpeter@jabber.org")); + resultSet->setLastID(std::string("peterpan@neverland.lit")); + resultSet->setAfter(std::string("09af3-cc343-b409f")); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "<count>800</count>" + "<first index=\"123\">stpeter@jabber.org</first>" + "<last>peterpan@neverland.lit</last>" + "<after>09af3-cc343-b409f</after>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeMaxItems() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setMaxItems(100); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeFirst() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setFirstID(std::string("stpeter@jabber.org")); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first>stpeter@jabber.org</first>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeFirstWithIndex() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setFirstID(std::string("stpeter@jabber.org")); + resultSet->setFirstIDIndex(123); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first index=\"123\">stpeter@jabber.org</first>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ResultSetSerializerTest); diff --git a/Swiften/Serializer/StanzaSerializer.cpp b/Swiften/Serializer/StanzaSerializer.cpp index 9a4fd2c..b5f0b22 100644 --- a/Swiften/Serializer/StanzaSerializer.cpp +++ b/Swiften/Serializer/StanzaSerializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -23,9 +23,13 @@ StanzaSerializer::StanzaSerializer(const std::string& tag, PayloadSerializerColl } SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<Element> element) const { + return serialize(element, ""); +} + +SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<Element> element, const std::string& xmlns) const { boost::shared_ptr<Stanza> stanza(boost::dynamic_pointer_cast<Stanza>(element)); - XMLElement stanzaElement(tag_); + XMLElement stanzaElement(tag_, xmlns); if (stanza->getFrom().isValid()) { stanzaElement.setAttribute("from", stanza->getFrom()); } diff --git a/Swiften/Serializer/StanzaSerializer.h b/Swiften/Serializer/StanzaSerializer.h index db18aa2..d569d82 100644 --- a/Swiften/Serializer/StanzaSerializer.h +++ b/Swiften/Serializer/StanzaSerializer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013-2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -18,7 +18,8 @@ namespace Swift { public: StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers); - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element, const std::string& xmlns) const; virtual void setStanzaSpecificAttributes(boost::shared_ptr<Element>, XMLElement&) const = 0; private: -- cgit v0.10.2-6-g49f6