From 9eff25182d1bea576d1910200909384ce79d90fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Thu, 13 Dec 2012 14:35:53 +0100
Subject: Make IDN implementation abstract.

Change-Id: I4c64f954ddeca7147d729b8be07237baa15c1795

diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index 48e38b9..c5a5c23 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -56,10 +56,12 @@ namespace Swift {
 
 ClientSession::ClientSession(
 		const JID& jid, 
-		boost::shared_ptr<SessionStream> stream) :
+		boost::shared_ptr<SessionStream> stream,
+		IDNConverter* idnConverter) :
 			localJID(jid),	
 			state(Initial), 
 			stream(stream),
+			idnConverter(idnConverter),
 			allowPLAINOverNonTLS(false),
 			useStreamCompression(true),
 			useTLS(UseTLSWhenAvailable),
@@ -224,7 +226,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) {
 					plus &= !finishMessage.empty();
 				}
 				s << boost::uuids::random_generator()();
-				SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus);
+				SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus, idnConverter);
 				if (plus) {
 					scramAuthenticator->setTLSChannelBindingData(finishMessage);
 				}
@@ -378,7 +380,7 @@ void ClientSession::handleTLSEncrypted() {
 		checkTrustOrFinish(certificateChain, verificationError);
 	}
 	else {
-		ServerIdentityVerifier identityVerifier(localJID);
+		ServerIdentityVerifier identityVerifier(localJID, idnConverter);
 		if (!certificateChain.empty() && identityVerifier.certificateVerifies(certificateChain[0])) {
 			continueAfterTLSEncrypted();
 		}
diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h
index c17ec9b..842412d 100644
--- a/Swiften/Client/ClientSession.h
+++ b/Swiften/Client/ClientSession.h
@@ -22,6 +22,7 @@
 namespace Swift {
 	class ClientAuthenticator;
 	class CertificateTrustChecker;
+	class IDNConverter;
 
 	class SWIFTEN_API ClientSession : public boost::enable_shared_from_this<ClientSession> {
 		public:
@@ -66,8 +67,8 @@ namespace Swift {
 
 			~ClientSession();
 
-			static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream) {
-				return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream));
+			static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream, IDNConverter* idnConverter) {
+				return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream, idnConverter));
 			}
 
 			State getState() const {
@@ -131,7 +132,8 @@ namespace Swift {
 		private:
 			ClientSession(
 					const JID& jid, 
-					boost::shared_ptr<SessionStream>);
+					boost::shared_ptr<SessionStream>,
+					IDNConverter* idnConverter);
 
 			void finishSession(Error::Type error);
 			void finishSession(boost::shared_ptr<Swift::Error> error);
@@ -161,6 +163,7 @@ namespace Swift {
 			JID localJID;
 			State state;
 			boost::shared_ptr<SessionStream> stream;
+			IDNConverter* idnConverter;
 			bool allowPLAINOverNonTLS;
 			bool useStreamCompression;
 			UseTLS useTLS;
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 5e19b4b..07124ed 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -142,7 +142,7 @@ void CoreClient::connect(const ClientOptions& o) {
 }
 
 void CoreClient::bindSessionToStream() {
-	session_ = ClientSession::create(jid_, sessionStream_);
+	session_ = ClientSession::create(jid_, sessionStream_, networkFactories->getIDNConverter());
 	session_->setCertificateTrustChecker(certificateTrustChecker);
 	session_->setUseStreamCompression(options.useStreamCompression);
 	session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS);
diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp
index a8cd53c..63c922c 100644
--- a/Swiften/Client/UnitTest/ClientSessionTest.cpp
+++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp
@@ -11,6 +11,8 @@
 #include <boost/optional.hpp>
 #include <boost/smart_ptr/make_shared.hpp>
 
+#include <Swiften/IDN/IDNConverter.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
 #include <Swiften/Session/SessionStream.h>
 #include <Swiften/Client/ClientSession.h>
 #include <Swiften/Elements/Message.h>
@@ -69,6 +71,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
 
 	public:
 		void setUp() {
+			idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create());
 			server = boost::make_shared<MockSessionStream>();
 			sessionFinishedReceived = false;
 			needCredentials = false;
@@ -339,7 +342,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
 
 	private:
 		boost::shared_ptr<ClientSession> createSession() {
-			boost::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server);
+			boost::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server, idnConverter.get());
 			session->onFinished.connect(boost::bind(&ClientSessionTest::handleSessionFinished, this, _1));
 			session->onNeedCredentials.connect(boost::bind(&ClientSessionTest::handleSessionNeedCredentials, this));
 			session->setAllowPLAINOverNonTLS(true);
@@ -616,6 +619,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
 				std::deque<Event> receivedEvents;
 		};
 
