diff options
| -rw-r--r-- | BuildTools/Eclipse/Swift (Mac OS X).launch | 2 | ||||
| -rw-r--r-- | QA/UnitTest/Unit Tests.launch | 22 | ||||
| -rw-r--r-- | Sluift/Examples/Login.lua | 5 | ||||
| -rw-r--r-- | Sluift/ResponseSink.h | 43 | ||||
| -rw-r--r-- | Sluift/SConscript | 17 | ||||
| -rw-r--r-- | Sluift/SluiftException.h | 60 | ||||
| -rw-r--r-- | Sluift/Watchdog.h | 44 | ||||
| -rw-r--r-- | Sluift/sluift.cpp | 209 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.cpp | 3 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.h | 11 | ||||
| -rw-r--r-- | Swiften/Client/CoreClient.cpp | 18 | ||||
| -rw-r--r-- | Swiften/Client/CoreClient.h | 16 | ||||
| -rw-r--r-- | Swiften/Client/UnitTest/ClientSessionTest.cpp | 3 | ||||
| -rw-r--r-- | Swiften/Component/UnitTest/ComponentSessionTest.cpp | 3 | ||||
| -rw-r--r-- | Swiften/Elements/RawXMLPayload.h | 7 | ||||
| -rw-r--r-- | Swiften/Queries/RawRequest.h | 49 | ||||
| -rw-r--r-- | Swiften/Queries/Request.cpp | 7 | ||||
| -rw-r--r-- | Swiften/Queries/UnitTest/RequestTest.cpp | 65 | ||||
| -rw-r--r-- | Swiften/Session/BasicSessionStream.cpp | 5 | ||||
| -rw-r--r-- | Swiften/Session/BasicSessionStream.h | 1 | ||||
| -rw-r--r-- | Swiften/Session/SessionStream.h | 1 | 
21 files changed, 467 insertions, 124 deletions
| diff --git a/BuildTools/Eclipse/Swift (Mac OS X).launch b/BuildTools/Eclipse/Swift (Mac OS X).launch index 1dc569f..ba5e5be 100644 --- a/BuildTools/Eclipse/Swift (Mac OS X).launch +++ b/BuildTools/Eclipse/Swift (Mac OS X).launch @@ -17,7 +17,7 @@  <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>  <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="Swift/QtUI/Swift.app/Contents/MacOS/Swift"/>  <stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="swift"/> -<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.980756260.1834106966.226646757"/> +<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.980756260.1834106966"/>  <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/>  <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">  <listEntry value="/swift"/> diff --git a/QA/UnitTest/Unit Tests.launch b/QA/UnitTest/Unit Tests.launch new file mode 100644 index 0000000..f58a6b0 --- /dev/null +++ b/QA/UnitTest/Unit Tests.launch @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType"> +<stringAttribute key="bad_container_name" value="/swift/QA/UnitTest/Un"/> +<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/> +<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/> +<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="--verbose"/> +<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="/Users/remko/src/swift/QA/UnitTest/checker"/> +<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="swift"/> +<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.980756260.1834106966"/> +<booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> +<listEntry value="/swift"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> +<listEntry value="4"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> +<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> +<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> +</listAttribute> +<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<memoryBlockExpressionList context="reserved-for-future-use"/>
"/> +</launchConfiguration> diff --git a/Sluift/Examples/Login.lua b/Sluift/Examples/Login.lua index 52c1521..d93e990 100644 --- a/Sluift/Examples/Login.lua +++ b/Sluift/Examples/Login.lua @@ -5,7 +5,8 @@  --  -- This script logs into an XMPP server, and sends initial presence --- Useful as initialization script for an interactive session ('-i') +-- Useful as initialization script for an interactive session ('-i'), +-- or as a starting point for scripts.  --   -- The following environment variables are used:  -- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with @@ -17,7 +18,7 @@ sluift.debug = os.getenv("SLUIFT_DEBUG") or false  print("Connecting " .. os.getenv("SLUIFT_JID") .. " ...")  c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) -c:set_options(os.getenv("SLUIFT_OPTIONS") or {}) +c:set_options({compress = false, tls = false})  c:connect()  c:send_presence("") diff --git a/Sluift/ResponseSink.h b/Sluift/ResponseSink.h new file mode 100644 index 0000000..042d6e0 --- /dev/null +++ b/Sluift/ResponseSink.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/ErrorPayload.h> + +namespace Swift { +	template<typename T> +	class ResponseSink { +		public: +			ResponseSink() : responseReceived(false) { +			} + +			bool hasResponse() const { +				return responseReceived; +			} + +			boost::shared_ptr<T> getResponsePayload() const { +				return payload; +			} + +			ErrorPayload::ref getResponseError() const { +				return error; +			} + +			void operator()(boost::shared_ptr<T> payload, ErrorPayload::ref error) { +				this->payload = payload; +				this->error = error; +				this->responseReceived = true; +			} + +		private: +			bool responseReceived; +			boost::shared_ptr<T> payload; +			ErrorPayload::ref error; +	}; +} diff --git a/Sluift/SConscript b/Sluift/SConscript index 44fabdf..816c234 100644 --- a/Sluift/SConscript +++ b/Sluift/SConscript @@ -6,12 +6,15 @@ if env["SCONS_STAGE"] == "build" :  	myenv.UseFlags(env["SWIFTEN_FLAGS"])  	myenv.UseFlags(env["SWIFTEN_DEP_FLAGS"])  	myenv["SHLIBPREFIX"] = "" -  	if myenv["PLATFORM"] == "win32" :  		myenv.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"])  	elif myenv["PLATFORM"] == "darwin" :  		myenv["SHLIBSUFFIX"] = ".so" +	sluift_lib = myenv.StaticLibrary("SluiftCore", [ +			"sluift.cpp" +		]); +  	def patchLua(env, target, source) :  		f = open(source[0].abspath, "r")  		contents = f.read() @@ -23,20 +26,16 @@ if env["SCONS_STAGE"] == "build" :  		f.close()  	sluift_bin_env = myenv.Clone() +	sluift_bin_env.Append(LIBS = sluift_lib)  	sluift_bin_env.Command("lua.c", ["#/3rdParty/Lua/src/lua.c"], env.Action(patchLua, cmdstr = "$GENCOMSTR"))  	if sluift_bin_env.get("HAVE_READLINE", False) :  		sluift_bin_env.Append(CPPDEFINES = ["LUA_USE_READLINE"])  		sluift_bin_env.MergeFlags(sluift_bin_env["READLINE_FLAGS"])  	env["SLUIFT"] = sluift_bin_env.Program("sluift", [ -			"sluift.cpp",  			"lua.c",  			"linit.c",  		]) -	# Create a copy of sluift.cpp to avoid conflicting targets -	# Ideally, we would use variants for this -	myenv.InstallAs("sluift_dll.cpp", "sluift.cpp") -	myenv.SharedLibrary("sluift", [ -			"sluift_dll.cpp", -		]) - +	sluift_dll_env = myenv.Clone() +	sluift_dll_env.Append(LIBS = sluift_lib) +	sluift_dll_env.SharedLibrary("sluift", []); diff --git a/Sluift/SluiftException.h b/Sluift/SluiftException.h new file mode 100644 index 0000000..92326b6 --- /dev/null +++ b/Sluift/SluiftException.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 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/Client/ClientError.h> + +namespace Swift { +	class SluiftException { +		public: +			SluiftException(const std::string& reason) : reason(reason) { +			} + +			SluiftException(const ClientError& error) { +				std::string reason("Disconnected: "); +				switch(error.getType()) { +					case ClientError::UnknownError: reason += "Unknown Error"; break; +					case ClientError::DomainNameResolveError: reason += "Unable to find server"; break; +					case ClientError::ConnectionError: reason += "Error connecting to server"; break; +					case ClientError::ConnectionReadError: reason += "Error while receiving server data"; break; +					case ClientError::ConnectionWriteError: reason += "Error while sending data to the server"; break; +					case ClientError::XMLError: reason += "Error parsing server data"; break; +					case ClientError::AuthenticationFailedError: reason += "Login/password invalid"; break; +					case ClientError::CompressionFailedError: reason += "Error while compressing stream"; break; +					case ClientError::ServerVerificationFailedError: reason += "Server verification failed"; break; +					case ClientError::NoSupportedAuthMechanismsError: reason += "Authentication mechanisms not supported"; break; +					case ClientError::UnexpectedElementError: reason += "Unexpected response"; break; +					case ClientError::ResourceBindError: reason += "Error binding resource"; break; +					case ClientError::SessionStartError: reason += "Error starting session"; break; +					case ClientError::StreamError: reason += "Stream error"; break; +					case ClientError::TLSError: reason += "Encryption error"; break; +					case ClientError::ClientCertificateLoadError: reason += "Error loading certificate (Invalid password?)"; break; +					case ClientError::ClientCertificateError: reason += "Certificate not authorized"; break; +					case ClientError::UnknownCertificateError: reason += "Unknown certificate"; break; +					case ClientError::CertificateExpiredError: reason += "Certificate has expired"; break; +					case ClientError::CertificateNotYetValidError: reason += "Certificate is not yet valid"; break; +					case ClientError::CertificateSelfSignedError: reason += "Certificate is self-signed"; break; +					case ClientError::CertificateRejectedError: reason += "Certificate has been rejected"; break; +					case ClientError::CertificateUntrustedError: reason += "Certificate is not trusted"; break; +					case ClientError::InvalidCertificatePurposeError: reason += "Certificate cannot be used for encrypting your connection"; break; +					case ClientError::CertificatePathLengthExceededError: reason += "Certificate path length constraint exceeded"; break; +					case ClientError::InvalidCertificateSignatureError: reason += "Invalid certificate signature"; break; +					case ClientError::InvalidCAError: reason += "Invalid Certificate Authority"; break; +					case ClientError::InvalidServerIdentityError: reason += "Certificate does not match the host identity"; break; +				} +			} + +			const std::string& getReason() const { +				return reason; +			} + +		private: +			std::string reason; +	}; +} diff --git a/Sluift/Watchdog.h b/Sluift/Watchdog.h new file mode 100644 index 0000000..95b6971 --- /dev/null +++ b/Sluift/Watchdog.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/TimerFactory.h> + +namespace Swift { +	class Watchdog { +		public: +			Watchdog(int timeout, TimerFactory* timerFactory) : timedOut(false) { +				if (timeout > 0) { +					timer = timerFactory->createTimer(timeout); +					timer->start(); +					timer->onTick.connect(boost::bind(&Watchdog::handleTimerTick, this)); +				} +				else if (timeout == 0) { +					timedOut = true; +				} +			} + +			~Watchdog() { +				if (timer) { +					timer->stop(); +				} +			} + +			bool getTimedOut() const { +				return timedOut; +			} + +		private: +			void handleTimerTick() { +				timedOut = true; +			} + +		private: +			Timer::ref timer; +			bool timedOut; +	}; +} diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp index 1ce9642..da2c93b 100644 --- a/Sluift/sluift.cpp +++ b/Sluift/sluift.cpp @@ -20,10 +20,14 @@ extern "C" {  #include <Swiften/Network/BoostNetworkFactories.h>  #include <Swiften/Network/TimerFactory.h>  #include <Swiften/Network/Timer.h> -#include <Swiften/Base/sleep.h>  #include <Swiften/Elements/SoftwareVersion.h>  #include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h> +#include <Swiften/Queries/RawRequest.h>  #include <Swiften/Roster/XMPPRoster.h> +#include <Swiften/Base/sleep.h> +#include "Watchdog.h" +#include "SluiftException.h" +#include "ResponseSink.h"  using namespace Swift; @@ -42,51 +46,6 @@ bool debug = false;  SimpleEventLoop eventLoop;  BoostNetworkFactories networkFactories(&eventLoop); -class Watchdog { -	public: -		Watchdog(int timeout) : timedOut(false) { -			if (timeout > 0) { -				timer = networkFactories.getTimerFactory()->createTimer(timeout); -				timer->start(); -				timer->onTick.connect(boost::bind(&Watchdog::handleTimerTick, this)); -			} -			else if (timeout == 0) { -				timedOut = true; -			} -		} - -		~Watchdog() { -			if (timer) { -				timer->stop(); -			} -		} - -		bool getTimedOut() const { -			return timedOut; -		} -	 -	private: -		void handleTimerTick() { -			timedOut = true; -		} -	 -	private: -		Timer::ref timer; -		bool timedOut; -}; - -class SluiftException { -	public: -		SluiftException(const std::string& reason) : reason(reason) { -		} - -		const std::string& getReason() const { -			return reason; -		} -	 -	private: -		std::string reason; -};  class SluiftClient {  	public: @@ -137,6 +96,17 @@ class SluiftClient {  			client->sendPresence(boost::make_shared<Presence>(status));  		} +		std::string sendQuery(const JID& jid, IQ::Type type, const std::string& data) { +			rawRequestResponse.reset(); +			RawRequest::ref request = RawRequest::create(type, jid, data, client->getIQRouter()); +			request->onResponse.connect(boost::bind(&SluiftClient::handleRawRequestResponse, this, _1)); +			request->send(); +			while (!rawRequestResponse) { +				eventLoop.runUntilEvents(); +			} +			return *rawRequestResponse; +		} +  		void disconnect() {  			client->disconnect();  			while (client->isActive()) { @@ -149,25 +119,23 @@ class SluiftClient {  		}  		boost::optional<SoftwareVersion> getSoftwareVersion(const JID& jid) { +			ResponseSink<SoftwareVersion> sink;  			GetSoftwareVersionRequest::ref request = GetSoftwareVersionRequest::create(jid, client->getIQRouter()); -			request->onResponse.connect(boost::bind(&SluiftClient::handleSoftwareVersionResponse, this, _1, _2)); -			softwareVersion.reset(); -			error.reset(); +			request->onResponse.connect(boost::ref(sink));  			request->send(); -			while (!softwareVersion && !error) { +			while (!sink.hasResponse()) {  				eventLoop.runUntilEvents();  			} -			return softwareVersion; +			return sink.getResponsePayload() ? *sink.getResponsePayload() : boost::optional<SoftwareVersion>();  		}  		Stanza::ref getNextEvent(int timeout) { -			eventLoop.runOnce();  			if (!pendingEvents.empty()) {  				Stanza::ref event = pendingEvents.front();  				pendingEvents.pop_front();  				return event;  			} -			Watchdog watchdog(timeout); +			Watchdog watchdog(timeout, networkFactories.getTimerFactory());  			while (!watchdog.getTimedOut() && pendingEvents.empty()) {  				eventLoop.runUntilEvents();  			} @@ -198,52 +166,13 @@ class SluiftClient {  			rosterReceived = true;  		} -		void handleSoftwareVersionResponse(boost::shared_ptr<SoftwareVersion> version, ErrorPayload::ref error) { -			if (error) { -				this->error = error; -			} -			else if (version) { -				this->softwareVersion = *version; -			} -			else { -				this->softwareVersion = SoftwareVersion("", "", ""); -			} +		void handleRawRequestResponse(const std::string& response) { +			rawRequestResponse = response;  		}  		void handleDisconnected(const boost::optional<ClientError>& error) {  			if (error) { -				std::string reason("Disconnected: "); -				switch(error->getType()) { -					case ClientError::UnknownError: reason += "Unknown Error"; break; -					case ClientError::DomainNameResolveError: reason += "Unable to find server"; break; -					case ClientError::ConnectionError: reason += "Error connecting to server"; break; -					case ClientError::ConnectionReadError: reason += "Error while receiving server data"; break; -					case ClientError::ConnectionWriteError: reason += "Error while sending data to the server"; break; -					case ClientError::XMLError: reason += "Error parsing server data"; break; -					case ClientError::AuthenticationFailedError: reason += "Login/password invalid"; break; -					case ClientError::CompressionFailedError: reason += "Error while compressing stream"; break; -					case ClientError::ServerVerificationFailedError: reason += "Server verification failed"; break; -					case ClientError::NoSupportedAuthMechanismsError: reason += "Authentication mechanisms not supported"; break; -					case ClientError::UnexpectedElementError: reason += "Unexpected response"; break; -					case ClientError::ResourceBindError: reason += "Error binding resource"; break; -					case ClientError::SessionStartError: reason += "Error starting session"; break; -					case ClientError::StreamError: reason += "Stream error"; break; -					case ClientError::TLSError: reason += "Encryption error"; break; -					case ClientError::ClientCertificateLoadError: reason += "Error loading certificate (Invalid password?)"; break; -					case ClientError::ClientCertificateError: reason += "Certificate not authorized"; break; -					case ClientError::UnknownCertificateError: reason += "Unknown certificate"; break; -					case ClientError::CertificateExpiredError: reason += "Certificate has expired"; break; -					case ClientError::CertificateNotYetValidError: reason += "Certificate is not yet valid"; break; -					case ClientError::CertificateSelfSignedError: reason += "Certificate is self-signed"; break; -					case ClientError::CertificateRejectedError: reason += "Certificate has been rejected"; break; -					case ClientError::CertificateUntrustedError: reason += "Certificate is not trusted"; break; -					case ClientError::InvalidCertificatePurposeError: reason += "Certificate cannot be used for encrypting your connection"; break; -					case ClientError::CertificatePathLengthExceededError: reason += "Certificate path length constraint exceeded"; break; -					case ClientError::InvalidCertificateSignatureError: reason += "Invalid certificate signature"; break; -					case ClientError::InvalidCAError: reason += "Invalid Certificate Authority"; break; -					case ClientError::InvalidServerIdentityError: reason += "Certificate does not match the host identity"; break; -				} -				throw SluiftException(reason); +				throw SluiftException(*error);  			}  		} @@ -251,9 +180,8 @@ class SluiftClient {  		Client* client;  		ClientXMLTracer* tracer;  		bool rosterReceived; -		boost::optional<SoftwareVersion> softwareVersion; -		ErrorPayload::ref error;  		std::deque<Stanza::ref> pendingEvents; +		boost::optional<std::string> rawRequestResponse;  };  /******************************************************************************* @@ -400,6 +328,43 @@ static int sluift_client_send_presence(lua_State *L) {  	return 0;  } +static int sluift_client_get(lua_State *L) { +	SluiftClient* client = getClient(L); +	JID jid; +	std::string data; +	if (lua_type(L, 3) != LUA_TNONE) { +		jid = JID(std::string(luaL_checkstring(L, 2))); +		data = std::string(luaL_checkstring(L, 3)); +	} +	else { +		data = std::string(luaL_checkstring(L, 2)); +	} +	std::string result = client->sendQuery(jid, IQ::Get, data); +	lua_pushstring(L, result.c_str()); +	return 1; +} + +static int sluift_client_set(lua_State *L) { +	SluiftClient* client = getClient(L); +	JID jid; +	std::string data; +	if (lua_type(L, 3) != LUA_TNONE) { +		jid = JID(std::string(luaL_checkstring(L, 2))); +		data = std::string(luaL_checkstring(L, 3)); +	} +	else { +		data = std::string(luaL_checkstring(L, 2)); +	} +	std::string result = client->sendQuery(jid, IQ::Set, data); +	lua_pushstring(L, result.c_str()); +	return 1; +} + +static int sluift_client_send(lua_State *L) { +	getClient(L)->getClient()->sendData(std::string(luaL_checkstring(L, 2))); +	return 0; +} +  static int sluift_client_set_options(lua_State* L) {  	SluiftClient* client = getClient(L);  	luaL_checktype(L, 2, LUA_TTABLE); @@ -407,7 +372,11 @@ static int sluift_client_set_options(lua_State* L) {  	if (!lua_isnil(L, -1)) {  		client->getClient()->setUseStreamCompression(lua_toboolean(L, -1));  	} -	lua_pop(L, -1); +	lua_getfield(L, 2, "tls"); +	if (!lua_isnil(L, -1)) { +		bool useTLS = lua_toboolean(L, -1); +		client->getClient()->setUseTLS(useTLS ? Client::UseTLSWhenAvailable : Client::NeverUseTLS); +	}  	return 0;  } @@ -437,6 +406,8 @@ static void pushEvent(lua_State* L, Stanza::ref event) {  static int sluift_client_for_event(lua_State *L) {  	try { +		eventLoop.runOnce(); +  		SluiftClient* client = getClient(L);  		luaL_checktype(L, 2, LUA_TFUNCTION);  		int timeout = -1; @@ -472,6 +443,8 @@ static int sluift_client_for_event(lua_State *L) {  static int sluift_client_get_next_event(lua_State *L) {  	try { +		eventLoop.runOnce(); +  		SluiftClient* client = getClient(L);  		int timeout = -1;  		if (lua_type(L, 2) != LUA_TNONE) { @@ -500,6 +473,9 @@ static const luaL_reg sluift_client_functions[] = {  	{"disconnect",  sluift_client_disconnect},  	{"send_message", sluift_client_send_message},  	{"send_presence", sluift_client_send_presence}, +	{"get", sluift_client_get}, +	{"set", sluift_client_set}, +	{"send", sluift_client_send},  	{"set_version", sluift_client_set_version},  	{"get_roster", sluift_client_get_roster},  	{"get_version", sluift_client_get_version}, @@ -515,15 +491,37 @@ static const luaL_reg sluift_client_functions[] = {   ******************************************************************************/  static int sluift_new_client(lua_State *L) { -	JID jid(std::string(luaL_checkstring(L, 1))); -	std::string password(luaL_checkstring(L, 2)); +	try { +		JID jid(std::string(luaL_checkstring(L, 1))); +		std::string password(luaL_checkstring(L, 2)); -	SluiftClient** client = reinterpret_cast<SluiftClient**>(lua_newuserdata(L, sizeof(SluiftClient*))); -	luaL_getmetatable(L, SLUIFT_CLIENT); -	lua_setmetatable(L, -2); +		SluiftClient** client = reinterpret_cast<SluiftClient**>(lua_newuserdata(L, sizeof(SluiftClient*))); +		luaL_getmetatable(L, SLUIFT_CLIENT); +		lua_setmetatable(L, -2); -	*client = new SluiftClient(jid, password); -	return 1; +		*client = new SluiftClient(jid, password); +		return 1; +	} +	catch (const SluiftException& e) { +		return luaL_error(L, e.getReason().c_str()); +	} +} + +static int sluift_sleep(lua_State *L) { +	try { +		eventLoop.runOnce(); + +		int timeout = luaL_checknumber(L, 1); +		Watchdog watchdog(timeout, networkFactories.getTimerFactory()); +		while (!watchdog.getTimedOut()) { +			Swift::sleep(std::min(100, timeout)); +			eventLoop.runOnce(); +		} +		return 0; +	} +	catch (const SluiftException& e) { +		return luaL_error(L, e.getReason().c_str()); +	}  }  static int sluift_index(lua_State *L) { @@ -550,6 +548,7 @@ static int sluift_newindex(lua_State *L) {  static const luaL_reg sluift_functions[] = {  	{"new_client", sluift_new_client}, +	{"sleep", sluift_sleep},  	{NULL, NULL}  }; diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 8d9e678..e1c1d8e 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -50,6 +50,7 @@ ClientSession::ClientSession(  			stream(stream),  			allowPLAINOverNonTLS(false),  			useStreamCompression(true), +			useTLS(UseTLSWhenAvailable),  			needSessionStart(false),  			needResourceBind(false),  			needAcking(false), @@ -170,7 +171,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) {  			return;  		} -		if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption()) { +		if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption() && useTLS != NeverUseTLS) {  			state = WaitingForEncrypt;  			stream->writeElement(boost::shared_ptr<StartTLSRequest>(new StartTLSRequest()));  		} diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index ee3992d..25ee694 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -57,6 +57,11 @@ namespace Swift {  				Error(Type type) : type(type) {}  			}; +			enum UseTLS { +				NeverUseTLS, +				UseTLSWhenAvailable +			}; +  			~ClientSession();  			static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream) { @@ -75,6 +80,11 @@ namespace Swift {  				useStreamCompression = b;  			} +			void setUseTLS(UseTLS b) { +				useTLS = b; +			} + +  			bool getStreamManagementEnabled() const {  				return stanzaAckRequester_;  			} @@ -139,6 +149,7 @@ namespace Swift {  			boost::shared_ptr<SessionStream> stream;  			bool allowPLAINOverNonTLS;  			bool useStreamCompression; +			UseTLS useTLS;  			bool needSessionStart;  			bool needResourceBind;  			bool needAcking; diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index a199b16..f0c5333 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -22,7 +22,7 @@  namespace Swift { -CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), useStreamCompression(true), disconnectRequested_(false), certificateTrustChecker(NULL) { +CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), useStreamCompression(true), useTLS(UseTLSWhenAvailable), disconnectRequested_(false), certificateTrustChecker(NULL) {  	stanzaChannel_ = new ClientSessionStanzaChannel();  	stanzaChannel_->onMessageReceived.connect(boost::bind(&CoreClient::handleMessageReceived, this, _1));  	stanzaChannel_->onPresenceReceived.connect(boost::bind(&CoreClient::handlePresenceReceived, this, _1)); @@ -83,6 +83,14 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio  		session_ = ClientSession::create(jid_, sessionStream_);  		session_->setCertificateTrustChecker(certificateTrustChecker);  		session_->setUseStreamCompression(useStreamCompression); +		switch(useTLS) { +			case UseTLSWhenAvailable: +				session_->setUseTLS(ClientSession::UseTLSWhenAvailable); +				break; +			case NeverUseTLS: +				session_->setUseTLS(ClientSession::NeverUseTLS); +				break; +		}  		stanzaChannel_->setSession(session_);  		session_->onFinished.connect(boost::bind(&CoreClient::handleSessionFinished, this, _1));  		session_->onNeedCredentials.connect(boost::bind(&CoreClient::handleNeedCredentials, this)); @@ -242,6 +250,10 @@ void CoreClient::sendPresence(boost::shared_ptr<Presence> presence) {  	stanzaChannel_->sendPresence(presence);  } +void CoreClient::sendData(const std::string& data) { +	sessionStream_->writeData(data); +} +  bool CoreClient::isActive() const {  	return (session_ && !session_->isFinished()) || connector_;  } @@ -267,5 +279,9 @@ void CoreClient::setUseStreamCompression(bool b) {  	useStreamCompression = b;  } +void CoreClient::setUseTLS(UseTLS b) { +	useTLS = b; +} +  } diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index ee73396..eb9c42c 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -48,6 +48,11 @@ namespace Swift {  	 */  	class CoreClient : public Entity {  		public:  +			enum UseTLS { +				NeverUseTLS, +				UseTLSWhenAvailable +			}; +  			/**  			 * Constructs a client for the given JID with the given password.  			 * The given eventLoop will be used to post events to. @@ -83,6 +88,11 @@ namespace Swift {  			void sendPresence(Presence::ref);  			/** +			 * Sends raw, unchecked data. +			 */ +			void sendData(const std::string& data); + +			/**  			 * Returns the IQ router for this client.  			 */  			IQRouter* getIQRouter() const { @@ -148,6 +158,11 @@ namespace Swift {  			 */  			void setUseStreamCompression(bool b); +			/** +			 * Sets whether TLS encryption should be used. +			 */ +			void setUseTLS(UseTLS useTLS); +  		public:  			/**  			 * Emitted when the client was disconnected from the network. @@ -213,6 +228,7 @@ namespace Swift {  			std::string password_;  			NetworkFactories* networkFactories;  			bool useStreamCompression; +			UseTLS useTLS;  			ClientSessionStanzaChannel* stanzaChannel_;  			IQRouter* iqRouter_;  			Connector::ref connector_; diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 21c0ffb..756287c 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -329,6 +329,9 @@ class ClientSessionTest : public CppUnit::TestFixture {  					receivedEvents.push_back(Event(element));  				} +				virtual void writeData(const std::string&) { +				} +  				virtual bool supportsTLSEncryption() {  					return canTLSEncrypt;  				} diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp index af8962a..953973c 100644 --- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp +++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp @@ -115,6 +115,9 @@ class ComponentSessionTest : public CppUnit::TestFixture {  					receivedEvents.push_back(Event(element));  				} +				virtual void writeData(const std::string&) { +				} +  				virtual bool supportsTLSEncryption() {  					return false;  				} diff --git a/Swiften/Elements/RawXMLPayload.h b/Swiften/Elements/RawXMLPayload.h index b042b95..e583c12 100644 --- a/Swiften/Elements/RawXMLPayload.h +++ b/Swiften/Elements/RawXMLPayload.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2011 Remko Tronçon   * Licensed under the GNU General Public License v3.   * See Documentation/Licenses/GPLv3.txt for more information.   */ @@ -7,12 +7,13 @@  #pragma once  #include <string> -#include "Swiften/Elements/Payload.h" + +#include <Swiften/Elements/Payload.h>  namespace Swift {  	class RawXMLPayload : public Payload {  		public: -			RawXMLPayload() {} +			RawXMLPayload(const std::string& data = "") : rawXML_(data) {}  			void setRawXML(const std::string& data) {  				rawXML_ = data; diff --git a/Swiften/Queries/RawRequest.h b/Swiften/Queries/RawRequest.h new file mode 100644 index 0000000..477952f --- /dev/null +++ b/Swiften/Queries/RawRequest.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> +#include <typeinfo> + +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +namespace Swift { +	class RawRequest : public Request { +		public: +			typedef boost::shared_ptr<RawRequest> ref; + +			static ref create(IQ::Type type, const JID& recipient, const std::string& data, IQRouter* router) { +				return ref(new RawRequest(type, recipient, data, router)); +			} + +			boost::signal<void (const std::string&)> onResponse; + +		private: +			RawRequest(IQ::Type type, const JID& receiver, const std::string& data, IQRouter* router) : Request(type, receiver, boost::make_shared<RawXMLPayload>(data), router) { +			} + +			virtual void handleResponse(Payload::ref payload, ErrorPayload::ref error) { +				if (error) { +					onResponse(ErrorSerializer().serializePayload(error)); +				} +				else { +					assert(payload); +					PayloadSerializer* serializer = serializers.getPayloadSerializer(payload); +					assert(serializer); +					onResponse(serializer->serialize(payload)); +				} +			} + +		private: +			FullPayloadSerializerCollection serializers; +	}; +} diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp index 35475c1..6c47725 100644 --- a/Swiften/Queries/Request.cpp +++ b/Swiften/Queries/Request.cpp @@ -6,6 +6,7 @@  #include "Swiften/Queries/Request.h"  #include "Swiften/Queries/IQRouter.h" +#include <Swiften/Elements/RawXMLPayload.h>  namespace Swift { @@ -40,7 +41,11 @@ bool Request::handleIQ(boost::shared_ptr<IQ> iq) {  	bool handled = false;  	if (sent_ && iq->getID() == id_) {  		if (iq->getType() == IQ::Result) { -			handleResponse(iq->getPayloadOfSameType(payload_), ErrorPayload::ref()); +			boost::shared_ptr<Payload> payload = iq->getPayloadOfSameType(payload_); +			if (!payload && boost::dynamic_pointer_cast<RawXMLPayload>(payload_) && !iq->getPayloads().empty()) { +				payload = iq->getPayloads().front(); +			} +			handleResponse(payload, ErrorPayload::ref());  		}  		else {  			ErrorPayload::ref errorPayload = iq->getPayload<ErrorPayload>(); diff --git a/Swiften/Queries/UnitTest/RequestTest.cpp b/Swiften/Queries/UnitTest/RequestTest.cpp index e99149e..34d07c9 100644 --- a/Swiften/Queries/UnitTest/RequestTest.cpp +++ b/Swiften/Queries/UnitTest/RequestTest.cpp @@ -8,11 +8,13 @@  #include <cppunit/extensions/TestFactoryRegistry.h>  #include <boost/shared_ptr.hpp>  #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp>  #include "Swiften/Queries/GenericRequest.h"  #include "Swiften/Queries/IQRouter.h"  #include "Swiften/Queries/DummyIQChannel.h"  #include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/RawXMLPayload.h>  using namespace Swift; @@ -25,6 +27,8 @@ class RequestTest : public CppUnit::TestFixture {  		CPPUNIT_TEST(testHandleIQ_Error);  		CPPUNIT_TEST(testHandleIQ_ErrorWithoutPayload);  		CPPUNIT_TEST(testHandleIQ_BeforeSend); +		CPPUNIT_TEST(testHandleIQ_DifferentPayload); +		CPPUNIT_TEST(testHandleIQ_RawXMLPayload);  		CPPUNIT_TEST_SUITE_END();  	public: @@ -34,7 +38,26 @@ class RequestTest : public CppUnit::TestFixture {  				std::string text_;  		}; -		typedef GenericRequest<MyPayload> MyRequest; +		struct MyOtherPayload : public Payload { +		}; + +		class MyRequest : public Request { +			public: +				MyRequest( +						IQ::Type type, +						const JID& receiver, +						boost::shared_ptr<Payload> payload, +						IQRouter* router) : +							Request(type, receiver, payload, router) { +				} + +				virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { +					onResponse(payload, error); +				} + +			public: +				boost::signal<void (boost::shared_ptr<Payload>, ErrorPayload::ref)> onResponse; +		};  	public:  		void setUp() { @@ -132,6 +155,33 @@ class RequestTest : public CppUnit::TestFixture {  			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel_->iqs_.size()));  		} +		void testHandleIQ_DifferentPayload() { +			MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); +			testling.onResponse.connect(boost::bind(&RequestTest::handleDifferentResponse, this, _1, _2)); +			testling.send(); + +			responsePayload_ = boost::make_shared<MyOtherPayload>(); +			channel_->onIQReceived(createResponse("test-id")); + +			CPPUNIT_ASSERT_EQUAL(1, responsesReceived_); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedErrors.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); +		} + +		void testHandleIQ_RawXMLPayload() { +			payload_ = boost::make_shared<RawXMLPayload>("<bla/>"); +			MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); +			testling.onResponse.connect(boost::bind(&RequestTest::handleRawXMLResponse, this, _1, _2)); +			testling.send(); + +			responsePayload_ = boost::make_shared<MyOtherPayload>(); +			channel_->onIQReceived(createResponse("test-id")); + +			CPPUNIT_ASSERT_EQUAL(1, responsesReceived_); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedErrors.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); +		} +  	private:  		void handleResponse(boost::shared_ptr<Payload> p, ErrorPayload::ref e) {  			if (e) { @@ -145,6 +195,19 @@ class RequestTest : public CppUnit::TestFixture {  			}  		} +		void handleDifferentResponse(boost::shared_ptr<Payload> p, ErrorPayload::ref e) { +			CPPUNIT_ASSERT(!e); +			CPPUNIT_ASSERT(!p); +			++responsesReceived_; +		} + +		void handleRawXMLResponse(boost::shared_ptr<Payload> p, ErrorPayload::ref e) { +			CPPUNIT_ASSERT(!e); +			CPPUNIT_ASSERT(p); +			CPPUNIT_ASSERT(boost::dynamic_pointer_cast<MyOtherPayload>(p)); +			++responsesReceived_; +		} +  		boost::shared_ptr<IQ> createResponse(const std::string& id) {  			boost::shared_ptr<IQ> iq(new IQ(IQ::Result));  			iq->addPayload(responsePayload_); diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index 1736f80..ddb833e 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -88,6 +88,11 @@ void BasicSessionStream::writeFooter() {  	xmppLayer->writeFooter();  } +void BasicSessionStream::writeData(const std::string& data) { +	assert(available); +	xmppLayer->writeData(data); +} +  void BasicSessionStream::close() {  	connection->disconnect();  } diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index 747177a..b3f7421 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -42,6 +42,7 @@ namespace Swift {  			virtual void writeHeader(const ProtocolHeader& header);  			virtual void writeElement(boost::shared_ptr<Element>);  			virtual void writeFooter(); +			virtual void writeData(const std::string& data);  			virtual void addZLibCompression(); diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h index 017d3d4..2753878 100644 --- a/Swiften/Session/SessionStream.h +++ b/Swiften/Session/SessionStream.h @@ -43,6 +43,7 @@ namespace Swift {  			virtual void writeHeader(const ProtocolHeader& header) = 0;  			virtual void writeFooter() = 0;  			virtual void writeElement(boost::shared_ptr<Element>) = 0; +			virtual void writeData(const std::string& data) = 0;  			virtual void addZLibCompression() = 0; | 
 Swift
 Swift