diff options
author | Remko Tronçon <git@el-tramo.be> | 2011-03-01 20:17:23 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-03-01 20:17:23 (GMT) |
commit | ca3f25d09a703ff7c27267a5591ce5379886e1c9 (patch) | |
tree | b14c38655ea3c61beb79f8a895fc7e6ce2989a9e /Sluift | |
parent | 5ad284705760c451012a5d896251af538e7bcede (diff) | |
download | swift-contrib-ca3f25d09a703ff7c27267a5591ce5379886e1c9.zip swift-contrib-ca3f25d09a703ff7c27267a5591ce5379886e1c9.tar.bz2 |
Some more Sluift enhancements.
Diffstat (limited to 'Sluift')
-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 |
6 files changed, 262 insertions, 116 deletions
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} }; |