+		boost::shared_ptr<IDNConverter> idnConverter;
 		boost::shared_ptr<MockSessionStream> server;
 		bool sessionFinishedReceived;
 		bool needCredentials;
diff --git a/Swiften/IDN/IDNA.h b/Swiften/IDN/IDNA.h
deleted file mode 100644
index 6ac51bf..0000000
--- a/Swiften/IDN/IDNA.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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 <string>
-
-#include <Swiften/Base/API.h>
-
-namespace Swift {
-	class SWIFTEN_API IDNA {
-		public:
-			static std::string getEncoded(const std::string& s);
-	};
-}
diff --git a/Swiften/IDN/IDNConverter.cpp b/Swiften/IDN/IDNConverter.cpp
new file mode 100644
index 0000000..7705812
--- /dev/null
+++ b/Swiften/IDN/IDNConverter.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/IDN/IDNConverter.h>
+
+namespace Swift {
+
+IDNConverter::~IDNConverter() {
+}
+
+}
diff --git a/Swiften/IDN/IDNConverter.h b/Swiften/IDN/IDNConverter.h
new file mode 100644
index 0000000..c55d969
--- /dev/null
+++ b/Swiften/IDN/IDNConverter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/SafeByteArray.h>
+
+namespace Swift {
+	class SWIFTEN_API IDNConverter {
+		public:
+			virtual ~IDNConverter();
+
+			enum StringPrepProfile {
+				NamePrep,
+				XMPPNodePrep,
+				XMPPResourcePrep,
+				SASLPrep
+			};
+
+			virtual std::string getStringPrepared(const std::string& s, StringPrepProfile profile) = 0;
+			virtual SafeByteArray getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) = 0;
+
+			// Thread-safe
+			virtual std::string getIDNAEncoded(const std::string& s) = 0;
+	};
+}
diff --git a/Swiften/IDN/LibIDNConverter.cpp b/Swiften/IDN/LibIDNConverter.cpp
new file mode 100644
index 0000000..c4a1c18
--- /dev/null
+++ b/Swiften/IDN/LibIDNConverter.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012-2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/IDN/LibIDNConverter.h>
+
+extern "C" {
+	#include <stringprep.h>
+	#include <idna.h>
+}
+
+#include <vector>
+#include <cassert>
+#include <cstdlib>
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/SafeAllocator.h>
+#include <boost/shared_ptr.hpp>
+
+using namespace Swift;
+
+namespace {
+	static const int MAX_STRINGPREP_SIZE = 1024;
+
+	const Stringprep_profile* getLibIDNProfile(IDNConverter::StringPrepProfile profile) {
+		switch(profile) {
+			case IDNConverter::NamePrep: return stringprep_nameprep;
+			case IDNConverter::XMPPNodePrep: return stringprep_xmpp_nodeprep;
+			case IDNConverter::XMPPResourcePrep: return stringprep_xmpp_resourceprep;
+			case IDNConverter::SASLPrep: return stringprep_saslprep;
+		}
+		assert(false);
+		return 0;
+	}
+
+	template<typename StringType, typename ContainerType>
+	ContainerType getStringPreparedInternal(const StringType& s, IDNConverter::StringPrepProfile profile) {
+		ContainerType input(s.begin(), s.end());
+		input.resize(MAX_STRINGPREP_SIZE);
+		if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) {
+			return input;
+		}
+		else {
+			return ContainerType();
+		}
+	}
+}
+
+namespace Swift {
+
+std::string LibIDNConverter::getStringPrepared(const std::string& s, StringPrepProfile profile) {
+	std::vector<char> preparedData = getStringPreparedInternal< std::string, std::vector<char> >(s, profile);
+	if (preparedData.empty()) {
+		throw std::exception();
+	}
+	return std::string(vecptr(preparedData));
+}
+
+SafeByteArray LibIDNConverter::getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) {
+	std::vector<char, SafeAllocator<char> > preparedData = getStringPreparedInternal<SafeByteArray, std::vector<char, SafeAllocator<char> > >(s, profile);
+	if (preparedData.empty()) {
+		throw std::exception();
+	}
+	return createSafeByteArray(reinterpret_cast<const char*>(vecptr(preparedData)));
+}
+
+std::string LibIDNConverter::getIDNAEncoded(const std::string& domain) {
+	char* output;
+	if (idna_to_ascii_8z(domain.c_str(), &output, 0) == IDNA_SUCCESS) {
+		std::string result(output);
+		free(output);
+		return result;
+	}
+	else {
+		return domain;
+	}
+}
+
+}
diff --git a/Swiften/IDN/LibIDNConverter.h b/Swiften/IDN/LibIDNConverter.h
new file mode 100644
index 0000000..23f6bbd
--- /dev/null
+++ b/Swiften/IDN/LibIDNConverter.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012-2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/Override.h>
+#include <Swiften/IDN/IDNConverter.h>
+
+namespace Swift {
+	class SWIFTEN_API LibIDNConverter : public IDNConverter {
+		public:
+			virtual std::string getStringPrepared(const std::string& s, StringPrepProfile profile) SWIFTEN_OVERRIDE;
+			virtual SafeByteArray getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) SWIFTEN_OVERRIDE;
+
+			virtual std::string getIDNAEncoded(const std::string& s) SWIFTEN_OVERRIDE;
+	};
+}
+
diff --git a/Swiften/IDN/PlatformIDNConverter.cpp b/Swiften/IDN/PlatformIDNConverter.cpp
new file mode 100644
index 0000000..6d9cff7
--- /dev/null
+++ b/Swiften/IDN/PlatformIDNConverter.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/IDN/PlatformIDNConverter.h>
+#if defined(HAVE_LIBIDN)
+#include <Swiften/IDN/LibIDNConverter.h>
+#elif defined(HAVE_ICU)
+#include <Swiften/IDN/ICUConverter.h>
+#endif
+
+namespace Swift {
+
+IDNConverter* PlatformIDNConverter::create() {
+#if defined(HAVE_LIBIDN)
+	return new LibIDNConverter();
+#elif defined(HAVE_ICU)
+	return new ICUConverter();
+#else
+#error "No IDN implementation"
+	return 0;
+#endif
+}
+
+}
diff --git a/Swiften/IDN/PlatformIDNConverter.h b/Swiften/IDN/PlatformIDNConverter.h
new file mode 100644
index 0000000..82a4a87
--- /dev/null
+++ b/Swiften/IDN/PlatformIDNConverter.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2012 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+
+namespace Swift {
+	class IDNConverter;
+
+	namespace SWIFTEN_API PlatformIDNConverter {
+		IDNConverter* create();
+	}
+}
diff --git a/Swiften/IDN/SConscript b/Swiften/IDN/SConscript
index 1433318..1011563 100644
--- a/Swiften/IDN/SConscript
+++ b/Swiften/IDN/SConscript
@@ -1,20 +1,23 @@
 Import("swiften_env", "env")
 
