1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 local st = require "util.stanza";
16 local um_is_admin = require "core.usermanager".is_admin;
17
18 local telnet_def_env = module:shared("/*/admin_telnet/env");
19 local telnet_commands = module:shared("/*/admin_telnet/commands")
20 local default_env_mt = { __index = telnet_def_env };
21
22 local host = module.host;
23
24
25
26 local function new_session ()
27 local session = {
28 send = function () end;
29 quit = function () end;
30 disconnect = function () end;
31 };
32
33 session.print = function (...)
34 local t = {};
35 for i=1,select("#", ...) do
36 t[i] = tostring(select(i, ...));
37 end
38 local text = "| "..table.concat(t, "\t");
39 if session.fulltext then
40 session.fulltext = session.fulltext .. "\n" .. text;
41 else
42 session.fulltext = text;
43 end
44 end;
45
46 session.env = setmetatable({}, default_env_mt);
47
48
49 for name, t in pairs(telnet_def_env) do
50 if type(t) == "table" then
51 session.env[name] = setmetatable({ session = session },
52 { __index = t });
53 end
54 end
55
56 return session;
57 end
58
59
60 local function redirect_output(_G, session)
61 local env = setmetatable({ print = session.print },
62 { __index = function (t, k) return rawget(_G, k); end });
63 env.dofile = function(name)
64 local f, err = loadfile(name);
65 if not f then return f, err; end
66 return setfenv(f, env)();
67 end;
68 return env;
69 end
70
71
72 function onincoming(session, data)
73
74 local commands = telnet_commands;
75 local partial = session.partial_data;
76 if partial then
77 data = partial..data;
78 end
79
80
81 for line in data:gmatch("[^\n]*[\n\004]") do
82
83 repeat
84 local useglobalenv;
85
86 if line:match("^>") then
87 line = line:gsub("^>", "");
88 useglobalenv = true;
89 elseif line == "\004" then
90 commands["bye"](session, line);
91 break;
92 else
93 local command = line:lower();
94 command = line:match("^%w+") or line:match("%p");
95 if commands[command] then
96 commands[command](session, line);
97 break;
98 end
99 end
100
101 session.env._ = line;
102
103 local chunkname = "=console";
104 local chunk, err = loadstring("return "..line, chunkname);
105 if not chunk then
106 chunk, err = loadstring(line, chunkname);
107 if not chunk then
108 err = err:gsub("^%[string .-%]:%d+: ", "");
109 err = err:gsub("^:%d+: ", "");
110 err = err:gsub("'<eof>'", "the end of the line");
111 session.print("Sorry, I couldn't understand that... "..err);
112 break;
113 end
114 end
115
116 setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
117
118 local ranok, taskok, message = pcall(chunk);
119
120 if not (ranok or message or useglobalenv) and commands[line:lower()] then
121 commands[line:lower()](session, line);
122 break;
123 end
124
125 if not ranok then
126 session.print("Fatal error while running command, it did not complete");
127 session.print("Error: "..taskok);
128 break;
129 end
130
131 if not message then
132 session.print("Result: "..tostring(taskok));
133 break;
134 elseif (not taskok) and message then
135 session.print("Command completed with a problem");
136 session.print("Message: "..tostring(message));
137 break;
138 end
139
140 session.print("OK: "..tostring(message));
141 until true
142
143 session.send(string.char(0));
144 end
145 session.partial_data = data:match("[^\n]+$");
146 end
147
148 function on_message(event)
149
150 if event.stanza.attr.type == "error" then
151 return;
152 end
153
154 local userjid = event.stanza.attr.from;
155 local bodytag = event.stanza:get_child("body");
156 local body = bodytag and bodytag:get_text() or "";
157 if not body or body == "" then
158 return;
159 end
160
161
162 if not um_is_admin(userjid, module.host) then
163 module:log("info", "Ignored request from non-admin: %s",
164 userjid);
165 return;
166 end
167
168
169 local session = new_session();
170
171
172 onincoming(session, body.."\n");
173
174
175 session.fulltext = tostring(session.fulltext):gsub("\n\|%s*$", "")
176
177
178 local reply_stanza = st.message({ from = host, to = userjid,
179 type = "chat" });
180 reply_stanza = reply_stanza:body(session.fulltext);
181 module:send(reply_stanza);
182
183 XXX
184
185 end
186
187 module:hook("message/bare", on_message);
188 module:depends("admin_telnet");
189
190