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