+
+objects = swiften_env.SwiftenObject(["IDNConverter.cpp"])
+
 myenv = swiften_env.Clone()
 if myenv.get("HAVE_ICU") :
 	myenv.MergeFlags(swiften_env["ICU_FLAGS"])
 	myenv.Append(CPPDEFINES = ["HAVE_ICU"])
-elif myenv.get("HAVE_LIBIDN") :
+	objects += myenv.SwiftenObject(["ICUConverter.cpp"])
+if myenv.get("HAVE_LIBIDN") :
 	myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"])
 	myenv.Append(CPPDEFINES = ["HAVE_LIBIDN"])
+	objects += myenv.SwiftenObject(["LibIDNConverter.cpp"])
+objects += myenv.SwiftenObject(["PlatformIDNConverter.cpp"])
 
-objects = myenv.SwiftenObject([
-			"StringPrep.cpp",
-			"IDNA.cpp",
-		])
 swiften_env.Append(SWIFTEN_OBJECTS = [objects])
 
-env.Append(UNITTEST_SOURCES = [
-			File("UnitTest/StringPrepTest.cpp"),
-			File("UnitTest/IDNATest.cpp"),
-	])
+#env.Append(UNITTEST_OBJECTS = myenv.SwiftenObject([
+#			File("UnitTest/IDNATest.cpp"),
+#])
+
+
diff --git a/Swiften/IDN/StringPrep.h b/Swiften/IDN/StringPrep.h
deleted file mode 100644
index 35c4593..0000000
--- a/Swiften/IDN/StringPrep.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 <string>
-#include <Swiften/Base/API.h>
-#include <Swiften/Base/SafeByteArray.h>
-
-namespace Swift {
-	class SWIFTEN_API StringPrep {
-		public:
-			enum Profile {
-				NamePrep,
-				XMPPNodePrep,
-				XMPPResourcePrep,
-				SASLPrep
-			};
-
-			static std::string getPrepared(const std::string& s, Profile profile);
-			static SafeByteArray getPrepared(const SafeByteArray& s, Profile profile);
-	};
-}
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp
index 1bdf390..6af3c33 100644
--- a/Swiften/JID/JID.cpp
+++ b/Swiften/JID/JID.cpp
@@ -23,7 +23,11 @@
 
 #include <Swiften/Base/String.h>
 #include <Swiften/JID/JID.h>
