From db95fac71be96a8279d987edf2abc1fa448c0cae Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Mon, 30 May 2011 10:15:50 +0100
Subject: Allow payloads inside Errors


diff --git a/Swiften/Elements/ErrorPayload.h b/Swiften/Elements/ErrorPayload.h
index 9245a83..6d31a98 100644
--- a/Swiften/Elements/ErrorPayload.h
+++ b/Swiften/Elements/ErrorPayload.h
@@ -69,9 +69,18 @@ namespace Swift {
 				return text_; 
 			}
 
+			void setPayload(boost::shared_ptr<Payload> payload) {
+				payload_ = payload;
+			}
+
+			boost::shared_ptr<Payload> getPayload() {
+				return payload_;
+			}
+
 		private:
 			Type type_;
 			Condition condition_;
 			std::string text_;
+			boost::shared_ptr<Payload> payload_;
 	};
 }
diff --git a/Swiften/Parser/PayloadParsers/ErrorParser.cpp b/Swiften/Parser/PayloadParsers/ErrorParser.cpp
index 74eb31d..1b0094e 100644
--- a/Swiften/Parser/PayloadParsers/ErrorParser.cpp
+++ b/Swiften/Parser/PayloadParsers/ErrorParser.cpp
@@ -5,13 +5,15 @@
  */
 
 #include <Swiften/Parser/PayloadParsers/ErrorParser.h>
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
 
 namespace Swift {
 
-ErrorParser::ErrorParser() : level_(TopLevel) {
+ErrorParser::ErrorParser(PayloadParserFactoryCollection* factories) : factories(factories), level_(TopLevel) {
 }
 
-void ErrorParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) {
+void ErrorParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
 	if (level_ == TopLevel) {
 		std::string type = attributes.getAttribute("type");
 		if (type == "continue") {
@@ -30,14 +32,9 @@ void ErrorParser::handleStartElement(const std::string&, const std::string&, con
 			getPayloadInternal()->setType(ErrorPayload::Cancel);
 		}
 	}
-	++level_;
-}
-
-void ErrorParser::handleEndElement(const std::string& element, const std::string&) {
-	--level_;
-	if (level_ == PayloadLevel) {
+	else if (level_ == PayloadLevel) {
 		if (element == "text") {
-			getPayloadInternal()->setText(currentText_);
+
 		}
 		else if (element == "bad-request") {
 			getPayloadInternal()->setCondition(ErrorPayload::BadRequest);
@@ -103,13 +100,46 @@ void ErrorParser::handleEndElement(const std::string& element, const std::string
 			getPayloadInternal()->setCondition(ErrorPayload::UnexpectedRequest);
 		}
 		else {
-			getPayloadInternal()->setCondition(ErrorPayload::UndefinedCondition);
+			PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes);
+			if (payloadParserFactory) {
+				currentPayloadParser.reset(payloadParserFactory->createPayloadParser());
+			} else {
+				getPayloadInternal()->setCondition(ErrorPayload::UndefinedCondition);
+			}
+		}
+	}
+	if (level_ >= PayloadLevel && currentPayloadParser.get()) {
+		currentPayloadParser->handleStartElement(element, ns, attributes);
+	}
+	++level_;
+}
+
+void ErrorParser::handleEndElement(const std::string& element, const std::string& ns) {
+	--level_;
+	if (currentPayloadParser.get()) {
+		if (level_ >= PayloadLevel) {
+			currentPayloadParser->handleEndElement(element, ns);
+		}
+
+		if (level_ == PayloadLevel) {
+			getPayloadInternal()->setPayload(currentPayloadParser->getPayload());
+			currentPayloadParser.reset();
+		}
+	}
+	else if (level_ == PayloadLevel) {
+		if (element == "text") {
+			getPayloadInternal()->setText(currentText_);
 		}
 	}
 }
 
 void ErrorParser::handleCharacterData(const std::string& data) {
-	currentText_ += data;
+	if (level_ > PayloadLevel && currentPayloadParser.get()) {
+		currentPayloadParser->handleCharacterData(data);
+	}
+	else {
+		currentText_ += data;
+	}
 }
 
 }
diff --git a/Swiften/Parser/PayloadParsers/ErrorParser.h b/Swiften/Parser/PayloadParsers/ErrorParser.h
index 0093cb4..b2d05cf 100644
--- a/Swiften/Parser/PayloadParsers/ErrorParser.h
+++ b/Swiften/Parser/PayloadParsers/ErrorParser.h
@@ -10,9 +10,10 @@
 #include <Swiften/Parser/GenericPayloadParser.h>
 
 namespace Swift {
+	class PayloadParserFactoryCollection;
 	class ErrorParser : public GenericPayloadParser<ErrorPayload> {
 		public:
-			ErrorParser();
+			ErrorParser(PayloadParserFactoryCollection* factories);
 
 			virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
 			virtual void handleEndElement(const std::string& element, const std::string&);
@@ -23,7 +24,9 @@ namespace Swift {
 				TopLevel = 0, 
 				PayloadLevel = 1
 			};
+			PayloadParserFactoryCollection* factories;
 			int level_;
 			std::string currentText_;
+			boost::shared_ptr<PayloadParser> currentPayloadParser;
 	};
 }
diff --git a/Swiften/Parser/PayloadParsers/ErrorParserFactory.h b/Swiften/Parser/PayloadParsers/ErrorParserFactory.h
new file mode 100644
index 0000000..8616cbc
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/ErrorParserFactory.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/ErrorParser.h>
+
+namespace Swift {
+	class PayloadParserFactoryCollection;
+
+	class ErrorParserFactory : public PayloadParserFactory {
+		public:
+			ErrorParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) {
+			}
+
+			virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const {
+				return element == "error";
+			}
+
+			virtual PayloadParser* createPayloadParser() {
+				return new ErrorParser(factories);
+			}
+
+		private:
+			PayloadParserFactoryCollection* factories;
+
+	};
+}
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index db9c371..8d75089 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -9,6 +9,7 @@
 #include <Swiften/Parser/GenericPayloadParser.h>
 #include <Swiften/Parser/PayloadParserFactory.h>
 #include <Swiften/Parser/PayloadParsers/ErrorParser.h>
+#include <Swiften/Parser/PayloadParsers/ErrorParserFactory.h>
 #include <Swiften/Parser/PayloadParsers/BodyParser.h>
 #include <Swiften/Parser/PayloadParsers/SubjectParser.h>
 #include <Swiften/Parser/PayloadParsers/ChatStateParserFactory.h>
@@ -54,7 +55,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
 	factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BodyParser>("body")));
 	factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SubjectParser>("subject")));
 	factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<PriorityParser>("priority")));
