diff options
Diffstat (limited to 'Swiftob/LuaCommands.cpp')
-rw-r--r-- | Swiftob/LuaCommands.cpp | 465 |
1 files changed, 0 insertions, 465 deletions
diff --git a/Swiftob/LuaCommands.cpp b/Swiftob/LuaCommands.cpp deleted file mode 100644 index 18535f3..0000000 --- a/Swiftob/LuaCommands.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2011-2016 Isode Limited. - * All rights reserved. - * See the COPYING file for more information. - */ - -#include <Swiftob/LuaCommands.h> - -#include <boost/bind.hpp> -#include <vector> -#include <algorithm> -#include <iostream> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Client/Client.h> -#include <Swiften/Network/TimerFactory.h> -#include <boost/filesystem/operations.hpp> -#include <Swiften/Base/Path.h> - -#include <Swiftob/Commands.h> - -#include <Swiften/Base/BoostFilesystemVersion.h> - -#define LUA_COMMANDS "__Lua_Commands" -#define STORAGE "__Storage" - -static const luaL_Reg defaultLibraries[] = { - {"", luaopen_base}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_OSLIBNAME, luaopen_os}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_DBLIBNAME, luaopen_debug}, - {NULL, NULL} -}; - -static void initialize(lua_State* L) { - lua_gc(L, LUA_GCSTOP, 0); - for (const luaL_Reg* lib = defaultLibraries; lib->func; lib++) { -#if LUA_VERSION_NUM >= 502 - luaL_requiref(L, lib->name, lib->func, 1); - lua_pop(L, 1); -#else - lua_pushcfunction(L, lib->func); - lua_pushstring(L, lib->name); - lua_call(L, 1, 0); -#endif - } - lua_gc(L, LUA_GCRESTART, 0); -} - -LuaCommands::LuaCommands(Commands* commands, const std::string& path, Client* client, TimerFactory* timerFactory, MUCs* mucs) : path_(path), scriptsPath_(boost::filesystem::path(path_) / "scripts") { - commands_ = commands; - client_ = client; - timerFactory_ = timerFactory; - mucs_ = mucs; - commands_->onReset.connect(boost::bind(&LuaCommands::registerCommands, this)); - registerCommands(); -} - -void LuaCommands::registerCommands() { - std::cout << "Trying to load all scripts in " << scriptsPath_ << std::endl; - if (boost::filesystem::exists(scriptsPath_) && boost::filesystem::is_directory(scriptsPath_)) { - std::vector<boost::filesystem::path> files; - copy(boost::filesystem::directory_iterator(scriptsPath_), boost::filesystem::directory_iterator(), std::back_inserter(files)); - foreach (boost::filesystem::path file, files) { - if (boost::filesystem::is_regular_file(file) && file.extension() == ".lua") { - loadScript(file); - } - } - } -} - -static int l_register_listener(lua_State *L) { - LuaCommands* commands = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, LUA_COMMANDS); - commands = static_cast<LuaCommands*>(lua_touserdata(L, -1)); - lua_pop(L, 1); - if (!lua_isfunction(L, 1)) { - return luaL_error(L, "register_listener parameter must be a callback function"); - } - lua_pushvalue(L, 1); - int callbackIndex = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pop(L, 1); - commands->getCommands()->registerListener(boost::bind(&LuaCommands::handleLuaListener, commands, callbackIndex, L, _1)); - return 0; -} - -static int l_register_command(lua_State *L) { - LuaCommands* commands = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, LUA_COMMANDS); - commands = static_cast<LuaCommands*>(lua_touserdata(L, -1)); - lua_pop(L, 1); - if (!lua_isfunction(L, 4)) { - return luaL_error(L, "register_command callback parameter must be a function"); - } - //luaL_ref callback(lua_to(L, 4)); - lua_pushvalue(L, 4); - int callbackIndex = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pop(L, 1); - - if (!lua_isstring(L, 3)) { - return luaL_error(L, "register_command description parameter must be a string"); - } - std::string description(lua_tostring(L, 3)); - lua_pop(L, 1); - - if (!lua_isstring(L, 2)) { - return luaL_error(L, "register_command allowed roles parameter must be a string"); - } - std::string roleString(lua_tostring(L, 2)); - lua_pop(L, 1); - Commands::RoleList roleList = Commands::Owner; - if (roleString == "Owner") { - roleList = Commands::Owner; - } else if (roleString == "Anyone") { - roleList = Commands::Anyone; - } else { - return luaL_error(L, "register_command allowed roles parameter has illegal value"); - } - if (!lua_isstring(L, 1)) { - return luaL_error(L, "register_command command name parameter must be a string"); - } - std::string name(lua_tostring(L, 1)); - lua_pop(L, 1); - std::cout << "Registering lua command '" << name << "' for '" << roleString << "' with callback index " << callbackIndex << std::endl; - commands->getCommands()->registerCommand(name, roleList, description, boost::bind(&LuaCommands::handleLuaCommand, commands, callbackIndex, L, _1, _2, _3)); - - return 0; -} - -static std::string luatable_asstring(lua_State *L, const char* key) { - lua_getfield(L, -1, key); - const char* valueChars = lua_tostring(L, -1); - std::string value(valueChars != NULL ? valueChars : ""); - lua_pop(L, 1); - return value; -} - -static int luatable_asint(lua_State *L, const char* key) { - lua_getfield(L, -1, key); - int value = lua_tointeger(L, -1); - lua_pop(L, 1); - return value; -} - -static int luatable_asfunction(lua_State *L, const char* key) { - lua_getfield(L, -1, key); - int callbackIndex = luaL_ref(L, LUA_REGISTRYINDEX); - return callbackIndex; -} - -static Message::ref messageFromTable(lua_State *L) { - Message::ref message(new Message()); - message->setFrom(JID(luatable_asstring(L, "from"))); - message->setBody(luatable_asstring(L, "body")); - Message::Type type = Message::Normal; - std::string typeString(luatable_asstring(L, "type")); - if (typeString == "normal") { - type = Message::Normal; - } else if (typeString == "chat") { - type = Message::Chat; - } else if (typeString == "groupchat") { - type = Message::Groupchat; - } else if (typeString == "error") { - type = Message::Error; - } else if (typeString == "headline") { - type = Message::Headline; - } else { - return Message::ref(); - } - message->setType(type); - return message; -} - -LuaCommands* LuaCommands::commandsFromLua(lua_State *L) { - LuaCommands* commands = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, LUA_COMMANDS); - commands = static_cast<LuaCommands*>(lua_touserdata(L, -1)); - lua_pop(L, 1); - return commands; -} - -Storage* LuaCommands::storageFromLua(lua_State *L) { - Storage* storage = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, STORAGE); - storage = static_cast<Storage*>(lua_touserdata(L, -1)); - lua_pop(L, 1); - return storage; -} - -static int l_reply_to(lua_State *L) { - LuaCommands* commands = LuaCommands::commandsFromLua(L); - - if (!lua_isboolean(L, 3) && lua_gettop(L) > 2) { - return luaL_error(L, "reply_to parameter 3 must be boolean if present"); - } - bool outOfMUC = lua_toboolean(L, 3); - if (lua_gettop(L) == 3) { - lua_pop(L, 1); - } - - if (!lua_isstring(L, 2)) { - return luaL_error(L, "reply_to body parameter must be a string"); - } - std::string body(lua_tostring(L, 2)); - lua_pop(L, 1); - - if (!lua_istable(L, 1)) { - return luaL_error(L, "reply_to message parameter must be a table"); - } - lua_pushvalue(L, 1); - Message::ref message(messageFromTable(L)); - if (!message) { - return luaL_error(L, "message parameter invalid"); - } - commands->getCommands()->replyTo(message, body, outOfMUC); - lua_pop(L, 1); - - return 0; -} - -static int l_muc_input_to_jid(lua_State *L) { - LuaCommands* commands = LuaCommands::commandsFromLua(L); - return commands->muc_input_to_jid(L); -} - -int LuaCommands::muc_input_to_jid(lua_State *L) { - if (!lua_isstring(L, 2)) { - return luaL_error(L, "must pass a string to muc_input_to_jid p2"); - } - std::string source = lua_tostring(L, 2); - JID sourceJID(source); - lua_pop(L, 1); - if (!lua_isstring(L, 1)) { - return luaL_error(L, "must pass a string to muc_input_to_jid p1"); - } - std::string input = lua_tostring(L, 1); - lua_pop(L, 1); - JID result(input); - if (mucs_->contains(sourceJID.toBare())) { - if (result.isBare() && result.getNode().empty()) { - if (mucs_->getMUC(sourceJID.toBare())->hasOccupant(input)) { - result = JID(sourceJID.getNode(), sourceJID.getDomain(), input); - } - } - } - - lua_pushstring(L, result.isValid() ? result.toString().c_str() : ""); - return 1; -} - -void LuaCommands::handleSoftwareVersionResponse(boost::shared_ptr<SoftwareVersion> version, ErrorPayload::ref error, bool timeout, GetSoftwareVersionRequest::ref request, Timer::ref timer, lua_State* L, Callbacks callbacks) { - request->onResponse.disconnect_all_slots(); - timer->onTick.disconnect_all_slots(); - timer->stop(); - int callback = callbacks.failure; - int stackCount = 0; - if (timeout) { - callback = callbacks.timeout; - } else if (version) { - callback = callbacks.success; - } - lua_rawgeti(L, LUA_REGISTRYINDEX, callback); - if (error) { - lua_pushstring(L, error->getText().empty() ? "No error text" : error->getText().c_str()); - stackCount++; - } - else if (version) { - lua_createtable(L, 0, 3); - lua_pushstring(L, version->getName().c_str()); - lua_setfield(L, -2, "name"); - lua_pushstring(L, version->getVersion().c_str()); - lua_setfield(L, -2, "version"); - lua_pushstring(L, version->getOS().c_str()); - lua_setfield(L, -2, "os"); - stackCount++; - } - else { - lua_pushliteral(L, "Missing payload"); - stackCount++; - } - int result = lua_pcall(L, stackCount, 0, 0); - if (result != 0) { - std::string error(lua_tostring(L, -1)); - lua_pop(L, 1); - std::cout << error << std::endl; - callbacks.erase(L); - luaL_error(L, error.c_str()); - } else { - callbacks.erase(L); - } - -} - -static int l_get_software_version(lua_State *L) { - LuaCommands* commands = LuaCommands::commandsFromLua(L); - return commands->get_software_version(L); -} - -int LuaCommands::get_software_version(lua_State *L) { - if (!lua_istable(L, 1)) { - return luaL_error(L, "get_software_version requires a table parameter."); - } - lua_pushvalue(L, 1); - JID to(luatable_asstring(L, "to")); - if (!to.isValid()) { - return luaL_error(L, "invalid JID."); - } - int timeout = luatable_asint(L, "timeout"); - if (timeout == 0) { - return luaL_error(L, "invalid timeout."); - } - - int successCallback = luatable_asfunction(L, "success_callback"); - int failureCallback = luatable_asfunction(L, "failure_callback"); - int timeoutCallback = luatable_asfunction(L, "timeout_callback"); - GetSoftwareVersionRequest::ref request = GetSoftwareVersionRequest::create(to, client_->getIQRouter()); - Timer::ref timer = timerFactory_->createTimer(timeout * 1000); - Callbacks callbacks(successCallback, failureCallback, timeoutCallback); - request->onResponse.connect(boost::bind(&LuaCommands::handleSoftwareVersionResponse, this, _1, _2, false, request, timer, L, callbacks)); - boost::shared_ptr<SoftwareVersion> fakePayload; - ErrorPayload::ref fakeError; - timer->onTick.connect(boost::bind(&LuaCommands::handleSoftwareVersionResponse, this, fakePayload, fakeError, true, request, timer, L, callbacks)); - timer->start(); - request->send(); - return 1; -} - -int LuaCommands::muc_kick(lua_State *L) { - if (!lua_isstring(L, 2)) { - return luaL_error(L, "muc_kick requires a nick to kick"); - } - std::string nick = lua_tostring(L, 2); - if (!lua_isstring(L, 1)) { - return luaL_error(L, "muc_kick requires a muc to kick from"); - } - JID mucJID(lua_tostring(L, 1)); - MUC::ref muc = mucs_->getMUC(mucJID); - muc->kickOccupant(JID(mucJID.getNode(), mucJID.getDomain(), nick)); - return 0; -} - -static int l_muc_kick(lua_State *L) { - LuaCommands* commands = LuaCommands::commandsFromLua(L); - return commands->muc_kick(L); -} - -static int l_store_setting(lua_State *L) { - return LuaCommands::commandsFromLua(L)->store_setting(L); -} - -static int l_get_setting(lua_State *L) { - return LuaCommands::commandsFromLua(L)->get_setting(L); -} - -int LuaCommands::store_setting(lua_State *L) { - if (!lua_isstring(L, 2) || !lua_isstring(L, 1)) { - return luaL_error(L, "both setting and key must be strings"); - } - std::string value(lua_tostring(L, 2)); - std::string key(lua_tostring(L, 1)); - lua_pop(L, 2); - storageFromLua(L)->saveSetting(key, value); - return 0; -} - -int LuaCommands::get_setting(lua_State *L) { - if (!lua_isstring(L, 1)) { - return luaL_error(L, "key must be a string"); - } - std::string key(lua_tostring(L, 1)); - lua_pop(L, 1); - lua_pushstring(L, storageFromLua(L)->getSetting(key).c_str()); - return 1; - -} - -void LuaCommands::handleLuaListener(int callbackIndex, lua_State* L, Swift::Message::ref message) { - lua_rawgeti(L, LUA_REGISTRYINDEX, callbackIndex); - lua_pushstring(L, message->getBody().get_value_or("").c_str()); - lua_pushstring(L, message->getFrom().toBare().toString().c_str()); - lua_pushstring(L, message->getFrom().getResource().c_str()); - messageOntoStack(message, L); - int result = lua_pcall(L, 4, 0, 0); - if (result != 0) { - std::string error(lua_tostring(L, -1)); - lua_pop(L, 1); - error = "Listener failed: " + error; - std::cout << error << std::endl; - } -} - -void LuaCommands::handleLuaCommand(int callbackIndex, lua_State* L, const std::string& command, const std::string& params, Swift::Message::ref message) { - lua_rawgeti(L, LUA_REGISTRYINDEX, callbackIndex); - lua_pushstring(L, command.c_str()); - lua_pushstring(L, params.c_str()); - messageOntoStack(message, L); - int result = lua_pcall(L, 3, 0, 0); - if (result != 0) { - std::string error(lua_tostring(L, -1)); - lua_pop(L, 1); - error = "Command '" + command + "' failed: " + error; - std::cout << error << std::endl; - commands_->replyTo(message, error, false); - } -} - -void LuaCommands::messageOntoStack(Swift::Message::ref message, lua_State* L) { - lua_createtable(L, 0, 4); - std::string typeString; - switch (message->getType()) { - case Message::Chat : typeString = "chat";break; - case Message::Groupchat : typeString = "groupchat";break; - case Message::Normal : typeString = "normal";break; - case Message::Error : typeString = "error";break; - case Message::Headline : typeString = "headline";break; - } - lua_pushstring(L, typeString.c_str()); - lua_setfield(L, -2, "type"); - lua_pushstring(L, message->getFrom().toString().c_str()); - lua_setfield(L, -2, "from"); - lua_pushstring(L, message->getFrom().toBare().toString().c_str()); - lua_setfield(L, -2, "frombare"); - lua_pushstring(L, message->getTo().toString().c_str()); - lua_setfield(L, -2, "to"); - lua_pushstring(L, message->getBody().get_value_or("").c_str()); - lua_setfield(L, -2, "body"); -} - -void LuaCommands::loadScript(boost::filesystem::path filePath) { - std::cout << "Trying to load file from " << filePath << std::endl; - lua_State* lua = luaL_newstate(); - initialize(lua); - lua_pushlightuserdata(lua, this); - lua_setfield(lua, LUA_REGISTRYINDEX, LUA_COMMANDS); -#if BOOST_FILESYSTEM_VERSION == 2 // TODO: Delete this when boost 1.44 becomes a minimum requirement, and we no longer need v2 - std::string filename = filePath.filename(); -#else - std::string filename = filePath.filename().string(); -#endif - filename += ".storage"; - boost::filesystem::path storagePath(boost::filesystem::path(path_) / stringToPath(filename)); - Storage* storage = new Storage(storagePath); - lua_pushlightuserdata(lua, storage); - lua_setfield(lua, LUA_REGISTRYINDEX, STORAGE); - lua_register(lua, "swiftob_register_command", &l_register_command); - lua_register(lua, "swiftob_register_listener", &l_register_listener); - lua_register(lua, "swiftob_reply_to", &l_reply_to); - lua_register(lua, "swiftob_get_software_version", &l_get_software_version); - lua_register(lua, "swiftob_muc_input_to_jid", &l_muc_input_to_jid); - lua_register(lua, "swiftob_store_setting", &l_store_setting); - lua_register(lua, "swiftob_get_setting", &l_get_setting); - lua_register(lua, "swiftob_muc_kick", &l_muc_kick); - int fileLoaded = luaL_dofile(lua, filePath.string().c_str()); - if (fileLoaded == 0 ) { - std::cout << "Loaded" << std::endl; - } else { - const char* error = lua_tostring(lua, -1); - std::cout << "Error: " << error << std::endl; - lua_pop(lua, -1); - } -} |