From 0630c01cf274a9de6b67856b8c00b1503b39353e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sun, 5 Sep 2010 13:01:20 +0200
Subject: Don't lose unknown roster content.

Resolves: #555

diff --git a/Swiften/Elements/RosterItemPayload.h b/Swiften/Elements/RosterItemPayload.h
index 9120e12..84b2887 100644
--- a/Swiften/Elements/RosterItemPayload.h
+++ b/Swiften/Elements/RosterItemPayload.h
@@ -37,12 +37,18 @@ namespace Swift {
 			void setSubscriptionRequested() { ask_ = true; }
 			bool getSubscriptionRequested() const { return ask_; }
 
+			const String& getUnknownContent() const { return unknownContent_; }
+			void addUnknownContent(const String& c) { 
+				unknownContent_ += c;
+			}
+
 		private:
 			JID jid_;
 			String name_;
 			Subscription subscription_;
 			std::vector<String> groups_;
 			bool ask_;
+			String unknownContent_;
 	};
 }
 
diff --git a/Swiften/Parser/PayloadParsers/RosterParser.cpp b/Swiften/Parser/PayloadParsers/RosterParser.cpp
index b35c035..c3a35b6 100644
--- a/Swiften/Parser/PayloadParsers/RosterParser.cpp
+++ b/Swiften/Parser/PayloadParsers/RosterParser.cpp
@@ -5,13 +5,14 @@
  */
 
 #include "Swiften/Parser/PayloadParsers/RosterParser.h"
+#include "Swiften/Parser/SerializingParser.h"
 
 namespace Swift {
 
-RosterParser::RosterParser() : level_(TopLevel) {
+RosterParser::RosterParser() : level_(TopLevel), unknownContentParser_(0) {
 }
 
-void RosterParser::handleStartElement(const String& element, const String&, const AttributeMap& attributes) {
+void RosterParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) {
 	if (level_ == PayloadLevel) {
 		if (element == "item") {
 			inItem_ = true;
@@ -46,11 +47,19 @@ void RosterParser::handleStartElement(const String& element, const String&, cons
 		if (element == "group") {
 			currentText_ = "";
 		}
+		else {
+			assert(!unknownContentParser_);
+			unknownContentParser_ = new SerializingParser();
+			unknownContentParser_->handleStartElement(element, ns, attributes);
+		}
+	}
+	else if (unknownContentParser_) {
+		unknownContentParser_->handleStartElement(element, ns, attributes);
 	}
 	++level_;
 }
 
-void RosterParser::handleEndElement(const String& element, const String&) {
+void RosterParser::handleEndElement(const String& element, const String& ns) {
 	--level_;
 	if (level_ == PayloadLevel) {
 		if (inItem_) {
@@ -59,14 +68,27 @@ void RosterParser::handleEndElement(const String& element, const String&) {
 		}
 	}
 	else if (level_ == ItemLevel) {
-		if (element == "group") {
+		if (unknownContentParser_) {
+			unknownContentParser_->handleEndElement(element, ns);
+			currentItem_.addUnknownContent(unknownContentParser_->getResult());
+			unknownContentParser_ = NULL;
+		}
+		else if (element == "group") {
 			currentItem_.addGroup(currentText_);
 		}
 	}
+	else if (unknownContentParser_) {
+		unknownContentParser_->handleEndElement(element, ns);
+	}
 }
 
 void RosterParser::handleCharacterData(const String& data) {
-	currentText_ += data;
+	if (unknownContentParser_) {
+		unknownContentParser_->handleCharacterData(data);
+	}
+	else {
+		currentText_ += data;
+	}
 }
 
 }
diff --git a/Swiften/Parser/PayloadParsers/RosterParser.h b/Swiften/Parser/PayloadParsers/RosterParser.h
index a039ff4..4a28618 100644
--- a/Swiften/Parser/PayloadParsers/RosterParser.h
+++ b/Swiften/Parser/PayloadParsers/RosterParser.h
@@ -11,6 +11,8 @@
 #include "Swiften/Parser/GenericPayloadParser.h"
 
 namespace Swift {
+	class SerializingParser;
+
 	class RosterParser : public GenericPayloadParser<RosterPayload> {
 		public:
 			RosterParser();
@@ -29,6 +31,7 @@ namespace Swift {
 			bool inItem_;
 			RosterItemPayload currentItem_;
 			String currentText_;
+			SerializingParser* unknownContentParser_;
 	};
 }
 
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp
index e085d58..aea9dc4 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp
@@ -16,6 +16,7 @@ class RosterParserTest : public CppUnit::TestFixture
 {
 		CPPUNIT_TEST_SUITE(RosterParserTest);
 		CPPUNIT_TEST(testParse);
+		CPPUNIT_TEST(testParse_ItemWithUnknownContent);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -51,6 +52,30 @@ class RosterParserTest : public CppUnit::TestFixture
 			CPPUNIT_ASSERT(!items[1].getSubscriptionRequested());
 			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), items[1].getGroups().size());
 		}
+
+		void testParse_ItemWithUnknownContent() {
+			PayloadsParserTester parser;
+			parser.parse(
+				"<query xmlns='jabber:iq:roster'>"
+				"	<item jid='foo@bar.com' name='Foo @ Bar' subscription='from' ask='subscribe'>"
+				"		<group>Group 1</group>"
+				"		<foo xmlns=\"http://example.com\"><bar>Baz</bar></foo>"
+				"		<group>Group 2</group>"
+				"		<baz><fum>foo</fum></baz>"
+				"	</item>"
+				"</query>");
+
+			RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get());
+			const RosterPayload::RosterItemPayloads& items = payload->getItems();
+
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), items.size());
+			CPPUNIT_ASSERT_EQUAL(String("Group 1"), items[0].getGroups()[0]);
+			CPPUNIT_ASSERT_EQUAL(String("Group 2"), items[0].getGroups()[1]);
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<foo xmlns=\"http://example.com\"><bar xmlns=\"http://example.com\">Baz</bar></foo>"
+				"<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>"
+				), items[0].getUnknownContent());
+		}
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(RosterParserTest);
diff --git a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp
index fc3c03a..b56f404 100644
--- a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp
@@ -10,6 +10,7 @@
 
 #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 {
