1 --[==========================================================================[
2 telnet
.lua
: VLM interface plugin
3 --[==========================================================================[
4 Copyright (C
) 2007 the VideoLAN team
7 Authors
: Antoine Cellerier
<dionoea at videolan dot org
>
9 This program is free software
; you can redistribute it
and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation
; either version
2 of the License
, or
12 (at your option
) any later version
.
14 This program is distributed
in the hope that it will be useful
,
15 but WITHOUT ANY WARRANTY
; without even the implied warranty of
16 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE
. See the
17 GNU General Public License
for more details
.
19 You should have received a copy of the GNU General Public License
20 along with this program
; if not, write to the Free Software
21 Foundation
, Inc
., 51 Franklin Street
, Fifth Floor
, Boston MA
02110-1301, USA
.
22 --]==========================================================================]
25 [============================================================================[
28 Copy (features wise) of the original VLC modules/control/telnet.c module.
32 * 'lock' command to lock the telnet promt
33 * possibility to listen on different hosts including stdin
35 listen on stdin: vlc -I lua --lua-intf telnet --lua-config "telnet={host='*console'}"
36 listen on stdin + 2 ports on localhost: vlc -I lua --lua-intf telnet --lua-config "telnet={hosts={'localhost:4212','localhost:5678','*console'}}"
38 Configuration options setable throught the --lua-config option are:
39 * hosts: A list of hosts to listen on (see examples above).
40 * host: A host to listen on. (won't be used if `hosts' is set)
41 * password: The password used for remote clients.
43 ]============================================================================]
47 --[[ Some telnet command special characters ]]
48 WILL
= "\251" -- Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option.
49 WONT
= "\252" -- Indicates the refusal to perform, or continue performing, the indicated option.
50 DO
= "\253" -- Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option.
51 DONT
= "\254" -- Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.
52 IAC
= "\255" -- Interpret as command
56 --[[ Client status change callbacks ]]
57 function on_password( client
)
58 if client
.type == host
.client_type
.net
then
59 client
:send( "Password: " ..IAC
..WILL
..ECHO
)
61 -- no authentication needed on stdin
62 client
:switch_status( host
.status
.read )
65 function on_read( client
)
66 client
:send( config
.prompt
and tostring(config
.prompt
) or "> " )
68 function on_write( client
)
71 --[[ Misc functions ]]
72 function telnet_commands( client
)
73 -- remove telnet command replies from the client's data
74 client
.buffer
= string.gsub( client
.buffer
, IAC
.."["..DO
..DONT
..WILL
..WONT
.."].", "" )
77 function vlm_message_to_string(client
,message
,prefix
)
78 local prefix
= prefix
or ""
80 client
:append(prefix
.. message
.name
.. " : " .. message
.value
)
83 client
:append(prefix
.. message
.name
)
84 if message
.children
then
85 for i
,c
in ipairs(message
.children
) do
86 vlm_message_to_string(client
,c
,prefix
.." ")
93 --[[ Configure the host ]]
96 h
.status_callbacks
[host
.status
.password
] = on_password
97 h
.status_callbacks
[host
.status
.read] = on_read
98 h
.status_callbacks
[host
.status
.write] = on_write
100 h
:listen( config
.hosts
or config
.host
or "localhost:4212" )
101 password
= config
.password
or "admin"
107 function shutdown(client
)
108 h
:broadcast("Shutting down.\r\n")
109 vlc
.msg
.err("shutdown requested")
113 function logout(client
)
117 function quit(client
)
118 if client
.type == host
.client_type
.net
then
119 return logout(client
)
121 return shutdown(client
)
124 function lock(client
)
126 client
:switch_status( host
.status
.password
)
130 function print_text(text
)
131 return function(client
)
132 client
:append(string.gsub(text
,"\r?\n","\r\n"))
136 function help(client
)
137 client
:append(" Telnet Specific Commands:")
138 for c
,t
in pairs(commands
) do
139 client
:append(" "..c
.." : "..t
.help
)
144 ["shutdown"] = { func
= shutdown
, help
= "shutdown VLC" },
145 ["quit"] = { func
= quit
, help
= "logout from telnet/shutdown VLC from local shell" },
146 ["logout"] = { func
= logout
, help
= "logout" },
147 ["lock"] = { func
= lock
, help
= "lock the telnet prompt" },
148 ["description"] = { func
= print_text(description
), help
= "describe this module" },
149 ["license"] = { func
= print_text(vlc
.misc
.license()), help
= "print VLC's license message" },
150 ["help"] = { func
= help
, help
= "show this help", dovlm
= true },
153 function client_command( client
)
154 local cmd
= client
.buffer
156 if not commands
[cmd
] or not commands
[cmd
].func
or commands
[cmd
].dovlm
then
157 -- if it's not an interface specific command, it has to be a VLM command
158 local message
, vlc_err
= vlm
:execute_command( cmd
)
159 vlm_message_to_string( client
, message
)
160 if not commands
[cmd
] or not commands
[cmd
].func
and not commands
[cmd
].dovlm
then
161 if vlc_err
~= 0 then client
:append( "Type `help' for help." ) end
165 ok
, msg
= pcall( commands
[cmd
].func
, client
)
167 client
:append( "Error in `"..cmd
.."' "..msg
)
173 --[[ The main loop ]]
174 while not vlc
.misc
.should_die() do
175 local w
, r
= h
:accept_and_select()
178 for _
, client
in pairs(w
) do
179 local len
= client
:send()
180 client
.buffer
= string.sub(client
.buffer
,len
+1)
181 if client
.buffer
== "" then client
:switch_status( host
.status
.read ) end
185 for _
, client
in pairs(r
) do
186 local str
= string.gsub(client
:recv(1000),"\r","\n")
189 -- the telnet client program has leave
191 client
.buffer
= "quit"
195 elseif client
.buffer
== ""
196 and ((client
.type == host
.client_type
.stdio
and str
== "")
197 or (client
.type == host
.client_type
.net
and str
== "\004")) then
198 client
.buffer
= "quit"
201 -- '\n' found: a command was sent
202 elseif string.match(str
,"\n") then
203 client
.buffer
= client
.buffer
.. str
206 -- The command is not finished yet
208 client
.buffer
= client
.buffer
.. str
211 -- Some cleaning for telnet
212 if client
.type == host
.client_type
.net
then
213 telnet_commands( client
)
216 -- If a command must be parsed
218 -- loop on all commands (might have more than one commands seperated by '\n'
219 local returned_values
= ""
220 while not (client
.buffer
== "") do
221 -- pick the first command
223 if string.find(client
.buffer
, "\n") then
224 commands
= string.sub(client
.buffer
, string.find(client
.buffer
, "\n") + 1)
225 client
.buffer
= string.sub(client
.buffer
, 0, string.find(client
.buffer
, "\n") - 1)
227 local cmd
= client
.buffer
229 if client
.status
== host
.status
.password
then
230 if client
.buffer
== password
then
231 client
:send( IAC
..WONT
..ECHO
.."\r\nWelcome, Master\r\n" )
233 client
:switch_status( host
.status
.write )
235 client
:send( "\r\nWrong password\r\nPassword: " )
238 elseif client_command( client
) then
239 client
:switch_status( host
.status
.write )
240 -- special case to exit the loop
241 if cmd
== "quit" or cmd
== "shutdown" then break end
243 returned_values
= returned_values
.. client
.buffer
244 client
.buffer
= commands
246 vlc
.msg
.err("end of loop")
247 client
.buffer
= returned_values