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; + }; +} |