-	factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ErrorParser>("error")));
+	factories_.push_back(shared_ptr<PayloadParserFactory>(new ErrorParserFactory(this)));
 	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")));
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp
index dd3d167..005fc09 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp
@@ -9,12 +9,14 @@
 
 #include <Swiften/Parser/PayloadParsers/ErrorParser.h>
 #include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+#include <Swiften/Elements/Delay.h>
 
 using namespace Swift;
 
 class ErrorParserTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST_SUITE(ErrorParserTest);
 		CPPUNIT_TEST(testParse);
+		CPPUNIT_TEST(testParseWithPayload);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -31,7 +33,26 @@ class ErrorParserTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT_EQUAL(ErrorPayload::BadRequest, payload->getCondition());
 			CPPUNIT_ASSERT_EQUAL(ErrorPayload::Modify, payload->getType());
 			CPPUNIT_ASSERT_EQUAL(std::string("boo"), payload->getText());
+			CPPUNIT_ASSERT(!payload->getPayload());
 		}
+
+		void testParseWithPayload() {
+			PayloadsParserTester parser;
+
+			CPPUNIT_ASSERT(parser.parse(
+					"<error type=\"modify\">"
+					"<bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+					"<delay xmlns='urn:xmpp:delay' from='juliet@capulet.com/balcony' stamp='2002-09-10T23:41:07Z'/>"
+					"<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">boo</text>"
+					"</error>"));
+
+			ErrorPayload::ref payload = boost::dynamic_pointer_cast<ErrorPayload>(parser.getPayload());
+			CPPUNIT_ASSERT_EQUAL(ErrorPayload::BadRequest, payload->getCondition());
+			CPPUNIT_ASSERT_EQUAL(ErrorPayload::Modify, payload->getType());
+			CPPUNIT_ASSERT_EQUAL(std::string("boo"), payload->getText());
+			CPPUNIT_ASSERT(boost::dynamic_pointer_cast<Delay>(payload->getPayload()));
+		}
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ErrorParserTest);
-- 
cgit v0.10.2-6-g49f6