-#include <Swiften/IDN/StringPrep.h>
+#include <Swiften/IDN/IDNConverter.h>
+#ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER
+#include <boost/shared_ptr.hpp>
+#include <Swiften/IDN/PlatformIDNConverter.h>
+#endif
 
 using namespace Swift;
 
@@ -38,6 +42,19 @@ static PrepCache resourcePrepCache;
 
 static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':');
 
+static IDNConverter* idnConverter = NULL;
+
+#ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER
+namespace {
+	struct IDNInitializer {
+		IDNInitializer() : defaultIDNConverter(PlatformIDNConverter::create()) {
+			idnConverter = defaultIDNConverter.get();
+		}
+		boost::shared_ptr<IDNConverter> defaultIDNConverter;
+	} initializer;
+}
+#endif
+
 static std::string getEscaped(char c) {
 	return makeString() << '\\' << std::hex << static_cast<int>(c);
 }
@@ -164,9 +181,9 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d
 	}
 	try {
 #ifndef SWIFTEN_CACHE_JID_PREP
-		node_ = StringPrep::getPrepared(node, StringPrep::NamePrep);
-		domain_ = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep);
-		resource_ = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep);
+		node_ = idnConverter->getStringPrepared(node, IDNConverter::NamePrep);
+		domain_ = idnConverter->getStringPrepared(domain, IDNConverter::XMPPNodePrep);
+		resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
 #else
 		boost::mutex::scoped_lock lock(namePrepCacheMutex);
 
@@ -174,19 +191,19 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d
 
 		r = nodePrepCache.insert(std::make_pair(node, std::string()));
 		if (r.second) {
-			r.first->second = StringPrep::getPrepared(node, StringPrep::NamePrep);
+			r.first->second = idnConverter->getStringPrepared(node, IDNConverter::NamePrep);
 		}
 		node_ = r.first->second;
 
 		r = domainPrepCache.insert(std::make_pair(domain, std::string()));
 		if (r.second) {
-			r.first->second = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep);
+			r.first->second = idnConverter->getStringPrepared(domain, IDNConverter::XMPPNodePrep);
 		}
 		domain_ = r.first->second;
 
 		r = resourcePrepCache.insert(std::make_pair(resource, std::string()));
 		if (r.second) {
-			r.first->second = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep);
+			r.first->second = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep);
 		}
 		resource_ = r.first->second;
 #endif
@@ -274,6 +291,10 @@ std::string JID::getUnescapedNode() const {
 	//return boost::find_format_all_copy(node_, EscapedCharacterFinder(), EscapedCharacterFormatter());
 }
 
