diff options
| -rw-r--r-- | Swiften/Elements/SearchPayload.h | 94 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp | 2 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp | 110 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/SearchPayloadParser.h | 39 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h | 17 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp | 71 | ||||
| -rw-r--r-- | Swiften/Parser/SConscript | 1 | ||||
| -rw-r--r-- | Swiften/SConscript | 3 | ||||
| -rw-r--r-- | Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp | 62 | ||||
| -rw-r--r-- | Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h | 22 | 
10 files changed, 421 insertions, 0 deletions
| diff --git a/Swiften/Elements/SearchPayload.h b/Swiften/Elements/SearchPayload.h new file mode 100644 index 0000000..61b8547 --- /dev/null +++ b/Swiften/Elements/SearchPayload.h @@ -0,0 +1,94 @@ +/* + * 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 <boost/shared_ptr.hpp> +#include <boost/optional.hpp> + +#include "Swiften/Elements/Payload.h" +#include "Swiften/Elements/Form.h" +#include "Swiften/Base/String.h" + +namespace Swift { +	/** +	 * XEP-0055 search payload. +	 */ +	class SearchPayload : public Payload { +		public: +			typedef boost::shared_ptr<SearchPayload> ref; + +			struct Item { +				String first; +				String last; +				String nick; +				String email; +				JID jid; +			}; + +			SearchPayload() {} + +			Form::ref getForm() const { return form; } +			void setForm(Form::ref f) { form = f; } + +			const boost::optional<String>& getInstructions() const { +				return instructions; +			} + +			const boost::optional<String>& getNick() const { +				return nick; +			} + +			const boost::optional<String>& getFirst() const { +				return first; +			} + +			const boost::optional<String>& getLast() const { +				return last; +			} + +			const boost::optional<String>& getEMail() const { +				return email; +			} + +			void setInstructions(const String& v) { +				this->instructions = v; +			} + +			void setNick(const String& v) { +				this->nick = v; +			} + +			void setFirst(const String& v) { +				this->first = v; +			} + +			void setLast(const String& v) { +				this->last = v; +			} + +			void setEMail(const String& v) { +				this->email = v; +			} + +			const std::vector<Item> getItems() const { +				return items; +			} + +			void addItem(const Item& item) { +				items.push_back(item); +			} + +		private: +			Form::ref form; +			boost::optional<String> instructions; +			boost::optional<String> nick; +			boost::optional<String> first; +			boost::optional<String> last; +			boost::optional<String> email; +			std::vector<Item> items; +	}; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 41bba11..70dd81e 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -28,6 +28,7 @@  #include "Swiften/Parser/PayloadParsers/FormParserFactory.h"  #include "Swiften/Parser/PayloadParsers/CommandParserFactory.h"  #include "Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h" +#include "Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h"  #include "Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h"  #include "Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h"  #include "Swiften/Parser/PayloadParsers/IBBParserFactory.h" @@ -64,6 +65,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {  	factories_.push_back(shared_ptr<PayloadParserFactory>(new FormParserFactory()));  	factories_.push_back(shared_ptr<PayloadParserFactory>(new CommandParserFactory()));  	factories_.push_back(shared_ptr<PayloadParserFactory>(new InBandRegistrationPayloadParserFactory())); +	factories_.push_back(shared_ptr<PayloadParserFactory>(new SearchPayloadParserFactory()));  	factories_.push_back(shared_ptr<PayloadParserFactory>(new StreamInitiationParserFactory()));  	factories_.push_back(shared_ptr<PayloadParserFactory>(new BytestreamsParserFactory()));  	factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardUpdateParserFactory())); diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp b/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp new file mode 100644 index 0000000..f2cf1dd --- /dev/null +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/SearchPayloadParser.h" +#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" +#include "Swiften/Parser/PayloadParsers/FormParser.h" + +namespace Swift { + +SearchPayloadParser::SearchPayloadParser() : level(TopLevel), formParser(NULL)  { +	formParserFactory = new FormParserFactory(); +} + +SearchPayloadParser::~SearchPayloadParser() { +	delete formParserFactory; +} + +void SearchPayloadParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) { +	if (level == TopLevel) { +	} +	else if (level == PayloadLevel) { +		if (element == "x" && ns == "jabber:x:data") { +			assert(!formParser); +			formParser = dynamic_cast<FormParser*>(formParserFactory->createPayloadParser()); +		} +		else if (element == "item") { +			assert(!currentItem); +			currentItem.reset(SearchPayload::Item()); +			currentItem->jid = JID(attributes.getAttribute("jid")); +		} +		else { +			currentText.clear(); +		} +	} +	else if (level == ItemLevel && currentItem) { +		currentText.clear(); +	} + +	if (formParser) { +		formParser->handleStartElement(element, ns, attributes); +	} + +	++level; +} + +void SearchPayloadParser::handleEndElement(const String& element, const String& ns) { +	--level; + +	if (formParser) { +		formParser->handleEndElement(element, ns); +	} + +	if (level == TopLevel) { +	} +	else if (level == PayloadLevel) { +		if (formParser) { +			getPayloadInternal()->setForm(formParser->getPayloadInternal()); +			delete formParser; +			formParser = NULL; +		} +		else if (element == "item") { +			assert(currentItem); +			getPayloadInternal()->addItem(*currentItem); +			currentItem.reset(); +		} +		else if (element == "instructions") { +			getPayloadInternal()->setInstructions(currentText); +		} +		else if (element == "nick") { +			getPayloadInternal()->setNick(currentText); +		} +		else if (element == "first") { +			getPayloadInternal()->setFirst(currentText); +		} +		else if (element == "last") { +			getPayloadInternal()->setLast(currentText); +		} +		else if (element == "email") { +			getPayloadInternal()->setEMail(currentText); +		} +	} +	else if (level == ItemLevel && currentItem) { +		if (element == "nick") { +			currentItem->nick = currentText; +		} +		else if (element == "first") { +			currentItem->first = currentText; +		} +		else if (element == "last") { +			currentItem->last = currentText; +		} +		else if (element == "email") { +			currentItem->email = currentText; +		} +	} +} + +void SearchPayloadParser::handleCharacterData(const String& data) { +	if (formParser) { +		formParser->handleCharacterData(data); +	} +	else { +		currentText += data; +	} +} + +} diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParser.h b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h new file mode 100644 index 0000000..55177b0 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h @@ -0,0 +1,39 @@ +/* + * 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 <boost/optional.hpp> + +#include "Swiften/Elements/SearchPayload.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { +	class FormParserFactory; +	class FormParser; + +	class SearchPayloadParser : public GenericPayloadParser<SearchPayload> { +		public: +			SearchPayloadParser(); +			~SearchPayloadParser(); + +			virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes); +			virtual void handleEndElement(const String& element, const String&); +			virtual void handleCharacterData(const String& data); + +		private: +			enum Level {  +				TopLevel = 0,  +				PayloadLevel = 1, +				ItemLevel = 2, +			}; +			int level; +			FormParserFactory* formParserFactory; +			FormParser* formParser; +			String currentText; +			boost::optional<SearchPayload::Item> currentItem; +	}; +} diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h new file mode 100644 index 0000000..0f8a6c7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h @@ -0,0 +1,17 @@ +/* + * 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 "Swiften/Parser/GenericPayloadParserFactory.h" +#include "Swiften/Parser/PayloadParsers/SearchPayloadParser.h" + +namespace Swift { +	class SearchPayloadParserFactory : public GenericPayloadParserFactory<SearchPayloadParser> { +		public: +			SearchPayloadParserFactory() : GenericPayloadParserFactory<SearchPayloadParser>("query", "jabber:iq:search") {} +	}; +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp new file mode 100644 index 0000000..1d94c15 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp @@ -0,0 +1,71 @@ +/* + * 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/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include "Swiften/Elements/SearchPayload.h" + +using namespace Swift; + +class SearchPayloadParserTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(SearchPayloadParserTest); +		CPPUNIT_TEST(testParse_FormRequestResponse); +		CPPUNIT_TEST(testParse_Results); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void testParse_FormRequestResponse() { +			PayloadsParserTester parser; + +			CPPUNIT_ASSERT(parser.parse( +					"<query xmlns=\"jabber:iq:search\">" +						"<instructions>Foo</instructions>" +						"<first/>" +						"<last/>" +					"</query>" +				)); + +			SearchPayload::ref payload = parser.getPayload<SearchPayload>(); +			CPPUNIT_ASSERT_EQUAL(String("Foo"), *payload->getInstructions()); +			CPPUNIT_ASSERT(payload->getFirst()); +			CPPUNIT_ASSERT(payload->getLast()); +			CPPUNIT_ASSERT(!payload->getNick()); +		} + +		void testParse_Results() { +			PayloadsParserTester parser; + +			CPPUNIT_ASSERT(parser.parse( +					"<query xmlns=\"jabber:iq:search\">" +						"<item jid=\"juliet@capulet.com\">" +							"<first>Juliet</first>" +							"<last>Capulet</last>" +							"<nick>JuliC</nick>" +							"<email>juliet@shakespeare.lit</email>" +						"</item>" +						"<item jid=\"tybalt@shakespeare.lit\">" +							"<first>Tybalt</first>" +							"<last>Capulet</last>" +							"<nick>ty</nick>" +							"<email>tybalt@shakespeare.lit</email>" +						"</item>" +					"</query>" +				)); + +			SearchPayload::ref payload = parser.getPayload<SearchPayload>(); +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getItems().size())); +			CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.com"), payload->getItems()[0].jid); +			CPPUNIT_ASSERT_EQUAL(String("Juliet"), payload->getItems()[0].first); +			CPPUNIT_ASSERT_EQUAL(String("Capulet"), payload->getItems()[0].last); +			CPPUNIT_ASSERT_EQUAL(String("JuliC"), payload->getItems()[0].nick); +			CPPUNIT_ASSERT_EQUAL(String("juliet@shakespeare.lit"), payload->getItems()[0].email); +			CPPUNIT_ASSERT_EQUAL(JID("tybalt@shakespeare.lit"), payload->getItems()[1].jid); +		} +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SearchPayloadParserTest); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 92d5aa9..29398f0 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -30,6 +30,7 @@ sources = [  		"PayloadParsers/IBBParser.cpp",  		"PayloadParsers/CommandParser.cpp",  		"PayloadParsers/InBandRegistrationPayloadParser.cpp", +		"PayloadParsers/SearchPayloadParser.cpp",  		"PayloadParsers/FullPayloadParserFactoryCollection.cpp",  		"PayloadParsers/PriorityParser.cpp",  		"PayloadParsers/PrivateStorageParser.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index 7da329b..335dfa5 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -98,6 +98,7 @@ if env["SCONS_STAGE"] == "build" :  			"Serializer/PayloadSerializers/DelaySerializer.cpp",  			"Serializer/PayloadSerializers/CommandSerializer.cpp",  			"Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.cpp", +			"Serializer/PayloadSerializers/SearchPayloadSerializer.cpp",  			"Serializer/PayloadSerializers/FormSerializer.cpp",  			"Serializer/PayloadSerializers/NicknameSerializer.cpp",  			"Serializer/PresenceSerializer.cpp", @@ -198,6 +199,7 @@ if env["SCONS_STAGE"] == "build" :  			File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/IBBParserTest.cpp"), +			File("Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp"), @@ -238,6 +240,7 @@ if env["SCONS_STAGE"] == "build" :  			File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"),  			File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"),  			File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), +			File("Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp"),  			File("Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp"),  			File("Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp"),  			File("Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp"), diff --git a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp new file mode 100644 index 0000000..5d71fd3 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h" + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Serializer/XML/XMLElement.h" +#include "Swiften/Serializer/XML/XMLRawTextNode.h" +#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" + +namespace Swift { + +SearchPayloadSerializer::SearchPayloadSerializer() { +} + +String SearchPayloadSerializer::serializePayload(boost::shared_ptr<SearchPayload> searchPayload)	const { +	XMLElement searchElement("query", "jabber:iq:search"); + +	if (searchPayload->getInstructions()) { +		searchElement.addNode(XMLElement::ref(new XMLElement("instructions", "", *searchPayload->getInstructions()))); +	} + +	if (searchPayload->getNick()) { +		searchElement.addNode(XMLElement::ref(new XMLElement("nick", "", *searchPayload->getNick()))); +	} + +	if (searchPayload->getFirst()) { +		searchElement.addNode(XMLElement::ref(new XMLElement("first", "", *searchPayload->getFirst()))); +	} + +	if (searchPayload->getLast()) { +		searchElement.addNode(XMLElement::ref(new XMLElement("last", "", *searchPayload->getLast()))); +	} + +	if (searchPayload->getEMail()) { +		searchElement.addNode(XMLElement::ref(new XMLElement("email", "", *searchPayload->getEMail()))); +	} + +	foreach(const SearchPayload::Item& item, searchPayload->getItems()) { +		XMLElement::ref itemElement(new XMLElement("item")); +		itemElement->setAttribute("jid", item.jid); +		itemElement->addNode(XMLElement::ref(new XMLElement("first", "", item.first))); +		itemElement->addNode(XMLElement::ref(new XMLElement("last", "", item.last))); +		itemElement->addNode(XMLElement::ref(new XMLElement("nick", "", item.nick))); +		itemElement->addNode(XMLElement::ref(new XMLElement("email", "", item.email))); + +		searchElement.addNode(itemElement); +	} + +	if (Form::ref form = searchPayload->getForm()) { +		searchElement.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(FormSerializer().serialize(form)))); +	} + +	return searchElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h new file mode 100644 index 0000000..b64749b --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h @@ -0,0 +1,22 @@ +/* + * 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 "Swiften/Serializer/GenericPayloadSerializer.h" +#include "Swiften/Elements/SearchPayload.h" + +namespace Swift { +	class PayloadSerializerCollection; + +	class SearchPayloadSerializer : public GenericPayloadSerializer<SearchPayload> { +		public: +			SearchPayloadSerializer(); + +			virtual String serializePayload(boost::shared_ptr<SearchPayload>)  const; +	}; +} | 
 Swift
 Swift