From a4e59529239902ac352e791767db63a31e2e0634 Mon Sep 17 00:00:00 2001
From: Jan Kaluza <hanzz.k@gmail.com>
Date: Thu, 14 Apr 2011 10:50:27 +0200
Subject: Added support for JID Escaping XEP.

License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php

diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp
index e4611b3..5fd7524 100644
--- a/Swiften/JID/JID.cpp
+++ b/Swiften/JID/JID.cpp
@@ -13,6 +13,7 @@
 #ifdef SWIFTEN_CACHE_JID_PREP
 #include <boost/unordered_map.hpp>
 #endif
+#include <boost/algorithm/string/replace.hpp>
 #include <stringprep.h>
 
 #include <Swiften/Base/String.h>
@@ -126,5 +127,40 @@ int JID::compare(const Swift::JID& o, CompareType compareType) const {
 	return 0;
 }
 
+std::string JID::getEscapedNode(const std::string& node) {
+	std::string escaped = node;
+	
+	boost::algorithm::replace_all(escaped, "\\", "\\5c");
+	boost::algorithm::replace_all(escaped, " ", "\\20");
+	boost::algorithm::replace_all(escaped, "\"", "\\22");
+	boost::algorithm::replace_all(escaped, "&", "\\26");
+	boost::algorithm::replace_all(escaped, "'", "\\27");
+	boost::algorithm::replace_all(escaped, "/", "\\2f");
+	boost::algorithm::replace_all(escaped, "<", "\\3c");
+	boost::algorithm::replace_all(escaped, ">", "\\3e");
+	boost::algorithm::replace_all(escaped, "@", "\\40");
+	boost::algorithm::replace_all(escaped, ":", "\\3a");
+
+	return escaped;
+}
+
+std::string JID::getUnescapedNode() const {
+	std::string unescaped = node_;
+
+	boost::algorithm::replace_all(unescaped, "\\20", " ");
+	boost::algorithm::replace_all(unescaped, "\\22", "\"");
+	boost::algorithm::replace_all(unescaped, "\\26", "&");
+	boost::algorithm::replace_all(unescaped, "\\27", "'");
+	boost::algorithm::replace_all(unescaped, "\\2f", "/");
+	boost::algorithm::replace_all(unescaped, "\\3c", "<");
+	boost::algorithm::replace_all(unescaped, "\\3e", ">");
+	boost::algorithm::replace_all(unescaped, "\\40", "@");
+	boost::algorithm::replace_all(unescaped, "\\3a", ":");
+	boost::algorithm::replace_all(unescaped, "\\5c", "\\");
+	
+
+	return unescaped;
+}
+
 } // namespace Swift
 
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h
index 9f447db..f2a95be 100644
--- a/Swiften/JID/JID.h
+++ b/Swiften/JID/JID.h
@@ -38,6 +38,10 @@ namespace Swift {
 				return !hasResource_;
 			}
 
+			static std::string getEscapedNode(const std::string& node);
+
+			std::string getUnescapedNode() const;
+
 			JID toBare() const {
 				JID result(*this);
 				result.hasResource_ = false;
diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp
index 0f22e15..619df7f 100644
--- a/Swiften/JID/UnitTest/JIDTest.cpp
+++ b/Swiften/JID/UnitTest/JIDTest.cpp
@@ -51,6 +51,8 @@ class JIDTest : public CppUnit::TestFixture
 		CPPUNIT_TEST(testSmallerThan_Larger);
 		CPPUNIT_TEST(testHasResource);
 		CPPUNIT_TEST(testHasResource_NoResource);
+		CPPUNIT_TEST(testGetEscapedNode);
+		CPPUNIT_TEST(testGetUnescapedNode);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -311,6 +313,21 @@ class JIDTest : public CppUnit::TestFixture
 
 			CPPUNIT_ASSERT(testling.isBare());
 		}
+
+		void testGetEscapedNode() {
+			std::string escaped = JID::getEscapedNode("alice@wonderland.lit");
+			CPPUNIT_ASSERT_EQUAL(std::string("alice\\40wonderland.lit"), escaped);
+
+			escaped = JID::getEscapedNode("\\& \" ' / <\\\\> @ :\\3a\\40");
+			CPPUNIT_ASSERT_EQUAL(std::string("\\5c\\26\\20\\22\\20\\27\\20\\2f\\20\\3c\\5c\\5c\\3e\\20\\40\\20\\3a\\5c3a\\5c40"), escaped);
+		}
+
+		void testGetUnescapedNode() {
+			std::string input = "\\& \" ' / <\\\\> @ : \\5c\\40";
+			JID testling(JID::getEscapedNode(input) + "@y");
+			CPPUNIT_ASSERT(testling.isValid());
+			CPPUNIT_ASSERT_EQUAL(input, testling.getUnescapedNode());
+		}
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest);
-- 
cgit v0.10.2-6-g49f6