GPL->MIT!
[prosody.git] / plugins / mod_console.lua
1 -- Prosody IM v0.2
2 -- Copyright (C) 2008 Matthew Wild
3 -- Copyright (C) 2008 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9 module.host = "*";
10
11 local connlisteners_register = require "net.connlisteners".register;
12
13 local console_listener = { default_port = 5582; default_mode = "*l"; };
14
15 local commands = {};
16 local def_env = {};
17 local default_env_mt = { __index = def_env };
18
19 console = {};
20
21 function console:new_session(conn)
22         local w = function(s) conn.write(s:gsub("\n", "\r\n")); end;
23         local session = { conn = conn;
24                         send = function (t) w(tostring(t)); end;
25                         print = function (t) w("| "..tostring(t).."\n"); end;
26                         disconnect = function () conn.close(); end;
27                         };
28         session.env = setmetatable({}, default_env_mt);
29         
30         -- Load up environment with helper objects
31         for name, t in pairs(def_env) do
32                 if type(t) == "table" then
33                         session.env[name] = setmetatable({ session = session }, { __index = t });
34                 end
35         end
36         
37         return session;
38 end
39
40 local sessions = {};
41
42 function console_listener.listener(conn, data)
43         local session = sessions[conn];
44         
45         if not session then
46                 -- Handle new connection
47                 session = console:new_session(conn);
48                 sessions[conn] = session;
49                 printbanner(session);
50         end
51         if data then
52                 -- Handle data
53                 (function(session, data)
54                         if data:match("[!.]$") then
55                                 local command = data:lower();
56                                 command = data:match("^%w+") or data:match("%p");
57                                 if commands[command] then
58                                         commands[command](session, data);
59                                         return;
60                                 end
61                         end
62                         
63                         session.env._ = data;
64                         
65                         local chunk, err = loadstring("return "..data);
66                         if not chunk then
67                                 chunk, err = loadstring(data);
68                                 if not chunk then
69                                         err = err:gsub("^%[string .-%]:%d+: ", "");
70                                         err = err:gsub("^:%d+: ", "");
71                                         err = err:gsub("'<eof>'", "the end of the line");
72                                         session.print("Sorry, I couldn't understand that... "..err);
73                                         return;
74                                 end
75                         end
76                         
77                         setfenv(chunk, session.env);
78                         local ranok, taskok, message = pcall(chunk);
79                         
80                         if not ranok then
81                                 session.print("Fatal error while running command, it did not complete");
82                                 session.print("Error: "..taskok);
83                                 return;
84                         end
85                         
86                         if not message then
87                                 session.print("Result: "..tostring(taskok));
88                                 return;
89                         elseif (not taskok) and message then
90                                 session.print("Command completed with a problem");
91                                 session.print("Message: "..tostring(message));
92                                 return;
93                         end
94                         
95                         session.print("OK: "..tostring(message));
96                 end)(session, data);
97         end
98         session.send(string.char(0));
99 end
100
101 function console_listener.disconnect(conn, err)
102         
103 end
104
105 connlisteners_register('console', console_listener);
106
107 -- Console commands --
108 -- These are simple commands, not valid standalone in Lua
109
110 function commands.bye(session)
111         session.print("See you! :)");
112         session.disconnect();
113 end
114
115 commands["!"] = function (session, data)
116         if data:match("^!!") then
117                 session.print("!> "..session.env._);
118                 return console_listener.listener(session.conn, session.env._);
119         end
120         local old, new = data:match("^!(.-[^\\])!(.-)!$");
121         if old and new then
122                 local ok, res = pcall(string.gsub, session.env._, old, new);
123                 if not ok then
124                         session.print(res)
125                         return;
126                 end
127                 session.print("!> "..res);
128                 return console_listener.listener(session.conn, res);
129         end
130         session.print("Sorry, not sure what you want");
131 end
132
133 -- Session environment --
134 -- Anything in def_env will be accessible within the session as a global variable
135
136 def_env.server = {};
137 function def_env.server:reload()
138         dofile "prosody"
139         return true, "Server reloaded";
140 end
141
142 def_env.module = {};
143 function def_env.module:load(name, host, config)
144         local mm = require "modulemanager";
145         local ok, err = mm.load(host or self.env.host, name, config);
146         if not ok then
147                 return false, err or "Unknown error loading module";
148         end
149         return true, "Module loaded";
150 end
151
152 function def_env.module:unload(name, host)
153         local mm = require "modulemanager";
154         local ok, err = mm.unload(host or self.env.host, name);
155         if not ok then
156                 return false, err or "Unknown error unloading module";
157         end
158         return true, "Module unloaded";
159 end
160
161 function def_env.module:reload(name, host)
162         local mm = require "modulemanager";
163         local ok, err = mm.reload(host or self.env.host, name);
164         if not ok then
165                 return false, err or "Unknown error reloading module";
166         end
167         return true, "Module reloaded";
168 end
169
170 def_env.config = {};
171 function def_env.config:load(filename, format)
172         local config_load = require "core.configmanager".load;
173         local ok, err = config_load(filename, format);
174         if not ok then
175                 return false, err or "Unknown error loading config";
176         end
177         return true, "Config loaded";
178 end
179
180 function def_env.config:get(host, section, key)
181         local config_get = require "core.configmanager".get
182         return true, tostring(config_get(host, section, key));
183 end
184
185 def_env.hosts = {};
186 function def_env.hosts:list()
187         for host, host_session in pairs(hosts) do
188                 self.session.print(host);
189         end
190         return true, "Done";
191 end
192
193 function def_env.hosts:add(name)
194 end
195
196 -------------
197
198 function printbanner(session)
199 session.print [[
200                    ____                \   /     _       
201                     |  _ \ _ __ ___  ___  _-_   __| |_   _ 
202                     | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
203                     |  __/| | | (_) \__ \ |_| | (_| | |_| |
204                     |_|   |_|  \___/|___/\___/ \__,_|\__, |
205                     A study in simplicity            |___/ 
206
207 ]]
208 session.print("Welcome to the Prosody administration console. For a list of commands, type: help");
209 session.print("You may find more help on using this console in our online documentation at ");
210 session.print("http://prosody.im/doc/console\n");
211 end