diff options
Diffstat (limited to 'Sluift')
147 files changed, 8113 insertions, 1039 deletions
diff --git a/Sluift/.gitignore b/Sluift/.gitignore index 35a18c0..e5fd1e5 100644 --- a/Sluift/.gitignore +++ b/Sluift/.gitignore @@ -2,3 +2,6 @@ lua.c sluift_dll.cpp sluift dll.c +boot.c +dll/ +exe/ diff --git a/Sluift/ClientHelpers.cpp b/Sluift/ClientHelpers.cpp new file mode 100644 index 0000000..8e07112 --- /dev/null +++ b/Sluift/ClientHelpers.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ClientHelpers.h> + +#include <Swiften/Client/ClientError.h> + +using namespace Swift; + +std::string Swift::getClientErrorString(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::RevokedError: reason += "Certificate got revoked"; break; + case ClientError::RevocationCheckFailedError: reason += "Failed to do revokation check"; 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::CertificateCardRemoved: reason += "Certificate card removed"; 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; + } + return reason; +} + diff --git a/Sluift/ClientHelpers.h b/Sluift/ClientHelpers.h new file mode 100644 index 0000000..eb78ba6 --- /dev/null +++ b/Sluift/ClientHelpers.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> + +#include <string> + +namespace Swift { + class ClientError; + + std::string getClientErrorString(const ClientError& error); +} diff --git a/Sluift/ElementConvertors/BodyConvertor.cpp b/Sluift/ElementConvertors/BodyConvertor.cpp new file mode 100644 index 0000000..a7abc1e --- /dev/null +++ b/Sluift/ElementConvertors/BodyConvertor.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/BodyConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Sluift/Lua/LuaUtils.h> + +using namespace Swift; + +BodyConvertor::BodyConvertor() : GenericLuaElementConvertor<Body>("body") { +} + +BodyConvertor::~BodyConvertor() { +} + +boost::shared_ptr<Body> BodyConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<Body> result = boost::make_shared<Body>(); + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "text")) { + result->setText(*value); + } + return result; +} + +void BodyConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<Body> payload) { + lua_createtable(L, 0, 0); + if (!payload->getText().empty()) { + lua_pushstring(L, payload->getText().c_str()); + lua_setfield(L, -2, "text"); + } +} diff --git a/Sluift/ElementConvertors/BodyConvertor.h b/Sluift/ElementConvertors/BodyConvertor.h new file mode 100644 index 0000000..b1cd494 --- /dev/null +++ b/Sluift/ElementConvertors/BodyConvertor.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/Body.h> + +namespace Swift { + class LuaElementConvertors; + + class BodyConvertor : public GenericLuaElementConvertor<Body> { + public: + BodyConvertor(); + virtual ~BodyConvertor(); + + virtual boost::shared_ptr<Body> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<Body>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/CommandConvertor.cpp b/Sluift/ElementConvertors/CommandConvertor.cpp new file mode 100644 index 0000000..7fb7b22 --- /dev/null +++ b/Sluift/ElementConvertors/CommandConvertor.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/CommandConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/Value.h> +#include <Sluift/LuaElementConvertors.h> + +using namespace Swift; + +static Command::Action convertActionFromString(const std::string& action) { + if (action == "cancel") { return Command::Cancel; } + else if (action == "execute") { return Command::Execute; } + else if (action == "complete") { return Command::Complete; } + else if (action == "prev") { return Command::Prev; } + else if (action == "next") { return Command::Next; } + return Command::NoAction; +} + +static std::string convertActionToString(Command::Action action) { + switch (action) { + case Command::Cancel: return "cancel"; + case Command::Execute: return "execute"; + case Command::Complete: return "complete"; + case Command::Prev: return "prev"; + case Command::Next: return "next"; + case Command::NoAction: assert(false); return ""; + } + assert(false); + return ""; +} + +CommandConvertor::CommandConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<Command>("command"), + convertors(convertors) { +} + +CommandConvertor::~CommandConvertor() { +} + +boost::shared_ptr<Command> CommandConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<Command> result = boost::make_shared<Command>(); + + lua_getfield(L, -1, "node"); + if (!lua_isnil(L, -1)) { + result->setNode(std::string(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + + lua_getfield(L, -1, "session_id"); + if (!lua_isnil(L, -1)) { + result->setSessionID(std::string(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + + lua_getfield(L, -1, "status"); + if (!lua_isnil(L, -1)) { + std::string statusText = Lua::checkString(L, -1); + Command::Status status = Command::NoStatus; + if (statusText == "executing") { status = Command::Executing; } + else if (statusText == "completed") { status = Command::Completed; } + else if (statusText == "canceled") { status = Command::Canceled; } + result->setStatus(status); + } + lua_pop(L, 1); + + lua_getfield(L, -1, "action"); + if (!lua_isnil(L, -1)) { + result->setAction(convertActionFromString(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + + lua_getfield(L, -1, "execute_action"); + if (!lua_isnil(L, -1)) { + result->setExecuteAction(convertActionFromString(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + + lua_getfield(L, -1, "available_actions"); + if (!lua_isnil(L, -1)) { + Lua::checkType(L, -1, LUA_TTABLE); + lua_pushnil(L); + for (lua_pushnil(L); lua_next(L, -2) != 0; ) { + result->addAvailableAction(convertActionFromString(Lua::checkString(L, -1))); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "notes"); + if (!lua_isnil(L, -1)) { + Lua::checkType(L, -1, LUA_TTABLE); + lua_pushnil(L); + for (lua_pushnil(L); lua_next(L, -2) != 0; ) { + Lua::checkType(L, -1, LUA_TTABLE); + std::string note; + lua_getfield(L, -1, "note"); + if (!lua_isnil(L, -1)) { + note = Lua::checkString(L, -1); + } + lua_pop(L, 1); + + Command::Note::Type noteType = Command::Note::Info; + lua_getfield(L, -1, "type"); + if (!lua_isnil(L, -1)) { + std::string type = Lua::checkString(L, -1); + if (type == "info") { noteType = Command::Note::Info; } + else if (type == "warn") { noteType = Command::Note::Warn; } + else if (type == "error") { noteType = Command::Note::Error; } + } + lua_pop(L, 1); + + result->addNote(Command::Note(note, noteType)); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "form"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> form = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setForm(form); + } + } + lua_pop(L, 1); + + return result; +} + +void CommandConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<Command> payload) { + Lua::Table result; + if (!payload->getNode().empty()) { + result["node"] = Lua::valueRef(payload->getNode()); + } + if (!payload->getSessionID().empty()) { + result["session_id"] = Lua::valueRef(payload->getSessionID()); + } + switch (payload->getStatus()) { + case Command::Executing: result["status"] = Lua::valueRef("executing"); break; + case Command::Completed: result["status"] = Lua::valueRef("completed"); break; + case Command::Canceled: result["status"] = Lua::valueRef("canceled"); break; + case Command::NoStatus: break; + } + + if (!payload->getNotes().empty()) { + std::vector<Lua::Value> notes; + foreach (const Command::Note& note, payload->getNotes()) { + Lua::Table noteTable; + if (!note.note.empty()) { + noteTable["note"] = Lua::valueRef(note.note); + } + switch (note.type) { + case Command::Note::Info: noteTable["type"] = Lua::valueRef("info"); break; + case Command::Note::Warn: noteTable["type"] = Lua::valueRef("warn"); break; + case Command::Note::Error: noteTable["type"] = Lua::valueRef("error"); break; + } + notes.push_back(noteTable); + } + result["notes"] = Lua::valueRef(notes); + } + + if (payload->getAction() != Command::NoAction) { + result["action"] = Lua::valueRef(convertActionToString(payload->getAction())); + } + + if (payload->getExecuteAction() != Command::NoAction) { + result["execute_action"] = Lua::valueRef(convertActionToString(payload->getAction())); + } + + if (!payload->getAvailableActions().empty()) { + std::vector<Lua::Value> availableActions; + foreach (const Command::Action& action, payload->getAvailableActions()) { + if (action != Command::NoAction) { + availableActions.push_back(convertActionToString(action)); + } + } + result["available_actions"] = Lua::valueRef(availableActions); + } + + Lua::pushValue(L, result); + + if (payload->getForm()) { + convertors->convertToLuaUntyped(L, payload->getForm()); + lua_setfield(L, -2, "form"); + } +} diff --git a/Sluift/ElementConvertors/CommandConvertor.h b/Sluift/ElementConvertors/CommandConvertor.h new file mode 100644 index 0000000..7008b50 --- /dev/null +++ b/Sluift/ElementConvertors/CommandConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/Command.h> + +namespace Swift { + class LuaElementConvertors; + + class CommandConvertor : public GenericLuaElementConvertor<Command> { + public: + CommandConvertor(LuaElementConvertors* convertors); + virtual ~CommandConvertor(); + + virtual boost::shared_ptr<Command> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<Command>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/DOMElementConvertor.cpp b/Sluift/ElementConvertors/DOMElementConvertor.cpp new file mode 100644 index 0000000..bb4256d --- /dev/null +++ b/Sluift/ElementConvertors/DOMElementConvertor.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/DOMElementConvertor.h> + +#include <iostream> +#include <boost/smart_ptr/make_shared.hpp> +#include <lua.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/LuaUtils.h> +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Parser/AttributeMap.h> +#include <Swiften/Parser/Attribute.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Sluift/Lua/Debug.h> + +using namespace Swift; + +namespace { + class ParserClient : public XMLParserClient { + public: + ParserClient(lua_State* L) : L(L), currentIndex(1) { + } + + virtual void handleStartElement( + const std::string& element, const std::string& ns, + const AttributeMap& attributes) SWIFTEN_OVERRIDE { + lua_pushnumber(L, currentIndex); + lua_newtable(L); + lua_pushstring(L, element.c_str()); + lua_setfield(L, -2, "tag"); + if (!ns.empty()) { + lua_pushstring(L, ns.c_str()); + lua_setfield(L, -2, "ns"); + } + if (!attributes.getEntries().empty()) { + lua_newtable(L); + int i = 1; + foreach(const AttributeMap::Entry& entry, attributes.getEntries()) { + lua_pushnumber(L, i); + lua_newtable(L); + lua_pushstring(L, entry.getAttribute().getName().c_str()); + lua_setfield(L, -2, "name"); + if (!entry.getAttribute().getNamespace().empty()) { + lua_pushstring(L, entry.getAttribute().getNamespace().c_str()); + lua_setfield(L, -2, "ns"); + } + lua_pushstring(L, entry.getValue().c_str()); + lua_setfield(L, -2, "value"); + lua_settable(L, -3); + ++i; + } + lua_setfield(L, -2, "attributes"); + } + + indexStack.push_back(currentIndex); + currentIndex = 1; + lua_newtable(L); + } + + virtual void handleEndElement( + const std::string&, const std::string&) SWIFTEN_OVERRIDE { + lua_setfield(L, -2, "children"); + lua_settable(L, -3); + currentIndex = indexStack.back(); + indexStack.pop_back(); + currentIndex++; + } + + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE { + lua_pushnumber(L, currentIndex); + lua_pushstring(L, data.c_str()); + lua_settable(L, -3); + currentIndex++; + } + + private: + lua_State* L; + std::vector<int> indexStack; + int currentIndex; + }; + + std::string serializeElement(lua_State* L) { + std::string tag; + lua_getfield(L, -1, "tag"); + if (lua_isstring(L, -1)) { + tag = lua_tostring(L, -1); + } + lua_pop(L, 1); + + std::string ns; + lua_getfield(L, -1, "ns"); + if (lua_isstring(L, -1)) { + ns = lua_tostring(L, -1); + } + lua_pop(L, 1); + + XMLElement element(tag, ns); + + lua_getfield(L, -1, "attributes"); + if (lua_istable(L, -1)) { + int index = Lua::absoluteOffset(L, -1); + for (lua_pushnil(L); lua_next(L, index) != 0; ) { + if (lua_istable(L, -1)) { + std::string attributeName; + lua_getfield(L, -1, "name"); + if (lua_isstring(L, -1)) { + attributeName = lua_tostring(L, -1); + } + lua_pop(L, 1); + + std::string attributeValue; + lua_getfield(L, -1, "value"); + if (lua_isstring(L, -1)) { + attributeValue = lua_tostring(L, -1); + } + lua_pop(L, 1); + + if (!attributeName.empty()) { + element.setAttribute(attributeName, attributeValue); + } + } + lua_pop(L, 1); // value + } + } + lua_pop(L, 1); // children + + lua_getfield(L, -1, "children"); + if (lua_istable(L, -1)) { + int index = Lua::absoluteOffset(L, -1); + for (lua_pushnil(L); lua_next(L, index) != 0; ) { + if (lua_isstring(L, -1)) { + element.addNode(boost::make_shared<XMLTextNode>(lua_tostring(L, -1))); + } + else if (lua_istable(L, -1)) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializeElement(L))); + } + lua_pop(L, 1); // value + } + } + lua_pop(L, 1); // children + + return element.serialize(); + } +} + +DOMElementConvertor::DOMElementConvertor() { +} + +DOMElementConvertor::~DOMElementConvertor() { +} + +boost::shared_ptr<Payload> DOMElementConvertor::convertFromLua(lua_State* L, int index, const std::string& type) { + if (!lua_istable(L, index) || type != "dom") { + return boost::shared_ptr<Payload>(); + } + return boost::make_shared<RawXMLPayload>(serializeElement(L).c_str()); +} + +boost::optional<std::string> DOMElementConvertor::convertToLua( + lua_State* L, boost::shared_ptr<Payload> payload) { + // Serialize payload to XML + PayloadSerializer* serializer = serializers.getPayloadSerializer(payload); + assert(serializer); + std::string serializedPayload = serializer->serialize(payload); + + lua_newtable(L); + + // Parse the payload again + ParserClient parserClient(L); + boost::shared_ptr<XMLParser> parser(parsers.createXMLParser(&parserClient)); + bool result = parser->parse(serializedPayload); + assert(result); + + // There can only be one element, so stripping the list + lua_pushnil(L); + lua_next(L, -2); + Lua::registerTableToString(L, -1); + + lua_replace(L, -3); + lua_settop(L, -2); + + return std::string("dom"); +} diff --git a/Sluift/ElementConvertors/DOMElementConvertor.h b/Sluift/ElementConvertors/DOMElementConvertor.h new file mode 100644 index 0000000..94d0669 --- /dev/null +++ b/Sluift/ElementConvertors/DOMElementConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/LuaElementConvertor.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> + +namespace Swift { + class DOMElementConvertor : public LuaElementConvertor { + public: + DOMElementConvertor(); + virtual ~DOMElementConvertor(); + + virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE; + virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE; + + private: + PlatformXMLParserFactory parsers; + FullPayloadSerializerCollection serializers; + }; +} diff --git a/Sluift/ElementConvertors/DefaultElementConvertor.cpp b/Sluift/ElementConvertors/DefaultElementConvertor.cpp new file mode 100644 index 0000000..62c799b --- /dev/null +++ b/Sluift/ElementConvertors/DefaultElementConvertor.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/DefaultElementConvertor.h> + +#include <iostream> +#include <typeinfo> +#include <string> + +using namespace Swift; + +DefaultElementConvertor::DefaultElementConvertor() { +} + +DefaultElementConvertor::~DefaultElementConvertor() { +} + +boost::shared_ptr<Payload> DefaultElementConvertor::convertFromLua(lua_State*, int, const std::string& type) { + std::cerr << "Warning: Unable to convert type '" << type << "'" << std::endl; + return boost::shared_ptr<Payload>(); +} + +boost::optional<std::string> DefaultElementConvertor::convertToLua(lua_State*, boost::shared_ptr<Payload>) { + // Should have been handled by the raw XML convertor + assert(false); + return NO_RESULT; +} diff --git a/Sluift/ElementConvertors/DefaultElementConvertor.h b/Sluift/ElementConvertors/DefaultElementConvertor.h new file mode 100644 index 0000000..ad8fe75 --- /dev/null +++ b/Sluift/ElementConvertors/DefaultElementConvertor.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/LuaElementConvertor.h> + +namespace Swift { + class DefaultElementConvertor : public LuaElementConvertor { + public: + DefaultElementConvertor(); + virtual ~DefaultElementConvertor(); + + virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE; + virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/DiscoInfoConvertor.cpp b/Sluift/ElementConvertors/DiscoInfoConvertor.cpp new file mode 100644 index 0000000..ac0cf2e --- /dev/null +++ b/Sluift/ElementConvertors/DiscoInfoConvertor.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/DiscoInfoConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/LuaUtils.h> + +using namespace Swift; + +DiscoInfoConvertor::DiscoInfoConvertor() : GenericLuaElementConvertor<DiscoInfo>("disco_info") { +} + +DiscoInfoConvertor::~DiscoInfoConvertor() { +} + +boost::shared_ptr<DiscoInfo> DiscoInfoConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<DiscoInfo> result = boost::make_shared<DiscoInfo>(); + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "node")) { + result->setNode(*value); + } + + lua_getfield(L, -1, "identities"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + result->addIdentity(DiscoInfo::Identity( + Lua::getStringField(L, -1, "name").get_value_or(""), + Lua::getStringField(L, -1, "category").get_value_or("client"), + Lua::getStringField(L, -1, "type").get_value_or("pc"), + Lua::getStringField(L, -1, "language").get_value_or(""))); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "features"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + if (lua_isstring(L, -1)) { + result->addFeature(lua_tostring(L, -1)); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + // TODO: Extension + + return result; +} + +void DiscoInfoConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<DiscoInfo> payload) { + lua_newtable(L); + if (!payload->getNode().empty()) { + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + } + + const std::vector<DiscoInfo::Identity>& identities = payload->getIdentities(); + if (!identities.empty()) { + lua_createtable(L, boost::numeric_cast<int>(identities.size()), 0); + for (size_t i = 0; i < identities.size(); ++i) { + lua_createtable(L, 0, 0); + if (!identities[i].getName().empty()) { + lua_pushstring(L, identities[i].getName().c_str()); + lua_setfield(L, -2, "name"); + } + if (!identities[i].getCategory().empty()) { + lua_pushstring(L, identities[i].getCategory().c_str()); + lua_setfield(L, -2, "category"); + } + if (!identities[i].getType().empty()) { + lua_pushstring(L, identities[i].getType().c_str()); + lua_setfield(L, -2, "type"); + } + if (!identities[i].getLanguage().empty()) { + lua_pushstring(L, identities[i].getLanguage().c_str()); + lua_setfield(L, -2, "language"); + } + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + } + lua_setfield(L, -2, "identities"); + } + + const std::vector<std::string>& features = payload->getFeatures(); + if (!features.empty()) { + lua_createtable(L, boost::numeric_cast<int>(features.size()), 0); + for (size_t i = 0; i < features.size(); ++i) { + lua_pushstring(L, features[i].c_str()); + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + } + lua_setfield(L, -2, "features"); + } + + // TODO: Extension +} diff --git a/Sluift/ElementConvertors/DiscoInfoConvertor.h b/Sluift/ElementConvertors/DiscoInfoConvertor.h new file mode 100644 index 0000000..7a2270e --- /dev/null +++ b/Sluift/ElementConvertors/DiscoInfoConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/DiscoInfo.h> + +namespace Swift { + class DiscoInfoConvertor : public GenericLuaElementConvertor<DiscoInfo> { + public: + DiscoInfoConvertor(); + virtual ~DiscoInfoConvertor(); + + virtual boost::shared_ptr<DiscoInfo> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<DiscoInfo>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/DiscoItemsConvertor.cpp b/Sluift/ElementConvertors/DiscoItemsConvertor.cpp new file mode 100644 index 0000000..9049912 --- /dev/null +++ b/Sluift/ElementConvertors/DiscoItemsConvertor.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/DiscoItemsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/LuaUtils.h> + +using namespace Swift; + +DiscoItemsConvertor::DiscoItemsConvertor() : GenericLuaElementConvertor<DiscoItems>("disco_items") { +} + +DiscoItemsConvertor::~DiscoItemsConvertor() { +} + +boost::shared_ptr<DiscoItems> DiscoItemsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<DiscoItems> result = boost::make_shared<DiscoItems>(); + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "node")) { + result->setNode(*value); + } + lua_getfield(L, -1, "items"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + result->addItem(DiscoItems::Item( + Lua::getStringField(L, -1, "name").get_value_or(""), + JID(Lua::getStringField(L, -1, "jid").get_value_or("")), + Lua::getStringField(L, -1, "node").get_value_or(""))); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + return result; +} + +void DiscoItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<DiscoItems> payload) { + lua_newtable(L); + if (!payload->getNode().empty()) { + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + } + const std::vector<DiscoItems::Item>& items = payload->getItems(); + if (!items.empty()) { + lua_createtable(L, boost::numeric_cast<int>(items.size()), 0); + for (size_t i = 0; i < items.size(); ++i) { + lua_createtable(L, 0, 0); + if (!items[i].getName().empty()) { + lua_pushstring(L, items[i].getName().c_str()); + lua_setfield(L, -2, "name"); + } + if (!items[i].getNode().empty()) { + lua_pushstring(L, items[i].getNode().c_str()); + lua_setfield(L, -2, "node"); + } + if (items[i].getJID().isValid()) { + lua_pushstring(L, items[i].getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + } + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + } + lua_setfield(L, -2, "items"); + } +} diff --git a/Sluift/ElementConvertors/DiscoItemsConvertor.h b/Sluift/ElementConvertors/DiscoItemsConvertor.h new file mode 100644 index 0000000..8972a84 --- /dev/null +++ b/Sluift/ElementConvertors/DiscoItemsConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/DiscoItems.h> + +namespace Swift { + class DiscoItemsConvertor : public GenericLuaElementConvertor<DiscoItems> { + public: + DiscoItemsConvertor(); + virtual ~DiscoItemsConvertor(); + + virtual boost::shared_ptr<DiscoItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<DiscoItems>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/ElementConvertors.ipp b/Sluift/ElementConvertors/ElementConvertors.ipp new file mode 100644 index 0000000..b7b9166 --- /dev/null +++ b/Sluift/ElementConvertors/ElementConvertors.ipp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubRetractConvertor.h> +#include <Sluift/ElementConvertors/PubSubAffiliationsConvertor.h> +#include <Sluift/ElementConvertors/PubSubPublishConvertor.h> +#include <Sluift/ElementConvertors/PubSubItemsConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h> +#include <Sluift/ElementConvertors/PubSubConfigureConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h> +#include <Sluift/ElementConvertors/UserLocationConvertor.h> +#include <Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h> +#include <Sluift/ElementConvertors/PubSubDefaultConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventCollectionConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventRetractConvertor.h> +#include <Sluift/ElementConvertors/PubSubItemConvertor.h> +#include <Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventDeleteConvertor.h> +#include <Sluift/ElementConvertors/PubSubCreateConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventItemsConvertor.h> +#include <Sluift/ElementConvertors/PubSubOptionsConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventItemConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventPurgeConvertor.h> +#include <Sluift/ElementConvertors/PubSubAffiliationConvertor.h> +#include <Sluift/ElementConvertors/PubSubSubscribeConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h> +#include <Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h> +#include <Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventAssociateConvertor.h> +#include <Sluift/ElementConvertors/PubSubSubscriptionConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h> + +void LuaElementConvertors::registerConvertors() { + convertors.push_back(boost::make_shared<PubSubRetractConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubAffiliationsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubPublishConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubItemsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerRedirectConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventRedirectConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubConfigureConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventDisassociateConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerAffiliationsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerConfigureConvertor>(this)); + convertors.push_back(boost::make_shared<UserLocationConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubSubscribeOptionsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerSubscriptionsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubDefaultConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventCollectionConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventSubscriptionConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventRetractConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubItemConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubUnsubscribeConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventDeleteConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubCreateConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerPurgeConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventItemsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOptionsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventItemConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerSubscriptionConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerAffiliationConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventPurgeConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubAffiliationConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubSubscribeConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerDeleteConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubOwnerDefaultConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubSubscriptionsConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventAssociateConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubSubscriptionConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventConfigurationConvertor>(this)); +} diff --git a/Sluift/ElementConvertors/FormConvertor.cpp b/Sluift/ElementConvertors/FormConvertor.cpp new file mode 100644 index 0000000..e44ca3e --- /dev/null +++ b/Sluift/ElementConvertors/FormConvertor.cpp @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/FormConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/Value.h> +#include <Swiften/Base/foreach.h> +#include <boost/assign/list_of.hpp> +#include <sstream> + +using namespace Swift; + +namespace { + int formIndex(lua_State* L) { + lua_getfield(L, 1, "fields"); + if (lua_type(L, -1) != LUA_TTABLE) { + return 0; + } + int index = Lua::absoluteOffset(L, -1); + lua_pushnil(L); + for (lua_pushnil(L); lua_next(L, index) != 0; ) { + lua_getfield(L, -1, "name"); + if (lua_equal(L, -1, 2)) { + lua_pop(L, 1); + return 1; + } + lua_pop(L, 2); + } + return 0; + } + + int formNewIndex(lua_State* L) { + lua_getfield(L, 1, "fields"); + bool foundField = false; + if (lua_type(L, -1) == LUA_TTABLE) { + for (lua_pushnil(L); lua_next(L, -2) != 0; ) { + lua_getfield(L, -1, "name"); + if (lua_equal(L, -1, 2)) { + lua_pushvalue(L, 3); + lua_setfield(L, -3, "value"); + foundField = true; + lua_pop(L, 3); + break; + } + lua_pop(L, 2); + } + } + lua_pop(L, 1); + + if (!foundField) { + lua_pushvalue(L, 2); + lua_pushvalue(L, 3); + lua_rawset(L, 1); + } + return 0; + } + + Lua::Table convertFieldToLua(boost::shared_ptr<FormField> field) { + Lua::Table luaField = boost::assign::map_list_of("name", Lua::valueRef(field->getName())); + std::string type; + switch (field->getType()) { + case FormField::UnknownType: type = ""; break; + case FormField::BooleanType: type = "boolean"; break; + case FormField::FixedType: type = "fixed"; break; + case FormField::HiddenType: type = "hidden"; break; + case FormField::ListSingleType: type = "list-single"; break; + case FormField::TextMultiType: type = "text-multi"; break; + case FormField::TextPrivateType: type = "text-private"; break; + case FormField::TextSingleType: type = "text-single"; break; + case FormField::JIDSingleType: type = "jid-single"; break; + case FormField::JIDMultiType: type = "jid-multi"; break; + case FormField::ListMultiType: type = "list-multi"; break; + } + if (!type.empty()) { + luaField["type"] = Lua::valueRef(type); + } + if (!field->getLabel().empty()) { + luaField["label"] = Lua::valueRef(field->getLabel()); + } + if (field->getRequired()) { + luaField["required"] = Lua::boolRef(field->getRequired()); + } + if (!field->getDescription().empty()) { + luaField["description"] = Lua::valueRef(field->getDescription()); + } + + if (field->getType() == FormField::ListMultiType || field->getType() == FormField::JIDMultiType || field->getType() == FormField::TextMultiType) { + luaField["values"] = Lua::valueRef(Lua::Array(field->getValues().begin(), field->getValues().end())); + } + else if (field->getType() == FormField::BooleanType) { + luaField["value"] = Lua::boolRef(field->getBoolValue()); + } + else if (!field->getValues().empty()) { + luaField["value"] = Lua::valueRef(field->getValues()[0]); + } + + if (!field->getOptions().empty()) { + Lua::Array options; + foreach(const FormField::Option& option, field->getOptions()) { + Lua::Table luaOption = boost::assign::map_list_of + ("label", Lua::valueRef(option.label)) + ("value", Lua::valueRef(option.value)); + options.push_back(luaOption); + } + luaField["options"] = valueRef(options); + } + return luaField; + } + + Lua::Array convertFieldListToLua(const std::vector< boost::shared_ptr<FormField> >& fieldList) { + Lua::Array fields; + foreach(boost::shared_ptr<FormField> field, fieldList) { + fields.push_back(convertFieldToLua(field)); + } + return fields; + } + + + boost::shared_ptr<FormField> convertFieldFromLua(lua_State* L) { + boost::shared_ptr<FormField> result = boost::make_shared<FormField>(); + FormField::Type fieldType = FormField::UnknownType; + boost::optional<std::string> type = Lua::getStringField(L, -1, "type"); + if (type) { + if (*type == "boolean") { + fieldType = FormField::BooleanType; + } + if (*type == "fixed") { + fieldType = FormField::FixedType; + } + if (*type == "hidden") { + fieldType = FormField::HiddenType; + } + if (*type == "list-single") { + fieldType = FormField::ListSingleType; + } + if (*type == "text-multi") { + fieldType = FormField::TextMultiType; + } + if (*type == "text-private") { + fieldType = FormField::TextPrivateType; + } + if (*type == "text-single") { + fieldType = FormField::TextSingleType; + } + if (*type == "jid-single") { + fieldType = FormField::JIDSingleType; + } + if (*type == "jid-multi") { + fieldType = FormField::JIDMultiType; + } + if (*type == "list-multi") { + fieldType = FormField::ListMultiType; + } + } + result->setType(fieldType); + if (boost::optional<std::string> name = Lua::getStringField(L, -1, "name")) { + result->setName(*name); + } + if (boost::optional<std::string> description = Lua::getStringField(L, -1, "description")) { + result->setDescription(*description); + } + if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) { + result->setLabel(*label); + } + if (boost::optional<bool> required = Lua::getBooleanField(L, -1, "required")) { + result->setRequired(*required); + } + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) { + result->addValue(*value); + } + else if (boost::optional<bool> value = Lua::getBooleanField(L, -1, "value")) { + result->setBoolValue(*value); + } + else { + lua_getfield(L, -1, "values"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + if (lua_isstring(L, -1)) { + result->addValue(lua_tostring(L, -1)); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + lua_getfield(L, -1, "options"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + if (lua_istable(L, -1)) { + FormField::Option option("", ""); + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) { + option.value = *value; + } + if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) { + option.label = *label; + } + result->addOption(option); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + return result; + } + + std::vector< boost::shared_ptr<FormField> > convertFieldListFromLua(lua_State* L) { + std::vector< boost::shared_ptr<FormField> > result; + for (lua_pushnil(L); lua_next(L, -2);) { + result.push_back(convertFieldFromLua(L)); + lua_pop(L, 1); + } + return result; + } + + boost::shared_ptr<Form> convertFormFromLua(lua_State* L) { + boost::shared_ptr<Form> result = boost::make_shared<Form>(); + if (boost::optional<std::string> title = Lua::getStringField(L, -1, "title")) { + result->setTitle(*title); + } + if (boost::optional<std::string> instructions = Lua::getStringField(L, -1, "instructions")) { + result->setInstructions(*instructions); + } + if (boost::optional<std::string> type = Lua::getStringField(L, -1, "type")) { + Form::Type formType = Form::FormType; + if (*type == "submit") { + formType = Form::SubmitType; + } + else if (*type == "cancel") { + formType = Form::CancelType; + } + else if (*type == "result") { + formType = Form::ResultType; + } + result->setType(formType); + } + + lua_getfield(L, -1, "fields"); + if (lua_istable(L, -1)) { + foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) { + result->addField(formField); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "reported_fields"); + if (lua_istable(L, -1)) { + foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) { + result->addReportedField(formField); + } + } + lua_pop(L, 1); + + lua_getfield(L, -1, "items"); + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2);) { + result->addItem(convertFieldListFromLua(L)); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + return result; + } + + void convertFormToLua(lua_State* L, boost::shared_ptr<Form> payload) { + std::string type; + switch (payload->getType()) { + case Form::FormType: type = "form"; break; + case Form::SubmitType: type = "submit"; break; + case Form::CancelType: type = "cancel"; break; + case Form::ResultType: type = "result"; break; + } + + Lua::Table result = boost::assign::map_list_of("type", Lua::valueRef(type)); + if (!payload->getTitle().empty()) { + result["title"] = Lua::valueRef(payload->getTitle()); + } + if (!payload->getInstructions().empty()) { + result["instructions"] = Lua::valueRef(payload->getInstructions()); + } + if (!payload->getFields().empty()) { + result["fields"] = valueRef(convertFieldListToLua(payload->getFields())); + } + if (!payload->getReportedFields().empty()) { + result["reported_fields"] = valueRef(convertFieldListToLua(payload->getReportedFields())); + } + + if (!payload->getItems().empty()) { + Lua::Array luaItems; + foreach(const Form::FormItem& item, payload->getItems()) { + if (!item.empty()) { + luaItems.push_back(convertFieldListToLua(item)); + } + } + result["items"] = valueRef(luaItems); + } + + Lua::pushValue(L, result); + + lua_newtable(L); + lua_pushcfunction(L, formIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, formNewIndex); + lua_setfield(L, -2, "__newindex"); + lua_setmetatable(L, -2); + } + + int createSubmission(lua_State* L) { + boost::shared_ptr<Form> form = convertFormFromLua(L); + + // Remove all redundant elements + form->setInstructions(""); + form->setTitle(""); + form->clearItems(); + form->clearReportedFields(); + std::vector< boost::shared_ptr<FormField> > fields(form->getFields()); + form->clearFields(); + foreach (boost::shared_ptr<FormField> field, fields) { + if (field->getType() == FormField::FixedType) { + continue; + } + field->clearOptions(); + field->setLabel(""); + field->setType(FormField::UnknownType); + field->setDescription(""); + form->addField(field); + } + form->setType(Form::SubmitType); + + // Convert back + convertFormToLua(L, form); + Lua::registerTableToString(L, -1); + + return 1; + } +} + +FormConvertor::FormConvertor() : GenericLuaElementConvertor<Form>("form") { +} + +FormConvertor::~FormConvertor() { +} + +boost::shared_ptr<Form> FormConvertor::doConvertFromLua(lua_State* L) { + return convertFormFromLua(L); +} + +void FormConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<Form> payload) { + convertFormToLua(L, payload); + + lua_pushstring(L, "create_submission"); + lua_pushcfunction(L, createSubmission); + lua_rawset(L, -3); +} diff --git a/Sluift/ElementConvertors/FormConvertor.h b/Sluift/ElementConvertors/FormConvertor.h new file mode 100644 index 0000000..eaccf74 --- /dev/null +++ b/Sluift/ElementConvertors/FormConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/Form.h> + +namespace Swift { + class FormConvertor : public GenericLuaElementConvertor<Form> { + public: + FormConvertor(); + virtual ~FormConvertor(); + + virtual boost::shared_ptr<Form> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<Form>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp b/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp new file mode 100644 index 0000000..73d7d6a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubAffiliationConvertor.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubAffiliationConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubAffiliationConvertor::PubSubAffiliationConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubAffiliation>("pubsub_affiliation"), + convertors(convertors) { +} + +PubSubAffiliationConvertor::~PubSubAffiliationConvertor() { +} + +boost::shared_ptr<PubSubAffiliation> PubSubAffiliationConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubAffiliation> result = boost::make_shared<PubSubAffiliation>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "type"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setType(PubSubAffiliation::None); + } + if (std::string(lua_tostring(L, -1)) == "member") { + result->setType(PubSubAffiliation::Member); + } + if (std::string(lua_tostring(L, -1)) == "outcast") { + result->setType(PubSubAffiliation::Outcast); + } + if (std::string(lua_tostring(L, -1)) == "owner") { + result->setType(PubSubAffiliation::Owner); + } + if (std::string(lua_tostring(L, -1)) == "publisher") { + result->setType(PubSubAffiliation::Publisher); + } + if (std::string(lua_tostring(L, -1)) == "publish_only") { + result->setType(PubSubAffiliation::PublishOnly); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubAffiliationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubAffiliation> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + switch (payload->getType()) { + case PubSubAffiliation::None: + lua_pushstring(L, "none"); + break; + case PubSubAffiliation::Member: + lua_pushstring(L, "member"); + break; + case PubSubAffiliation::Outcast: + lua_pushstring(L, "outcast"); + break; + case PubSubAffiliation::Owner: + lua_pushstring(L, "owner"); + break; + case PubSubAffiliation::Publisher: + lua_pushstring(L, "publisher"); + break; + case PubSubAffiliation::PublishOnly: + lua_pushstring(L, "publish_only"); + break; + } + lua_setfield(L, -2, "type"); +} diff --git a/Sluift/ElementConvertors/PubSubAffiliationConvertor.h b/Sluift/ElementConvertors/PubSubAffiliationConvertor.h new file mode 100644 index 0000000..632a8d7 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubAffiliationConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubAffiliation.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubAffiliationConvertor : public GenericLuaElementConvertor<PubSubAffiliation> { + public: + PubSubAffiliationConvertor(LuaElementConvertors* convertors); + virtual ~PubSubAffiliationConvertor(); + + virtual boost::shared_ptr<PubSubAffiliation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubAffiliation>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp new file mode 100644 index 0000000..9f34235 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubAffiliationsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubAffiliationsConvertor::PubSubAffiliationsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubAffiliations>("pubsub_affiliations"), + convertors(convertors) { +} + +PubSubAffiliationsConvertor::~PubSubAffiliationsConvertor() { +} + +boost::shared_ptr<PubSubAffiliations> PubSubAffiliationsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubAffiliations> result = boost::make_shared<PubSubAffiliations>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubAffiliation> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubAffiliation> payload = boost::dynamic_pointer_cast<PubSubAffiliation>(convertors->convertFromLuaUntyped(L, -1, "pubsub_affiliation"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setAffiliations(items); + } + return result; +} + +void PubSubAffiliationsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubAffiliations> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (!payload->getAffiliations().empty()) { + { + int i = 0; + foreach(boost::shared_ptr<PubSubAffiliation> item, payload->getAffiliations()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + } +} diff --git a/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h new file mode 100644 index 0000000..fb0279a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubAffiliationsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubAffiliations.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubAffiliationsConvertor : public GenericLuaElementConvertor<PubSubAffiliations> { + public: + PubSubAffiliationsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubAffiliationsConvertor(); + + virtual boost::shared_ptr<PubSubAffiliations> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubAffiliations>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp b/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp new file mode 100644 index 0000000..893bc27 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubConfigureConvertor.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubConfigureConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubConfigureConvertor::PubSubConfigureConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubConfigure>("pubsub_configure"), + convertors(convertors) { +} + +PubSubConfigureConvertor::~PubSubConfigureConvertor() { +} + +boost::shared_ptr<PubSubConfigure> PubSubConfigureConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubConfigure> result = boost::make_shared<PubSubConfigure>(); + lua_getfield(L, -1, "data"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setData(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubConfigureConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubConfigure> payload) { + lua_createtable(L, 0, 0); + if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) { + lua_setfield(L, -2, "data"); + } +} diff --git a/Sluift/ElementConvertors/PubSubConfigureConvertor.h b/Sluift/ElementConvertors/PubSubConfigureConvertor.h new file mode 100644 index 0000000..0dd9094 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubConfigureConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubConfigure.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubConfigureConvertor : public GenericLuaElementConvertor<PubSubConfigure> { + public: + PubSubConfigureConvertor(LuaElementConvertors* convertors); + virtual ~PubSubConfigureConvertor(); + + virtual boost::shared_ptr<PubSubConfigure> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubConfigure>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubCreateConvertor.cpp b/Sluift/ElementConvertors/PubSubCreateConvertor.cpp new file mode 100644 index 0000000..64e2ee3 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubCreateConvertor.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubCreateConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubCreateConvertor::PubSubCreateConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubCreate>("pubsub_create"), + convertors(convertors) { +} + +PubSubCreateConvertor::~PubSubCreateConvertor() { +} + +boost::shared_ptr<PubSubCreate> PubSubCreateConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubCreate> result = boost::make_shared<PubSubCreate>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "configure"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubConfigure> payload = boost::dynamic_pointer_cast<PubSubConfigure>(convertors->convertFromLuaUntyped(L, -1, "pubsub_configure"))) { + result->setConfigure(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubCreateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubCreate> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (convertors->convertToLuaUntyped(L, payload->getConfigure()) > 0) { + lua_setfield(L, -2, "configure"); + } +} diff --git a/Sluift/ElementConvertors/PubSubCreateConvertor.h b/Sluift/ElementConvertors/PubSubCreateConvertor.h new file mode 100644 index 0000000..2cb1ea6 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubCreateConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubCreate.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubCreateConvertor : public GenericLuaElementConvertor<PubSubCreate> { + public: + PubSubCreateConvertor(LuaElementConvertors* convertors); + virtual ~PubSubCreateConvertor(); + + virtual boost::shared_ptr<PubSubCreate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubCreate>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp b/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp new file mode 100644 index 0000000..d9b68ac --- /dev/null +++ b/Sluift/ElementConvertors/PubSubDefaultConvertor.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubDefaultConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubDefaultConvertor::PubSubDefaultConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubDefault>("pubsub_default"), + convertors(convertors) { +} + +PubSubDefaultConvertor::~PubSubDefaultConvertor() { +} + +boost::shared_ptr<PubSubDefault> PubSubDefaultConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubDefault> result = boost::make_shared<PubSubDefault>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "type"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setType(PubSubDefault::None); + } + if (std::string(lua_tostring(L, -1)) == "collection") { + result->setType(PubSubDefault::Collection); + } + if (std::string(lua_tostring(L, -1)) == "leaf") { + result->setType(PubSubDefault::Leaf); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubDefaultConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubDefault> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + switch (payload->getType()) { + case PubSubDefault::None: + lua_pushstring(L, "none"); + break; + case PubSubDefault::Collection: + lua_pushstring(L, "collection"); + break; + case PubSubDefault::Leaf: + lua_pushstring(L, "leaf"); + break; + } + lua_setfield(L, -2, "type"); +} diff --git a/Sluift/ElementConvertors/PubSubDefaultConvertor.h b/Sluift/ElementConvertors/PubSubDefaultConvertor.h new file mode 100644 index 0000000..89dd9be --- /dev/null +++ b/Sluift/ElementConvertors/PubSubDefaultConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubDefault.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubDefaultConvertor : public GenericLuaElementConvertor<PubSubDefault> { + public: + PubSubDefaultConvertor(LuaElementConvertors* convertors); + virtual ~PubSubDefaultConvertor(); + + virtual boost::shared_ptr<PubSubDefault> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubDefault>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp new file mode 100644 index 0000000..2b004c8 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventAssociateConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventAssociateConvertor::PubSubEventAssociateConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventAssociate>("pubsub_event_associate"), + convertors(convertors) { +} + +PubSubEventAssociateConvertor::~PubSubEventAssociateConvertor() { +} + +boost::shared_ptr<PubSubEventAssociate> PubSubEventAssociateConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventAssociate> result = boost::make_shared<PubSubEventAssociate>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventAssociateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventAssociate> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); +} diff --git a/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h new file mode 100644 index 0000000..60c9d28 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventAssociateConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventAssociate.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventAssociateConvertor : public GenericLuaElementConvertor<PubSubEventAssociate> { + public: + PubSubEventAssociateConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventAssociateConvertor(); + + virtual boost::shared_ptr<PubSubEventAssociate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventAssociate>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp new file mode 100644 index 0000000..d05b479 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventCollectionConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventCollectionConvertor::PubSubEventCollectionConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventCollection>("pubsub_event_collection"), + convertors(convertors) { +} + +PubSubEventCollectionConvertor::~PubSubEventCollectionConvertor() { +} + +boost::shared_ptr<PubSubEventCollection> PubSubEventCollectionConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventCollection> result = boost::make_shared<PubSubEventCollection>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "disassociate"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubEventDisassociate> payload = boost::dynamic_pointer_cast<PubSubEventDisassociate>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_disassociate"))) { + result->setDisassociate(payload); + } + } + lua_pop(L, 1); + lua_getfield(L, -1, "associate"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubEventAssociate> payload = boost::dynamic_pointer_cast<PubSubEventAssociate>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_associate"))) { + result->setAssociate(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubEventCollectionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventCollection> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (convertors->convertToLuaUntyped(L, payload->getDisassociate()) > 0) { + lua_setfield(L, -2, "disassociate"); + } + if (convertors->convertToLuaUntyped(L, payload->getAssociate()) > 0) { + lua_setfield(L, -2, "associate"); + } +} diff --git a/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h new file mode 100644 index 0000000..eed2541 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventCollectionConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventCollection.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventCollectionConvertor : public GenericLuaElementConvertor<PubSubEventCollection> { + public: + PubSubEventCollectionConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventCollectionConvertor(); + + virtual boost::shared_ptr<PubSubEventCollection> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventCollection>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp new file mode 100644 index 0000000..ecdf145 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventConfigurationConvertor::PubSubEventConfigurationConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventConfiguration>("pubsub_event_configuration"), + convertors(convertors) { +} + +PubSubEventConfigurationConvertor::~PubSubEventConfigurationConvertor() { +} + +boost::shared_ptr<PubSubEventConfiguration> PubSubEventConfigurationConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventConfiguration> result = boost::make_shared<PubSubEventConfiguration>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "data"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setData(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubEventConfigurationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventConfiguration> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) { + lua_setfield(L, -2, "data"); + } +} diff --git a/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h new file mode 100644 index 0000000..4347ebc --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventConfigurationConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventConfiguration.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventConfigurationConvertor : public GenericLuaElementConvertor<PubSubEventConfiguration> { + public: + PubSubEventConfigurationConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventConfigurationConvertor(); + + virtual boost::shared_ptr<PubSubEventConfiguration> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventConfiguration>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventConvertor.cpp b/Sluift/ElementConvertors/PubSubEventConvertor.cpp new file mode 100644 index 0000000..46d870a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventConvertor.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventConvertor::PubSubEventConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEvent>("pubsub_event"), + convertors(convertors) { +} + +PubSubEventConvertor::~PubSubEventConvertor() { +} + +boost::shared_ptr<PubSubEvent> PubSubEventConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEvent> result = boost::make_shared<PubSubEvent>(); + if (boost::shared_ptr<PubSubEventPayload> payload = boost::dynamic_pointer_cast<PubSubEventPayload>(convertors->convertFromLua(L, -1))) { + result->setPayload(payload); + } + return result; +} + +void PubSubEventConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEvent> event) { + convertors->convertToLua(L, event->getPayload()); +} diff --git a/Sluift/ElementConvertors/PubSubEventConvertor.h b/Sluift/ElementConvertors/PubSubEventConvertor.h new file mode 100644 index 0000000..8250fc4 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEvent.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventConvertor : public GenericLuaElementConvertor<PubSubEvent> { + public: + PubSubEventConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventConvertor(); + + virtual boost::shared_ptr<PubSubEvent> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEvent>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp new file mode 100644 index 0000000..b03f22a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventDeleteConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventDeleteConvertor::PubSubEventDeleteConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventDelete>("pubsub_event_delete"), + convertors(convertors) { +} + +PubSubEventDeleteConvertor::~PubSubEventDeleteConvertor() { +} + +boost::shared_ptr<PubSubEventDelete> PubSubEventDeleteConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventDelete> result = boost::make_shared<PubSubEventDelete>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "redirects"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubEventRedirect> payload = boost::dynamic_pointer_cast<PubSubEventRedirect>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_redirect"))) { + result->setRedirects(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubEventDeleteConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventDelete> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (convertors->convertToLuaUntyped(L, payload->getRedirects()) > 0) { + lua_setfield(L, -2, "redirects"); + } +} diff --git a/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h new file mode 100644 index 0000000..a0cfd3d --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventDeleteConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventDelete.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventDeleteConvertor : public GenericLuaElementConvertor<PubSubEventDelete> { + public: + PubSubEventDeleteConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventDeleteConvertor(); + + virtual boost::shared_ptr<PubSubEventDelete> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventDelete>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp new file mode 100644 index 0000000..ccd8c6e --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventDisassociateConvertor::PubSubEventDisassociateConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventDisassociate>("pubsub_event_disassociate"), + convertors(convertors) { +} + +PubSubEventDisassociateConvertor::~PubSubEventDisassociateConvertor() { +} + +boost::shared_ptr<PubSubEventDisassociate> PubSubEventDisassociateConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventDisassociate> result = boost::make_shared<PubSubEventDisassociate>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventDisassociateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventDisassociate> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); +} diff --git a/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h new file mode 100644 index 0000000..90c8232 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventDisassociate.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventDisassociateConvertor : public GenericLuaElementConvertor<PubSubEventDisassociate> { + public: + PubSubEventDisassociateConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventDisassociateConvertor(); + + virtual boost::shared_ptr<PubSubEventDisassociate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventDisassociate>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp b/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp new file mode 100644 index 0000000..fab4bff --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventItemConvertor.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventItemConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventItemConvertor::PubSubEventItemConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventItem>("pubsub_event_item"), + convertors(convertors) { +} + +PubSubEventItemConvertor::~PubSubEventItemConvertor() { +} + +boost::shared_ptr<PubSubEventItem> PubSubEventItemConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventItem> result = boost::make_shared<PubSubEventItem>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "publisher"); + if (lua_isstring(L, -1)) { + result->setPublisher(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "data"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<Payload> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Payload> payload = convertors->convertFromLua(L, -1)) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setData(items); + } + lua_pop(L, 1); + lua_getfield(L, -1, "id"); + if (lua_isstring(L, -1)) { + result->setID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventItemConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventItem> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (payload->getPublisher()) { + lua_pushstring(L, (*payload->getPublisher()).c_str()); + lua_setfield(L, -2, "publisher"); + } + if (!payload->getData().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getData().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<Payload> item, payload->getData()) { + if (convertors->convertToLua(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "data"); + } + if (payload->getID()) { + lua_pushstring(L, (*payload->getID()).c_str()); + lua_setfield(L, -2, "id"); + } +} diff --git a/Sluift/ElementConvertors/PubSubEventItemConvertor.h b/Sluift/ElementConvertors/PubSubEventItemConvertor.h new file mode 100644 index 0000000..340602a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventItemConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventItem.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventItemConvertor : public GenericLuaElementConvertor<PubSubEventItem> { + public: + PubSubEventItemConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventItemConvertor(); + + virtual boost::shared_ptr<PubSubEventItem> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventItem>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp b/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp new file mode 100644 index 0000000..9996cc6 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventItemsConvertor.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventItemsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventItemsConvertor::PubSubEventItemsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventItems>("pubsub_event_items"), + convertors(convertors) { +} + +PubSubEventItemsConvertor::~PubSubEventItemsConvertor() { +} + +boost::shared_ptr<PubSubEventItems> PubSubEventItemsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventItems> result = boost::make_shared<PubSubEventItems>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "items"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubEventItem> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubEventItem> payload = boost::dynamic_pointer_cast<PubSubEventItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_item"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setItems(items); + } + lua_pop(L, 1); + lua_getfield(L, -1, "retracts"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubEventRetract> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubEventRetract> payload = boost::dynamic_pointer_cast<PubSubEventRetract>(convertors->convertFromLuaUntyped(L, -1, "pubsub_event_retract"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setRetracts(items); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventItems> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getItems().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<PubSubEventItem> item, payload->getItems()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "items"); + } + if (!payload->getRetracts().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getRetracts().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<PubSubEventRetract> item, payload->getRetracts()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "retracts"); + } +} diff --git a/Sluift/ElementConvertors/PubSubEventItemsConvertor.h b/Sluift/ElementConvertors/PubSubEventItemsConvertor.h new file mode 100644 index 0000000..9adbf15 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventItemsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventItems.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventItemsConvertor : public GenericLuaElementConvertor<PubSubEventItems> { + public: + PubSubEventItemsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventItemsConvertor(); + + virtual boost::shared_ptr<PubSubEventItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventItems>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp new file mode 100644 index 0000000..e389fcf --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventPurgeConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventPurgeConvertor::PubSubEventPurgeConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventPurge>("pubsub_event_purge"), + convertors(convertors) { +} + +PubSubEventPurgeConvertor::~PubSubEventPurgeConvertor() { +} + +boost::shared_ptr<PubSubEventPurge> PubSubEventPurgeConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventPurge> result = boost::make_shared<PubSubEventPurge>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventPurgeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventPurge> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); +} diff --git a/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h new file mode 100644 index 0000000..d94aa36 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventPurgeConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventPurge.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventPurgeConvertor : public GenericLuaElementConvertor<PubSubEventPurge> { + public: + PubSubEventPurgeConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventPurgeConvertor(); + + virtual boost::shared_ptr<PubSubEventPurge> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventPurge>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp new file mode 100644 index 0000000..6e128da --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventRedirectConvertor::PubSubEventRedirectConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventRedirect>("pubsub_event_redirect"), + convertors(convertors) { +} + +PubSubEventRedirectConvertor::~PubSubEventRedirectConvertor() { +} + +boost::shared_ptr<PubSubEventRedirect> PubSubEventRedirectConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventRedirect> result = boost::make_shared<PubSubEventRedirect>(); + lua_getfield(L, -1, "uri"); + if (lua_isstring(L, -1)) { + result->setURI(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventRedirectConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventRedirect> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getURI().c_str()); + lua_setfield(L, -2, "uri"); +} diff --git a/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h new file mode 100644 index 0000000..4904102 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventRedirectConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventRedirect.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventRedirectConvertor : public GenericLuaElementConvertor<PubSubEventRedirect> { + public: + PubSubEventRedirectConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventRedirectConvertor(); + + virtual boost::shared_ptr<PubSubEventRedirect> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventRedirect>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp b/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp new file mode 100644 index 0000000..aed29a0 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventRetractConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventRetractConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventRetractConvertor::PubSubEventRetractConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventRetract>("pubsub_event_retract"), + convertors(convertors) { +} + +PubSubEventRetractConvertor::~PubSubEventRetractConvertor() { +} + +boost::shared_ptr<PubSubEventRetract> PubSubEventRetractConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventRetract> result = boost::make_shared<PubSubEventRetract>(); + lua_getfield(L, -1, "id"); + if (lua_isstring(L, -1)) { + result->setID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventRetractConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventRetract> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getID().c_str()); + lua_setfield(L, -2, "id"); +} diff --git a/Sluift/ElementConvertors/PubSubEventRetractConvertor.h b/Sluift/ElementConvertors/PubSubEventRetractConvertor.h new file mode 100644 index 0000000..7a7c0f9 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventRetractConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventRetract.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventRetractConvertor : public GenericLuaElementConvertor<PubSubEventRetract> { + public: + PubSubEventRetractConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventRetractConvertor(); + + virtual boost::shared_ptr<PubSubEventRetract> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventRetract>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp new file mode 100644 index 0000000..a4c160f --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Swiften/Base/DateTime.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubEventSubscriptionConvertor::PubSubEventSubscriptionConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubEventSubscription>("pubsub_event_subscription"), + convertors(convertors) { +} + +PubSubEventSubscriptionConvertor::~PubSubEventSubscriptionConvertor() { +} + +boost::shared_ptr<PubSubEventSubscription> PubSubEventSubscriptionConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubEventSubscription> result = boost::make_shared<PubSubEventSubscription>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscription"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setSubscription(PubSubEventSubscription::None); + } + if (std::string(lua_tostring(L, -1)) == "pending") { + result->setSubscription(PubSubEventSubscription::Pending); + } + if (std::string(lua_tostring(L, -1)) == "subscribed") { + result->setSubscription(PubSubEventSubscription::Subscribed); + } + if (std::string(lua_tostring(L, -1)) == "unconfigured") { + result->setSubscription(PubSubEventSubscription::Unconfigured); + } + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscriptionid"); + if (lua_isstring(L, -1)) { + result->setSubscriptionID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "expiry"); + if (lua_isstring(L, -1)) { + result->setExpiry(stringToDateTime(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + return result; +} + +void PubSubEventSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubEventSubscription> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + switch (payload->getSubscription()) { + case PubSubEventSubscription::None: + lua_pushstring(L, "none"); + break; + case PubSubEventSubscription::Pending: + lua_pushstring(L, "pending"); + break; + case PubSubEventSubscription::Subscribed: + lua_pushstring(L, "subscribed"); + break; + case PubSubEventSubscription::Unconfigured: + lua_pushstring(L, "unconfigured"); + break; + } + lua_setfield(L, -2, "subscription"); + if (payload->getSubscriptionID()) { + lua_pushstring(L, (*payload->getSubscriptionID()).c_str()); + lua_setfield(L, -2, "subscriptionid"); + } + lua_pushstring(L, dateTimeToString(payload->getExpiry()).c_str()); + lua_setfield(L, -2, "expiry"); +} diff --git a/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h new file mode 100644 index 0000000..fa04fb7 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubEventSubscriptionConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubEventSubscription.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubEventSubscriptionConvertor : public GenericLuaElementConvertor<PubSubEventSubscription> { + public: + PubSubEventSubscriptionConvertor(LuaElementConvertors* convertors); + virtual ~PubSubEventSubscriptionConvertor(); + + virtual boost::shared_ptr<PubSubEventSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubEventSubscription>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubItemConvertor.cpp b/Sluift/ElementConvertors/PubSubItemConvertor.cpp new file mode 100644 index 0000000..e06065b --- /dev/null +++ b/Sluift/ElementConvertors/PubSubItemConvertor.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubItemConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubItemConvertor::PubSubItemConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubItem>("pubsub_item"), + convertors(convertors) { +} + +PubSubItemConvertor::~PubSubItemConvertor() { +} + +boost::shared_ptr<PubSubItem> PubSubItemConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubItem> result = boost::make_shared<PubSubItem>(); + lua_getfield(L, -1, "data"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<Payload> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Payload> payload = convertors->convertFromLua(L, -1)) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setData(items); + } + lua_pop(L, 1); + lua_getfield(L, -1, "id"); + if (lua_isstring(L, -1)) { + result->setID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubItemConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubItem> payload) { + lua_createtable(L, 0, 0); + if (!payload->getData().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getData().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<Payload> item, payload->getData()) { + if (convertors->convertToLua(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "data"); + } + lua_pushstring(L, payload->getID().c_str()); + lua_setfield(L, -2, "id"); +} diff --git a/Sluift/ElementConvertors/PubSubItemConvertor.h b/Sluift/ElementConvertors/PubSubItemConvertor.h new file mode 100644 index 0000000..176e1c4 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubItemConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubItem.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubItemConvertor : public GenericLuaElementConvertor<PubSubItem> { + public: + PubSubItemConvertor(LuaElementConvertors* convertors); + virtual ~PubSubItemConvertor(); + + virtual boost::shared_ptr<PubSubItem> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubItem>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubItemsConvertor.cpp b/Sluift/ElementConvertors/PubSubItemsConvertor.cpp new file mode 100644 index 0000000..5ecb72e --- /dev/null +++ b/Sluift/ElementConvertors/PubSubItemsConvertor.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubItemsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubItemsConvertor::PubSubItemsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubItems>("pubsub_items"), + convertors(convertors) { +} + +PubSubItemsConvertor::~PubSubItemsConvertor() { +} + +boost::shared_ptr<PubSubItems> PubSubItemsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubItems> result = boost::make_shared<PubSubItems>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubItem> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setItems(items); + } + lua_getfield(L, -1, "maximum_items"); + if (lua_isnumber(L, -1)) { + result->setMaximumItems(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscriptionid"); + if (lua_isstring(L, -1)) { + result->setSubscriptionID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubItemsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubItems> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getItems().empty()) { + { + int i = 0; + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + } + if (payload->getMaximumItems()) { + lua_pushnumber(L, (*payload->getMaximumItems())); + lua_setfield(L, -2, "maximum_items"); + } + if (payload->getSubscriptionID()) { + lua_pushstring(L, (*payload->getSubscriptionID()).c_str()); + lua_setfield(L, -2, "subscriptionid"); + } +} diff --git a/Sluift/ElementConvertors/PubSubItemsConvertor.h b/Sluift/ElementConvertors/PubSubItemsConvertor.h new file mode 100644 index 0000000..9978806 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubItemsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubItems.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubItemsConvertor : public GenericLuaElementConvertor<PubSubItems> { + public: + PubSubItemsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubItemsConvertor(); + + virtual boost::shared_ptr<PubSubItems> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubItems>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp new file mode 100644 index 0000000..cc27973 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOptionsConvertor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOptionsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOptionsConvertor::PubSubOptionsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOptions>("pubsub_options"), + convertors(convertors) { +} + +PubSubOptionsConvertor::~PubSubOptionsConvertor() { +} + +boost::shared_ptr<PubSubOptions> PubSubOptionsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOptions> result = boost::make_shared<PubSubOptions>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "data"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setData(payload); + } + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscriptionid"); + if (lua_isstring(L, -1)) { + result->setSubscriptionID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubOptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOptions> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) { + lua_setfield(L, -2, "data"); + } + if (payload->getSubscriptionID()) { + lua_pushstring(L, (*payload->getSubscriptionID()).c_str()); + lua_setfield(L, -2, "subscriptionid"); + } +} diff --git a/Sluift/ElementConvertors/PubSubOptionsConvertor.h b/Sluift/ElementConvertors/PubSubOptionsConvertor.h new file mode 100644 index 0000000..95a1dc8 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOptionsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOptions.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOptionsConvertor : public GenericLuaElementConvertor<PubSubOptions> { + public: + PubSubOptionsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOptionsConvertor(); + + virtual boost::shared_ptr<PubSubOptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOptions>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp new file mode 100644 index 0000000..f1a7b50 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerAffiliationConvertor::PubSubOwnerAffiliationConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerAffiliation>("pubsub_owner_affiliation"), + convertors(convertors) { +} + +PubSubOwnerAffiliationConvertor::~PubSubOwnerAffiliationConvertor() { +} + +boost::shared_ptr<PubSubOwnerAffiliation> PubSubOwnerAffiliationConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerAffiliation> result = boost::make_shared<PubSubOwnerAffiliation>(); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "type"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setType(PubSubOwnerAffiliation::None); + } + if (std::string(lua_tostring(L, -1)) == "member") { + result->setType(PubSubOwnerAffiliation::Member); + } + if (std::string(lua_tostring(L, -1)) == "outcast") { + result->setType(PubSubOwnerAffiliation::Outcast); + } + if (std::string(lua_tostring(L, -1)) == "owner") { + result->setType(PubSubOwnerAffiliation::Owner); + } + if (std::string(lua_tostring(L, -1)) == "publisher") { + result->setType(PubSubOwnerAffiliation::Publisher); + } + if (std::string(lua_tostring(L, -1)) == "publish_only") { + result->setType(PubSubOwnerAffiliation::PublishOnly); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerAffiliationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerAffiliation> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + switch (payload->getType()) { + case PubSubOwnerAffiliation::None: + lua_pushstring(L, "none"); + break; + case PubSubOwnerAffiliation::Member: + lua_pushstring(L, "member"); + break; + case PubSubOwnerAffiliation::Outcast: + lua_pushstring(L, "outcast"); + break; + case PubSubOwnerAffiliation::Owner: + lua_pushstring(L, "owner"); + break; + case PubSubOwnerAffiliation::Publisher: + lua_pushstring(L, "publisher"); + break; + case PubSubOwnerAffiliation::PublishOnly: + lua_pushstring(L, "publish_only"); + break; + } + lua_setfield(L, -2, "type"); +} diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h new file mode 100644 index 0000000..72bfaa1 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerAffiliation.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerAffiliationConvertor : public GenericLuaElementConvertor<PubSubOwnerAffiliation> { + public: + PubSubOwnerAffiliationConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerAffiliationConvertor(); + + virtual boost::shared_ptr<PubSubOwnerAffiliation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerAffiliation>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp new file mode 100644 index 0000000..bee8539 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerAffiliationsConvertor::PubSubOwnerAffiliationsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerAffiliations>("pubsub_owner_affiliations"), + convertors(convertors) { +} + +PubSubOwnerAffiliationsConvertor::~PubSubOwnerAffiliationsConvertor() { +} + +boost::shared_ptr<PubSubOwnerAffiliations> PubSubOwnerAffiliationsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerAffiliations> result = boost::make_shared<PubSubOwnerAffiliations>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubOwnerAffiliation> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubOwnerAffiliation> payload = boost::dynamic_pointer_cast<PubSubOwnerAffiliation>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_affiliation"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setAffiliations(items); + } + return result; +} + +void PubSubOwnerAffiliationsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerAffiliations> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getAffiliations().empty()) { + { + int i = 0; + foreach(boost::shared_ptr<PubSubOwnerAffiliation> item, payload->getAffiliations()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + } +} diff --git a/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h new file mode 100644 index 0000000..377e108 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerAffiliations.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerAffiliationsConvertor : public GenericLuaElementConvertor<PubSubOwnerAffiliations> { + public: + PubSubOwnerAffiliationsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerAffiliationsConvertor(); + + virtual boost::shared_ptr<PubSubOwnerAffiliations> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerAffiliations>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp new file mode 100644 index 0000000..87505e1 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerConfigureConvertor::PubSubOwnerConfigureConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerConfigure>("pubsub_owner_configure"), + convertors(convertors) { +} + +PubSubOwnerConfigureConvertor::~PubSubOwnerConfigureConvertor() { +} + +boost::shared_ptr<PubSubOwnerConfigure> PubSubOwnerConfigureConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerConfigure> result = boost::make_shared<PubSubOwnerConfigure>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "data"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setData(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerConfigureConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerConfigure> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) { + lua_setfield(L, -2, "data"); + } +} diff --git a/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h new file mode 100644 index 0000000..83b1153 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerConfigureConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerConfigure.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerConfigureConvertor : public GenericLuaElementConvertor<PubSubOwnerConfigure> { + public: + PubSubOwnerConfigureConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerConfigureConvertor(); + + virtual boost::shared_ptr<PubSubOwnerConfigure> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerConfigure>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp new file mode 100644 index 0000000..17612cc --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerDefaultConvertor::PubSubOwnerDefaultConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerDefault>("pubsub_owner_default"), + convertors(convertors) { +} + +PubSubOwnerDefaultConvertor::~PubSubOwnerDefaultConvertor() { +} + +boost::shared_ptr<PubSubOwnerDefault> PubSubOwnerDefaultConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerDefault> result = boost::make_shared<PubSubOwnerDefault>(); + lua_getfield(L, -1, "data"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<Form> payload = boost::dynamic_pointer_cast<Form>(convertors->convertFromLuaUntyped(L, -1, "form"))) { + result->setData(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerDefaultConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerDefault> payload) { + lua_createtable(L, 0, 0); + if (convertors->convertToLuaUntyped(L, payload->getData()) > 0) { + lua_setfield(L, -2, "data"); + } +} diff --git a/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h new file mode 100644 index 0000000..3a0f8ee --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerDefaultConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerDefault.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerDefaultConvertor : public GenericLuaElementConvertor<PubSubOwnerDefault> { + public: + PubSubOwnerDefaultConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerDefaultConvertor(); + + virtual boost::shared_ptr<PubSubOwnerDefault> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerDefault>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp new file mode 100644 index 0000000..f67ed1e --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerDeleteConvertor::PubSubOwnerDeleteConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerDelete>("pubsub_owner_delete"), + convertors(convertors) { +} + +PubSubOwnerDeleteConvertor::~PubSubOwnerDeleteConvertor() { +} + +boost::shared_ptr<PubSubOwnerDelete> PubSubOwnerDeleteConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerDelete> result = boost::make_shared<PubSubOwnerDelete>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "redirect"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubOwnerRedirect> payload = boost::dynamic_pointer_cast<PubSubOwnerRedirect>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_redirect"))) { + result->setRedirect(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerDeleteConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerDelete> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (convertors->convertToLuaUntyped(L, payload->getRedirect()) > 0) { + lua_setfield(L, -2, "redirect"); + } +} diff --git a/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h new file mode 100644 index 0000000..7475e9c --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerDeleteConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerDelete.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerDeleteConvertor : public GenericLuaElementConvertor<PubSubOwnerDelete> { + public: + PubSubOwnerDeleteConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerDeleteConvertor(); + + virtual boost::shared_ptr<PubSubOwnerDelete> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerDelete>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp new file mode 100644 index 0000000..a060db9 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerPurgeConvertor::PubSubOwnerPurgeConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerPurge>("pubsub_owner_purge"), + convertors(convertors) { +} + +PubSubOwnerPurgeConvertor::~PubSubOwnerPurgeConvertor() { +} + +boost::shared_ptr<PubSubOwnerPurge> PubSubOwnerPurgeConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerPurge> result = boost::make_shared<PubSubOwnerPurge>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerPurgeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerPurge> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); +} diff --git a/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h new file mode 100644 index 0000000..34c979b --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerPurgeConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerPurge.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerPurgeConvertor : public GenericLuaElementConvertor<PubSubOwnerPurge> { + public: + PubSubOwnerPurgeConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerPurgeConvertor(); + + virtual boost::shared_ptr<PubSubOwnerPurge> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerPurge>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp new file mode 100644 index 0000000..d11df72 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerRedirectConvertor::PubSubOwnerRedirectConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerRedirect>("pubsub_owner_redirect"), + convertors(convertors) { +} + +PubSubOwnerRedirectConvertor::~PubSubOwnerRedirectConvertor() { +} + +boost::shared_ptr<PubSubOwnerRedirect> PubSubOwnerRedirectConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerRedirect> result = boost::make_shared<PubSubOwnerRedirect>(); + lua_getfield(L, -1, "uri"); + if (lua_isstring(L, -1)) { + result->setURI(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerRedirectConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerRedirect> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getURI().c_str()); + lua_setfield(L, -2, "uri"); +} diff --git a/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h new file mode 100644 index 0000000..fc1ddce --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerRedirect.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerRedirectConvertor : public GenericLuaElementConvertor<PubSubOwnerRedirect> { + public: + PubSubOwnerRedirectConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerRedirectConvertor(); + + virtual boost::shared_ptr<PubSubOwnerRedirect> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerRedirect>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp new file mode 100644 index 0000000..dbba238 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerSubscriptionConvertor::PubSubOwnerSubscriptionConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerSubscription>("pubsub_owner_subscription"), + convertors(convertors) { +} + +PubSubOwnerSubscriptionConvertor::~PubSubOwnerSubscriptionConvertor() { +} + +boost::shared_ptr<PubSubOwnerSubscription> PubSubOwnerSubscriptionConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerSubscription> result = boost::make_shared<PubSubOwnerSubscription>(); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscription"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setSubscription(PubSubOwnerSubscription::None); + } + if (std::string(lua_tostring(L, -1)) == "pending") { + result->setSubscription(PubSubOwnerSubscription::Pending); + } + if (std::string(lua_tostring(L, -1)) == "subscribed") { + result->setSubscription(PubSubOwnerSubscription::Subscribed); + } + if (std::string(lua_tostring(L, -1)) == "unconfigured") { + result->setSubscription(PubSubOwnerSubscription::Unconfigured); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubOwnerSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerSubscription> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + switch (payload->getSubscription()) { + case PubSubOwnerSubscription::None: + lua_pushstring(L, "none"); + break; + case PubSubOwnerSubscription::Pending: + lua_pushstring(L, "pending"); + break; + case PubSubOwnerSubscription::Subscribed: + lua_pushstring(L, "subscribed"); + break; + case PubSubOwnerSubscription::Unconfigured: + lua_pushstring(L, "unconfigured"); + break; + } + lua_setfield(L, -2, "subscription"); +} diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h new file mode 100644 index 0000000..ca80c82 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerSubscription.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerSubscriptionConvertor : public GenericLuaElementConvertor<PubSubOwnerSubscription> { + public: + PubSubOwnerSubscriptionConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerSubscriptionConvertor(); + + virtual boost::shared_ptr<PubSubOwnerSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerSubscription>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp new file mode 100644 index 0000000..045cf12 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubOwnerSubscriptionsConvertor::PubSubOwnerSubscriptionsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubOwnerSubscriptions>("pubsub_owner_subscriptions"), + convertors(convertors) { +} + +PubSubOwnerSubscriptionsConvertor::~PubSubOwnerSubscriptionsConvertor() { +} + +boost::shared_ptr<PubSubOwnerSubscriptions> PubSubOwnerSubscriptionsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubOwnerSubscriptions> result = boost::make_shared<PubSubOwnerSubscriptions>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubOwnerSubscription> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubOwnerSubscription> payload = boost::dynamic_pointer_cast<PubSubOwnerSubscription>(convertors->convertFromLuaUntyped(L, -1, "pubsub_owner_subscription"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setSubscriptions(items); + } + return result; +} + +void PubSubOwnerSubscriptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubOwnerSubscriptions> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getSubscriptions().empty()) { + { + int i = 0; + foreach(boost::shared_ptr<PubSubOwnerSubscription> item, payload->getSubscriptions()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + } +} diff --git a/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h new file mode 100644 index 0000000..2e12c93 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubOwnerSubscriptionsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubOwnerSubscriptionsConvertor : public GenericLuaElementConvertor<PubSubOwnerSubscriptions> { + public: + PubSubOwnerSubscriptionsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubOwnerSubscriptionsConvertor(); + + virtual boost::shared_ptr<PubSubOwnerSubscriptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubOwnerSubscriptions>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubPublishConvertor.cpp b/Sluift/ElementConvertors/PubSubPublishConvertor.cpp new file mode 100644 index 0000000..880d9fc --- /dev/null +++ b/Sluift/ElementConvertors/PubSubPublishConvertor.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubPublishConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubPublishConvertor::PubSubPublishConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubPublish>("pubsub_publish"), + convertors(convertors) { +} + +PubSubPublishConvertor::~PubSubPublishConvertor() { +} + +boost::shared_ptr<PubSubPublish> PubSubPublishConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubPublish> result = boost::make_shared<PubSubPublish>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "items"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubItem> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setItems(items); + } + lua_pop(L, 1); + return result; +} + +void PubSubPublishConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubPublish> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getItems().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "items"); + } +} diff --git a/Sluift/ElementConvertors/PubSubPublishConvertor.h b/Sluift/ElementConvertors/PubSubPublishConvertor.h new file mode 100644 index 0000000..4415566 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubPublishConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubPublish.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubPublishConvertor : public GenericLuaElementConvertor<PubSubPublish> { + public: + PubSubPublishConvertor(LuaElementConvertors* convertors); + virtual ~PubSubPublishConvertor(); + + virtual boost::shared_ptr<PubSubPublish> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubPublish>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubRetractConvertor.cpp b/Sluift/ElementConvertors/PubSubRetractConvertor.cpp new file mode 100644 index 0000000..61ca3df --- /dev/null +++ b/Sluift/ElementConvertors/PubSubRetractConvertor.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubRetractConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubRetractConvertor::PubSubRetractConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubRetract>("pubsub_retract"), + convertors(convertors) { +} + +PubSubRetractConvertor::~PubSubRetractConvertor() { +} + +boost::shared_ptr<PubSubRetract> PubSubRetractConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubRetract> result = boost::make_shared<PubSubRetract>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "items"); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubItem> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubItem> payload = boost::dynamic_pointer_cast<PubSubItem>(convertors->convertFromLuaUntyped(L, -1, "pubsub_item"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setItems(items); + } + lua_pop(L, 1); + lua_getfield(L, -1, "notify"); + if (lua_isboolean(L, -1)) { + result->setNotify(lua_toboolean(L, -1)); + } + lua_pop(L, 1); + return result; +} + +void PubSubRetractConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubRetract> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getNode().c_str()); + lua_setfield(L, -2, "node"); + if (!payload->getItems().empty()) { + lua_createtable(L, boost::numeric_cast<int>(payload->getItems().size()), 0); + { + int i = 0; + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + lua_setfield(L, -2, "items"); + } + lua_pushboolean(L, payload->isNotify()); + lua_setfield(L, -2, "notify"); +} diff --git a/Sluift/ElementConvertors/PubSubRetractConvertor.h b/Sluift/ElementConvertors/PubSubRetractConvertor.h new file mode 100644 index 0000000..80d888b --- /dev/null +++ b/Sluift/ElementConvertors/PubSubRetractConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubRetract.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubRetractConvertor : public GenericLuaElementConvertor<PubSubRetract> { + public: + PubSubRetractConvertor(LuaElementConvertors* convertors); + virtual ~PubSubRetractConvertor(); + + virtual boost::shared_ptr<PubSubRetract> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubRetract>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp new file mode 100644 index 0000000..06d6447 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscribeConvertor.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubSubscribeConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubSubscribeConvertor::PubSubSubscribeConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubSubscribe>("pubsub_subscribe"), + convertors(convertors) { +} + +PubSubSubscribeConvertor::~PubSubSubscribeConvertor() { +} + +boost::shared_ptr<PubSubSubscribe> PubSubSubscribeConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubSubscribe> result = boost::make_shared<PubSubSubscribe>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "options"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubOptions> payload = boost::dynamic_pointer_cast<PubSubOptions>(convertors->convertFromLuaUntyped(L, -1, "pubsub_options"))) { + result->setOptions(payload); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubSubscribeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscribe> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + if (convertors->convertToLuaUntyped(L, payload->getOptions()) > 0) { + lua_setfield(L, -2, "options"); + } +} diff --git a/Sluift/ElementConvertors/PubSubSubscribeConvertor.h b/Sluift/ElementConvertors/PubSubSubscribeConvertor.h new file mode 100644 index 0000000..2073c09 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscribeConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubSubscribe.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubSubscribeConvertor : public GenericLuaElementConvertor<PubSubSubscribe> { + public: + PubSubSubscribeConvertor(LuaElementConvertors* convertors); + virtual ~PubSubSubscribeConvertor(); + + virtual boost::shared_ptr<PubSubSubscribe> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscribe>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp new file mode 100644 index 0000000..e8053fb --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubSubscribeOptionsConvertor::PubSubSubscribeOptionsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubSubscribeOptions>("pubsub_subscribe_options"), + convertors(convertors) { +} + +PubSubSubscribeOptionsConvertor::~PubSubSubscribeOptionsConvertor() { +} + +boost::shared_ptr<PubSubSubscribeOptions> PubSubSubscribeOptionsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubSubscribeOptions> result = boost::make_shared<PubSubSubscribeOptions>(); + lua_getfield(L, -1, "required"); + if (lua_isboolean(L, -1)) { + result->setRequired(lua_toboolean(L, -1)); + } + lua_pop(L, 1); + return result; +} + +void PubSubSubscribeOptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscribeOptions> payload) { + lua_createtable(L, 0, 0); + lua_pushboolean(L, payload->isRequired()); + lua_setfield(L, -2, "required"); +} diff --git a/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h new file mode 100644 index 0000000..71e1baf --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscribeOptionsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubSubscribeOptions.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubSubscribeOptionsConvertor : public GenericLuaElementConvertor<PubSubSubscribeOptions> { + public: + PubSubSubscribeOptionsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubSubscribeOptionsConvertor(); + + virtual boost::shared_ptr<PubSubSubscribeOptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscribeOptions>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp new file mode 100644 index 0000000..69cd85a --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubSubscriptionConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + +#include <Sluift/LuaElementConvertors.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubSubscriptionConvertor::PubSubSubscriptionConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubSubscription>("pubsub_subscription"), + convertors(convertors) { +} + +PubSubSubscriptionConvertor::~PubSubSubscriptionConvertor() { +} + +boost::shared_ptr<PubSubSubscription> PubSubSubscriptionConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubSubscription> result = boost::make_shared<PubSubSubscription>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscriptionid"); + if (lua_isstring(L, -1)) { + result->setSubscriptionID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "options"); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubSubscribeOptions> payload = boost::dynamic_pointer_cast<PubSubSubscribeOptions>(convertors->convertFromLuaUntyped(L, -1, "pubsub_subscribe_options"))) { + result->setOptions(payload); + } + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscription"); + if (lua_isstring(L, -1)) { + if (std::string(lua_tostring(L, -1)) == "none") { + result->setSubscription(PubSubSubscription::None); + } + if (std::string(lua_tostring(L, -1)) == "pending") { + result->setSubscription(PubSubSubscription::Pending); + } + if (std::string(lua_tostring(L, -1)) == "subscribed") { + result->setSubscription(PubSubSubscription::Subscribed); + } + if (std::string(lua_tostring(L, -1)) == "unconfigured") { + result->setSubscription(PubSubSubscription::Unconfigured); + } + } + lua_pop(L, 1); + return result; +} + +void PubSubSubscriptionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscription> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (payload->getSubscriptionID()) { + lua_pushstring(L, (*payload->getSubscriptionID()).c_str()); + lua_setfield(L, -2, "subscriptionid"); + } + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + if (convertors->convertToLuaUntyped(L, payload->getOptions()) > 0) { + lua_setfield(L, -2, "options"); + } + switch (payload->getSubscription()) { + case PubSubSubscription::None: + lua_pushstring(L, "none"); + break; + case PubSubSubscription::Pending: + lua_pushstring(L, "pending"); + break; + case PubSubSubscription::Subscribed: + lua_pushstring(L, "subscribed"); + break; + case PubSubSubscription::Unconfigured: + lua_pushstring(L, "unconfigured"); + break; + } + lua_setfield(L, -2, "subscription"); +} diff --git a/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h new file mode 100644 index 0000000..2da4930 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscriptionConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubSubscription.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubSubscriptionConvertor : public GenericLuaElementConvertor<PubSubSubscription> { + public: + PubSubSubscriptionConvertor(LuaElementConvertors* convertors); + virtual ~PubSubSubscriptionConvertor(); + + virtual boost::shared_ptr<PubSubSubscription> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscription>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp new file mode 100644 index 0000000..04f8da8 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/Base/foreach.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubSubscriptionsConvertor::PubSubSubscriptionsConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubSubscriptions>("pubsub_subscriptions"), + convertors(convertors) { +} + +PubSubSubscriptionsConvertor::~PubSubSubscriptionsConvertor() { +} + +boost::shared_ptr<PubSubSubscriptions> PubSubSubscriptionsConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubSubscriptions> result = boost::make_shared<PubSubSubscriptions>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TTABLE) { + std::vector< boost::shared_ptr<PubSubSubscription> > items; + for(size_t i = 0; i < lua_objlen(L, -1); ++i) { + lua_pushnumber(L, i + 1); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + if (boost::shared_ptr<PubSubSubscription> payload = boost::dynamic_pointer_cast<PubSubSubscription>(convertors->convertFromLuaUntyped(L, -1, "pubsub_subscription"))) { + items.push_back(payload); + } + } + lua_pop(L, 1); + } + + result->setSubscriptions(items); + } + return result; +} + +void PubSubSubscriptionsConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubSubscriptions> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + if (!payload->getSubscriptions().empty()) { + { + int i = 0; + foreach(boost::shared_ptr<PubSubSubscription> item, payload->getSubscriptions()) { + if (convertors->convertToLuaUntyped(L, item) > 0) { + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + ++i; + } + } + } + } +} diff --git a/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h new file mode 100644 index 0000000..7f18f64 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubSubscriptionsConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubSubscriptions.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubSubscriptionsConvertor : public GenericLuaElementConvertor<PubSubSubscriptions> { + public: + PubSubSubscriptionsConvertor(LuaElementConvertors* convertors); + virtual ~PubSubSubscriptionsConvertor(); + + virtual boost::shared_ptr<PubSubSubscriptions> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubSubscriptions>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp new file mode 100644 index 0000000..323cb29 --- /dev/null +++ b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> + + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +PubSubUnsubscribeConvertor::PubSubUnsubscribeConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<PubSubUnsubscribe>("pubsub_unsubscribe"), + convertors(convertors) { +} + +PubSubUnsubscribeConvertor::~PubSubUnsubscribeConvertor() { +} + +boost::shared_ptr<PubSubUnsubscribe> PubSubUnsubscribeConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<PubSubUnsubscribe> result = boost::make_shared<PubSubUnsubscribe>(); + lua_getfield(L, -1, "node"); + if (lua_isstring(L, -1)) { + result->setNode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "jid"); + if (lua_isstring(L, -1)) { + result->setJID(JID(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "subscriptionid"); + if (lua_isstring(L, -1)) { + result->setSubscriptionID(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void PubSubUnsubscribeConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<PubSubUnsubscribe> payload) { + lua_createtable(L, 0, 0); + if (payload->getNode()) { + lua_pushstring(L, (*payload->getNode()).c_str()); + lua_setfield(L, -2, "node"); + } + lua_pushstring(L, payload->getJID().toString().c_str()); + lua_setfield(L, -2, "jid"); + if (payload->getSubscriptionID()) { + lua_pushstring(L, (*payload->getSubscriptionID()).c_str()); + lua_setfield(L, -2, "subscriptionid"); + } +} diff --git a/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h new file mode 100644 index 0000000..16d279f --- /dev/null +++ b/Sluift/ElementConvertors/PubSubUnsubscribeConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/PubSubUnsubscribe.h> + +namespace Swift { + class LuaElementConvertors; + + class PubSubUnsubscribeConvertor : public GenericLuaElementConvertor<PubSubUnsubscribe> { + public: + PubSubUnsubscribeConvertor(LuaElementConvertors* convertors); + virtual ~PubSubUnsubscribeConvertor(); + + virtual boost::shared_ptr<PubSubUnsubscribe> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<PubSubUnsubscribe>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/RawXMLElementConvertor.cpp b/Sluift/ElementConvertors/RawXMLElementConvertor.cpp new file mode 100644 index 0000000..35a53ca --- /dev/null +++ b/Sluift/ElementConvertors/RawXMLElementConvertor.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/RawXMLElementConvertor.h> + +#include <iostream> +#include <boost/smart_ptr/make_shared.hpp> +#include <lua.hpp> + +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Sluift/Lua/Check.h> + +using namespace Swift; + +RawXMLElementConvertor::RawXMLElementConvertor() { +} + +RawXMLElementConvertor::~RawXMLElementConvertor() { +} + +boost::shared_ptr<Payload> RawXMLElementConvertor::convertFromLua(lua_State* L, int index, const std::string& type) { + if (type == "xml") { + return boost::make_shared<RawXMLPayload>(std::string(Lua::checkString(L, index))); + } + return boost::shared_ptr<Payload>(); +} + +boost::optional<std::string> RawXMLElementConvertor::convertToLua(lua_State* L, boost::shared_ptr<Payload> payload) { + PayloadSerializer* serializer = serializers.getPayloadSerializer(payload); + assert(serializer); + lua_pushstring(L, serializer->serialize(payload).c_str()); + return std::string("xml"); +} diff --git a/Sluift/ElementConvertors/RawXMLElementConvertor.h b/Sluift/ElementConvertors/RawXMLElementConvertor.h new file mode 100644 index 0000000..6087ba0 --- /dev/null +++ b/Sluift/ElementConvertors/RawXMLElementConvertor.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/LuaElementConvertor.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +namespace Swift { + class RawXMLElementConvertor : public LuaElementConvertor { + public: + RawXMLElementConvertor(); + virtual ~RawXMLElementConvertor(); + + virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) SWIFTEN_OVERRIDE; + virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE; + + private: + FullPayloadSerializerCollection serializers; + }; +} diff --git a/Sluift/ElementConvertors/SConscript b/Sluift/ElementConvertors/SConscript new file mode 100644 index 0000000..e98f7c4 --- /dev/null +++ b/Sluift/ElementConvertors/SConscript @@ -0,0 +1,42 @@ + +Import('env') + +convertors = [ + env.File("PubSubRetractConvertor.cpp"), + env.File("PubSubAffiliationsConvertor.cpp"), + env.File("PubSubPublishConvertor.cpp"), + env.File("PubSubItemsConvertor.cpp"), + env.File("PubSubOwnerRedirectConvertor.cpp"), + env.File("PubSubEventRedirectConvertor.cpp"), + env.File("PubSubConfigureConvertor.cpp"), + env.File("PubSubEventDisassociateConvertor.cpp"), + env.File("PubSubOwnerAffiliationsConvertor.cpp"), + env.File("PubSubOwnerConfigureConvertor.cpp"), + env.File("UserLocationConvertor.cpp"), + env.File("PubSubSubscribeOptionsConvertor.cpp"), + env.File("PubSubOwnerSubscriptionsConvertor.cpp"), + env.File("PubSubDefaultConvertor.cpp"), + env.File("PubSubEventCollectionConvertor.cpp"), + env.File("PubSubEventSubscriptionConvertor.cpp"), + env.File("PubSubEventRetractConvertor.cpp"), + env.File("PubSubItemConvertor.cpp"), + env.File("PubSubUnsubscribeConvertor.cpp"), + env.File("PubSubEventDeleteConvertor.cpp"), + env.File("PubSubCreateConvertor.cpp"), + env.File("PubSubOwnerPurgeConvertor.cpp"), + env.File("PubSubEventItemsConvertor.cpp"), + env.File("PubSubOptionsConvertor.cpp"), + env.File("PubSubEventItemConvertor.cpp"), + env.File("PubSubOwnerSubscriptionConvertor.cpp"), + env.File("PubSubOwnerAffiliationConvertor.cpp"), + env.File("PubSubEventPurgeConvertor.cpp"), + env.File("PubSubAffiliationConvertor.cpp"), + env.File("PubSubSubscribeConvertor.cpp"), + env.File("PubSubOwnerDeleteConvertor.cpp"), + env.File("PubSubOwnerDefaultConvertor.cpp"), + env.File("PubSubSubscriptionsConvertor.cpp"), + env.File("PubSubEventAssociateConvertor.cpp"), + env.File("PubSubSubscriptionConvertor.cpp"), + env.File("PubSubEventConfigurationConvertor.cpp") +] +Return('convertors') diff --git a/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp b/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp new file mode 100644 index 0000000..5799614 --- /dev/null +++ b/Sluift/ElementConvertors/SoftwareVersionConvertor.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/SoftwareVersionConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/Check.h> + +using namespace Swift; + +SoftwareVersionConvertor::SoftwareVersionConvertor() : GenericLuaElementConvertor<SoftwareVersion>("software_version") { +} + +SoftwareVersionConvertor::~SoftwareVersionConvertor() { +} + +boost::shared_ptr<SoftwareVersion> SoftwareVersionConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<SoftwareVersion> result = boost::make_shared<SoftwareVersion>(); + lua_getfield(L, -1, "name"); + if (!lua_isnil(L, -1)) { + result->setName(std::string(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "version"); + if (!lua_isnil(L, -1)) { + result->setVersion(std::string(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "os"); + if (!lua_isnil(L, -1)) { + result->setOS(std::string(Lua::checkString(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void SoftwareVersionConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<SoftwareVersion> payload) { + lua_createtable(L, 0, 0); + lua_pushstring(L, payload->getName().c_str()); + lua_setfield(L, -2, "name"); + lua_pushstring(L, payload->getVersion().c_str()); + lua_setfield(L, -2, "version"); + lua_pushstring(L, payload->getOS().c_str()); + lua_setfield(L, -2, "os"); +} diff --git a/Sluift/ElementConvertors/SoftwareVersionConvertor.h b/Sluift/ElementConvertors/SoftwareVersionConvertor.h new file mode 100644 index 0000000..5fa3cc3 --- /dev/null +++ b/Sluift/ElementConvertors/SoftwareVersionConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/SoftwareVersion.h> + +namespace Swift { + class SoftwareVersionConvertor : public GenericLuaElementConvertor<SoftwareVersion> { + public: + SoftwareVersionConvertor(); + virtual ~SoftwareVersionConvertor(); + + virtual boost::shared_ptr<SoftwareVersion> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<SoftwareVersion>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/UserLocationConvertor.cpp b/Sluift/ElementConvertors/UserLocationConvertor.cpp new file mode 100644 index 0000000..97cb288 --- /dev/null +++ b/Sluift/ElementConvertors/UserLocationConvertor.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/UserLocationConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Base/DateTime.h> + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +UserLocationConvertor::UserLocationConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<UserLocation>("user_location"), + convertors(convertors) { +} + +UserLocationConvertor::~UserLocationConvertor() { +} + +boost::shared_ptr<UserLocation> UserLocationConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<UserLocation> result = boost::make_shared<UserLocation>(); + lua_getfield(L, -1, "area"); + if (lua_isstring(L, -1)) { + result->setArea(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "altitude"); + if (lua_isnumber(L, -1)) { + result->setAltitude(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "locality"); + if (lua_isstring(L, -1)) { + result->setLocality(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "latitude"); + if (lua_isnumber(L, -1)) { + result->setLatitude(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "accuracy"); + if (lua_isnumber(L, -1)) { + result->setAccuracy(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "description"); + if (lua_isstring(L, -1)) { + result->setDescription(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "country_code"); + if (lua_isstring(L, -1)) { + result->setCountryCode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "timestamp"); + if (lua_isstring(L, -1)) { + result->setTimestamp(stringToDateTime(std::string(lua_tostring(L, -1)))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "floor"); + if (lua_isstring(L, -1)) { + result->setFloor(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "building"); + if (lua_isstring(L, -1)) { + result->setBuilding(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "room"); + if (lua_isstring(L, -1)) { + result->setRoom(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "country"); + if (lua_isstring(L, -1)) { + result->setCountry(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "region"); + if (lua_isstring(L, -1)) { + result->setRegion(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "uri"); + if (lua_isstring(L, -1)) { + result->setURI(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "longitude"); + if (lua_isnumber(L, -1)) { + result->setLongitude(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "error"); + if (lua_isnumber(L, -1)) { + result->setError(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "postal_code"); + if (lua_isstring(L, -1)) { + result->setPostalCode(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "bearing"); + if (lua_isnumber(L, -1)) { + result->setBearing(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "text"); + if (lua_isstring(L, -1)) { + result->setText(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "datum"); + if (lua_isstring(L, -1)) { + result->setDatum(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "street"); + if (lua_isstring(L, -1)) { + result->setStreet(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "speed"); + if (lua_isnumber(L, -1)) { + result->setSpeed(boost::numeric_cast<float>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void UserLocationConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<UserLocation> payload) { + lua_createtable(L, 0, 0); + if (payload->getArea()) { + lua_pushstring(L, (*payload->getArea()).c_str()); + lua_setfield(L, -2, "area"); + } + if (payload->getAltitude()) { + lua_pushnumber(L, (*payload->getAltitude())); + lua_setfield(L, -2, "altitude"); + } + if (payload->getLocality()) { + lua_pushstring(L, (*payload->getLocality()).c_str()); + lua_setfield(L, -2, "locality"); + } + if (payload->getLatitude()) { + lua_pushnumber(L, (*payload->getLatitude())); + lua_setfield(L, -2, "latitude"); + } + if (payload->getAccuracy()) { + lua_pushnumber(L, (*payload->getAccuracy())); + lua_setfield(L, -2, "accuracy"); + } + if (payload->getDescription()) { + lua_pushstring(L, (*payload->getDescription()).c_str()); + lua_setfield(L, -2, "description"); + } + if (payload->getCountryCode()) { + lua_pushstring(L, (*payload->getCountryCode()).c_str()); + lua_setfield(L, -2, "country_code"); + } + if (payload->getTimestamp()) { + lua_pushstring(L, dateTimeToString((*payload->getTimestamp())).c_str()); + lua_setfield(L, -2, "timestamp"); + } + if (payload->getFloor()) { + lua_pushstring(L, (*payload->getFloor()).c_str()); + lua_setfield(L, -2, "floor"); + } + if (payload->getBuilding()) { + lua_pushstring(L, (*payload->getBuilding()).c_str()); + lua_setfield(L, -2, "building"); + } + if (payload->getRoom()) { + lua_pushstring(L, (*payload->getRoom()).c_str()); + lua_setfield(L, -2, "room"); + } + if (payload->getCountry()) { + lua_pushstring(L, (*payload->getCountry()).c_str()); + lua_setfield(L, -2, "country"); + } + if (payload->getRegion()) { + lua_pushstring(L, (*payload->getRegion()).c_str()); + lua_setfield(L, -2, "region"); + } + if (payload->getURI()) { + lua_pushstring(L, (*payload->getURI()).c_str()); + lua_setfield(L, -2, "uri"); + } + if (payload->getLongitude()) { + lua_pushnumber(L, (*payload->getLongitude())); + lua_setfield(L, -2, "longitude"); + } + if (payload->getError()) { + lua_pushnumber(L, (*payload->getError())); + lua_setfield(L, -2, "error"); + } + if (payload->getPostalCode()) { + lua_pushstring(L, (*payload->getPostalCode()).c_str()); + lua_setfield(L, -2, "postal_code"); + } + if (payload->getBearing()) { + lua_pushnumber(L, (*payload->getBearing())); + lua_setfield(L, -2, "bearing"); + } + if (payload->getText()) { + lua_pushstring(L, (*payload->getText()).c_str()); + lua_setfield(L, -2, "text"); + } + if (payload->getDatum()) { + lua_pushstring(L, (*payload->getDatum()).c_str()); + lua_setfield(L, -2, "datum"); + } + if (payload->getStreet()) { + lua_pushstring(L, (*payload->getStreet()).c_str()); + lua_setfield(L, -2, "street"); + } + if (payload->getSpeed()) { + lua_pushnumber(L, (*payload->getSpeed())); + lua_setfield(L, -2, "speed"); + } +} diff --git a/Sluift/ElementConvertors/UserLocationConvertor.h b/Sluift/ElementConvertors/UserLocationConvertor.h new file mode 100644 index 0000000..a5eb153 --- /dev/null +++ b/Sluift/ElementConvertors/UserLocationConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/UserLocation.h> + +namespace Swift { + class LuaElementConvertors; + + class UserLocationConvertor : public GenericLuaElementConvertor<UserLocation> { + public: + UserLocationConvertor(LuaElementConvertors* convertors); + virtual ~UserLocationConvertor(); + + virtual boost::shared_ptr<UserLocation> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<UserLocation>) SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/ElementConvertors/VCardConvertor.cpp b/Sluift/ElementConvertors/VCardConvertor.cpp new file mode 100644 index 0000000..a1c57be --- /dev/null +++ b/Sluift/ElementConvertors/VCardConvertor.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/VCardConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/LuaUtils.h> +#include <Swiften/Base/ByteArray.h> + +using namespace Swift; + +VCardConvertor::VCardConvertor() : GenericLuaElementConvertor<VCard>("vcard") { +} + +VCardConvertor::~VCardConvertor() { +} + +boost::shared_ptr<VCard> VCardConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<VCard> result = boost::make_shared<VCard>(); + lua_getfield(L, -1, "photo"); + if (lua_isstring(L, -1)) { + size_t len; + const char* data = lua_tolstring(L, -1, &len); + result->setPhoto(createByteArray(data, len)); + } + lua_pop(L, 1); + + // TODO + + return result; +} + +void VCardConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<VCard> payload) { + lua_newtable(L); + if (!payload->getPhoto().empty()) { + lua_pushlstring(L, + reinterpret_cast<const char*>(vecptr(payload->getPhoto())), + payload->getPhoto().size()); + lua_setfield(L, -2, "photo"); + } +} diff --git a/Sluift/ElementConvertors/VCardConvertor.h b/Sluift/ElementConvertors/VCardConvertor.h new file mode 100644 index 0000000..1cf4e9f --- /dev/null +++ b/Sluift/ElementConvertors/VCardConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/VCard.h> + +namespace Swift { + class VCardConvertor : public GenericLuaElementConvertor<VCard> { + public: + VCardConvertor(); + virtual ~VCardConvertor(); + + virtual boost::shared_ptr<VCard> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<VCard>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/ElementConvertors/VCardUpdateConvertor.cpp b/Sluift/ElementConvertors/VCardUpdateConvertor.cpp new file mode 100644 index 0000000..0010ca5 --- /dev/null +++ b/Sluift/ElementConvertors/VCardUpdateConvertor.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/VCardUpdateConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/Lua/LuaUtils.h> + +using namespace Swift; + +VCardUpdateConvertor::VCardUpdateConvertor() : GenericLuaElementConvertor<VCardUpdate>("vcard_update") { +} + +VCardUpdateConvertor::~VCardUpdateConvertor() { +} + +boost::shared_ptr<VCardUpdate> VCardUpdateConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<VCardUpdate> result = boost::make_shared<VCardUpdate>(); + if (boost::optional<std::string> value = Lua::getStringField(L, -1, "photo_hash")) { + result->setPhotoHash(*value); + } + return result; +} + +void VCardUpdateConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<VCardUpdate> payload) { + lua_newtable(L); + if (!payload->getPhotoHash().empty()) { + lua_pushstring(L, payload->getPhotoHash().c_str()); + lua_setfield(L, -2, "photo_hash"); + } +} diff --git a/Sluift/ElementConvertors/VCardUpdateConvertor.h b/Sluift/ElementConvertors/VCardUpdateConvertor.h new file mode 100644 index 0000000..e9bcd0f --- /dev/null +++ b/Sluift/ElementConvertors/VCardUpdateConvertor.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/VCardUpdate.h> + +namespace Swift { + class VCardUpdateConvertor : public GenericLuaElementConvertor<VCardUpdate> { + public: + VCardUpdateConvertor(); + virtual ~VCardUpdateConvertor(); + + virtual boost::shared_ptr<VCardUpdate> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<VCardUpdate>) SWIFTEN_OVERRIDE; + }; +} diff --git a/Sluift/Examples/AdHocCommands.lua b/Sluift/Examples/AdHocCommands.lua new file mode 100644 index 0000000..9e83f0c --- /dev/null +++ b/Sluift/Examples/AdHocCommands.lua @@ -0,0 +1,48 @@ +--[[ + Copyright (c) 2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] + +--[[ + + Ad-hoc command example. + + This script logs into an XMPP server, and executes a + multi-step ad-hoc command. + + The following environment variables are used: + * SLUIFT_JID, SWIFT_PASS: JID and password to log in with + * SLUIFT_DEBUG: Sets whether debugging should be turned on + +--]] + +require "sluift" + +sluift.debug = os.getenv("SLUIFT_DEBUG") or false + +c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) +c:connect(function () + to = sluift.jid.domain(os.getenv("SLUIFT_JID")) + + -- Get the list of commands + commands = assert(c:get_disco_items{ to = to, disco_items = { + node = sluift.disco.features.COMMANDS }}) + print(commands) + + -- Get the initial form + result = assert(c:set_command{ to = to, command = { + action = 'execute', node = 'http://jabber.org/protocol/admin#get-user-roster'}}) + + -- Fill in the form + submission = result.form:create_submission() + submission.accountjid = os.getenv("SLUIFT_JID") + + -- Submit the form + result = assert(c:set_command{ to = to, command = { + action = 'complete', node = 'http://jabber.org/protocol/admin#get-user-roster', + session_id = result.session_id, form = submission}}) + for _, v in ipairs(result.form.roster.values) do + print(v) + end +end) diff --git a/Sluift/Examples/CollectVersions.lua b/Sluift/Examples/CollectVersions.lua index c93c8c8..38bf6ac 100644 --- a/Sluift/Examples/CollectVersions.lua +++ b/Sluift/Examples/CollectVersions.lua @@ -1,22 +1,22 @@ --- --- Copyright (c) 2010 Remko Tronçon --- Licensed under the GNU General Public License v3. --- See Documentation/Licenses/GPLv3.txt for more information. --- +--[[ + + Copyright (c) 2010-2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. --- This script logs into an XMPP server, and collects statistics about --- the server software of all contacts in your roster + This script logs into an XMPP server, and collects statistics about + the server software of all contacts in your roster -require "sluift" +--]] -c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) -c:connect() +require 'sluift' -versions = {} -for jid, _ in pairs(c:get_contacts()) do - v = c:get_version(sluift.jid_domain(jid)) - if v then versions[v["name"]] = (versions[v["name"]] or 0) + 1 end -end -for name, count in pairs(versions) do print(name .. ": " .. count) end - -c:disconnect() +c = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS')) +c:connect(function () + versions = {} + for jid in pairs(c:get_contacts()) do + local v = c:get_software_version {to = sluift.jid.domain(jid), timeout = 3000} or {name = 'Unknown'} + versions[v['name']] = (versions[v['name']] or 0) + 1 + end + for name, count in pairs(versions) do print(name .. ': ' .. count) end +end) diff --git a/Sluift/Examples/ContactsMap.lua b/Sluift/Examples/ContactsMap.lua new file mode 100644 index 0000000..d248dc7 --- /dev/null +++ b/Sluift/Examples/ContactsMap.lua @@ -0,0 +1,120 @@ +--[[ + Copyright (c) 2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] + +--[[ + + Contacts map + + Creates an HTML file of a map with all your contacts on it. + + The following environment variables are used: + - SLUIFT_JID, SWIFT_PASS: JID and password to log in with + +--]] + +require "sluift" + +output_dir = arg[1] +if not output_dir then + error("Please specify the directory to write the map to") +end + +-- Collect all data +geolocs = {} +avatars = {} +c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) +c:connect(function () + -- Indicate we're interested in getting user location information, and send initial presence + c:set_caps_node("http://swift.im/ContactsMap") + c:set_disco_info({identities = {{name = 'ContactsMap'}}, features = { + sluift.disco.features.DISCO_INFO, + sluift.disco.features.USER_LOCATION .. '+notify', + }}) + c:send_presence() + + -- Collect geoloc info + for event in c:pubsub_events {timeout = 10000} do + local from = sluift.jid.to_bare(event.from) + if event._type == 'pubsub_event_items' and event.item then + if event.node == sluift.disco.features.USER_LOCATION then + local lat, lon = event.item.latitude, event.item.longitude + if lat and lon then geolocs[from] = {lat = lat, lon = lon} end + end + end + end + + -- Download the necessary avatars + for contact in pairs(geolocs) do + local vcard = c:get_vcard {to = contact} + if vcard and vcard.photo then + local avatar_hash = sluift.hexify(sluift.sha1(vcard.photo)) + local file = io.open(output_dir.."/" .. avatar_hash .. ".png", "wb") + file:write(vcard.photo) + file:close() + avatars[contact] = avatar_hash + end + end +end) + +-- Generate html +min_lat, max_lat = 90, -90 +min_lon, max_lon = 180, -180 +contacts_html = {} +for contact, geoloc in pairs(geolocs) do + if geoloc.lat < min_lat then min_lat = geoloc.lat end + if geoloc.lon < min_lon then min_lon = geoloc.lon end + if geoloc.lat > max_lat then max_lat = geoloc.lat end + if geoloc.lon > max_lon then max_lon = geoloc.lon end + local image = 'null' + if avatars[contact] then + image = "'" .. avatars[contact] .. ".png'" + end + contacts_html[#contacts_html+1] = "['" .. contact .. "'," .. geoloc.lat .. "," .. geoloc.lon .. "," .. image .. "]" +end +center_html = ((min_lat + max_lat) / 2) .. ',' .. ((min_lon + max_lon) / 2) + +map_html = [[ +<html> + <head> + <title>Contacts Map</title> + <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> + </head> + <body> + <div id="map" style="height: 100%; width: 100%;"/> + <script> + var map = new google.maps.Map(document.getElementById('map'), { + zoom: 2, + center: new google.maps.LatLng(%(CENTER)), + mapTypeId: google.maps.MapTypeId.ROADMAP + }); + var infowindow = new google.maps.InfoWindow(); + var contacts = [%(CONTACTS)]; + for (var i = 0; i < contacts.length; i++) { + var icon = null; + if (contacts[i][3]) { + icon = { url: contacts[i][3], scaledSize: { width: 30, height: 30} }; + } + var marker = new google.maps.Marker({ + position: new google.maps.LatLng(contacts[i][1], contacts[i][2]), + map: map, + icon: icon, + }); + google.maps.event.addListener(marker, 'click', (function(marker, i) { + return function() { + infowindow.setContent(contacts[i][0]); + infowindow.open(map, marker); + } + })(marker, i)); + } + </script> + </body> +</html> +]] +local file = io.open(output_dir .. "/index.html", "w") +file:write(map_html: + gsub('%%%(CONTACTS%)', table.concat(contacts_html, ",")): + gsub('%%%(CENTER%)', center_html)) +file:close() diff --git a/Sluift/Examples/EchoBot.lua b/Sluift/Examples/EchoBot.lua index 09da63b..fc495c4 100644 --- a/Sluift/Examples/EchoBot.lua +++ b/Sluift/Examples/EchoBot.lua @@ -1,27 +1,31 @@ --- --- Copyright (c) 2010 Remko Tronçon --- Licensed under the GNU General Public License v3. --- See Documentation/Licenses/GPLv3.txt for more information. --- +--[[ + Copyright (c) 2010-2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] --- --- An XMPP Echoing Bot --- --- This script logs into an XMPP server, sends initial presence, --- and then waits for incoming messages, and echoes them back. --- --- The following environment variables are used: --- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with --- * SLUIFT_DEBUG: Sets whether debugging should be turned on --- +--[[ + + An XMPP Echoing Bot + + This script logs into an XMPP server, sends initial presence, + and then waits for incoming messages, and echoes them back. + + The following environment variables are used: + * SLUIFT_JID, SWIFT_PASS: JID and password to log in with + * SLUIFT_DEBUG: Sets whether debugging should be turned on + +--]] require "sluift" sluift.debug = os.getenv("SLUIFT_DEBUG") or false c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) -c:connect() -c:send_presence("Send me a message") -c:for_event(function(e) - if e["type"] == "message" then c:send_message(e["from"], e["body"]) end - end) +c:connect(function () + c:set_version{name = "EchoBot", version = "0.1"} + c:send_presence("Send me a message") + for message in c:messages() do + c:send_message{to = message["from"], body = message["body"]} + end +end) diff --git a/Sluift/Examples/Login.lua b/Sluift/Examples/Login.lua index 1733bb9..c43b72a 100644 --- a/Sluift/Examples/Login.lua +++ b/Sluift/Examples/Login.lua @@ -1,16 +1,20 @@ --- --- Copyright (c) 2010 Remko Tronçon --- Licensed under the GNU General Public License v3. --- See Documentation/Licenses/GPLv3.txt for more information. --- +--[[ + Copyright (c) 2010-2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] --- This script logs into an XMPP server, and sends initial presence --- 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 --- * SLUIFT_DEBUG: Sets whether debugging should be turned on +--[[ + + This script logs into an XMPP server, and sends initial presence + 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 + * SLUIFT_DEBUG: Sets whether debugging should be turned on + +--]] require "sluift" sluift.debug = os.getenv("SLUIFT_DEBUG") or false @@ -18,6 +22,8 @@ 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({compress = false, tls = false}) -c:connect():send_presence("") +c:connect() +c:send_presence("") print("Connected ...") +print("Use the 'c' variable to communicate.") diff --git a/Sluift/Examples/PEPListener.lua b/Sluift/Examples/PEPListener.lua new file mode 100644 index 0000000..f196f84 --- /dev/null +++ b/Sluift/Examples/PEPListener.lua @@ -0,0 +1,46 @@ +--[[ + Copyright (c) 2010-2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] + +--[[ + + PEP Listener + + Listens to a series of PEP events of all contacts. + + The following environment variables are used: + - SLUIFT_JID, SWIFT_PASS: JID and password to log in with + - SLUIFT_DEBUG: Sets whether debugging should be turned on + +--]] + +require "sluift" + +sluift.debug = os.getenv("SLUIFT_DEBUG") or false + +pep_protocols = { + [sluift.disco.features.USER_LOCATION] = true, + [sluift.disco.features.USER_TUNE] = true, + [sluift.disco.features.USER_ACTIVITY] = true, + [sluift.disco.features.USER_AVATAR_METADATA] = true, + [sluift.disco.features.USER_PROFILE] = true, +} + +client = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) +client:connect(function (c) + features = {sluift.disco.features.DISCO_INFO} + for protocol in pairs(pep_protocols) do + features[#features+1] = protocol .. '+notify' + end + + c:set_caps_node("http://swift.im/PEPListener") + c:set_disco_info({identities = {{name = 'PEPListener'}}, features = features}) + c:send_presence() + for event in c:pubsub_events() do + if event._type == 'pubsub_event_items' and pep_protocols[event.node] then + print("<" .. event.from .. "> " .. tostring(event.item)) + end + end +end) diff --git a/Sluift/Examples/RemoveUnreachableContacts.lua b/Sluift/Examples/RemoveUnreachableContacts.lua index 90122df..a202e62 100644 --- a/Sluift/Examples/RemoveUnreachableContacts.lua +++ b/Sluift/Examples/RemoveUnreachableContacts.lua @@ -1,37 +1,38 @@ --- --- Copyright (c) 2010 Remko Tronçon --- Licensed under the GNU General Public License v3. --- See Documentation/Licenses/GPLv3.txt for more information. --- +--[[ + Copyright (c) 2010-2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] --- This script logs into an XMPP server, iterates over all roster items, --- and checks if their server is still alive. If not, the script asks you --- whether it should remove the contact from your contact list. --- --- The following environment variables are used: --- * SLUIFT_JID, SWIFT_PASS: JID and password to log in with --- * SLUIFT_DEBUG: Sets whether debugging should be turned on +--[[ + This script logs into an XMPP server, iterates over all roster items, + and checks if their server is still alive. If not, the script asks you + whether it should remove the contact from your contact list. -require "sluift" -sluift.debug = os.getenv("SLUIFT_DEBUG") + The following environment variables are used: + * SLUIFT_JID, SWIFT_PASS: JID and password to log in with + * SLUIFT_DEBUG: Sets whether debugging should be turned on +--]] -print "Connecting ..." -c = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) -c:connect() +require 'sluift' +sluift.debug = os.getenv('SLUIFT_DEBUG') -print "Checking for unreachable contacts ..." -for jid, _ in pairs(c:get_contacts()) do - _, err = c:get_version(sluift.jid_domain(jid), 10000) - if err == "Remote server not found" or err == "Timeout" then - print("Delete " .. jid .. " (" .. err .. ") ? [y/n/q]") - answer = io.read() - if answer == "y" then - c:remove_contact(jid) - elseif answer == "q" then - break +print 'Connecting ...' +c = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS')) +c:connect(function (c) + print 'Checking for unreachable contacts ...' + for jid in pairs(c:get_contacts()) do + _, err = c:get_software_version {to = sluift.jid.domain(jid), timeout = 10000} + print(err) + if err == 'Remote server not found' or err == 'Remote server timeout' then + print('Delete ' .. jid .. ' (' .. err .. ') ? [y/n/q]') + answer = io.read() + if answer == 'y' then + c:remove_contact(jid) + elseif answer == 'q' then + break + end end end -end - -print "Done. Exiting ..." -c:disconnect() + print 'Done. Exiting ...' +end) diff --git a/Sluift/Examples/Wonderland.lua b/Sluift/Examples/Wonderland.lua index 58c00ca..426ec07 100755 --- a/Sluift/Examples/Wonderland.lua +++ b/Sluift/Examples/Wonderland.lua @@ -8,45 +8,97 @@ -- require "sluift" ---sluift.debug = true +sluift.debug = true characters = { - {jid = "alice@wonderland.lit", name = "Alice", groups = {}, presence = "<presence/>"}, - {jid = "hatter@wonderland.lit", name = "Mad Hatter", groups = {}, presence = "<presence><show>away</show><status>At the Tea Party</status></presence>"}, - {jid ="queen@wonderland.lit", name = "Queen of Hearts", groups = {}, presence = "<presence><show>dnd</show><status>Executing</status></presence>"}, - {jid = "rabbit@wonderland.lit", name = "White Rabbit", groups = {"Animals"}, presence = "<presence><status>Oh dear!</status></presence>"}, - {jid = "turtle@wonderland.lit", name = "Mock Turtle", groups = {"Animals"}, presence = "<presence/>"}, + ["Alice"] = { + jid = "alice@wonderland.lit", groups = {}, presence = "<presence/>" + }, + ["Mad Hatter"] = { + jid = "hatter@wonderland.lit", groups = {}, + presence = "<presence><show>away</show><status>At the Tea Party</status></presence>" + }, + ["Queen of Hearts"] = { + jid ="queen@wonderland.lit", groups = {}, + presence = "<presence><show>dnd</show><status>Executing</status></presence>" + }, + ["White Rabbit"] = { + jid = "rabbit@wonderland.lit", groups = {"Animals"}, + presence = "<presence><status>Oh dear!</status></presence>"}, + ["Mock Turtle"] = { + jid = "turtle@wonderland.lit", groups = {"Animals"}, + presence = "<presence/>" + }, } -clients = {} -for _, character in ipairs(characters) do - print("Connecting " .. character["name"] .. "...") - client = sluift.new_client(character["jid"], os.getenv("SLUIFT_PASS")) +for name, character in pairs(characters) do + print("Connecting " .. name .. "...") + local client = sluift.new_client(character.jid, os.getenv("SLUIFT_PASS")) client:set_options({compress = false, tls = false}) client:connect() client:get_contacts() - client:send(character["presence"]) - table.insert(clients, client) - for _, contact in ipairs(characters) do - if contact["jid"] ~= character["jid"] then + client:send(character.presence) + for contact_name, contact in pairs(characters) do + if contact.jid ~= character.jid then client:add_contact(contact) end end + character.client = client end print("Confirming subscriptions") -for _, client in ipairs(clients) do - for _, contact in ipairs(characters) do - client:confirm_subscription(contact["jid"]) +for _, character in pairs(characters) do + for _, contact in pairs(characters) do + character.client:confirm_subscription(contact.jid) end end +print("Setting up PubSub nodes") +local hatters_riddles = characters["Mad Hatter"].client:pubsub("pubsub.wonderland.lit"):node("hatters_riddles") +hatters_riddles:delete() +assert(hatters_riddles:create()) + +local queen_quotes = characters["Queen of Hearts"].client:pubsub("pubsub.wonderland.lit"):node("queen_quotes") +queen_quotes:delete() +assert(queen_quotes:create()) +queen_quotes:publish{id = 'quote1', item = {_type = 'body', text = 'Off with his head!'}} +queen_quotes:publish{id = 'quote2', item = {_type = 'body', text = 'Off with her head!'}} +queen_quotes:publish{id = 'quote3', item = {_type = 'body', text = 'Off with their heads!'}} + +characters['Mad Hatter'].client:pubsub():node('http://jabber.org/protocol/geoloc'):publish{ + item = {_type = 'user_location', latitude = 50.376739, longitude = -4.200709}} +characters['Queen of Hearts'].client:pubsub():node('http://jabber.org/protocol/geoloc'):publish{ + item = {_type = 'user_location', latitude = 50.551123, longitude = -4.141654}} +characters['Mock Turtle'].client:pubsub():node('http://jabber.org/protocol/geoloc'):publish{ + item = {_type = 'user_location', latitude = 50.366630, longitude = -4.134518}} +characters['White Rabbit'].client:pubsub():node('http://jabber.org/protocol/geoloc'):publish{ + item = {_type = 'user_location', latitude = 50.332907, longitude = -4.759194}} + + + +print("Disconnecting alice") +characters['Alice'].client:disconnect() + print("Done. Waiting ...") while true do - for _, client in ipairs(clients) do - client:for_event(function(e) - if e["type"] == "message" then client:send_message(e["from"], "Off with their heads!") end - end, 1000) + for name, character in pairs(characters) do + if name == 'Queen of Hearts' then + for message in character.client:messages{timeout = 1000} do + if message.body == 'publish' then + queen_quotes:publish{item = {_type = 'body', text = 'Off with her head!'}} + queen_quotes:publish{item = {_type = 'body', text = 'Off with his head!'}} + else + character.client:send_message{to = e["from"], body = "Off with their heads!"} + end + end + elseif name == "Mad Hatter" then + for message in character.client:messages{timeout = 1000} do + if message.body == 'publish' then + hatters_riddles:publish{item = {_type = 'body', text = 'Why is a raven like a writing desk?'}} + end + end + else + for message in character.client:messages{timeout = 100} do end + end end - sluift.sleep(1000) end diff --git a/Sluift/GenericLuaElementConvertor.h b/Sluift/GenericLuaElementConvertor.h new file mode 100644 index 0000000..afad481 --- /dev/null +++ b/Sluift/GenericLuaElementConvertor.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <lua.hpp> +#include <string> + +#include <Swiften/Base/Override.h> +#include <Sluift/LuaElementConvertor.h> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/LuaUtils.h> + +namespace Swift { + template<typename T> + class GenericLuaElementConvertor : public LuaElementConvertor { + public: + GenericLuaElementConvertor(const std::string& type) : type(type) { + } + + virtual ~GenericLuaElementConvertor() {} + + virtual boost::shared_ptr<Payload> convertFromLua(lua_State* L, int index, const std::string& payloadType) SWIFTEN_OVERRIDE { + if (payloadType == type) { + Lua::checkType(L, index, LUA_TTABLE); + lua_pushvalue(L, index); + boost::shared_ptr<Payload> result = doConvertFromLua(L); + lua_pop(L, 1); + return result; + } + return boost::shared_ptr<Payload>(); + } + + virtual boost::optional<std::string> convertToLua( + lua_State* L, boost::shared_ptr<Payload> payload) SWIFTEN_OVERRIDE { + if (boost::shared_ptr<T> actualPayload = boost::dynamic_pointer_cast<T>(payload)) { + doConvertToLua(L, actualPayload); + assert(lua_type(L, -1) == LUA_TTABLE); + return type; + } + return NO_RESULT; + } + + protected: + virtual boost::shared_ptr<T> doConvertFromLua(lua_State*) = 0; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<T>) = 0; + + private: + std::string type; + }; +} diff --git a/Sluift/Lua/Check.cpp b/Sluift/Lua/Check.cpp new file mode 100644 index 0000000..cfb726a --- /dev/null +++ b/Sluift/Lua/Check.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/Check.h> + +#include <boost/numeric/conversion/cast.hpp> +#include <iostream> +#include <sstream> +#include <lua.hpp> + +#include <Sluift/Lua/Exception.h> + +using namespace Swift; + + +static std::string getArgTypeError(lua_State* L, int arg, int tag) { + std::ostringstream s; + s << "Arg " << arg << ": expected " << lua_typename(L, tag) << ", got " << luaL_typename(L, arg); + return s.str(); +} + +void Lua::checkType(lua_State* L, int arg, int type) { + if (lua_type(L, arg) != type) { + throw Lua::Exception(getArgTypeError(L, arg, type)); + } +} + +int Lua::checkIntNumber(lua_State* L, int arg) { + if (!lua_isnumber(L, arg)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TNUMBER)); + } + return boost::numeric_cast<int>(lua_tonumber(L, arg)); +} + +std::string Lua::checkString(lua_State* L, int arg) { + const char *s = lua_tolstring(L, arg, NULL); + if (!s) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TSTRING)); + } + return std::string(s); +} + +void* Lua::checkUserDataRaw(lua_State* L, int arg, const char* tableName) { + void* userData = lua_touserdata(L, arg); + if (!userData) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + if (!lua_getmetatable(L, arg)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + lua_getfield(L, LUA_REGISTRYINDEX, tableName); + if (!lua_rawequal(L, -1, -2)) { + throw Lua::Exception(getArgTypeError(L, arg, LUA_TUSERDATA)); + } + lua_pop(L, 2); + return userData; +} diff --git a/Sluift/Lua/Check.h b/Sluift/Lua/Check.h new file mode 100644 index 0000000..a569826 --- /dev/null +++ b/Sluift/Lua/Check.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> + +struct lua_State; + +namespace Swift { + namespace Lua { + void checkType(lua_State* L, int arg, int type); + int checkIntNumber(lua_State* L, int arg); + std::string checkString(lua_State* L, int arg); + + void* checkUserDataRaw(lua_State* L, int arg, const char* tableName); + + template<typename T> + T** checkUserData(lua_State* L, int arg, const char* tableName) { + return reinterpret_cast<T**>(checkUserDataRaw(L, arg, tableName)); + } + } +} diff --git a/Sluift/Lua/Debug.h b/Sluift/Lua/Debug.h new file mode 100644 index 0000000..8e86b89 --- /dev/null +++ b/Sluift/Lua/Debug.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <lua.hpp> +#include <iostream> + +namespace Swift { + namespace Lua { + inline void dumpStack(lua_State *L) { + for (int i = 1; i <= lua_gettop(L); i++) { + int type = lua_type(L, i); + std::cout << i << ": [" << lua_typename(L, type) << "] "; + switch (type) { + case LUA_TSTRING: std::cout << lua_tostring(L, i); break; + case LUA_TNUMBER: std::cout << lua_tonumber(L, i); break; + case LUA_TBOOLEAN: std::cout << lua_toboolean(L, i); break; + default: break; + } + std::cout << std::endl; + } + } + } +} diff --git a/Sluift/Lua/Exception.cpp b/Sluift/Lua/Exception.cpp new file mode 100644 index 0000000..d80b9fb --- /dev/null +++ b/Sluift/Lua/Exception.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/Exception.h> + +using namespace Swift::Lua; + +Exception::Exception(const std::string& what) : std::runtime_error(what) { +} + +Exception::~Exception() throw() { +} diff --git a/Sluift/Lua/Exception.h b/Sluift/Lua/Exception.h new file mode 100644 index 0000000..6d00d01 --- /dev/null +++ b/Sluift/Lua/Exception.h @@ -0,0 +1,20 @@ +/* + * 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 <stdexcept> + +namespace Swift { + namespace Lua { + class Exception : public std::runtime_error { + public: + Exception(const std::string& what); + virtual ~Exception() throw(); + }; + } +} + diff --git a/Sluift/Lua/FunctionRegistration.cpp b/Sluift/Lua/FunctionRegistration.cpp new file mode 100644 index 0000000..b773952 --- /dev/null +++ b/Sluift/Lua/FunctionRegistration.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/FunctionRegistration.h> + +using namespace Swift::Lua; + +FunctionRegistration::FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type) { + FunctionRegistry::getInstance().addFunction(name, function, type); +} + +FunctionRegistration::~FunctionRegistration() { +} diff --git a/Sluift/Lua/FunctionRegistration.h b/Sluift/Lua/FunctionRegistration.h new file mode 100644 index 0000000..0df1da1 --- /dev/null +++ b/Sluift/Lua/FunctionRegistration.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Sluift/Lua/FunctionRegistry.h> +#include <lua.hpp> +#include <string> + +namespace Swift { + namespace Lua { + class FunctionRegistration { + public: + FunctionRegistration(const std::string& name, lua_CFunction function, const std::string& type); + ~FunctionRegistration(); + }; + } +} +#define SLUIFT_LUA_FUNCTION(TYPE, NAME) \ + static int TYPE##_##NAME(lua_State* L); \ + static int TYPE##_##NAME##_wrapper(lua_State* L); \ + static ::Swift::Lua::FunctionRegistration TYPE##_##NAME##_registration( #NAME , TYPE##_##NAME##_wrapper, #TYPE); \ + static int TYPE##_##NAME##_wrapper(lua_State* L) { \ + try { \ + return TYPE ## _ ## NAME (L); \ + } \ + catch (const std::exception& e) { \ + return luaL_error(L, e.what()); \ + } \ + } \ + static int TYPE ## _ ## NAME (lua_State* L) diff --git a/Sluift/Lua/FunctionRegistry.cpp b/Sluift/Lua/FunctionRegistry.cpp new file mode 100644 index 0000000..99ea096 --- /dev/null +++ b/Sluift/Lua/FunctionRegistry.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/FunctionRegistry.h> + +#include <Swiften/Base/foreach.h> + +using namespace Swift::Lua; + +FunctionRegistry::FunctionRegistry() { +} + +FunctionRegistry::~FunctionRegistry() { +} + +FunctionRegistry& FunctionRegistry::getInstance() { + static FunctionRegistry instance; + return instance; +} + +void FunctionRegistry::addFunction(const std::string& name, lua_CFunction function, const std::string& type) { + Registration registration; + registration.name = name; + registration.function = function; + registration.type = type; + registrations.push_back(registration); +} + +std::string FunctionRegistry::getMetaTableNameForType(const std::string& type) { + return "Sluift_" + type; +} + +void FunctionRegistry::registerTypeMetaTable(lua_State* L, const std::string& type) { + luaL_newmetatable(L, getMetaTableNameForType(type).c_str()); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + addFunctionsToTable(L, type); +} + +void FunctionRegistry::createFunctionTable(lua_State* L, const std::string& type) { + lua_newtable(L); + addFunctionsToTable(L, type); +} + +void FunctionRegistry::addFunctionsToTable(lua_State* L, const std::string& type) { + foreach(const Registration& registration, registrations) { + if (registration.type == type) { + lua_pushcclosure(L, registration.function, 0); + lua_setfield(L, -2, registration.name.c_str()); + } + } +} diff --git a/Sluift/Lua/FunctionRegistry.h b/Sluift/Lua/FunctionRegistry.h new file mode 100644 index 0000000..e3ad620 --- /dev/null +++ b/Sluift/Lua/FunctionRegistry.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <lua.hpp> +#include <string> +#include <vector> + +namespace Swift { + namespace Lua { + class FunctionRegistry { + public: + ~FunctionRegistry(); + static FunctionRegistry& getInstance(); + + void addFunction(const std::string& name, lua_CFunction function, const std::string& type); + + static std::string getMetaTableNameForType(const std::string& type); + void registerTypeMetaTable(lua_State* L, const std::string& type); + + void createFunctionTable(lua_State* L, const std::string& type); + + /** + * Adds the functions to the table on the top of the stack. + */ + void addFunctionsToTable(lua_State* L, const std::string& type); + + private: + FunctionRegistry(); + + + private: + struct Registration { + std::string name; + lua_CFunction function; + std::string type; + }; + std::vector<Registration> registrations; + }; + } +} diff --git a/Sluift/Lua/LuaUtils.cpp b/Sluift/Lua/LuaUtils.cpp new file mode 100644 index 0000000..7052abe --- /dev/null +++ b/Sluift/Lua/LuaUtils.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Lua/LuaUtils.h> + +#include <lua.hpp> + +#include <boost/scope_exit.hpp> +#include <Sluift/Lua/Exception.h> +#include <iostream> +#include <cassert> +#include <sstream> +#include <boost/numeric/conversion/cast.hpp> +#include <Sluift/globals.h> + +using namespace Swift::Lua; + +static const std::string INDENT = " "; + +void Swift::Lua::registerTableToString(lua_State* L, int index) { + index = Lua::absoluteOffset(L, index); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "register_table_tostring"); + lua_pushvalue(L, index); + if (lua_pcall(L, 1, 0, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + lua_pop(L, 1); +} + +void Swift::Lua::registerGetByTypeIndex(lua_State* L, int index) { + index = Lua::absoluteOffset(L, index); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "register_get_by_type_index"); + lua_pushvalue(L, index); + if (lua_pcall(L, 1, 0, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + lua_pop(L, 1); +} + +boost::optional<std::string> Swift::Lua::getStringField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + // Seems to generate warnings with some versions of CLang that i can't turn off. + // Leaving the more elegant code here, hoping we can re-enable it later (newer boost? c++11?). + // The same applies to the other get*Field functions. + //BOOST_SCOPE_EXIT(&L) { lua_pop(L,1); } BOOST_SCOPE_EXIT_END + //return lua_isstring(L, -1) ? std::string(lua_tostring(L, -1)) : boost::optional<std::string>(); + + boost::optional<std::string> result; + if (lua_isstring(L, -1)) { + result = std::string(lua_tostring(L, -1)); + } + lua_pop(L, 1); + return result; +} + +boost::optional<bool> Swift::Lua::getBooleanField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + boost::optional<bool> result; + if (lua_isboolean(L, -1)) { + result = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return result; +} + +boost::optional<int> Swift::Lua::getIntField(lua_State* L, int index, const std::string& field) { + lua_getfield(L, index, field.c_str()); + boost::optional<int> result; + if (lua_isnumber(L, -1)) { + result = boost::numeric_cast<int>(lua_tonumber(L, -1)); + } + lua_pop(L, 1); + return result; +} diff --git a/Sluift/Lua/LuaUtils.h b/Sluift/Lua/LuaUtils.h new file mode 100644 index 0000000..bad307c --- /dev/null +++ b/Sluift/Lua/LuaUtils.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <lua.hpp> +#include <boost/optional.hpp> + +struct lua_State; + +namespace Swift { + namespace Lua { + /** + * Can be used as __tostring metamethod on a table. + */ + int convertTableToString(lua_State* L); + + void registerTableToString(lua_State* L, int index); + void registerGetByTypeIndex(lua_State* L, int index); + + inline int absoluteOffset(lua_State* L, int index) { + return index > 0 ? index : lua_gettop(L) + index + 1; + } + + boost::optional<std::string> getStringField(lua_State* L, int index, const std::string&); + boost::optional<bool> getBooleanField(lua_State* L, int index, const std::string&); + boost::optional<int> getIntField(lua_State* L, int index, const std::string&); + } +} diff --git a/Sluift/Lua/Value.cpp b/Sluift/Lua/Value.cpp index 3164ec6..4f8078e 100644 --- a/Sluift/Lua/Value.cpp +++ b/Sluift/Lua/Value.cpp @@ -6,8 +6,11 @@ #include "Value.h" -#include <lualib.h> +extern "C" { + #include <lualib.h> +} #include <boost/variant/apply_visitor.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/foreach.h> using namespace Swift; @@ -35,15 +38,15 @@ namespace { } void operator()(const std::vector<Value>& values) const { - lua_createtable(state, values.size(), 0); + lua_createtable(state, boost::numeric_cast<int>(values.size()), 0); for(size_t i = 0; i < values.size(); ++i) { boost::apply_visitor(PushVisitor(state), values[i]); - lua_rawseti(state, -2, i + 1); + lua_rawseti(state, -2, boost::numeric_cast<int>(i + 1)); } } void operator()(const std::map<std::string, boost::shared_ptr<Value> >& table) const { - lua_createtable(state, 0, table.size()); + lua_createtable(state, 0, boost::numeric_cast<int>(table.size())); for(std::map<std::string, boost::shared_ptr<Value> >::const_iterator i = table.begin(); i != table.end(); ++i) { boost::apply_visitor(PushVisitor(state), *i->second); lua_setfield(state, -2, i->first.c_str()); diff --git a/Sluift/Lua/Value.h b/Sluift/Lua/Value.h index 7b10cd2..55aa347 100644 --- a/Sluift/Lua/Value.h +++ b/Sluift/Lua/Value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 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,7 @@ #include <vector> #include <boost/variant.hpp> #include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> struct lua_State; @@ -28,7 +29,32 @@ namespace Swift { >::type Value; typedef std::map<std::string, boost::shared_ptr<Value> > Table; + typedef std::vector<Value> Array; + inline boost::shared_ptr<Value> nilRef() { + return boost::make_shared<Value>(Nil()); + } + + inline boost::shared_ptr<Value> valueRef(const std::string& value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> intRef(int value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> boolRef(bool value) { + return boost::make_shared<Value>(value); + } + + inline boost::shared_ptr<Value> valueRef(const Table& table) { + return boost::make_shared<Value>(table); + } + + inline boost::shared_ptr<Value> valueRef(const Array& array) { + return boost::make_shared<Value>(array); + } + void pushValue(lua_State* state, const Value& value); } } diff --git a/Sluift/LuaElementConvertor.cpp b/Sluift/LuaElementConvertor.cpp new file mode 100644 index 0000000..c1d0720 --- /dev/null +++ b/Sluift/LuaElementConvertor.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/LuaElementConvertor.h> + +using namespace Swift; + +LuaElementConvertor::~LuaElementConvertor() { +} + +boost::optional<std::string> LuaElementConvertor::NO_RESULT; diff --git a/Sluift/LuaElementConvertor.h b/Sluift/LuaElementConvertor.h new file mode 100644 index 0000000..187ccf1 --- /dev/null +++ b/Sluift/LuaElementConvertor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> + +struct lua_State; + +namespace Swift { + class Payload; + + class LuaElementConvertor { + public: + static boost::optional<std::string> NO_RESULT; + + virtual ~LuaElementConvertor(); + + virtual boost::shared_ptr<Payload> convertFromLua(lua_State*, int index, const std::string& type) = 0; + virtual boost::optional<std::string> convertToLua(lua_State*, boost::shared_ptr<Payload>) = 0; + }; +} diff --git a/Sluift/LuaElementConvertors.cpp b/Sluift/LuaElementConvertors.cpp new file mode 100644 index 0000000..71957c1 --- /dev/null +++ b/Sluift/LuaElementConvertors.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/LuaElementConvertors.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Sluift/LuaElementConvertor.h> +#include <Sluift/ElementConvertors/RawXMLElementConvertor.h> +#include <Sluift/ElementConvertors/PubSubEventConvertor.h> +#include <Sluift/ElementConvertors/DOMElementConvertor.h> +#include <Sluift/ElementConvertors/DefaultElementConvertor.h> +#include <Sluift/ElementConvertors/DiscoItemsConvertor.h> +#include <Sluift/ElementConvertors/DiscoInfoConvertor.h> +#include <Sluift/ElementConvertors/FormConvertor.h> +#include <Sluift/ElementConvertors/SoftwareVersionConvertor.h> +#include <Sluift/ElementConvertors/VCardUpdateConvertor.h> +#include <Sluift/ElementConvertors/VCardConvertor.h> +#include <Sluift/ElementConvertors/BodyConvertor.h> +#include <Sluift/ElementConvertors/CommandConvertor.h> +#include <Sluift/Lua/LuaUtils.h> +#include <Sluift/Lua/Exception.h> + +using namespace Swift; + +LuaElementConvertors::LuaElementConvertors() { + registerConvertors(); + convertors.push_back(boost::make_shared<CommandConvertor>(this)); + convertors.push_back(boost::make_shared<PubSubEventConvertor>(this)); + convertors.push_back(boost::make_shared<BodyConvertor>()); + convertors.push_back(boost::make_shared<VCardConvertor>()); + convertors.push_back(boost::make_shared<VCardUpdateConvertor>()); + convertors.push_back(boost::make_shared<FormConvertor>()); + convertors.push_back(boost::make_shared<SoftwareVersionConvertor>()); + convertors.push_back(boost::make_shared<DiscoInfoConvertor>()); + convertors.push_back(boost::make_shared<DiscoItemsConvertor>()); + convertors.push_back(boost::make_shared<DOMElementConvertor>()); + convertors.push_back(boost::make_shared<RawXMLElementConvertor>()); + convertors.push_back(boost::make_shared<DefaultElementConvertor>()); +} + +LuaElementConvertors::~LuaElementConvertors() { +} + +#include <Sluift/ElementConvertors/ElementConvertors.ipp> + +boost::shared_ptr<Payload> LuaElementConvertors::convertFromLua(lua_State* L, int index) { + if (lua_isstring(L, index)) { + return convertFromLuaUntyped(L, index, "xml"); + } + else if (lua_istable(L, index)) { + lua_getfield(L, index, "_type"); + if (lua_isstring(L, -1)) { + std::string type = lua_tostring(L, -1); + lua_pop(L, 1); + return convertFromLuaUntyped(L, index, type); + } + lua_pop(L, 1); + } + throw Lua::Exception("Unable to determine type"); +} + +boost::shared_ptr<Payload> LuaElementConvertors::convertFromLuaUntyped(lua_State* L, int index, const std::string& type) { + index = Lua::absoluteOffset(L, index); + foreach (boost::shared_ptr<LuaElementConvertor> convertor, convertors) { + if (boost::shared_ptr<Payload> result = convertor->convertFromLua(L, index, type)) { + return result; + } + } + return boost::shared_ptr<Payload>(); +} + + +int LuaElementConvertors::convertToLua(lua_State* L, boost::shared_ptr<Payload> payload) { + if (boost::optional<std::string> type = doConvertToLuaUntyped(L, payload)) { + if (lua_istable(L, -1)) { + lua_pushstring(L, type->c_str()); + lua_setfield(L, -2, "_type"); + Lua::registerTableToString(L, -1); + } + else { + assert(*type == "xml"); + } + return 1; + } + return 0; +} + +int LuaElementConvertors::convertToLuaUntyped(lua_State* L, boost::shared_ptr<Payload> payload) { + if (doConvertToLuaUntyped(L, payload)) { + return 1; + } + return 0; +} + +boost::optional<std::string> LuaElementConvertors::doConvertToLuaUntyped( + lua_State* L, boost::shared_ptr<Payload> payload) { + if (!payload) { + return LuaElementConvertor::NO_RESULT; + } + foreach (boost::shared_ptr<LuaElementConvertor> convertor, convertors) { + if (boost::optional<std::string> type = convertor->convertToLua(L, payload)) { + return *type; + } + } + return LuaElementConvertor::NO_RESULT; +} + diff --git a/Sluift/LuaElementConvertors.h b/Sluift/LuaElementConvertors.h new file mode 100644 index 0000000..36da15a --- /dev/null +++ b/Sluift/LuaElementConvertors.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <vector> +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> + +struct lua_State; + +namespace Swift { + class LuaElementConvertor; + class Payload; + + class LuaElementConvertors { + public: + LuaElementConvertors(); + virtual ~LuaElementConvertors(); + + boost::shared_ptr<Payload> convertFromLua(lua_State*, int index); + int convertToLua(lua_State*, boost::shared_ptr<Payload>); + + /** + * Adds a toplevel type+data table with the given type. + */ + boost::shared_ptr<Payload> convertFromLuaUntyped(lua_State*, int index, const std::string& type); + + /** + * Strips the toplevel type+data table, and only return the + * data. + */ + int convertToLuaUntyped(lua_State*, boost::shared_ptr<Payload>); + + private: + boost::optional<std::string> doConvertToLuaUntyped(lua_State*, boost::shared_ptr<Payload>); + void registerConvertors(); + + private: + std::vector< boost::shared_ptr<LuaElementConvertor> > convertors; + }; +} diff --git a/Sluift/README b/Sluift/README deleted file mode 100644 index 65fb648..0000000 --- a/Sluift/README +++ /dev/null @@ -1,2 +0,0 @@ -For example scripts, see the 'login.lua' script and the scripts in -Swiften/QA/ScriptedTests. diff --git a/Sluift/README.md b/Sluift/README.md new file mode 100644 index 0000000..ae43846 --- /dev/null +++ b/Sluift/README.md @@ -0,0 +1,52 @@ +# Sluift + +## Building/Installing + +If you have a Lua installed on your system, edit `config.py` to point the build +to it using the `lua_libdir`, `lua_includedir`, and `lua_libname` (usually +only needed on Windows) variables. + +In case no Lua installation is found, a bundled Lua version will be used. +Note that there are several limitations when using the bundled Lua: + +- The standalone Sluift binary will not support dynamic loading of modules. +- The Sluift module will not be built + +The standalone executable will be placed into `Sluift/exe`, and the loadable +Lua module in `Sluift/dll`. + +In order to use the Sluift Lua module, make sure it is copied to a location in the +Lua search path (`LUA_PATH`, or the built-in path). On Linux and Mac OS X, this is +typically `<LUA_INSTALLPREFIX>/lib/lua/<LUA_VERSION>/`. If `require 'sluift'` fails, +the error message will give an indication what this path is. + + +## Examples + +Example scripts can be found in `Examples/`, and in the Swift tree under +`Swiften/QA/ScriptedTests`. + +## Extending + +### Adding support for payloads + +To add support for a specific Swiften payload, create a new `LuaElementConvertor` +in `ElementConvertors/` by inheriting from `GenericLuaElementConvertor`, and register +it it `LuaElementConvertors.cpp`. The name of the convertor passed in the constructor +of `GenericLuaElementConvertor` should correspond to the snake case version of the +Swiften element it converts. For examples, see the existing convertors in +`ElementConvertors/`. + +When the convertor is registered, you can use it in message bodies, or in get/set +queries. For example, for the `command` convertor: + + client:set{to = 'alice@wonderland.lit', query = {_type = 'command', + type = 'execute', node = 'uptime'}} + +Optionally, you can add a convenience `set_<type>` shortcut on the client object by +adding it to the list of `get_set_shortcuts` in `boot.lua`. With such a shortcut, the +command above can be rewritten as: + + client:set_command{to = 'alice@wonderland.lit', command = { + type = 'execute', node = 'uptime'}} + diff --git a/Sluift/Response.cpp b/Sluift/Response.cpp new file mode 100644 index 0000000..519379c --- /dev/null +++ b/Sluift/Response.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/Response.h> + +#include <lua.hpp> + +#include <Sluift/globals.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Sluift/Lua/LuaUtils.h> + +using namespace Swift; +using namespace Swift::Sluift; + +static std::string getErrorString(boost::shared_ptr<ErrorPayload> error) { + // Copied from ChatControllerBase. + // TODO: Share this code; + std::string defaultMessage = "Error sending message"; + if (!error->getText().empty()) { + return error->getText(); + } + else { + switch (error->getCondition()) { + case ErrorPayload::BadRequest: return "Bad request"; + case ErrorPayload::Conflict: return "Conflict"; + case ErrorPayload::FeatureNotImplemented: return "This feature is not implemented"; + case ErrorPayload::Forbidden: return "Forbidden"; + case ErrorPayload::Gone: return "Recipient can no longer be contacted"; + case ErrorPayload::InternalServerError: return "Internal server error"; + case ErrorPayload::ItemNotFound: return "Item not found"; + case ErrorPayload::JIDMalformed: return "JID Malformed"; + case ErrorPayload::NotAcceptable: return "Message was rejected"; + case ErrorPayload::NotAllowed: return "Not allowed"; + case ErrorPayload::NotAuthorized: return "Not authorized"; + case ErrorPayload::PaymentRequired: return "Payment is required"; + case ErrorPayload::RecipientUnavailable: return "Recipient is unavailable"; + case ErrorPayload::Redirect: return "Redirect"; + case ErrorPayload::RegistrationRequired: return "Registration required"; + case ErrorPayload::RemoteServerNotFound: return "Recipient's server not found"; + case ErrorPayload::RemoteServerTimeout: return "Remote server timeout"; + case ErrorPayload::ResourceConstraint: return "The server is low on resources"; + case ErrorPayload::ServiceUnavailable: return "The service is unavailable"; + case ErrorPayload::SubscriptionRequired: return "A subscription is required"; + case ErrorPayload::UndefinedCondition: return "Undefined condition"; + case ErrorPayload::UnexpectedRequest: return "Unexpected request"; + } + } + assert(false); + return defaultMessage; +} + +Response::~Response() { +} + +int Response::convertToLuaResult(lua_State* L) { + if (error) { + lua_pushnil(L); + lua_pushstring(L, getErrorString(error).c_str()); + Sluift::globals.elementConvertor.convertToLuaUntyped(L, error); + Lua::registerTableToString(L, -1); + return 3; + } + else { + if (result) { + Sluift::globals.elementConvertor.convertToLuaUntyped(L, result); + Lua::registerTableToString(L, -1); + } + else { + lua_pushboolean(L, 1); + } + return 1; + } + +} + diff --git a/Sluift/Response.h b/Sluift/Response.h new file mode 100644 index 0000000..1cd059a --- /dev/null +++ b/Sluift/Response.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/ErrorPayload.h> + +struct lua_State; + +namespace Swift { + namespace Sluift { + struct Response { + Response(boost::shared_ptr<Payload> result, boost::shared_ptr<ErrorPayload> error) : result(result), error(error) {} + ~Response(); + + static Response withResult(boost::shared_ptr<Payload> response) { + return Response(response, boost::shared_ptr<ErrorPayload>()); + } + + static Response withError(boost::shared_ptr<ErrorPayload> error) { + return Response(boost::shared_ptr<Payload>(), error); + } + + int convertToLuaResult(lua_State* L); + + boost::shared_ptr<Payload> result; + boost::shared_ptr<ErrorPayload> error; + }; + } +} diff --git a/Sluift/ResponseSink.h b/Sluift/ResponseSink.h deleted file mode 100644 index 700363a..0000000 --- a/Sluift/ResponseSink.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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; - } - - void operator()(ErrorPayload::ref error) { - 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 f6388a0..1a29e43 100644 --- a/Sluift/SConscript +++ b/Sluift/SConscript @@ -2,32 +2,51 @@ import Version, os.path Import(["env", "conf_env"]) -if env["SCONS_STAGE"] == "build" : - lib_env = env.Clone() - lib_env.UseFlags(env["LUA_FLAGS"]) - lib_env.UseFlags(env["SWIFTEN_FLAGS"]) - lib_env.UseFlags(env["SWIFTEN_DEP_FLAGS"]) - sluift_lib = lib_env.StaticLibrary("SluiftCore", [ - "Lua/Value.cpp", - "sluift.cpp" - ]); +if env["SCONS_STAGE"] == "build" and not GetOption("help") and not env.get("HAVE_LUA", 0) : + print "Warning: Lua was not found. Sluift will not be built." + if "Sluift" in env["PROJECTS"] : + env["PROJECTS"].remove("Sluift") + +elif env["SCONS_STAGE"] == "build" : + sluift_sources = [ + "Lua/Value.cpp", + "Lua/Exception.cpp", + "Lua/Check.cpp", + "Lua/FunctionRegistration.cpp", + "Lua/FunctionRegistry.cpp", + "Lua/LuaUtils.cpp", + "LuaElementConvertors.cpp", + "LuaElementConvertor.cpp", + "Response.cpp", + "ElementConvertors/BodyConvertor.cpp", + "ElementConvertors/VCardUpdateConvertor.cpp", + "ElementConvertors/PubSubEventConvertor.cpp", + "ElementConvertors/RawXMLElementConvertor.cpp", + "ElementConvertors/DOMElementConvertor.cpp", + "ElementConvertors/DefaultElementConvertor.cpp", + "ElementConvertors/DiscoInfoConvertor.cpp", + "ElementConvertors/DiscoItemsConvertor.cpp", + "ElementConvertors/FormConvertor.cpp", + "ElementConvertors/SoftwareVersionConvertor.cpp", + "ElementConvertors/VCardConvertor.cpp", + "ElementConvertors/CommandConvertor.cpp", + "ClientHelpers.cpp", + "SluiftClient.cpp", + "boot.c", + "client.cpp", + "sluift.cpp" + ] + sluift_sources += env.SConscript("ElementConvertors/SConscript") - myenv = env.Clone() - myenv.Append(LIBS = sluift_lib) - myenv.UseFlags(env.get("LUA_FLAGS", {})) - 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" - if env["PLATFORM"] == "win32" : - myenv.Append(CFLAGS = ["/TP"]) - else : - myenv.Append(CFLAGS = ["-x", "c++"]) + sluift_env = env.Clone() + sluift_env.UseFlags(env.get("LUA_FLAGS", {})) + sluift_env.UseFlags(env["SWIFTEN_FLAGS"]) + sluift_env.UseFlags(env["SWIFTEN_DEP_FLAGS"]) + if sluift_env["PLATFORM"] == "win32" : + sluift_env.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"]) - myenv["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift") + # Generate a customized lua.c + sluift_env["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift") def patchLua(env, target, source) : f = open(source[0].abspath, "r") contents = f.read() @@ -41,24 +60,26 @@ if env["SCONS_STAGE"] == "build" : f = open(target[0].abspath, "w") f.write(contents) f.close() + sluift_env.Command("lua.c", ["#/3rdParty/Lua/src/lua.c", sluift_env.Value(sluift_env["SLUIFT_VERSION"])], env.Action(patchLua, cmdstr = "$GENCOMSTR")) - myenv.Command("lua.c", ["#/3rdParty/Lua/src/lua.c", myenv.Value(myenv["SLUIFT_VERSION"])], env.Action(patchLua, cmdstr = "$GENCOMSTR")) - if myenv.get("HAVE_READLINE", False) : - myenv.Append(CPPDEFINES = ["LUA_USE_READLINE"]) - myenv.MergeFlags(myenv["READLINE_FLAGS"]) - env["SLUIFT"] = myenv.Program("sluift", [ - "lua.c", - "linit.c", - ]) + # Generate boot.cpp + def generate_embedded_lua(env, target, source) : + f = open(source[0].abspath, "r") + data = f.read() + f.close() + f = open(target[0].abspath, "w") + f.write('const char ' + source[0].name.replace(".", "_") + "[] = \"" + data.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"') + "\";") + f.close() + sluift_env.Command("boot.c", ["boot.lua"], env.Action(generate_embedded_lua, cmdstr="$GENCOMSTR")) + + if sluift_env.get("HAVE_READLINE", False) : + sluift_env.Append(CPPDEFINES = ["LUA_USE_READLINE"]) + sluift_env.MergeFlags(sluift_env["READLINE_FLAGS"]) - myenv.WriteVal("dll.c", myenv.Value("")) - myenv.SharedLibrary("sluift", ["dll.c"]) + sluift_env.WriteVal("dll.c", sluift_env.Value("")) - if env["PLATFORM"] == "win32" : - ssl_libs = [] - if myenv.get("OPENSSL_DIR", False) : - ssl_libs = [ - os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), - os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll") - ] - myenv.WindowsBundle("Sluift", resources = {"": ssl_libs}) + sluift_sources = [env.File(x) for x in sluift_sources] + for sluift_variant in ['dll', 'exe'] : + SConscript(["SConscript.variant"], variant_dir = sluift_variant, + duplicate = 0, + exports = ['sluift_sources', 'sluift_variant', 'sluift_env']) diff --git a/Sluift/SConscript.variant b/Sluift/SConscript.variant new file mode 100644 index 0000000..92ee493 --- /dev/null +++ b/Sluift/SConscript.variant @@ -0,0 +1,25 @@ +import os + +Import('env') +Import('sluift_env') +Import('sluift_variant') +Import('sluift_sources') + +if sluift_variant == 'exe' : + env["SLUIFT"] = sluift_env.Program("sluift", sluift_sources + [ + "#/Sluift/lua.c", + "#/Sluift/linit.c", + ]) + if sluift_env.get("SLUIFT_INSTALLDIR", "") : + sluift_env.Install(os.path.join(sluift_env["SLUIFT_INSTALLDIR"], "bin"), env["SLUIFT"]) +else : + sluift_env["SLUIFT_DLL_SUFFIX"] = "${SHLIBSUFFIX}" + if sluift_env["PLATFORM"] == "darwin" : + sluift_env["SLUIFT_DLL_SUFFIX"] = ".so" + sluift_dll = sluift_env.SharedLibrary(sluift_env.File("sluift${SLUIFT_DLL_SUFFIX}"), + sluift_sources + ["#/Sluift/dll.c"]) + if sluift_env.get("SLUIFT_INSTALLDIR", False) and sluift_env.get("LUA_VERSION", False) : + sluift_env.Install( + os.path.join(sluift_env["SLUIFT_INSTALLDIR"], "lib", "lua", sluift_env["LUA_VERSION"]), + sluift_dll) + diff --git a/Sluift/SluiftClient.cpp b/Sluift/SluiftClient.cpp new file mode 100644 index 0000000..bfae621 --- /dev/null +++ b/Sluift/SluiftClient.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/SluiftClient.h> + +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/Client/Client.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Sluift/SluiftGlobals.h> +#include <Sluift/Lua/Exception.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/PubSubEvent.h> +#include <Swiften/Queries/RawRequest.h> +#include <Sluift/ClientHelpers.h> +#include <Swiften/Elements/Presence.h> + +using namespace Swift; + +SluiftClient::SluiftClient( + const JID& jid, + const std::string& password, + NetworkFactories* networkFactories, + SimpleEventLoop* eventLoop, + SluiftGlobals* globals) : + networkFactories(networkFactories), + eventLoop(eventLoop), + globals(globals), + tracer(NULL) { + client = new Client(jid, password, networkFactories); + client->setAlwaysTrustCertificates(); + client->onDisconnected.connect(boost::bind(&SluiftClient::handleDisconnected, this, _1)); + client->onMessageReceived.connect(boost::bind(&SluiftClient::handleIncomingMessage, this, _1)); + client->onPresenceReceived.connect(boost::bind(&SluiftClient::handleIncomingPresence, this, _1)); + client->getPubSubManager()->onEvent.connect(boost::bind(&SluiftClient::handleIncomingPubSubEvent, this, _1, _2)); + client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SluiftClient::handleInitialRosterPopulated, this)); + if (globals->debug) { + tracer = new ClientXMLTracer(client); + } +} + +SluiftClient::~SluiftClient() { + delete tracer; + delete client; +} + +void SluiftClient::connect() { + rosterReceived = false; + disconnectedError = boost::optional<ClientError>(); + client->connect(options); +} + +void SluiftClient::connect(const std::string& host, int port) { + rosterReceived = false; + options.manualHostname = host; + options.manualPort = port; + client->connect(options); +} + +void SluiftClient::waitConnected() { + Watchdog watchdog(globals->timeout, networkFactories->getTimerFactory()); + while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) { + eventLoop->runUntilEvents(); + } + if (watchdog.getTimedOut()) { + client->disconnect(); + throw Lua::Exception("Timeout while connecting"); + } + if (disconnectedError) { + throw Lua::Exception(getClientErrorString(*disconnectedError)); + } +} + +bool SluiftClient::isConnected() const { + return client->isAvailable(); +} + +void SluiftClient::disconnect() { + client->disconnect(); + while (client->isActive()) { + eventLoop->runUntilEvents(); + } +} + +void SluiftClient::setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) { + client->setSoftwareVersion(name, version, os); +} + +boost::optional<SluiftClient::Event> SluiftClient::getNextEvent( + int timeout, boost::function<bool (const Event&)> condition) { + Watchdog watchdog(timeout, networkFactories->getTimerFactory()); + while (true) { + // Look for pending events in the queue + while (!pendingEvents.empty()) { + Event event = pendingEvents.front(); + pendingEvents.pop_front(); + if (!condition || condition(event)) { + return event; + } + } + + // Wait for new events + while (!watchdog.getTimedOut() && pendingEvents.empty() && client->isActive()) { + eventLoop->runUntilEvents(); + } + + // Finish if we're disconnected or timed out + if (watchdog.getTimedOut() || !client->isActive()) { + return boost::optional<Event>(); + } + } +} + +std::vector<XMPPRosterItem> SluiftClient::getRoster() { + if (!rosterReceived) { + // If we haven't requested it yet, request it for the first time + client->requestRoster(); + } + while (!rosterReceived) { + eventLoop->runUntilEvents(); + } + return client->getRoster()->getItems(); +} + +void SluiftClient::handleIncomingMessage(boost::shared_ptr<Message> stanza) { + if (stanza->getPayload<PubSubEvent>()) { + // Already handled by pubsub manager + return; + } + pendingEvents.push_back(Event(stanza)); +} + +void SluiftClient::handleIncomingPresence(boost::shared_ptr<Presence> stanza) { + pendingEvents.push_back(Event(stanza)); +} + +void SluiftClient::handleIncomingPubSubEvent(const JID& from, boost::shared_ptr<PubSubEventPayload> event) { + pendingEvents.push_back(Event(from, event)); +} + +void SluiftClient::handleInitialRosterPopulated() { + rosterReceived = true; +} + +void SluiftClient::handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error) { + requestResponse = response; + requestError = error; + requestResponseReceived = true; +} + +void SluiftClient::handleDisconnected(const boost::optional<ClientError>& error) { + disconnectedError = error; +} + +Sluift::Response SluiftClient::doSendRequest(boost::shared_ptr<Request> request, int timeout) { + requestResponse.reset(); + requestError.reset(); + requestResponseReceived = false; + request->send(); + + Watchdog watchdog(timeout, networkFactories->getTimerFactory()); + while (!watchdog.getTimedOut() && !requestResponseReceived) { + eventLoop->runUntilEvents(); + } + return Sluift::Response(requestResponse, watchdog.getTimedOut() ? + boost::make_shared<ErrorPayload>(ErrorPayload::RemoteServerTimeout) : requestError); +} diff --git a/Sluift/SluiftClient.h b/Sluift/SluiftClient.h new file mode 100644 index 0000000..60eae16 --- /dev/null +++ b/Sluift/SluiftClient.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <deque> +#include <boost/optional.hpp> +#include <boost/bind.hpp> +#include <boost/function.hpp> + +#include <Swiften/Client/ClientOptions.h> +#include <Sluift/globals.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Roster/XMPPRosterItem.h> +#include <Swiften/Client/ClientError.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/Client/Client.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Sluift/Watchdog.h> +#include <Swiften/PubSub/PubSubManager.h> +#include <Sluift/Response.h> + +namespace Swift { + struct SluiftGlobals; + class ClientXMLTracer; + class Client; + class Stanza; + class Payload; + class ErrorPayload; + class JID; + + class SluiftClient { + public: + struct Event { + enum Type { + MessageType, + PresenceType, + PubSubEventType + }; + + Event(boost::shared_ptr<Message> stanza) : type(MessageType), stanza(stanza) {} + Event(boost::shared_ptr<Presence> stanza) : type(PresenceType), stanza(stanza) {} + Event(const JID& from, boost::shared_ptr<PubSubEventPayload> payload) : type(PubSubEventType), from(from), pubsubEvent(payload) {} + + Type type; + + // Message & Presence + boost::shared_ptr<Stanza> stanza; + + // PubSubEvent + JID from; + boost::shared_ptr<PubSubEventPayload> pubsubEvent; + }; + + SluiftClient( + const JID& jid, + const std::string& password, + NetworkFactories* networkFactories, + SimpleEventLoop* eventLoop, + SluiftGlobals* globals); + ~SluiftClient(); + + Client* getClient() { + return client; + } + + ClientOptions& getOptions() { + return options; + } + + void connect(); + void connect(const std::string& host, int port); + void waitConnected(); + bool isConnected() const; + + template<typename T> + Sluift::Response sendPubSubRequest( + IQ::Type type, const JID& jid, boost::shared_ptr<T> payload, int timeout) { + return sendRequest(client->getPubSubManager()->createRequest( + type, jid, payload), timeout); + } + + template<typename REQUEST_TYPE> + Sluift::Response sendRequest(REQUEST_TYPE request, int timeout) { + boost::signals::scoped_connection c = request->onResponse.connect( + boost::bind(&SluiftClient::handleRequestResponse, this, _1, _2)); + return doSendRequest(request, timeout); + } + + template<typename REQUEST_TYPE> + Sluift::Response sendVoidRequest(REQUEST_TYPE request, int timeout) { + boost::signals::scoped_connection c = request->onResponse.connect( + boost::bind(&SluiftClient::handleRequestResponse, this, boost::shared_ptr<Payload>(), _1)); + return doSendRequest(request, timeout); + } + + void disconnect(); + void setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os); + boost::optional<SluiftClient::Event> getNextEvent(int timeout, + boost::function<bool (const Event&)> condition = 0); + std::vector<XMPPRosterItem> getRoster(); + + private: + Sluift::Response doSendRequest(boost::shared_ptr<Request> request, int timeout); + + void handleIncomingMessage(boost::shared_ptr<Message> stanza); + void handleIncomingPresence(boost::shared_ptr<Presence> stanza); + void handleIncomingPubSubEvent(const JID& from, boost::shared_ptr<PubSubEventPayload> event); + void handleInitialRosterPopulated(); + void handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error); + void handleDisconnected(const boost::optional<ClientError>& error); + + private: + NetworkFactories* networkFactories; + SimpleEventLoop* eventLoop; + SluiftGlobals* globals; + Client* client; + ClientOptions options; + ClientXMLTracer* tracer; + bool rosterReceived; + std::deque<Event> pendingEvents; + boost::optional<ClientError> disconnectedError; + bool requestResponseReceived; + boost::shared_ptr<Payload> requestResponse; + boost::shared_ptr<ErrorPayload> requestError; + }; +} diff --git a/Sluift/SluiftException.h b/Sluift/SluiftException.h deleted file mode 100644 index 6964523..0000000 --- a/Sluift/SluiftException.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 std::exception { - public: - virtual ~SluiftException() throw() {} - - SluiftException(const std::string& reason) : reason(reason) { - } - - SluiftException(const ClientError& error) { - 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::RevokedError: reason += "Certificate got revoked"; break; - case ClientError::RevocationCheckFailedError: reason += "Failed to do revokation check"; 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::CertificateCardRemoved: reason += "Certificate card removed"; 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; - } - - virtual const char* what() const throw() { - return getReason().c_str(); - } - - - private: - std::string reason; - }; -} diff --git a/Sluift/SluiftGlobals.h b/Sluift/SluiftGlobals.h new file mode 100644 index 0000000..03c1c1a --- /dev/null +++ b/Sluift/SluiftGlobals.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Sluift/LuaElementConvertors.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Network/BoostNetworkFactories.h> + +namespace Swift { + struct SluiftGlobals { + SluiftGlobals() : networkFactories(&eventLoop) {} + + int timeout; + bool debug; + LuaElementConvertors elementConvertor; + SimpleEventLoop eventLoop; + BoostNetworkFactories networkFactories; + int bootIndex; + }; +} diff --git a/Sluift/Tests/ConnectTest.lua b/Sluift/Tests/ConnectTest.lua new file mode 100644 index 0000000..0afa3fa --- /dev/null +++ b/Sluift/Tests/ConnectTest.lua @@ -0,0 +1,6 @@ +-- Test connect with function parameter +client = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS")) +x, y, z = client:connect(function (c) return 1, '2', true end) +assert(x == 1) +assert(y == '2') +assert(z == true) diff --git a/Sluift/Tests/DOMTest.lua b/Sluift/Tests/DOMTest.lua new file mode 100644 index 0000000..0c31183 --- /dev/null +++ b/Sluift/Tests/DOMTest.lua @@ -0,0 +1,14 @@ +t = sluift.from_xml([[ + <foo xmlns='http://swift.im/test' myattr1='myval1' myattr2='myval2'> + <bar myattr3='myval3'> + <baz/> + </bar> + Some Text + <bam myattr4='myval4'> + Some other text + </bam> + </foo> +]]) + +print(t) +print(sluift.to_xml(t)) diff --git a/Sluift/Tests/FormTest.lua b/Sluift/Tests/FormTest.lua new file mode 100644 index 0000000..7b6b4af --- /dev/null +++ b/Sluift/Tests/FormTest.lua @@ -0,0 +1,79 @@ +--[[ + Copyright (c) 2013 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] + +example_form = [[ +<x xmlns='jabber:x:data' type='form'> + <title>Bot Configuration</title> + <instructions>Fill out this form to configure your new bot!</instructions> + <field type='hidden' var='FORM_TYPE'> + <value>jabber:bot</value> + </field> + <field type='fixed'><value>Section 1: Bot Info</value></field> + <field type='text-single' label='The name of your bot' var='botname'/> + <field type='text-multi' label='Helpful description of your bot' var='description'/> + <field type='boolean' label='Public bot?' var='public'> + <required/> + </field> + <field type='text-private' label='Password for special access' var='password'/> + <field type='fixed'><value>Section 2: Features</value></field> + <field type='list-multi' label='What features will the bot support?' var='features'> + <option label='Contests'><value>contests</value></option> + <option label='News'><value>news</value></option> + <option label='Polls'><value>polls</value></option> + <option label='Reminders'><value>reminders</value></option> + <option label='Search'><value>search</value></option> + <value>news</value> + <value>search</value> + </field> + <field type='fixed'><value>Section 3: Subscriber List</value></field> + <field type='list-single' label='Maximum number of subscribers' var='maxsubs'> + <value>20</value> + <option label='10'><value>10</value></option> + <option label='20'><value>20</value></option> + <option label='30'><value>30</value></option> + <option label='50'><value>50</value></option> + <option label='100'><value>100</value></option> + <option label='None'><value>none</value></option> + </field> + <field type='fixed'><value>Section 4: Invitations</value></field> + <field type='jid-multi' label='People to invite' var='invitelist'> + <desc>Tell all your friends about your new bot!</desc> + </field> +</x>]] + +form = sluift.from_xml(example_form) +--print(form) + +-- Test form properties +assert(form['title'] == 'Bot Configuration') + +-- Test boolean field +public_field = form['fields'][5] +assert(public_field['name'] == 'public') +assert(type(public_field['value']) == 'boolean') +assert(public_field['required'] == true) + +-- Test multi field +features_field = form['fields'][8] +assert(features_field['name'] == 'features') +assert(type(features_field['values']) == 'table') +assert(#features_field['values'] == 2) +assert(features_field['values'][1] == 'news') +assert(features_field['values'][2] == 'search') + +-- Test shortcut index +assert(form['features']['name'] == 'features') +assert(form['FORM_TYPE']['value'] == 'jabber:bot') + +-- Test response form +submission = form:create_submission() +assert(#(submission.fields) == 8) +submission['description'] = 'my description' +assert(submission['description']['value'] == 'my description') +submission['type'] = 'cancel' +assert(#(submission.fields) == 8) + +--print(sluift.to_xml({type = 'form', data = form})) diff --git a/Sluift/boot.lua b/Sluift/boot.lua new file mode 100644 index 0000000..e019fe6 --- /dev/null +++ b/Sluift/boot.lua @@ -0,0 +1,447 @@ +--[[ + Copyright (c) 2013 Remko Tronçon + Licensed under the GNU General Public License. + See the COPYING file for more information. +--]] + +local Client = {} +local PubSub = {} +local PubSubNode = {} + +-------------------------------------------------------------------------------- +-- Utility methods +-------------------------------------------------------------------------------- + +local function merge_tables(...) + local result = {} + for _, table in ipairs({...}) do + for k, v in pairs(table) do + result[k] = v + end + end + return result +end + +local function clone_table(table) + return merge_tables(table) +end + +local function parse_options(unnamed_parameters, arg1, arg2) + local options = {} + if type(arg1) == 'table' then + options = arg1 + f = arg2 + elseif type(arg1) == 'function' then + f = arg1 + end + options.f = f or options.f + return clone_table(options) +end + + +local function table_value_tostring(value) + local result = tostring(value) + if type(value) == 'number' then return result + elseif type(value) == 'boolean' then return result + elseif type(value) == 'string' then return "'" .. result .. "'" + else return '<' .. result .. '>' + end +end + +local function table_tostring(table, indent, accumulator) + local INDENT = ' ' + local accumulator = accumulator or '' + local indent = indent or '' + accumulator = accumulator .. '{' + local is_first = true + for key, value in pairs(table) do + if type(value) ~= 'function' then + if not is_first then + accumulator = accumulator .. ',' + end + is_first = false + accumulator = accumulator .. '\n' .. indent .. INDENT .. '[' .. table_value_tostring(key) .. '] = ' + if type(value) == 'table' then + accumulator = table_tostring(value, indent .. INDENT, accumulator) + else + accumulator = accumulator .. table_value_tostring(value) + end + end + end + if not is_first then + accumulator = accumulator .. '\n' .. indent + end + accumulator = accumulator .. '}' + return accumulator +end + +local function tprint(table) + print(table_tostring(table)) +end + +local function register_table_tostring(table) + if type(table) == 'table' then + local metatable = getmetatable(table) + if not metatable then + metatable = {} + setmetatable(table, metatable) + end + metatable.__tostring = table_tostring + end + return table +end + +local function get_by_type(table, typ) + for _, v in ipairs(table) do + if v['_type'] == typ then + return v + end + end +end + +local function register_get_by_type_index(table) + if type(table) == 'table' then + local metatable = getmetatable(table) + if not metatable then + metatable = {} + setmetatable(table, metatable) + end + metatable.__index = get_by_type + end + return table +end + +-------------------------------------------------------------------------------- +-- Client +-------------------------------------------------------------------------------- + +function Client.connect (client, ...) + local options = parse_options({}, ...) + local f = options.f + client:async_connect(options) + client:wait_connected() + if f then + local result = { xpcall(function() return f(client) end, debug.traceback) } + client:disconnect() + if result[1] then + table.remove(result, 1) + return unpack(result) + else + error(result[2]) + end + end + return true +end + +function Client.events (client, options) + local function client_events_iterator(s) + return s['client']:get_next_event(s['options']) + end + return client_events_iterator, {client = client, options = options} +end + +function Client.for_each_event (client, ...) + local options = parse_options({}, ...) + if not type(options.f) == 'function' then error('Expected function') end + for event in client:events(options) do + local result = options.f(event) + if result then + return result + end + end +end + +for method, event_type in pairs({message = 'message', presence = 'presence', pubsub_event = 'pubsub'}) do + Client['for_each_' .. method] = function (client, ...) + local options = parse_options({}, ...) + options['type'] = event_type + return client:for_each_event (options) + end + + Client['get_next_' .. method] = function (client, ...) + local options = parse_options({}, ...) + options['type'] = event_type + return client:get_next_event(options) + end +end + +for method, event_type in pairs({messages = 'message', pubsub_events = 'pubsub'}) do + Client[method] = function (client, ...) + local options = parse_options({}, ...) + options['type'] = event_type + return client:events (options) + end +end + +-- +-- Register get_* and set_* convenience methods for some type of queries +-- +-- Example usages: +-- client:get_software_version{to = 'alice@wonderland.lit'} +-- client:set_command{to = 'alice@wonderland.lit', command = { type = 'execute', node = 'uptime' }} +-- +local get_set_shortcuts = { + get = {'software_version', 'disco_items', 'xml', 'dom', 'vcard'}, + set = {'command'} +} +for query_action, query_types in pairs(get_set_shortcuts) do + for _, query_type in ipairs(query_types) do + Client[query_action .. '_' .. query_type] = function (client, options) + options = options or {} + if type(options) ~= 'table' then error('Invalid options: ' .. options) end + options['query'] = merge_tables({_type = query_type}, options[query_type] or {}) + return client[query_action](client, options) + end + end +end + +function Client.pubsub (client, jid) + local result = { client = client, jid = jid } + setmetatable(result, PubSub) + return result +end + +-------------------------------------------------------------------------------- +-- PubSub +-------------------------------------------------------------------------------- + +PubSub.__index = PubSub + +local function process_pubsub_event (event) + if event._type == 'pubsub_event_items' then + -- Add 'item' shortcut to payload of first item + event.item = event.items and event.items[1] and + event.items[1].data and event.items[1].data[1] + end +end + +function PubSub.list_nodes (service, options) + return service.client:get_disco_items(merge_tables({to = service.jid}, options)) +end + +function PubSub.node (service, node) + local result = { client = service.client, jid = service.jid, node = node } + setmetatable(result, PubSubNode) + return result +end + +local simple_pubsub_queries = { + get_default_configuration = 'pubsub_owner_default', + get_subscriptions = 'pubsub_subscriptions', + get_affiliations = 'pubsub_affiliations', + get_default_subscription_options = 'pubsub_default', +} +for method, query_type in pairs(simple_pubsub_queries) do + PubSub[method] = function (service, options) + options = options or {} + return service.client:query_pubsub(merge_tables( + { type = 'get', to = service.jid, query = { _type = query_type } }, + options)) + end +end + +for _, method in ipairs({'events', 'get_next_event', 'for_each_event'}) do + PubSub[method] = function (node, ...) + local options = parse_options({}, ...) + options['if'] = function (event) + return event.type == 'pubsub' and event.from == node.jid and event.node == node + end + return node.client[method](node.client, options) + end +end + +-------------------------------------------------------------------------------- +-- PubSubNode +-------------------------------------------------------------------------------- + +PubSubNode.__index = PubSubNode + +local function pubsub_node_configuration_to_form(configuration) + if not configuration then + return + end + local fields = { {name = 'form_type', value = 'http://jabber.org/protocol/pubsub#node_config'} } + for var, value in pairs(configuration) do + fields[#fields+1] = { name = var, value = value } + end + return { type = "submit", fields = fields } +end + +function PubSubNode.list_items (node, options) + return node.client:get_disco_items(merge_tables({to = node.jid, disco_items = { node = node.node }}, options)) +end + +local simple_pubsub_node_queries = { + get_configuration = 'pubsub_owner_configure', + get_subscriptions = 'pubsub_subscriptions', + get_affiliations = 'pubsub_affiliations', + get_owner_subscriptions = 'pubsub_owner_subscriptions', + get_owner_affiliations = 'pubsub_owner_affiliations', + get_default_subscription_options = 'pubsub_default', +} +for method, query_type in pairs(simple_pubsub_node_queries) do + PubSubNode[method] = function (node, options) + return node.client:query_pubsub(merge_tables({ + type = 'get', to = node.jid, query = { + _type = query_type, node = node.node + }}, options)) + end +end + +function PubSubNode.get_items (node, ...) + local options = parse_options({}, ...) + local items = options.items or {} + if options.maximum_items then + items = merge_tables({maximum_items = options.maximum_items}, items) + end + items = merge_tables({_type = 'pubsub_items', node = node.node}, items) + return node.client:query_pubsub(merge_tables({ + type = 'get', to = node.jid, query = items}, options)) +end + +function PubSubNode.get_item (node, ...) + local options = parse_options({}, ...) + if not type(options.id) == 'string' then error('Expected ID') end + return PubSubNode.get_items(node, {items = {{id = options.id}}}) +end + +function PubSubNode.create (node, options) + options = options or {} + local configure + if options['configuration'] then + configure = { data = pubsub_node_configuration_to_form(options['configuration']) } + end + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_create', node = node.node, configure = configure } + }, options)) +end + +function PubSubNode.delete (node, options) + options = options or {} + local redirect + if options['redirect'] then + redirect = {uri = options['redirect']} + end + return node.client:query_pubsub(merge_tables({ type = 'set', to = node.jid, query = { + _type = 'pubsub_owner_delete', node = node.node, redirect = redirect + }}, options)) +end + +function PubSubNode.set_configuration(node, options) + options = options or {} + local configuration = pubsub_node_configuration_to_form(options['configuration']) + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_owner_configure', node = node.node, data = configuration } + }, options)) +end + +function PubSubNode.set_owner_affiliations(node, ...) + local options = parse_options({}, ...) + return node.client:query_pubsub(merge_tables({ + type = 'set', to = node.jid, query = merge_tables({ + _type = 'pubsub_owner_affiliations', node = node.node, + }, options.affiliations)}, options)) +end + + +function PubSubNode.subscribe(node, ...) + local options = parse_options(...) + local jid = options.jid or sluift.jid.to_bare(node.client:jid()) + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_subscribe', node = node.node, jid = jid } + }, options)) +end + +function PubSubNode.unsubscribe(node, options) + options = options or {} + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_unsubscribe', node = node.node, jid = options['jid'] } + }, options)) +end + +function PubSubNode.get_subscription_options (node, options) + return node.client:query_pubsub(merge_tables( + { type = 'get', to = node.jid, query = { + _type = 'pubsub_options', node = node.node, jid = options['jid'] } + }, options)) +end + +function PubSubNode.publish(node, ...) + local options = parse_options({}, ...) + local items = options.items or {} + if options.item then + if type(options.item) == 'string' or options.item._type then + items = {{id = options.id, data = { options.item } }} + options.id = nil + else + items = { options.item } + end + options.item = nil + end + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_publish', node = node.node, items = items } + }, options)) +end + +function PubSubNode.retract(node, ...) + local options = parse_options({}, ...) + local items = options.items + if options.id then + items = {{id = options.id}} + end + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_retract', node = node.node, items = items, notify = options['notify'] + }}, options)) +end + +function PubSubNode.purge(node, ...) + local options = parse_options({}, ...) + return node.client:query_pubsub(merge_tables( + { type = 'set', to = node.jid, query = { + _type = 'pubsub_owner_purge', node = node.node + }}, options)) +end + +-- Iterators over events +for _, method in ipairs({'events', 'get_next_event', 'for_each_event'}) do + PubSubNode[method] = function (node, ...) + local options = parse_options({}, ...) + options['if'] = function (event) + return event.type == 'pubsub' and event.from == node.jid and event.node == node.node + end + return node.client[method](node.client, options) + end +end + +-------------------------------------------------------------------------------- +-- Service discovery +-------------------------------------------------------------------------------- + +local disco = { + features = { + DISCO_INFO = 'http://jabber.org/protocol/disco#info', + COMMANDS = 'http://jabber.org/protocol/commands', + USER_LOCATION = 'http://jabber.org/protocol/geoloc', + USER_TUNE = 'http://jabber.org/protocol/tune', + USER_AVATAR_METADATA = 'urn:xmpp:avatar:metadata', + USER_ACTIVITY = 'http://jabber.org/protocol/activity', + USER_PROFILE = 'urn:xmpp:tmp:profile' + } +} + +-------------------------------------------------------------------------------- + +return { + Client = Client, + register_table_tostring = register_table_tostring, + register_get_by_type_index = register_get_by_type_index, + process_pubsub_event = process_pubsub_event, + tprint = tprint, + disco = disco, +} diff --git a/Sluift/client.cpp b/Sluift/client.cpp new file mode 100644 index 0000000..04ce8f4 --- /dev/null +++ b/Sluift/client.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> +#include <boost/assign/list_of.hpp> +#include <iostream> + +#include <Sluift/SluiftClient.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/SoftwareVersion.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Elements/RosterItemPayload.h> +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Disco/ClientDiscoManager.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Presence/PresenceSender.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Swiften/Roster/SetRosterRequest.h> +#include <Swiften/Presence/SubscriptionManager.h> +#include <Swiften/Roster/XMPPRosterItem.h> +#include <Sluift/Watchdog.h> +#include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h> +#include <Sluift/Lua/FunctionRegistration.h> +#include <Swiften/Base/foreach.h> +#include <Sluift/Lua/Check.h> +#include <Sluift/Lua/Value.h> +#include <Sluift/Lua/Exception.h> +#include <Sluift/Lua/LuaUtils.h> +#include <Sluift/globals.h> + +using namespace Swift; +namespace lambda = boost::lambda; + +static const std::string SLUIFT_CLIENT = Lua::FunctionRegistry::getMetaTableNameForType("Client"); + +static inline SluiftClient* getClient(lua_State* L) { + return *Lua::checkUserData<SluiftClient>(L, 1, SLUIFT_CLIENT.c_str()); +} + +SLUIFT_LUA_FUNCTION(Client, async_connect) { + SluiftClient* client = getClient(L); + + std::string host; + int port = -1; + if (lua_istable(L, 2)) { + if (boost::optional<std::string> hostString = Lua::getStringField(L, 2, "host")) { + host = *hostString; + } + if (boost::optional<int> portInt = Lua::getIntField(L, 2, "port")) { + port = *portInt; + } + } + if (host.empty() && port == -1) { + client->connect(); + } + else { + client->connect(host, port); + } + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, wait_connected) { + getClient(L)->waitConnected(); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, is_connected) { + lua_pushboolean(L, getClient(L)->isConnected()); + return 1; +} + +SLUIFT_LUA_FUNCTION(Client, disconnect) { + getClient(L)->disconnect(); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, set_version) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + if (boost::shared_ptr<SoftwareVersion> version = boost::dynamic_pointer_cast<SoftwareVersion>(Sluift::globals.elementConvertor.convertFromLuaUntyped(L, 2, "software_version"))) { + client->setSoftwareVersion(version->getName(), version->getVersion(), version->getOS()); + } + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, get_contacts) { + Sluift::globals.eventLoop.runOnce(); + + SluiftClient* client = getClient(L); + Lua::Table contactsTable; + foreach(const XMPPRosterItem& item, client->getRoster()) { + std::string subscription; + switch(item.getSubscription()) { + case RosterItemPayload::None: subscription = "none"; break; + case RosterItemPayload::To: subscription = "to"; break; + case RosterItemPayload::From: subscription = "from"; break; + case RosterItemPayload::Both: subscription = "both"; break; + case RosterItemPayload::Remove: subscription = "remove"; break; + } + Lua::Table itemTable = boost::assign::map_list_of + ("jid", boost::make_shared<Lua::Value>(item.getJID().toString())) + ("name", boost::make_shared<Lua::Value>(item.getName())) + ("subscription", boost::make_shared<Lua::Value>(subscription)) + ("groups", boost::make_shared<Lua::Value>(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end()))); + contactsTable[item.getJID().toString()] = boost::make_shared<Lua::Value>(itemTable); + } + pushValue(L, contactsTable); + Lua::registerTableToString(L, -1); + return 1; +} + +SLUIFT_LUA_FUNCTION(Client, send_message) { + Sluift::globals.eventLoop.runOnce(); + JID to; + std::string body; + int index = 2; + Message::Type type = Message::Chat; + if (lua_isstring(L, index)) { + to = std::string(lua_tostring(L, index)); + ++index; + if (!lua_isstring(L, index)) { + std::string body = lua_tostring(L, index); + ++index; + } + } + if (lua_istable(L, index)) { + if (boost::optional<std::string> value = Lua::getStringField(L, index, "to")) { + to = *value; + } + + if (boost::optional<std::string> value = Lua::getStringField(L, index, "body")) { + body = *value; + } + + if (boost::optional<std::string> value = Lua::getStringField(L, index, "type")) { + if (*value == "normal") { + type = Message::Normal; + } + else if (*value == "chat") { + type = Message::Chat; + } + else if (*value == "error") { + type = Message::Error; + } + else if (*value == "groupchat") { + type = Message::Groupchat; + } + else if (*value == "headline") { + type = Message::Headline; + } + } + } + + if (!to.isValid()) { + throw Lua::Exception("Missing 'to'"); + } + if (body.empty()) { + throw Lua::Exception("Missing 'body'"); + } + + Message::ref message = boost::make_shared<Message>(); + message->setTo(to); + message->setBody(body); + message->setType(type); + getClient(L)->getClient()->sendMessage(message); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, send_presence) { + Sluift::globals.eventLoop.runOnce(); + boost::shared_ptr<Presence> presence = boost::make_shared<Presence>(); + + int index = 2; + if (lua_isstring(L, index)) { + presence->setStatus(lua_tostring(L, index)); + ++index; + } + if (lua_istable(L, index)) { + if (boost::optional<std::string> value = Lua::getStringField(L, index, "to")) { + presence->setTo(*value); + } + if (boost::optional<std::string> value = Lua::getStringField(L, index, "status")) { + presence->setStatus(*value); + } + if (boost::optional<int> value = Lua::getIntField(L, index, "priority")) { + presence->setPriority(*value); + } + if (boost::optional<std::string> value = Lua::getStringField(L, index, "type")) { + if (*value == "available") { + presence->setType(Presence::Available); + } + else if (*value == "error") { + presence->setType(Presence::Error); + } + else if (*value == "probe") { + presence->setType(Presence::Probe); + } + else if (*value == "subscribe") { + presence->setType(Presence::Subscribe); + } + else if (*value == "subscribed") { + presence->setType(Presence::Subscribed); + } + else if (*value == "unavailable") { + presence->setType(Presence::Unavailable); + } + else if (*value == "unsubscribe") { + presence->setType(Presence::Unsubscribe); + } + else if (*value == "unsubscribed") { + presence->setType(Presence::Unsubscribed); + } + } + } + + getClient(L)->getClient()->getPresenceSender()->sendPresence(presence); + lua_pushvalue(L, 1); + return 0; +} + +static int sendQuery(lua_State* L, IQ::Type type) { + SluiftClient* client = getClient(L); + + JID to; + if (boost::optional<std::string> toString = Lua::getStringField(L, 2, "to")) { + to = JID(*toString); + } + + int timeout = Sluift::globals.timeout; + if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) { + timeout = *timeoutInt; + } + + boost::shared_ptr<Payload> payload; + lua_getfield(L, 2, "query"); + if (lua_type(L, -1) == LUA_TTABLE) { + payload = Sluift::globals.elementConvertor.convertFromLua(L, -1); + } + else if (lua_type(L, -1) == LUA_TSTRING) { + payload = boost::make_shared<RawXMLPayload>(Lua::checkString(L, -1)); + } + lua_pop(L, 1); + + return client->sendRequest( + boost::make_shared< GenericRequest<Payload> >(type, to, payload, client->getClient()->getIQRouter()), timeout).convertToLuaResult(L); +} + +#define DISPATCH_PUBSUB_PAYLOAD(payloadType, container, response) \ + else if (boost::shared_ptr<payloadType> p = boost::dynamic_pointer_cast<payloadType>(payload)) { \ + return client->sendPubSubRequest(type, to, p, timeout).convertToLuaResult(L); \ + } + +SLUIFT_LUA_FUNCTION(Client, query_pubsub) { + SluiftClient* client = getClient(L); + + JID to; + if (boost::optional<std::string> toString = Lua::getStringField(L, 2, "to")) { + to = JID(*toString); + } + + int timeout = Sluift::globals.timeout; + if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) { + timeout = *timeoutInt; + } + + IQ::Type type; + if (boost::optional<std::string> queryType = Lua::getStringField(L, 2, "type")) { + if (*queryType == "get") { + type = IQ::Get; + } + else if (*queryType == "set") { + type = IQ::Set; + } + else { + throw Lua::Exception("Illegal query type: '" + *queryType + "'"); + } + } + else { + throw Lua::Exception("Missing query type"); + } + + lua_getfield(L, 2, "query"); + if (!lua_istable(L, -1)) { + throw Lua::Exception("Missing/incorrect query"); + } + boost::shared_ptr<Payload> payload = Sluift::globals.elementConvertor.convertFromLua(L, -1); + + if (false) { } + SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(DISPATCH_PUBSUB_PAYLOAD) + else { + throw Lua::Exception("Incorrect PubSub payload"); + } +} + + +SLUIFT_LUA_FUNCTION(Client, get) { + return sendQuery(L, IQ::Get); +} + +SLUIFT_LUA_FUNCTION(Client, set) { + return sendQuery(L, IQ::Set); +} + +SLUIFT_LUA_FUNCTION(Client, send) { + Sluift::globals.eventLoop.runOnce(); + + getClient(L)->getClient()->sendData(std::string(Lua::checkString(L, 2))); + lua_pushvalue(L, 1); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, set_options) { + SluiftClient* client = getClient(L); + Lua::checkType(L, 2, LUA_TTABLE); + lua_getfield(L, 2, "host"); + if (!lua_isnil(L, -1)) { + client->getOptions().manualHostname = lua_tostring(L, -1); + } + lua_getfield(L, 2, "port"); + if (!lua_isnil(L, -1)) { + client->getOptions().manualPort = lua_tointeger(L, -1); + } + lua_getfield(L, 2, "ack"); + if (!lua_isnil(L, -1)) { + client->getOptions().useAcks = lua_toboolean(L, -1); + } + lua_getfield(L, 2, "compress"); + if (!lua_isnil(L, -1)) { + client->getOptions().useStreamCompression = lua_toboolean(L, -1); + } + lua_getfield(L, 2, "tls"); + if (!lua_isnil(L, -1)) { + bool useTLS = lua_toboolean(L, -1); + client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS); + } + lua_pushvalue(L, 1); + return 0; +} + +static void pushEvent(lua_State* L, const SluiftClient::Event& event) { + switch (event.type) { + case SluiftClient::Event::MessageType: { + Message::ref message = boost::dynamic_pointer_cast<Message>(event.stanza); + Lua::Table result = boost::assign::map_list_of + ("type", boost::make_shared<Lua::Value>(std::string("message"))) + ("from", boost::make_shared<Lua::Value>(message->getFrom().toString())) + ("body", boost::make_shared<Lua::Value>(message->getBody())); + Lua::pushValue(L, result); + Lua::registerTableToString(L, -1); + break; + } + case SluiftClient::Event::PresenceType: { + Presence::ref presence = boost::dynamic_pointer_cast<Presence>(event.stanza); + Lua::Table result = boost::assign::map_list_of + ("type", boost::make_shared<Lua::Value>(std::string("presence"))) + ("from", boost::make_shared<Lua::Value>(presence->getFrom().toString())) + ("status", boost::make_shared<Lua::Value>(presence->getStatus())); + Lua::pushValue(L, result); + if (!presence->getPayloads().empty()) { + const std::vector<boost::shared_ptr<Payload> > payloads = presence->getPayloads(); + lua_createtable(L, boost::numeric_cast<int>(payloads.size()), 0); + for (size_t i = 0; i < payloads.size(); ++i) { + Sluift::globals.elementConvertor.convertToLua(L, payloads[i]); + lua_rawseti(L, -2, boost::numeric_cast<int>(i+1)); + } + Lua::registerGetByTypeIndex(L, -1); + lua_setfield(L, -2, "payloads"); + } + Lua::registerTableToString(L, -1); + break; + } + case SluiftClient::Event::PubSubEventType: { + Sluift::globals.elementConvertor.convertToLua(L, event.pubsubEvent); + lua_pushstring(L, "pubsub"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, event.from.toString().c_str()); + lua_setfield(L, -2, "from"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "process_pubsub_event"); + lua_pushvalue(L, -3); + lua_call(L, 1, 0); + lua_pop(L, 1); + } + } +} + +struct CallUnaryLuaPredicateOnEvent { + CallUnaryLuaPredicateOnEvent(lua_State* L, int index) : L(L), index(index) { + } + + bool operator()(const SluiftClient::Event& event) { + lua_pushvalue(L, index); + pushEvent(L, event); + if (lua_pcall(L, 1, 1, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + bool result = lua_toboolean(L, -1); + lua_pop(L, 1); + return result; + } + + lua_State* L; + int index; +}; + + +SLUIFT_LUA_FUNCTION(Client, get_next_event) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + + int timeout = Sluift::globals.timeout; + boost::optional<SluiftClient::Event::Type> type; + int condition = 0; + if (lua_istable(L, 2)) { + if (boost::optional<std::string> typeString = Lua::getStringField(L, 2, "type")) { + if (*typeString == "message") { + type = SluiftClient::Event::MessageType; + } + else if (*typeString == "presence") { + type = SluiftClient::Event::PresenceType; + } + else if (*typeString == "pubsub") { + type = SluiftClient::Event::PubSubEventType; + } + } + if (boost::optional<int> timeoutInt = Lua::getIntField(L, 2, "timeout")) { + timeout = *timeoutInt; + } + lua_getfield(L, 2, "if"); + if (lua_isfunction(L, -1)) { + condition = Lua::absoluteOffset(L, -1); + } + } + + boost::optional<SluiftClient::Event> event; + if (condition) { + event = client->getNextEvent(timeout, CallUnaryLuaPredicateOnEvent(L, condition)); + } + else if (type) { + event = client->getNextEvent( + timeout, lambda::bind(&SluiftClient::Event::type, lambda::_1) == *type); + } + else { + event = client->getNextEvent(timeout); + } + + if (event) { + pushEvent(L, *event); + } + else { + lua_pushnil(L); + } + return 1; +} + + +SLUIFT_LUA_FUNCTION(Client, add_contact) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + RosterItemPayload item; + if (lua_type(L, 2) == LUA_TTABLE) { + lua_getfield(L, 2, "jid"); + const char* rawJID = lua_tostring(L, -1); + if (rawJID) { + item.setJID(std::string(rawJID)); + } + lua_getfield(L, 2, "name"); + const char* rawName = lua_tostring(L, -1); + if (rawName) { + item.setName(rawName); + } + lua_getfield(L, 2, "groups"); + if (!lua_isnil(L, -1)) { + if (lua_type(L, -1) == LUA_TTABLE) { + for (size_t i = 1; i <= lua_objlen(L, -1); ++i) { + lua_rawgeti(L, -1, boost::numeric_cast<int>(i)); + const char* rawGroup = lua_tostring(L, -1); + if (rawGroup) { + item.addGroup(rawGroup); + } + lua_pop(L, 1); + } + } + else { + throw Lua::Exception("Groups should be a table"); + } + } + } + else { + item.setJID(Lua::checkString(L, 2)); + } + + client->getRoster(); + if (!client->getClient()->getRoster()->containsJID(item.getJID())) { + RosterPayload::ref roster = boost::make_shared<RosterPayload>(); + roster->addItem(item); + + Sluift::Response response = client->sendVoidRequest( + SetRosterRequest::create(roster, client->getClient()->getIQRouter()), -1); + if (response.error) { + return response.convertToLuaResult(L); + } + } + client->getClient()->getSubscriptionManager()->requestSubscription(item.getJID()); + lua_pushboolean(L, true); + return 1; +} + +SLUIFT_LUA_FUNCTION(Client, remove_contact) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + JID jid(Lua::checkString(L, 2)); + + RosterPayload::ref roster = boost::make_shared<RosterPayload>(); + roster->addItem(RosterItemPayload(JID(Lua::checkString(L, 2)), "", RosterItemPayload::Remove)); + + return client->sendVoidRequest( + SetRosterRequest::create(roster, client->getClient()->getIQRouter()), -1).convertToLuaResult(L); +} + +SLUIFT_LUA_FUNCTION(Client, confirm_subscription) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + JID jid(Lua::checkString(L, 2)); + client->getClient()->getSubscriptionManager()->confirmSubscription(jid); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, cancel_subscription) { + Sluift::globals.eventLoop.runOnce(); + SluiftClient* client = getClient(L); + JID jid(Lua::checkString(L, 2)); + client->getClient()->getSubscriptionManager()->cancelSubscription(jid); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, set_disco_info) { + SluiftClient* client = getClient(L); + if (!lua_istable(L, 2)) { + throw Lua::Exception("Missing disco info"); + } + if (boost::shared_ptr<DiscoInfo> discoInfo = boost::dynamic_pointer_cast<DiscoInfo>(Sluift::globals.elementConvertor.convertFromLuaUntyped(L, 2, "disco_info"))) { + client->getClient()->getDiscoManager()->setDiscoInfo(*discoInfo); + } + else { + throw Lua::Exception("Illegal disco info"); + } + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, set_caps_node) { + SluiftClient* client = getClient(L); + std::string node(Lua::checkString(L, 2)); + client->getClient()->getDiscoManager()->setCapsNode(Lua::checkString(L, 2)); + return 0; +} + +SLUIFT_LUA_FUNCTION(Client, jid) { + SluiftClient* client = getClient(L); + lua_pushstring(L, client->getClient()->getJID().toString().c_str()); + return 1; +} + +SLUIFT_LUA_FUNCTION(Client, __gc) { + SluiftClient* client = getClient(L); + delete client; + return 0; +} diff --git a/Sluift/globals.h b/Sluift/globals.h new file mode 100644 index 0000000..3e7e1c9 --- /dev/null +++ b/Sluift/globals.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Sluift/SluiftGlobals.h> + +namespace Swift { + namespace Sluift { + extern SluiftGlobals globals; + } +} diff --git a/Sluift/linit.c b/Sluift/linit.c index 73f0522..8507609 100644 --- a/Sluift/linit.c +++ b/Sluift/linit.c @@ -3,35 +3,6 @@ #include <lauxlib.h> #include "sluift.h" -// A built-in table print function -// From: http://lua-users.org/wiki/TableSerialization -static const char tprint[] = - "function tprint (tt, indent, done)\n" - " done = done or {}\n" - " indent = indent or 0\n" - " if type(tt) == \"table\" then\n" - " for key, value in pairs (tt) do\n" - " io.write(string.rep (\" \", indent)) -- indent it\n" - " if type (value) == \"table\" and not done [value] then\n" - " done [value] = true\n" - " io.write(string.format(\"[%s] => table\\n\", tostring (key)));\n" - " io.write(string.rep (\" \", indent+4)) -- indent it\n" - " io.write(\"(\\n\");\n" - " tprint (value, indent + 7, done)\n" - " io.write(string.rep (\" \", indent+4)) -- indent it\n" - " io.write(\")\\n\");\n" - " else\n" - " io.write(string.format(\"[%s] => %s\\n\",\n" - " tostring (key), tostring(value)))\n" - " end\n" - " end\n" - " elseif type(tt) == \"nil\" then\n" - " io.write(\"nil\\n\")\n" - " else\n" - " io.write(tt .. \"\\n\")\n" - " end\n" - "end\n"; - static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, @@ -53,8 +24,4 @@ LUALIB_API void luaL_openlibs (lua_State *L) { lua_pushstring(L, lib->name); lua_call(L, 1, 0); } - if (luaL_dostring(L, tprint) != 0) { - fprintf(stderr, "%s\n", lua_tostring(L, -1)); - lua_pop(L, 1); - } } diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp index 8076f5a..e6096a0 100644 --- a/Sluift/sluift.cpp +++ b/Sluift/sluift.cpp @@ -1,832 +1,280 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "sluift.h" -#include <lauxlib.h> +#include <Sluift/sluift.h> + +#include <lua.hpp> -#include <iostream> #include <string> -#include <deque> +#include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <boost/assign/list_of.hpp> -#include <Swiften/Base/foreach.h> -#include <Swiften/Swiften.h> - #include "Watchdog.h" -#include "SluiftException.h" -#include "ResponseSink.h" -#include "Lua/Value.h" +#include <Sluift/Lua/Check.h> +#include <Sluift/SluiftClient.h> +#include <Sluift/globals.h> +#include <Sluift/Lua/Exception.h> +#include <Sluift/Lua/FunctionRegistration.h> +#include <Swiften/Base/sleep.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Sluift/Lua/Debug.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; -#define SLUIFT_CLIENT "SluiftClient*" - -/******************************************************************************* - * Forward declarations - ******************************************************************************/ - -static bool debug = false; -static int globalTimeout = 30000; - -/******************************************************************************* - * Helper classes - ******************************************************************************/ - -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); - - -class SluiftClient { - public: - SluiftClient(const JID& jid, const std::string& password) : tracer(NULL) { - client = new Client(jid, password, &networkFactories); - client->setAlwaysTrustCertificates(); - client->onDisconnected.connect(boost::bind(&SluiftClient::handleDisconnected, this, _1)); - client->onMessageReceived.connect(boost::bind(&SluiftClient::handleIncomingEvent, this, _1)); - client->onPresenceReceived.connect(boost::bind(&SluiftClient::handleIncomingEvent, this, _1)); - client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SluiftClient::handleInitialRosterPopulated, this)); - if (debug) { - tracer = new ClientXMLTracer(client); - } - } - - ~SluiftClient() { - delete tracer; - delete client; - } - - Client* getClient() { - return client; - } - - ClientOptions& getOptions() { - return options; - } - - void connect() { - rosterReceived = false; - client->connect(options); - } - - void connect(const std::string& host) { - rosterReceived = false; - options.manualHostname = host; - client->connect(options); - } - - void waitConnected() { - Watchdog watchdog(globalTimeout, networkFactories.getTimerFactory()); - while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) { - eventLoop.runUntilEvents(); - } - if (watchdog.getTimedOut()) { - client->disconnect(); - throw SluiftException("Timeout while connecting"); - } - } - - bool isConnected() const { - return client->isAvailable(); - } - - void sendMessage(const JID& to, const std::string& body) { - Message::ref message = boost::make_shared<Message>(); - message->setTo(to); - message->setBody(body); - client->sendMessage(message); - } - - void sendPresence(const std::string& status) { - client->sendPresence(boost::make_shared<Presence>(status)); - } - - boost::optional<std::string> sendQuery(const JID& jid, IQ::Type type, const std::string& data, int timeout) { - rawRequestResponse.reset(); - RawRequest::ref request = RawRequest::create(type, jid, data, client->getIQRouter()); - boost::signals::scoped_connection c = request->onResponse.connect(boost::bind(&SluiftClient::handleRawRequestResponse, this, _1)); - request->send(); - - Watchdog watchdog(timeout, networkFactories.getTimerFactory()); - while (!watchdog.getTimedOut() && !rawRequestResponse) { - eventLoop.runUntilEvents(); - } - - if (watchdog.getTimedOut()) { - return boost::optional<std::string>(); - } - else { - return *rawRequestResponse; - } - } - - void disconnect() { - client->disconnect(); - while (client->isActive()) { - eventLoop.runUntilEvents(); - } - } - - void setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) { - client->setSoftwareVersion(name, version, os); - } - - Stanza::ref getNextEvent(int timeout) { - if (!pendingEvents.empty()) { - Stanza::ref event = pendingEvents.front(); - pendingEvents.pop_front(); - return event; - } - Watchdog watchdog(timeout, networkFactories.getTimerFactory()); - while (!watchdog.getTimedOut() && pendingEvents.empty() && !client->isActive()) { - eventLoop.runUntilEvents(); - } - if (watchdog.getTimedOut() || !client->isActive()) { - return Stanza::ref(); - } - else if (!pendingEvents.empty()) { - Stanza::ref event = pendingEvents.front(); - pendingEvents.pop_front(); - return event; - } - else { - return Stanza::ref(); - } - } - - std::vector<XMPPRosterItem> getRoster() { - if (!rosterReceived) { - // If we haven't requested it yet, request it for the first time - client->requestRoster(); - } - while (!rosterReceived) { - eventLoop.runUntilEvents(); - } - return client->getRoster()->getItems(); - } - - private: - void handleIncomingEvent(Stanza::ref stanza) { - pendingEvents.push_back(stanza); - } - - void handleInitialRosterPopulated() { - rosterReceived = true; - } - - void handleRawRequestResponse(const std::string& response) { - rawRequestResponse = response; - } +namespace Swift { + namespace Sluift { + SluiftGlobals globals; + } +} - void handleDisconnected(const boost::optional<ClientError>& error) { - if (error) { - throw SluiftException(*error); - } - } - - private: - Client* client; - ClientOptions options; - ClientXMLTracer* tracer; - bool rosterReceived; - std::deque<Stanza::ref> pendingEvents; - boost::optional<std::string> rawRequestResponse; -}; +extern "C" const char boot_lua[]; /******************************************************************************* - * Client functions. + * Module functions ******************************************************************************/ -static inline SluiftClient* getClient(lua_State* L) { - return *reinterpret_cast<SluiftClient**>(luaL_checkudata(L, 1, SLUIFT_CLIENT)); -} - -static int sluift_client_connect(lua_State *L) { - try { - SluiftClient* client = getClient(L); - std::string host; - if (lua_type(L, 2) != LUA_TNONE) { - host = luaL_checkstring(L, 2); - } - if (host.empty()) { - client->connect(); - } - else { - client->connect(host); - } - client->waitConnected(); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_async_connect(lua_State *L) { - try { - getClient(L)->connect(); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} +SLUIFT_LUA_FUNCTION(Sluift, new_client) { + Lua::checkString(L, 1); + JID jid(std::string(Lua::checkString(L, 1))); + std::string password(Lua::checkString(L, 2)); -static int sluift_client_wait_connected(lua_State *L) { - try { - getClient(L)->waitConnected(); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} + SluiftClient** client = reinterpret_cast<SluiftClient**>(lua_newuserdata(L, sizeof(SluiftClient*))); + luaL_getmetatable(L, Lua::FunctionRegistry::getMetaTableNameForType("Client").c_str()); + lua_setmetatable(L, -2); -static int sluift_client_is_connected(lua_State *L) { - lua_pushboolean(L, getClient(L)->isConnected()); + *client = new SluiftClient(jid, password, &Sluift::globals.networkFactories, &Sluift::globals.eventLoop, &Sluift::globals); return 1; } -static int sluift_client_disconnect(lua_State *L) { - try { - getClient(L)->disconnect(); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_set_version(lua_State *L) { - try { - eventLoop.runOnce(); - - SluiftClient* client = getClient(L); - luaL_checktype(L, 2, LUA_TTABLE); - lua_getfield(L, 2, "name"); - const char* rawName = lua_tostring(L, -1); - lua_getfield(L, 2, "version"); - const char* rawVersion = lua_tostring(L, -1); - lua_getfield(L, 2, "os"); - const char* rawOS = lua_tostring(L, -1); - client->setSoftwareVersion(rawName ? rawName : "", rawVersion ? rawVersion : "", rawOS ? rawOS : ""); - lua_pop(L, 3); - lua_pushvalue(L, 1); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); +SLUIFT_LUA_FUNCTION(Sluift, sha1) { + static boost::shared_ptr<CryptoProvider> crypto(PlatformCryptoProvider::create()); + if (!lua_isstring(L, 1)) { + throw Lua::Exception("Expected string"); } + size_t len; + const char* data = lua_tolstring(L, 1, &len); + ByteArray result = crypto->getSHA1Hash(createByteArray(data, len)); + lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size()); + return 1; } -static int sluift_client_get_contacts(lua_State *L) { - try { - eventLoop.runOnce(); - - SluiftClient* client = getClient(L); - Lua::Table contactsTable; - foreach(const XMPPRosterItem& item, client->getRoster()) { - std::string subscription; - switch(item.getSubscription()) { - case RosterItemPayload::None: subscription = "none"; break; - case RosterItemPayload::To: subscription = "to"; break; - case RosterItemPayload::From: subscription = "from"; break; - case RosterItemPayload::Both: subscription = "both"; break; - case RosterItemPayload::Remove: subscription = "remove"; break; - } - Lua::Value groups(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end())); - Lua::Table itemTable = boost::assign::map_list_of - ("jid", boost::make_shared<Lua::Value>(item.getJID().toString())) - ("name", boost::make_shared<Lua::Value>(item.getName())) - ("subscription", boost::make_shared<Lua::Value>(subscription)) - ("groups", boost::make_shared<Lua::Value>(std::vector<Lua::Value>(item.getGroups().begin(), item.getGroups().end()))); - contactsTable[item.getJID().toString()] = boost::make_shared<Lua::Value>(itemTable); - } - pushValue(L, contactsTable); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); +SLUIFT_LUA_FUNCTION(Sluift, sleep) { + Sluift::globals.eventLoop.runOnce(); + int timeout = Lua::checkIntNumber(L, 1); + Watchdog watchdog(timeout, Sluift::globals.networkFactories.getTimerFactory()); + while (!watchdog.getTimedOut()) { + Swift::sleep(boost::numeric_cast<unsigned int>(std::min(100, timeout))); + Sluift::globals.eventLoop.runOnce(); } + return 0; } -static int sluift_client_get_version(lua_State *L) { +static int sluift_index(lua_State* L) { try { - SluiftClient* client = getClient(L); - int timeout = -1; - if (lua_type(L, 3) != LUA_TNONE) { - timeout = luaL_checknumber(L, 3); - } - - ResponseSink<SoftwareVersion> sink; - GetSoftwareVersionRequest::ref request = GetSoftwareVersionRequest::create(std::string(luaL_checkstring(L, 2)), client->getClient()->getIQRouter()); - boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink)); - request->send(); - - Watchdog watchdog(timeout, networkFactories.getTimerFactory()); - while (!watchdog.getTimedOut() && !sink.hasResponse()) { - eventLoop.runUntilEvents(); - } - - ErrorPayload::ref error = sink.getResponseError(); - if (error || watchdog.getTimedOut()) { - lua_pushnil(L); - if (watchdog.getTimedOut()) { - lua_pushstring(L, "Timeout"); - } - else if (error->getCondition() == ErrorPayload::RemoteServerNotFound) { - lua_pushstring(L, "Remote server not found"); - } - // TODO - else { - lua_pushstring(L, "Error"); - } - return 2; + std::string key(Lua::checkString(L, 2)); + if (key == "debug") { + lua_pushboolean(L, Sluift::globals.debug); + return 1; } - else if (SoftwareVersion::ref version = sink.getResponsePayload()) { - Lua::Table result = boost::assign::map_list_of - ("name", boost::make_shared<Lua::Value>(version->getName())) - ("version", boost::make_shared<Lua::Value>(version->getVersion())) - ("os", boost::make_shared<Lua::Value>(version->getOS())); - Lua::pushValue(L, result); + else if (key == "timeout") { + lua_pushnumber(L, Sluift::globals.timeout); + return 1; } - else { - lua_pushnil(L); - } - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_send_message(lua_State *L) { - try { - eventLoop.runOnce(); - - getClient(L)->sendMessage(std::string(luaL_checkstring(L, 2)), luaL_checkstring(L, 3)); - lua_pushvalue(L, 1); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_send_presence(lua_State *L) { - try { - eventLoop.runOnce(); - - getClient(L)->sendPresence(std::string(luaL_checkstring(L, 2))); - lua_pushvalue(L, 1); - return 0; + throw Lua::Exception("Unknown property"); } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); + catch (const std::exception& e) { + return luaL_error(L, e.what()); } } -static int sluift_client_get(lua_State *L) { - try { - SluiftClient* client = getClient(L); - JID jid; - std::string data; - int timeout = -1; - if (lua_type(L, 3) == LUA_TSTRING) { - jid = JID(std::string(luaL_checkstring(L, 2))); - data = std::string(luaL_checkstring(L, 3)); - if (lua_type(L, 4) != LUA_TNONE) { - timeout = luaL_checknumber(L, 4); - } - } - else { - data = std::string(luaL_checkstring(L, 2)); - if (lua_type(L, 3) != LUA_TNONE) { - timeout = luaL_checknumber(L, 3); - } - } - boost::optional<std::string> result = client->sendQuery(jid, IQ::Get, data, timeout); - if (result) { - lua_pushstring(L, result->c_str()); - } - else { - lua_pushnil(L); - } - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} -static int sluift_client_set(lua_State *L) { +static int sluift_newindex(lua_State* L) { try { - SluiftClient* client = getClient(L); - JID jid; - std::string data; - int timeout = -1; - if (lua_type(L, 3) == LUA_TSTRING) { - jid = JID(std::string(luaL_checkstring(L, 2))); - data = std::string(luaL_checkstring(L, 3)); - if (lua_type(L, 4) != LUA_TNONE) { - timeout = luaL_checknumber(L, 4); - } - } - else { - data = std::string(luaL_checkstring(L, 2)); - if (lua_type(L, 3) != LUA_TNONE) { - timeout = luaL_checknumber(L, 3); - } - } - boost::optional<std::string> result = client->sendQuery(jid, IQ::Set, data, timeout); - if (result) { - lua_pushstring(L, result->c_str()); + std::string key(Lua::checkString(L, 2)); + if (key == "debug") { + Sluift::globals.debug = lua_toboolean(L, 3); } - else { - lua_pushnil(L); + else if (key == "timeout") { + Sluift::globals.timeout = Lua::checkIntNumber(L, 3); } - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_send(lua_State *L) { - try { - eventLoop.runOnce(); - - getClient(L)->getClient()->sendData(std::string(luaL_checkstring(L, 2))); - lua_pushvalue(L, 1); return 0; } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_client_set_options(lua_State* L) { - SluiftClient* client = getClient(L); - luaL_checktype(L, 2, LUA_TTABLE); - lua_getfield(L, 2, "ack"); - if (!lua_isnil(L, -1)) { - client->getOptions().useAcks = lua_toboolean(L, -1); - } - lua_getfield(L, 2, "compress"); - if (!lua_isnil(L, -1)) { - client->getOptions().useStreamCompression = lua_toboolean(L, -1); - } - lua_getfield(L, 2, "tls"); - if (!lua_isnil(L, -1)) { - bool useTLS = lua_toboolean(L, -1); - client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS); - } - lua_pushvalue(L, 1); - return 0; -} - -static void pushEvent(lua_State* L, Stanza::ref event) { - if (Message::ref message = boost::dynamic_pointer_cast<Message>(event)) { - Lua::Table result = boost::assign::map_list_of - ("type", boost::make_shared<Lua::Value>(std::string("message"))) - ("from", boost::make_shared<Lua::Value>(message->getFrom().toString())) - ("body", boost::make_shared<Lua::Value>(message->getBody())); - Lua::pushValue(L, result); - } - else if (Presence::ref presence = boost::dynamic_pointer_cast<Presence>(event)) { - Lua::Table result = boost::assign::map_list_of - ("type", boost::make_shared<Lua::Value>(std::string("presence"))) - ("from", boost::make_shared<Lua::Value>(presence->getFrom().toString())) - ("status", boost::make_shared<Lua::Value>(presence->getStatus())); - Lua::pushValue(L, result); - } - else { - lua_pushnil(L); - } -} - -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; - if (lua_type(L, 3) != LUA_TNONE) { - timeout = lua_tonumber(L, 3); - } - - while (true) { - Stanza::ref event = client->getNextEvent(timeout); - if (!event) { - // We got a timeout - lua_pushnil(L); - return 1; - } - else { - // Push the function and event on the stack - lua_pushvalue(L, 2); - pushEvent(L, event); - int oldTop = lua_gettop(L) - 2; - lua_call(L, 1, LUA_MULTRET); - int returnValues = lua_gettop(L) - oldTop; - if (returnValues > 0) { - lua_remove(L, -1 - returnValues); - return returnValues; - } - } - } - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); + catch (const std::exception& e) { + return luaL_error(L, e.what()); } } -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) { - timeout = lua_tonumber(L, 2); - } - pushEvent(L, client->getNextEvent(timeout)); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - - -static int sluift_client_add_contact(lua_State* L) { - try { - eventLoop.runOnce(); - SluiftClient* client = getClient(L); - RosterItemPayload item; - if (lua_type(L, 2) == LUA_TTABLE) { - lua_getfield(L, 2, "jid"); - const char* rawJID = lua_tostring(L, -1); - if (rawJID) { - item.setJID(std::string(rawJID)); - } - lua_getfield(L, 2, "name"); - const char* rawName = lua_tostring(L, -1); - if (rawName) { - item.setName(rawName); - } - lua_getfield(L, 2, "groups"); - if (!lua_isnil(L, -1)) { - if (lua_type(L, -1) == LUA_TTABLE) { - for (size_t i = 1; i <= lua_objlen(L, -1); ++i) { - lua_rawgeti(L, -1, i); - const char* rawGroup = lua_tostring(L, -1); - if (rawGroup) { - item.addGroup(rawGroup); - } - lua_pop(L, 1); - } - } - else { - return luaL_error(L, "Groups should be a table"); - } - } - } - else { - item.setJID(luaL_checkstring(L, 2)); - } - - client->getRoster(); - if (!client->getClient()->getRoster()->containsJID(item.getJID())) { - RosterPayload::ref roster = boost::make_shared<RosterPayload>(); - roster->addItem(item); - - ResponseSink<RosterPayload> sink; - SetRosterRequest::ref request = SetRosterRequest::create(roster, client->getClient()->getIQRouter()); - boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink)); - request->send(); - while (!sink.hasResponse()) { - eventLoop.runUntilEvents(); - } - if (sink.getResponseError()) { - lua_pushboolean(L, false); - return 1; - } - } - client->getClient()->getSubscriptionManager()->requestSubscription(item.getJID()); - lua_pushboolean(L, true); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); +SLUIFT_LUA_FUNCTION(Sluift, from_xml) { + PayloadsParserTester parser; + if (!parser.parse(Lua::checkString(L, 1))) { + throw Lua::Exception("Error in XML"); } + return Sluift::globals.elementConvertor.convertToLua(L, parser.getPayload()); } -static int sluift_client_remove_contact(lua_State* L) { - try { - eventLoop.runOnce(); - SluiftClient* client = getClient(L); - JID jid(luaL_checkstring(L, 2)); - - RosterPayload::ref roster = boost::make_shared<RosterPayload>(); - roster->addItem(RosterItemPayload(JID(luaL_checkstring(L, 2)), "", RosterItemPayload::Remove)); - ResponseSink<RosterPayload> sink; - SetRosterRequest::ref request = SetRosterRequest::create(roster, client->getClient()->getIQRouter()); - boost::signals::scoped_connection c = request->onResponse.connect(boost::ref(sink)); - request->send(); - while (!sink.hasResponse()) { - eventLoop.runUntilEvents(); - } - lua_pushboolean(L, !sink.getResponseError()); - return 1; +SLUIFT_LUA_FUNCTION(Sluift, to_xml) { + static FullPayloadSerializerCollection serializers; + boost::shared_ptr<Payload> payload = Sluift::globals.elementConvertor.convertFromLua(L, 1); + if (!payload) { + throw Lua::Exception("Unrecognized XML"); } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); + PayloadSerializer* serializer = serializers.getPayloadSerializer(payload); + if (!payload) { + throw Lua::Exception("Unrecognized XML"); } + lua_pushstring(L, serializer->serialize(payload).c_str()); + return 1; } -static int sluift_client_confirm_subscription(lua_State* L) { - try { - eventLoop.runOnce(); - SluiftClient* client = getClient(L); - JID jid(luaL_checkstring(L, 2)); - client->getClient()->getSubscriptionManager()->confirmSubscription(jid); - return 0; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); +SLUIFT_LUA_FUNCTION(Sluift, hexify) { + if (!lua_isstring(L, 1)) { + throw Lua::Exception("Expected string"); } + size_t len; + const char* data = lua_tolstring(L, 1, &len); + lua_pushstring(L, Hexify::hexify(createByteArray(data, len)).c_str()); + return 1; } -static int sluift_client_cancel_subscription(lua_State* L) { - try { - eventLoop.runOnce(); - SluiftClient* client = getClient(L); - JID jid(luaL_checkstring(L, 2)); - client->getClient()->getSubscriptionManager()->cancelSubscription(jid); - return 0; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); +SLUIFT_LUA_FUNCTION(Sluift, unhexify) { + if (!lua_isstring(L, 1)) { + throw Lua::Exception("Expected string"); } + ByteArray result = Hexify::unhexify(lua_tostring(L, 1)); + lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size()); + return 1; } -static int sluift_client_gc (lua_State *L) { - SluiftClient* client = getClient(L); - delete client; - return 0; -} - -static const luaL_reg sluift_client_functions[] = { - {"connect", sluift_client_connect}, - {"async_connect", sluift_client_async_connect}, - {"wait_connected", sluift_client_wait_connected}, - {"is_connected", sluift_client_is_connected}, - {"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_contacts", sluift_client_get_contacts}, - {"get_version", sluift_client_get_version}, - {"set_options", sluift_client_set_options}, - {"for_event", sluift_client_for_event}, - {"get_next_event", sluift_client_get_next_event}, - {"add_contact", sluift_client_add_contact}, - {"remove_contact", sluift_client_remove_contact}, - {"confirm_subscription", sluift_client_confirm_subscription}, - {"cancel_subscription", sluift_client_cancel_subscription}, - {"__gc", sluift_client_gc}, - {NULL, NULL} -}; /******************************************************************************* - * Module functions + * JID Functions ******************************************************************************/ -static int sluift_new_client(lua_State *L) { - 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); - - *client = new SluiftClient(jid, password); - return 1; - } - catch (const SluiftException& e) { - return luaL_error(L, e.getReason().c_str()); - } -} - -static int sluift_jid_to_bare(lua_State *L) { - JID jid(std::string(luaL_checkstring(L, 1))); +SLUIFT_LUA_FUNCTION(JID, to_bare) { + JID jid(std::string(Lua::checkString(L, 1))); lua_pushstring(L, jid.toBare().toString().c_str()); return 1; } -static int sluift_jid_node(lua_State *L) { - JID jid(std::string(luaL_checkstring(L, 1))); +SLUIFT_LUA_FUNCTION(JID, node) { + JID jid(std::string(Lua::checkString(L, 1))); lua_pushstring(L, jid.getNode().c_str()); return 1; } -static int sluift_jid_domain(lua_State *L) { - JID jid(std::string(luaL_checkstring(L, 1))); +SLUIFT_LUA_FUNCTION(JID, domain) { + JID jid(std::string(Lua::checkString(L, 1))); lua_pushstring(L, jid.getDomain().c_str()); return 1; } -static int sluift_jid_resource(lua_State *L) { - JID jid(std::string(luaL_checkstring(L, 1))); +SLUIFT_LUA_FUNCTION(JID, resource) { + JID jid(std::string(Lua::checkString(L, 1))); lua_pushstring(L, jid.getResource().c_str()); return 1; } -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()); - } +SLUIFT_LUA_FUNCTION(JID, escape_node) { + lua_pushstring(L, JID::getEscapedNode(Lua::checkString(L, 1)).c_str()); + return 1; } -static int sluift_index(lua_State *L) { - std::string key(luaL_checkstring(L, 2)); - if (key == "debug") { - lua_pushboolean(L, debug); - return 1; - } - else if (key == "timeout") { - lua_pushnumber(L, globalTimeout); - return 1; - } - else { - return luaL_error(L, "Invalid index"); +/******************************************************************************* + * Base64 Functions + ******************************************************************************/ + +SLUIFT_LUA_FUNCTION(Base64, encode) { + if (!lua_isstring(L, 1)) { + throw Lua::Exception("Expected string"); } + size_t len; + const char* data = lua_tolstring(L, 1, &len); + lua_pushstring(L, Base64::encode(createByteArray(data, len)).c_str()); + return 1; } -static int sluift_newindex(lua_State *L) { - std::string key(luaL_checkstring(L, 2)); - if (key == "debug") { - debug = lua_toboolean(L, 3); - return 0; - } - else if (key == "timeout") { - globalTimeout = luaL_checknumber(L, 3); - return 0; - } - else { - return luaL_error(L, "Invalid index"); +SLUIFT_LUA_FUNCTION(Base64, decode) { + if (!lua_isstring(L, 1)) { + throw Lua::Exception("Expected string"); } + ByteArray result = Base64::decode(lua_tostring(L, 1)); + lua_pushlstring(L, reinterpret_cast<char*>(vecptr(result)), result.size()); + return 1; } -static const luaL_reg sluift_functions[] = { - {"new_client", sluift_new_client}, - {"jid_to_bare", sluift_jid_to_bare}, - {"jid_node", sluift_jid_node}, - {"jid_domain", sluift_jid_domain}, - {"jid_resource", sluift_jid_resource}, - {"sleep", sluift_sleep}, - {NULL, NULL} -}; - - /******************************************************************************* * Module registration ******************************************************************************/ -SLUIFT_API int luaopen_sluift(lua_State *L) { - // Register functions +static const luaL_reg sluift_functions[] = { {NULL, NULL} }; + +SLUIFT_API int luaopen_sluift(lua_State* L) { + // Initialize globals + Sluift::globals.debug = false; + Sluift::globals.timeout = -1; + luaL_register(L, "sluift", sluift_functions); + + // Load bootstrap code + if (luaL_loadbuffer(L, boot_lua, strlen(boot_lua), "boot.lua") != 0) { + lua_error(L); + } + lua_call(L, 0, 1); + Sluift::globals.bootIndex = luaL_ref(L, LUA_REGISTRYINDEX); + + // Register functions + Lua::FunctionRegistry::getInstance().addFunctionsToTable(L, "Sluift"); + Lua::FunctionRegistry::getInstance().createFunctionTable(L, "JID"); + lua_setfield(L, -2, "jid"); + Lua::FunctionRegistry::getInstance().createFunctionTable(L, "Base64"); + lua_setfield(L, -2, "base64"); + + // Register convenience functions + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "tprint"); + lua_setfield(L, -3, "tprint"); + lua_pop(L, 1); + + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, "disco"); + lua_setfield(L, -3, "disco"); + lua_pop(L, 1); + + // Set read only lua_createtable(L, 0, 0); lua_pushcclosure(L, sluift_index, 0); lua_setfield(L, -2, "__index"); lua_pushcclosure(L, sluift_newindex, 0); lua_setfield(L, -2, "__newindex"); lua_setmetatable(L, -2); - - // Register the client metatable - luaL_newmetatable(L, SLUIFT_CLIENT); - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - luaL_register(L, NULL, sluift_client_functions); - + + // Load client metatable + std::vector<std::string> tables = boost::assign::list_of("Client"); + foreach (const std::string& table, tables) { + Lua::FunctionRegistry::getInstance().registerTypeMetaTable(L, table); + luaL_getmetatable(L, Lua::FunctionRegistry::getMetaTableNameForType(table).c_str()); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.bootIndex); + lua_getfield(L, -1, table.c_str()); + if (!lua_isnil(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); ) { + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_settable(L, -7); + lua_pop(L, 1); + } + } + lua_pop(L, 2); + } return 1; } diff --git a/Sluift/sluift.h b/Sluift/sluift.h index 27b4eab..b82e1c4 100644 --- a/Sluift/sluift.h +++ b/Sluift/sluift.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,10 +8,19 @@ #if defined(SLUIFT_BUILD_DLL) #define SLUIFT_API __declspec(dllexport) +#elif __GNUC__ >= 4 +#define SLUIFT_API __attribute__((visibility("default"))) #else -#define SLUIFT_API extern +#define SLUIFT_API #endif +#if defined(__cplusplus) +#include <lua.hpp> +#else #include <lua.h> +#endif +#if defined(__cplusplus) +extern "C" +#endif SLUIFT_API int (luaopen_sluift)(lua_State *L); |