+void JID::setIDNConverter(IDNConverter* converter) {
+	idnConverter = converter;
+}
+
 std::ostream& operator<<(std::ostream& os, const JID& j) {
 	os << j.toString();
 	return os;
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h
index ea4bd43..798860d 100644
--- a/Swiften/JID/JID.h
+++ b/Swiften/JID/JID.h
@@ -13,6 +13,8 @@
 
 
 namespace Swift {
+	class IDNConverter;
+
 	/**
 	 * This represents the JID used in XMPP
 	 * (RFC6120 - http://tools.ietf.org/html/rfc6120 ).
@@ -156,6 +158,14 @@ namespace Swift {
 				return a.compare(b, Swift::JID::WithResource) != 0;
 			}
 
+
+			/**
+			 * If Swiften was compiled with SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER (not default), use this method at 
+			 * the beginning of the program to set an IDN converter to use for JID IDN conversions.
+			 * By default, this method shouldn't be used.
+			 */
+			static void setIDNConverter(IDNConverter*);
+
 		private:
 			void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource);
 			void initializeFromString(const std::string&);
diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp
index 488e519..41646c6 100644
--- a/Swiften/Network/BoostNetworkFactories.cpp
+++ b/Swiften/Network/BoostNetworkFactories.cpp
@@ -14,13 +14,14 @@
 #include <Swiften/Network/NullNATTraverser.h>
 #include <Swiften/TLS/PlatformTLSFactories.h>
 #include <Swiften/Network/PlatformProxyProvider.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
+#include <Swiften/IDN/IDNConverter.h>
 
 namespace Swift {
 
 BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(eventLoop){
 	timerFactory = new BoostTimerFactory(ioServiceThread.getIOService(), eventLoop);
 	connectionFactory = new BoostConnectionFactory(ioServiceThread.getIOService(), eventLoop);
-	domainNameResolver = new PlatformDomainNameResolver(eventLoop);
 	connectionServerFactory = new BoostConnectionServerFactory(ioServiceThread.getIOService(), eventLoop);
 #ifdef SWIFT_EXPERIMENTAL_FT
 	natTraverser = new PlatformNATTraversalWorker(eventLoop);
@@ -30,15 +31,18 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e
 	xmlParserFactory = new PlatformXMLParserFactory();
 	tlsFactories = new PlatformTLSFactories();
 	proxyProvider = new PlatformProxyProvider();
+	idnConverter = PlatformIDNConverter::create();
+	domainNameResolver = new PlatformDomainNameResolver(idnConverter, eventLoop);
 }
 
 BoostNetworkFactories::~BoostNetworkFactories() {
+	delete domainNameResolver;
+	delete idnConverter;
 	delete proxyProvider;
 	delete tlsFactories;
 	delete xmlParserFactory;
 	delete natTraverser;
 	delete connectionServerFactory;
-	delete domainNameResolver;
 	delete connectionFactory;
 	delete timerFactory;
 }
diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h
index 1968acd..11797c6 100644
--- a/Swiften/Network/BoostNetworkFactories.h
+++ b/Swiften/Network/BoostNetworkFactories.h
@@ -7,6 +7,7 @@
 #pragma once
 
 #include <Swiften/Base/API.h>
+#include <Swiften/Base/Override.h>
 #include <Swiften/Network/NetworkFactories.h>
 #include <Swiften/Network/BoostIOServiceThread.h>
 
@@ -20,11 +21,11 @@ namespace Swift {
 			BoostNetworkFactories(EventLoop* eventLoop);
 			~BoostNetworkFactories();
 
-			virtual TimerFactory* getTimerFactory() const {
+			virtual TimerFactory* getTimerFactory() const SWIFTEN_OVERRIDE {
 				return timerFactory;
 			}
 
-			virtual ConnectionFactory* getConnectionFactory() const {
+			virtual ConnectionFactory* getConnectionFactory() const SWIFTEN_OVERRIDE {
 				return connectionFactory;
 			}
 
@@ -32,32 +33,36 @@ namespace Swift {
 				return &ioServiceThread;
 			}
 
-			DomainNameResolver* getDomainNameResolver() const {
+			DomainNameResolver* getDomainNameResolver() const SWIFTEN_OVERRIDE {
 				return domainNameResolver;
 			}
 
-			ConnectionServerFactory* getConnectionServerFactory() const {
+			ConnectionServerFactory* getConnectionServerFactory() const SWIFTEN_OVERRIDE {
 				return connectionServerFactory;
 			}
 
-			NATTraverser* getNATTraverser() const {
+			NATTraverser* getNATTraverser() const SWIFTEN_OVERRIDE {
 				return natTraverser;
 			}
 
-			virtual XMLParserFactory* getXMLParserFactory() const {
+			virtual XMLParserFactory* getXMLParserFactory() const SWIFTEN_OVERRIDE {
 				return xmlParserFactory;
 			}
 
-			virtual TLSContextFactory* getTLSContextFactory() const;
+			virtual TLSContextFactory* getTLSContextFactory() const SWIFTEN_OVERRIDE;
 
-			virtual ProxyProvider* getProxyProvider() const {
+			virtual ProxyProvider* getProxyProvider() const SWIFTEN_OVERRIDE {
 				return proxyProvider;
 			}
 
-			virtual EventLoop* getEventLoop() const {
+			virtual EventLoop* getEventLoop() const SWIFTEN_OVERRIDE {
 				return eventLoop;
 			}
 
+			virtual IDNConverter* getIDNConverter() const SWIFTEN_OVERRIDE {
+				return idnConverter;
+			}
+
 		private:
 			BoostIOServiceThread ioServiceThread;
 			TimerFactory* timerFactory;
@@ -69,5 +74,6 @@ namespace Swift {
 			PlatformTLSFactories* tlsFactories;
 			ProxyProvider* proxyProvider;
 			EventLoop* eventLoop;
+			IDNConverter* idnConverter;
 	};
 }
diff --git a/Swiften/Network/NetworkFactories.h b/Swiften/Network/NetworkFactories.h
index c8009a6..f24f493 100644
--- a/Swiften/Network/NetworkFactories.h
+++ b/Swiften/Network/NetworkFactories.h
@@ -17,6 +17,7 @@ namespace Swift {
 	class CertificateFactory;
 	class ProxyProvider;
 	class EventLoop;
+	class IDNConverter;
 
 	/**
 	 * An interface collecting network factories.
@@ -34,5 +35,6 @@ namespace Swift {
 			virtual TLSContextFactory* getTLSContextFactory() const = 0;
 			virtual ProxyProvider* getProxyProvider() const = 0;
 			virtual EventLoop* getEventLoop() const = 0;
+			virtual IDNConverter* getIDNConverter() const = 0;
 	};
 }
diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp
index 63f7404..677f1d5 100644
--- a/Swiften/Network/PlatformDomainNameResolver.cpp
+++ b/Swiften/Network/PlatformDomainNameResolver.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -16,7 +16,7 @@
 #include <algorithm>
 
 #include <string>
-#include <Swiften/IDN/IDNA.h>
+#include <Swiften/IDN/IDNConverter.h>
 #include <Swiften/Network/HostAddress.h>
 #include <Swiften/EventLoop/EventLoop.h>
 #include <Swiften/Network/HostAddressPort.h>
@@ -27,7 +27,7 @@ using namespace Swift;
 
 namespace Swift {
 
-PlatformDomainNameResolver::PlatformDomainNameResolver(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false) {
+PlatformDomainNameResolver::PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop) : idnConverter(idnConverter), eventLoop(eventLoop), stopRequested(false) {
 	thread = new boost::thread(boost::bind(&PlatformDomainNameResolver::run, this));
 }
 
@@ -39,11 +39,11 @@ PlatformDomainNameResolver::~PlatformDomainNameResolver() {
 }
 
 boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const std::string& name) {
-	return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(IDNA::getEncoded(name), eventLoop, this));
+	return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(idnConverter->getIDNAEncoded(name), eventLoop, this));
 }
 
 boost::shared_ptr<DomainNameAddressQuery> PlatformDomainNameResolver::createAddressQuery(const std::string& name) {
-	return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(IDNA::getEncoded(name), eventLoop, this));
+	return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(idnConverter->getIDNAEncoded(name), eventLoop, this));
 }
 
 void PlatformDomainNameResolver::run() {
diff --git a/Swiften/Network/PlatformDomainNameResolver.h b/Swiften/Network/PlatformDomainNameResolver.h
index 0617d9e..25d87cf 100644
--- a/Swiften/Network/PlatformDomainNameResolver.h
+++ b/Swiften/Network/PlatformDomainNameResolver.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -18,12 +18,12 @@
 #include <Swiften/Network/DomainNameAddressQuery.h>
 
 namespace Swift {
-	
+	class IDNConverter;	
 	class EventLoop;
 
 	class SWIFTEN_API PlatformDomainNameResolver : public DomainNameResolver {
 		public:
-			PlatformDomainNameResolver(EventLoop* eventLoop);
+			PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop);
 			~PlatformDomainNameResolver();
 
 			virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name);
@@ -36,6 +36,7 @@ namespace Swift {
 		private:
 			friend class PlatformDomainNameServiceQuery;
 			friend class PlatformDomainNameAddressQuery;
+			IDNConverter* idnConverter;
 			EventLoop* eventLoop;
 			bool stopRequested;
 			boost::thread* thread;
diff --git a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp
index 7cb9ed3..7bbb1a6 100644
--- a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp
+++ b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp
@@ -17,6 +17,8 @@
 #include <Swiften/Network/DomainNameAddressQuery.h>
 #include <Swiften/Network/DomainNameServiceQuery.h>
 #include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/IDN/IDNConverter.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
 
 using namespace Swift;
 
@@ -42,7 +44,8 @@ class DomainNameResolverTest : public CppUnit::TestFixture {
 	public:
 		void setUp() {
 			eventLoop = new DummyEventLoop();
-			resolver = new PlatformDomainNameResolver(eventLoop);
+			idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create());
+			resolver = new PlatformDomainNameResolver(idnConverter.get(), eventLoop);
 			resultsAvailable = false;
 		}
 
@@ -209,6 +212,7 @@ class DomainNameResolverTest : public CppUnit::TestFixture {
 
 	private:
 		DummyEventLoop* eventLoop;
+		boost::shared_ptr<IDNConverter> idnConverter;
 		bool resultsAvailable;
 		std::vector<HostAddress> addressQueryResult;
 		std::vector<HostAddress> allAddressQueryResults;
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
index 09e202e..38e3289 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
@@ -14,7 +14,7 @@
 #include <Swiften/StringCodecs/Base64.h>
 #include <Swiften/StringCodecs/HMAC_SHA1.h>
 #include <Swiften/StringCodecs/PBKDF2.h>
-#include <Swiften/IDN/StringPrep.h>
+#include <Swiften/IDN/IDNConverter.h>
 #include <Swiften/Base/Concat.h>
 
 namespace Swift {
@@ -36,7 +36,7 @@ static std::string escape(const std::string& s) {
 }
 
 
-SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding) : ClientAuthenticator(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding) {
+SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding, IDNConverter* idnConverter) : ClientAuthenticator(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding), idnConverter(idnConverter) {
 }
 
 boost::optional<SafeByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const {
@@ -96,7 +96,7 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray>
 
 		// Compute all the values needed for the server signature
 		try {
-			saltedPassword = PBKDF2::encode<HMAC_SHA1>(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations);
+			saltedPassword = PBKDF2::encode<HMAC_SHA1>(idnConverter->getStringPrepared(getPassword(), IDNConverter::SASLPrep), salt, iterations);
 		}
 		catch (const std::exception&) {
 		}
@@ -148,7 +148,7 @@ std::map<char, std::string> SCRAMSHA1ClientAuthenticator::parseMap(const std::st
 ByteArray SCRAMSHA1ClientAuthenticator::getInitialBareClientMessage() const {
 	std::string authenticationID;
 	try {
-		authenticationID = StringPrep::getPrepared(getAuthenticationID(), StringPrep::SASLPrep);
+		authenticationID = idnConverter->getStringPrepared(getAuthenticationID(), IDNConverter::SASLPrep);
 	}
 	catch (const std::exception&) {
 	}
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
index ace69b0..da52bbc 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
@@ -15,9 +15,11 @@
 #include <Swiften/Base/API.h>
 
 namespace Swift {
+	class IDNConverter;
+
 	class SWIFTEN_API SCRAMSHA1ClientAuthenticator : public ClientAuthenticator {
 		public:
-			SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding = false);
+			SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding, IDNConverter*);
 
 			void setTLSChannelBindingData(const ByteArray& channelBindingData);
 			
@@ -44,6 +46,7 @@ namespace Swift {
 			ByteArray saltedPassword;
 			ByteArray serverSignature;
 			bool useChannelBinding;
+			IDNConverter* idnConverter;
 			boost::optional<ByteArray> tlsChannelBindingData;
 	};
 }
diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
index f0ca01c..6266f3e 100644
--- a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
+++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -11,6 +11,8 @@
 
 #include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h>
 #include <Swiften/Base/ByteArray.h>
+#include <Swiften/IDN/IDNConverter.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
 
 using namespace Swift;
 
@@ -39,10 +41,11 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 
 	public:
 		void setUp() {
+			idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create());
 		}
 
 		void testGetInitialResponse() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			SafeByteArray response = *testling.getResponse();
@@ -51,7 +54,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetInitialResponse_UsernameHasSpecialChars() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get());
 			testling.setCredentials(",us=,er=", createSafeByteArray("pass"), "");
 
 			SafeByteArray response = *testling.getResponse();
@@ -60,7 +63,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetInitialResponse_WithAuthorizationID() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "auth");
 
 			SafeByteArray response = *testling.getResponse();
@@ -69,7 +72,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetInitialResponse_WithAuthorizationIDWithSpecialChars() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "a=u,th");
 
 			SafeByteArray response = *testling.getResponse();
@@ -78,7 +81,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetInitialResponse_WithoutChannelBindingWithTLSChannelBindingData() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false);
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get());
 			testling.setTLSChannelBindingData(createByteArray("xyza"));
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
@@ -88,7 +91,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetInitialResponse_WithChannelBindingWithTLSChannelBindingData() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true);
+			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true, idnConverter.get());
 			testling.setTLSChannelBindingData(createByteArray("xyza"));
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
@@ -98,7 +101,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetFinalResponse() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 
@@ -108,7 +111,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetFinalResponse_WithoutChannelBindingWithTLSChannelBindingData() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false);
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setTLSChannelBindingData(createByteArray("xyza"));
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
@@ -119,7 +122,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetFinalResponse_WithChannelBindingWithTLSChannelBindingData() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh", true);
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", true, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setTLSChannelBindingData(createByteArray("xyza"));
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
@@ -130,7 +133,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetFinalChallenge() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 
@@ -140,7 +143,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
@@ -149,7 +152,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_InvalidClientNonce() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefgiABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
@@ -158,7 +161,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_OnlyClientNonce() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefgh,s=MTIzNDU2NzgK,i=4096"));
@@ -167,7 +170,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_InvalidIterations() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=bla"));
@@ -176,7 +179,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_MissingIterations() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK"));
@@ -185,7 +188,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_ZeroIterations() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=0"));
@@ -194,7 +197,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetChallenge_NegativeIterations() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 
 			bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=-1"));
@@ -203,7 +206,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testSetFinalChallenge_InvalidChallenge() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 			bool result = testling.setChallenge(createByteArray("v=e26kI69ICb6zosapLLxrER/631A="));
@@ -212,13 +215,15 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 		}
 
 		void testGetResponseAfterFinalChallenge() {
-			SCRAMSHA1ClientAuthenticator testling("abcdefgh");
+			SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get());
 			testling.setCredentials("user", createSafeByteArray("pass"), "");
 			testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 			testling.setChallenge(createByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo="));
 
 			CPPUNIT_ASSERT(!testling.getResponse());
 		}
+
+		boost::shared_ptr<IDNConverter> idnConverter;
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SCRAMSHA1ClientAuthenticatorTest);
diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp
index 59c0614..cc6e68a 100644
--- a/Swiften/TLS/ServerIdentityVerifier.cpp
+++ b/Swiften/TLS/ServerIdentityVerifier.cpp
@@ -9,13 +9,13 @@
 #include <boost/algorithm/string.hpp>
 
 #include <Swiften/Base/foreach.h>
-#include <Swiften/IDN/IDNA.h>
+#include <Swiften/IDN/IDNConverter.h>
 
 namespace Swift {
 
-ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid) {
+ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter) {
 	domain = jid.getDomain();
-	encodedDomain = IDNA::getEncoded(domain);
+	encodedDomain = idnConverter->getIDNAEncoded(domain);
 }
 
 bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) {
diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h
index 730ee74..4167ce8 100644
--- a/Swiften/TLS/ServerIdentityVerifier.h
+++ b/Swiften/TLS/ServerIdentityVerifier.h
@@ -14,9 +14,11 @@
 #include <Swiften/TLS/Certificate.h>
 
 namespace Swift {
+	class IDNConverter;
+
 	class SWIFTEN_API ServerIdentityVerifier {
 		public:
-			ServerIdentityVerifier(const JID& jid);
+			ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter);
 
 			bool certificateVerifies(Certificate::ref);
 
diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
index bd68c84..e974eb7 100644
--- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
+++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
@@ -12,6 +12,8 @@
 
 #include <Swiften/TLS/ServerIdentityVerifier.h>
 #include <Swiften/TLS/SimpleCertificate.h>
+#include <Swiften/IDN/IDNConverter.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
 
 using namespace Swift;
 
@@ -36,8 +38,12 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
+		void setUp() {
+			idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create());
+		}
+
 		void testCertificateVerifies_WithoutMatchingDNSName() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("foo.com");
 
@@ -45,7 +51,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingDNSName() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("bar.com");
 
@@ -53,7 +59,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithSecondMatchingDNSName() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("foo.com");
 			certificate->addDNSName("bar.com");
@@ -62,7 +68,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingInternationalDNSName() {
-			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7on.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7on.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("xn--tronon-zua.com");
 
@@ -70,7 +76,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingDNSNameWithWildcard() {
-			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("*.bar.com");
 
@@ -78,7 +84,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingDNSNameWithWildcardMatchingNoComponents() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("*.bar.com");
 
@@ -86,7 +92,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithDNSNameWithWildcardMatchingTwoComponents() {
-			ServerIdentityVerifier testling(JID("foo@xmpp.im.bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@xmpp.im.bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addDNSName("*.bar.com");
 
@@ -94,7 +100,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingSRVNameWithoutService() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addSRVName("bar.com");
 
@@ -102,7 +108,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingSRVNameWithService() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addSRVName("_xmpp-client.bar.com");
 
@@ -110,7 +116,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingSRVNameWithServiceAndWildcard() {
-			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addSRVName("_xmpp-client.*.bar.com");
 
@@ -118,7 +124,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingSRVNameWithDifferentService() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addSRVName("_xmpp-server.bar.com");
 
@@ -126,7 +132,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingXmppAddr() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addXMPPAddress("bar.com");
 
@@ -134,7 +140,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingXmppAddrWithWildcard() {
-			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addXMPPAddress("*.bar.com");
 
@@ -142,7 +148,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingInternationalXmppAddr() {
-			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addXMPPAddress("tron\xc3\xa7.com");
 
@@ -150,7 +156,7 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingCNWithoutSAN() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addCommonName("bar.com");
 
@@ -158,13 +164,15 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
 		}
 
 		void testCertificateVerifies_WithMatchingCNWithSAN() {
-			ServerIdentityVerifier testling(JID("foo@bar.com/baz"));
+			ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
 			SimpleCertificate::ref certificate(new SimpleCertificate());
 			certificate->addSRVName("foo.com");
 			certificate->addCommonName("bar.com");
 
 			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
 		}
+
+		boost::shared_ptr<IDNConverter> idnConverter;
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ServerIdentityVerifierTest);
-- 
cgit v0.10.2-6-g49f6