Automated merge with http://waqas.ath.cx/
[prosody.git] / plugins / mod_console.lua
1 -- Prosody IM v0.1
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 = conn.write;\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                 \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));\r
107         end\r
108 end\r
109 \r
110 function console_listener.disconnect(conn, err)\r
111         \r
112 end\r
113 \r
114 connlisteners_register('console', console_listener);\r
115 \r
116 -- Console commands --\r
117 -- These are simple commands, not valid standalone in Lua\r
118 \r
119 function commands.bye(session)\r
120         session.print("See you! :)");\r
121         session.disconnect();\r
122 end\r
123 \r
124 commands["!"] = function (session, data)\r
125         if data:match("^!!") then\r
126                 session.print("!> "..session.env._);\r
127                 return console_listener.listener(session.conn, session.env._);\r
128         end\r
129         local old, new = data:match("^!(.-[^\\])!(.-)!$");\r
130         if old and new then\r
131                 local ok, res = pcall(string.gsub, session.env._, old, new);\r
132                 if not ok then\r
133                         session.print(res)\r
134                         return;\r
135                 end\r
136                 session.print("!> "..res);\r
137                 return console_listener.listener(session.conn, res);\r
138         end\r
139         session.print("Sorry, not sure what you want");\r
140 end\r
141 \r
142 -- Session environment --\r
143 -- Anything in def_env will be accessible within the session as a global variable\r
144 \r
145 def_env.server = {};\r
146 function def_env.server:reload()\r
147         dofile "prosody"\r
148         return true, "Server reloaded";\r
149 end\r
150 \r
151 def_env.module = {};\r
152 function def_env.module:load(name, host, config)\r
153         local mm = require "modulemanager";\r
154         local ok, err = mm.load(host or self.env.host, name, config);\r
155         if not ok then\r
156                 return false, err or "Unknown error loading module";\r
157         end\r
158         return true, "Module loaded";\r
159 end\r
160 \r
161 function def_env.module:unload(name, host)\r
162         local mm = require "modulemanager";\r
163         local ok, err = mm.unload(host or self.env.host, name);\r
164         if not ok then\r
165                 return false, err or "Unknown error unloading module";\r
166         end\r
167         return true, "Module unloaded";\r
168 end\r
169 \r
170 def_env.config = {};\r
171 function def_env.config:load(filename, format)\r
172         local config_load = require "core.configmanager".load;\r
173         local ok, err = config_load(filename, format);\r
174         if not ok then\r
175                 return false, err or "Unknown error loading config";\r
176         end\r
177         return true, "Config loaded";\r
178 end\r
179 \r
180 function def_env.config:get(host, section, key)\r
181         local config_get = require "core.configmanager".get\r
182         return true, tostring(config_get(host, section, key));\r
183 end\r
184 \r
185 def_env.hosts = {};\r
186 function def_env.hosts:list()\r
187         for host, host_session in pairs(hosts) do\r
188                 self.session.print(host);\r
189         end\r
190         return true, "Done";\r
191 end\r
192 \r
193 function def_env.hosts:add(name)\r
194 end\r
195 \r
196 -------------\r
197 \r
198 function printbanner(session)\r
199 session.print [[\r
200                    ____                \   /     _       \r
201                     |  _ \ _ __ ___  ___  _-_   __| |_   _ \r
202                     | |_) | '__/ _ \/ __|/ _ \ / _` | | | |\r
203                     |  __/| | | (_) \__ \ |_| | (_| | |_| |\r
204                     |_|   |_|  \___/|___/\___/ \__,_|\__, |\r
205                     A study in simplicity            |___/ \r
206 \r
207 ]]\r
208 session.print("Welcome to the Prosody administration console. For a list of commands, type: help");\r
209 session.print("You may find more help on using this console in our online documentation at ");\r
210 session.print("http://prosody.im/doc/console\n");\r
211 end\r