@@ -42,6 +43,11 @@ String RosterSerializer::serializePayload(boost::shared_ptr<RosterPayload> roste
 			itemElement->addNode(groupElement);
 		}
 
+		if (!item.getUnknownContent().isEmpty()) {
+			itemElement->addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(item.getUnknownContent())));
+		}
+
+
 		queryElement.addNode(itemElement);
 	}
 
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp
index fdf93a9..bf30db8 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp
@@ -15,6 +15,7 @@ class RosterSerializerTest : public CppUnit::TestFixture
 {
 		CPPUNIT_TEST_SUITE(RosterSerializerTest);
 		CPPUNIT_TEST(testSerialize);
+		CPPUNIT_TEST(testSerialize_ItemWithUnknownContent);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -49,6 +50,33 @@ class RosterSerializerTest : public CppUnit::TestFixture
 
 			CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster));
 		}
+
+		void testSerialize_ItemWithUnknownContent() {
+			RosterSerializer testling;
+			boost::shared_ptr<RosterPayload> roster(new RosterPayload());
+
+			RosterItemPayload item;
+			item.setJID(JID("baz@blo.com"));
+			item.setName("Baz");
+			item.addGroup("Group 1");
+			item.addGroup("Group 2");
+			item.addUnknownContent(String(
+				"<foo xmlns=\"http://example.com\"><bar xmlns=\"http://example.com\">Baz</bar></foo>"
+				"<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>"));
+			roster->addItem(item);
+
+			String expectedResult = 
+				"<query xmlns=\"jabber:iq:roster\">"
+					"<item jid=\"baz@blo.com\" name=\"Baz\" subscription=\"none\">"
+						"<group>Group 1</group>"
+						"<group>Group 2</group>"
+						"<foo xmlns=\"http://example.com\"><bar xmlns=\"http://example.com\">Baz</bar></foo>"
+						"<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>"
+					"</item>"
+				"</query>";
+
+			CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster));
+		}
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(RosterSerializerTest);
-- 
cgit v0.10.2-6-g49f6