diff options
author | Jan Kaluza <hanzz.k@gmail.com> | 2011-04-12 11:36:52 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-04-18 19:11:42 (GMT) |
commit | e0578b8fc582d431cce61ecac833ecf7031f6e75 (patch) | |
tree | c03e5bbe9419c5e6aed19e22f06491801f9659c1 | |
parent | 92af1a97f318f7f623df3183e90e7e828fa2eeb9 (diff) | |
download | swift-e0578b8fc582d431cce61ecac833ecf7031f6e75.zip swift-e0578b8fc582d431cce61ecac833ecf7031f6e75.tar.bz2 |
Added Roster Item Exchange XEP support.
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
13 files changed, 349 insertions, 3 deletions
diff --git a/Swiften/Elements/RosterItemExchangePayload.cpp b/Swiften/Elements/RosterItemExchangePayload.cpp new file mode 100644 index 0000000..846e184 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Base/foreach.h" + +namespace Swift { + +RosterItemExchangePayload::RosterItemExchangePayload() { +} + +} diff --git a/Swiften/Elements/RosterItemExchangePayload.h b/Swiften/Elements/RosterItemExchangePayload.h new file mode 100644 index 0000000..f573039 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <string> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Elements/Payload.h" +#include "Swiften/JID/JID.h" + + +namespace Swift { + class RosterItemExchangePayload : public Payload { + public: + typedef boost::shared_ptr<RosterItemExchangePayload> ref; + + enum Action { Add, Modify, Delete }; + + struct Item { + Action action; + JID jid; + std::string name; + std::vector<std::string> groups; + }; + + typedef std::vector<RosterItemExchangePayload::Item> RosterItemExchangePayloadItems; + + public: + RosterItemExchangePayload(); + + void addItem(const RosterItemExchangePayload::Item& item) { + items_.push_back(item); + } + + const RosterItemExchangePayloadItems& getItems() const { + return items_; + } + + private: + RosterItemExchangePayloadItems items_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index e20c06d..5052e67 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -17,6 +17,7 @@ #include "Swiften/Parser/PayloadParsers/StartSessionParser.h" #include "Swiften/Parser/PayloadParsers/StatusParser.h" #include "Swiften/Parser/PayloadParsers/StatusShowParser.h" +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" #include "Swiften/Parser/PayloadParsers/RosterParser.h" #include "Swiften/Parser/PayloadParsers/SoftwareVersionParser.h" #include "Swiften/Parser/PayloadParsers/StorageParser.h" @@ -54,6 +55,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ErrorParser>("error"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SoftwareVersionParser>("query", "jabber:iq:version"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StorageParser>("storage", "storage:bookmarks"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterItemExchangeParser>("x", "http://jabber.org/protocol/rosterx"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterParser>("query", "jabber:iq:roster"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoInfoParser>("query", "http://jabber.org/protocol/disco#info"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoItemsParser>("query", "http://jabber.org/protocol/disco#items"))); diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp new file mode 100644 index 0000000..7d59cc3 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" +#include "Swiften/Parser/SerializingParser.h" + +namespace Swift { + +RosterItemExchangeParser::RosterItemExchangeParser() : level_(TopLevel), inItem_(false) { +} + +void RosterItemExchangeParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "item") { + inItem_ = true; + + currentItem_ = RosterItemExchangePayload::Item(); + + currentItem_.jid = JID(attributes.getAttribute("jid")); + currentItem_.name = attributes.getAttribute("name"); + + std::string action = attributes.getAttribute("action"); + if (action == "add") { + currentItem_.action = RosterItemExchangePayload::Add; + } + else if (action == "modify") { + currentItem_.action = RosterItemExchangePayload::Modify; + } + else if (action == "delete") { + currentItem_.action = RosterItemExchangePayload::Delete; + } + else { + // Add is default action according to XEP + currentItem_.action = RosterItemExchangePayload::Add; + } + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentText_ = ""; + } + } + ++level_; +} + +void RosterItemExchangeParser::handleEndElement(const std::string& element, const std::string& /*ns*/) { + --level_; + if (level_ == PayloadLevel) { + if (inItem_) { + getPayloadInternal()->addItem(currentItem_); + inItem_ = false; + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentItem_.groups.push_back(currentText_); + } + } +} + +void RosterItemExchangeParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} + +} diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h new file mode 100644 index 0000000..3d6b8f4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class SerializingParser; + + class RosterItemExchangeParser : public GenericPayloadParser<RosterItemExchangePayload> { + public: + RosterItemExchangeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + ItemLevel = 2 + }; + int level_; + bool inItem_; + RosterItemExchangePayload::Item currentItem_; + std::string currentText_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp new file mode 100644 index 0000000..ceba45f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" + +using namespace Swift; + +class RosterItemExchangeParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>")); + + RosterItemExchangePayload* payload = dynamic_cast<RosterItemExchangePayload*>(parser.getPayload().get()); + const RosterItemExchangePayload::RosterItemExchangePayloadItems& items = payload->getItems(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), items[0].jid); + CPPUNIT_ASSERT_EQUAL(std::string("Foo @ Bar"), items[0].name); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Add, items[0].action); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items[0].groups.size()); + CPPUNIT_ASSERT_EQUAL(std::string("Group 1"), items[0].groups[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Group 2"), items[0].groups[1]); + + CPPUNIT_ASSERT_EQUAL(JID("baz@blo.com"), items[1].jid); + CPPUNIT_ASSERT_EQUAL(std::string("Baz"), items[1].name); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Modify, items[1].action); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), items[1].groups.size()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeParserTest); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 2bd5aff..03e4208 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -38,6 +38,7 @@ sources = [ "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", + "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", "PayloadParsers/SecurityLabelParser.cpp", "PayloadParsers/SecurityLabelsCatalogParser.cpp", diff --git a/Swiften/Roster/SetRosterRequest.h b/Swiften/Roster/SetRosterRequest.h index e5ae974..2066089 100644 --- a/Swiften/Roster/SetRosterRequest.h +++ b/Swiften/Roster/SetRosterRequest.h @@ -18,12 +18,12 @@ namespace Swift { public: typedef boost::shared_ptr<SetRosterRequest> ref; - static ref create(RosterPayload::ref payload, IQRouter* router) { - return ref(new SetRosterRequest(payload, router)); + static ref create(RosterPayload::ref payload, IQRouter* router, const JID& to = JID()) { + return ref(new SetRosterRequest(payload, router, to)); } private: - SetRosterRequest(boost::shared_ptr<RosterPayload> payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr<RosterPayload>(payload), router) { + SetRosterRequest(boost::shared_ptr<RosterPayload> payload, IQRouter* router, const JID& to) : Request(IQ::Set, to, boost::shared_ptr<RosterPayload>(payload), router) { } virtual void handleResponse(boost::shared_ptr<Payload> /*payload*/, ErrorPayload::ref error) { diff --git a/Swiften/SConscript b/Swiften/SConscript index d66bfb3..57c95fc 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -73,6 +73,7 @@ if env["SCONS_STAGE"] == "build" : "Elements/Element.cpp", "Elements/IQ.cpp", "Elements/Payload.cpp", + "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", "Elements/Stanza.cpp", "Elements/VCard.cpp", @@ -117,6 +118,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", + "Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp", @@ -235,6 +237,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/IBBParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp"), @@ -276,6 +279,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp"), diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 1bbcbf2..0f05580 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -14,6 +14,7 @@ #include "Swiften/Serializer/PayloadSerializers/PrioritySerializer.h" #include "Swiften/Serializer/PayloadSerializers/ErrorSerializer.h" #include "Swiften/Serializer/PayloadSerializers/RosterSerializer.h" +#include "Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h" #include "Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h" #include "Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h" #include "Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h" @@ -51,6 +52,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new PrioritySerializer()); serializers_.push_back(new ErrorSerializer()); serializers_.push_back(new RosterSerializer()); + serializers_.push_back(new RosterItemExchangeSerializer()); serializers_.push_back(new MUCPayloadSerializer()); serializers_.push_back(new MUCUserPayloadSerializer()); serializers_.push_back(new MUCOwnerPayloadSerializer(this)); diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp new file mode 100644 index 0000000..76c742c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h" + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Serializer/XML/XMLTextNode.h" +#include "Swiften/Serializer/XML/XMLRawTextNode.h" +#include "Swiften/Serializer/XML/XMLElement.h" + +namespace Swift { + +RosterItemExchangeSerializer::RosterItemExchangeSerializer() : GenericPayloadSerializer<RosterItemExchangePayload>() { +} + +std::string RosterItemExchangeSerializer::serializePayload(boost::shared_ptr<RosterItemExchangePayload> roster) const { + XMLElement queryElement("x", "http://jabber.org/protocol/rosterx"); + foreach(const RosterItemExchangePayload::Item& item, roster->getItems()) { + boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); + itemElement->setAttribute("jid", item.jid); + itemElement->setAttribute("name", item.name); + + switch (item.action) { + case RosterItemExchangePayload::Add: itemElement->setAttribute("action", "add"); break; + case RosterItemExchangePayload::Modify: itemElement->setAttribute("action", "modify"); break; + case RosterItemExchangePayload::Delete: itemElement->setAttribute("action", "delete"); break; + default: itemElement->setAttribute("action", "add"); break; + } + + foreach(const std::string& group, item.groups) { + boost::shared_ptr<XMLElement> groupElement(new XMLElement("group")); + groupElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(group))); + itemElement->addNode(groupElement); + } + + queryElement.addNode(itemElement); + } + + return queryElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h new file mode 100644 index 0000000..ec2cc13 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Serializer/GenericPayloadSerializer.h" +#include "Swiften/Elements/RosterItemExchangePayload.h" + +namespace Swift { + class RosterItemExchangeSerializer : public GenericPayloadSerializer<RosterItemExchangePayload> { + public: + RosterItemExchangeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<RosterItemExchangePayload>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp new file mode 100644 index 0000000..0fb44c9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h" + +using namespace Swift; + +class RosterItemExchangeSerializerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + RosterItemExchangeSerializerTest() {} + + void testSerialize() { + RosterItemExchangeSerializer testling; + boost::shared_ptr<RosterItemExchangePayload> roster(new RosterItemExchangePayload()); + + RosterItemExchangePayload::Item item1; + item1.jid = JID("foo@bar.com"); + item1.name = "Foo @ Bar"; + item1.action = RosterItemExchangePayload::Add; + item1.groups.push_back("Group 1"); + item1.groups.push_back("Group 2"); + roster->addItem(item1); + + RosterItemExchangePayload::Item item2; + item2.jid = JID("baz@blo.com"); + item2.name = "Baz"; + item2.action = RosterItemExchangePayload::Modify; + roster->addItem(item2); + + std::string expectedResult = + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeSerializerTest); |