prosody/plugins/mod_admin_telnet.lua

176 lines
4.5 KiB
Lua

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
-- luacheck: ignore 212/self
module:set_global();
module:depends("admin_shell");
local console_listener = { default_port = 5582; default_mode = "*a"; interface = "127.0.0.1" };
local async = require "prosody.util.async";
local st = require "prosody.util.stanza";
local def_env = module:shared("admin_shell/env");
local default_env_mt = { __index = def_env };
local function printbanner(session)
local option = module:get_option_string("console_banner", "full");
if option == "full" or option == "graphic" then
session.print [[
____ \ / _
| _ \ _ __ ___ ___ _-_ __| |_ _
| |_) | '__/ _ \/ __|/ _ \ / _` | | | |
| __/| | | (_) \__ \ |_| | (_| | |_| |
|_| |_| \___/|___/\___/ \__,_|\__, |
A study in simplicity |___/
]]
end
if option == "short" or option == "full" then
session.print("Welcome to the Prosody administration console. For a list of commands, type: help");
session.print("You may find more help on using this console in our online documentation at ");
session.print("https://prosody.im/doc/console\n");
end
if option ~= "short" and option ~= "full" and option ~= "graphic" then
session.print(option);
end
end
console = {};
local runner_callbacks = {};
function runner_callbacks:ready()
self.data.conn:resume();
end
function runner_callbacks:waiting()
self.data.conn:pause();
end
function runner_callbacks:error(err)
module:log("error", "Traceback[telnet]: %s", err);
self.data.print("Fatal error while running command, it did not complete");
self.data.print("Error: "..tostring(err));
end
function console:new_session(conn)
local w = function(s) conn:write(s:gsub("\n", "\r\n")); end;
local session = { conn = conn;
send = function (t)
if st.is_stanza(t) and (t.name == "repl-result" or t.name == "repl-output") then
t = "| "..t:get_text().."\n";
end
w(tostring(t));
end;
print = function (...)
local t = {};
for i=1,select("#", ...) do
t[i] = tostring(select(i, ...));
end
w("| "..table.concat(t, "\t").."\n");
end;
serialize = tostring;
disconnect = function () conn:close(); end;
};
session.env = setmetatable({}, default_env_mt);
session.thread = async.runner(function (line)
console:process_line(session, line);
session.send(string.char(0));
end, runner_callbacks, session);
-- Load up environment with helper objects
for name, t in pairs(def_env) do
if type(t) == "table" then
session.env[name] = setmetatable({ session = session }, { __index = t });
end
end
session.env.output:configure();
return session;
end
function console:process_line(session, line)
line = line:gsub("\r?\n$", "");
if line == "bye" or line == "quit" or line == "exit" or line:byte() == 4 then
session.print("See you!");
session:disconnect();
return;
end
return module:fire_event("admin/repl-input", { origin = session, stanza = st.stanza("repl-input"):text(line) });
end
local sessions = {};
function module.save()
return { sessions = sessions }
end
function module.restore(data)
if data.sessions then
for conn in pairs(data.sessions) do
conn:setlistener(console_listener);
local session = console:new_session(conn);
sessions[conn] = session;
end
end
end
function console_listener.onconnect(conn)
-- Handle new connection
local session = console:new_session(conn);
sessions[conn] = session;
printbanner(session);
session.send(string.char(0));
end
function console_listener.onincoming(conn, data)
local session = sessions[conn];
local partial = session.partial_data;
if partial then
data = partial..data;
end
for line in data:gmatch("[^\n]*[\n\004]") do
if session.closed then return end
session.thread:run(line);
end
session.partial_data = data:match("[^\n]+$");
end
function console_listener.onreadtimeout(conn)
local session = sessions[conn];
if session then
session.send("\0");
return true;
end
end
function console_listener.ondisconnect(conn, err) -- luacheck: ignore 212/err
local session = sessions[conn];
if session then
session.disconnect();
sessions[conn] = nil;
end
end
function console_listener.ondetach(conn)
sessions[conn] = nil;
end
module:provides("net", {
name = "console";
listener = console_listener;
default_port = 5582;
private = true;
});