From 76d967cf7cef073501d152cb4863af418e74cdbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Wed, 17 Nov 2010 21:04:40 +0100 Subject: Added search parserialement. 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 +#include + +#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 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& getInstructions() const { + return instructions; + } + + const boost::optional& getNick() const { + return nick; + } + + const boost::optional& getFirst() const { + return first; + } + + const boost::optional& getLast() const { + return last; + } + + const boost::optional& 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 getItems() const { + return items; + } + + void addItem(const Item& item) { + items.push_back(item); + } + + private: + Form::ref form; + boost::optional instructions; + boost::optional nick; + boost::optional first; + boost::optional last; + boost::optional email; + std::vector 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(new FormParserFactory())); factories_.push_back(shared_ptr(new CommandParserFactory())); factories_.push_back(shared_ptr(new InBandRegistrationPayloadParserFactory())); + factories_.push_back(shared_ptr(new SearchPayloadParserFactory())); factories_.push_back(shared_ptr(new StreamInitiationParserFactory())); factories_.push_back(shared_ptr(new BytestreamsParserFactory())); factories_.push_back(shared_ptr(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(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 + +#include "Swiften/Elements/SearchPayload.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class FormParserFactory; + class FormParser; + + class SearchPayloadParser : public GenericPayloadParser { + 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 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 { + public: + SearchPayloadParserFactory() : GenericPayloadParserFactory("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 +#include + +#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( + "" + "Foo" + "" + "" + "" + )); + + SearchPayload::ref payload = parser.getPayload(); + 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( + "" + "" + "Juliet" + "Capulet" + "JuliC" + "juliet@shakespeare.lit" + "" + "" + "Tybalt" + "Capulet" + "ty" + "tybalt@shakespeare.lit" + "" + "" + )); + + SearchPayload::ref payload = parser.getPayload(); + CPPUNIT_ASSERT_EQUAL(2, static_cast(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 + +#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) 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(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 { + public: + SearchPayloadSerializer(); + + virtual String serializePayload(boost::shared_ptr) const; + }; +} -- cgit v0.10.2-6-g49f6