summaryrefslogtreecommitdiff
path: root/lib/telnet.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/telnet.rb')
-rw-r--r--lib/telnet.rb742
1 files changed, 6 insertions, 736 deletions
diff --git a/lib/telnet.rb b/lib/telnet.rb
index 47a0926f8e..b861ffa783 100644
--- a/lib/telnet.rb
+++ b/lib/telnet.rb
@@ -1,739 +1,9 @@
-=begin
-$Date: 2000/01/24 17:02:57 $
+#
+# telnet.rb
+#
-== SIMPLE TELNET CLIENT LIBRARY
+$stderr.puts 'Warning: telnet.rb is obsolete: use net/telnet'
-telnet.rb
+require 'net/telnet'
-Version 1.20
-
-Wakou Aoyama <wakou@fsinet.or.jp>
-
-
-=== MAKE NEW TELNET OBJECT
-
- host = Telnet.new({"Binmode" => false, # default: false
- "Host" => "localhost", # default: "localhost"
- "Output_log" => "output_log", # default: not output
- "Dump_log" => "dump_log", # default: not output
- "Port" => 23, # default: 23
- "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n
- "Telnetmode" => true, # default: true
- "Timeout" => 10, # default: 10
- # if ignore timeout then set "Timeout" to false.
- "Waittime" => 0, # default: 0
- "Proxy" => proxy}) # default: nil
- # proxy is Telnet or TCPsocket object
-
-Telnet object has socket class methods.
-
-if set "Telnetmode" option to false. not telnet command interpretation.
-"Waittime" is time to confirm "Prompt". There is a possibility that
-the same character as "Prompt" is included in the data, and, when
-the network or the host is very heavy, the value is enlarged.
-
-=== STATUS OUTPUT
-
- host = Telnet.new({"Host" => "localhost"}){|c| print c }
-
-connection status output.
-
-example
-
- Trying localhost...
- Connected to localhost.
-
-
-=== WAIT FOR MATCH
-
- line = host.waitfor(/match/)
- line = host.waitfor({"Match" => /match/,
- "String" => "string",
- "Timeout" => secs})
- # if ignore timeout then set "Timeout" to false.
-
-if set "String" option, then Match == Regexp.new(quote("string"))
-
-
-==== REALTIME OUTPUT
-
- host.waitfor(/match/){|c| print c }
- host.waitfor({"Match" => /match/,
- "String" => "string",
- "Timeout" => secs}){|c| print c}
-
-of cource, set sync=true or flush is necessary.
-
-
-=== SEND STRING AND WAIT PROMPT
-
- line = host.cmd("string")
- line = host.cmd({"String" => "string",
- "Prompt" => /[$%#>] \z/n,
- "Timeout" => 10})
-
-
-==== REALTIME OUTPUT
-
- host.cmd("string"){|c| print c }
- host.cmd({"String" => "string",
- "Prompt" => /[$%#>] \z/n,
- "Timeout" => 10}){|c| print c }
-
-of cource, set sync=true or flush is necessary.
-
-
-=== SEND STRING
-
- host.print("string")
- # == host.write("string\n")
-
-
-=== TURN TELNET COMMAND INTERPRETATION
-
- host.telnetmode # turn on/off
- host.telnetmode(true) # on
- host.telnetmode(false) # off
-
-
-=== TOGGLE NEWLINE TRANSLATION
-
- host.binmode # turn true/false
- host.binmode(true) # no translate newline
- host.binmode(false) # translate newline
-
-
-=== LOGIN
-
- host.login("username", "password")
- host.login({"Name" => "username",
- "Password" => "password",
- "Prompt" => /[$%#>] \z/n,
- "Timeout" => 10})
-
-if no password prompt.
-
- host.login("username")
- host.login({"Name" => "username",
- "Prompt" => /[$%#>] \z/n,
- "Timeout" => 10})
-
-
-==== REALTIME OUTPUT
-
- host.login("username", "password"){|c| print c }
- host.login({"Name" => "username",
- "Password" => "password",
- "Prompt" => /[$%#>] \z/n,
- "Timeout" => 10}){|c| print c }
-
-of cource, set sync=true or flush is necessary.
-
-
-== EXAMPLE
-
-=== LOGIN AND SEND COMMAND
-
- localhost = Telnet.new({"Host" => "localhost",
- "Timeout" => 10,
- "Prompt" => /[$%#>] \z/n})
- localhost.login("username", "password"){|c| print c }
- localhost.cmd("command"){|c| print c }
- localhost.close
-
-
-=== CHECKS A POP SERVER TO SEE IF YOU HAVE MAIL
-
- pop = Telnet.new({"Host" => "your_destination_host_here",
- "Port" => 110,
- "Telnetmode" => false,
- "Prompt" => /^\+OK/n})
- pop.cmd("user " + "your_username_here"){|c| print c}
- pop.cmd("pass " + "your_password_here"){|c| print c}
- pop.cmd("list"){|c| print c}
-
-
-== HISTORY
-
-=== Version 1.20
-
-2000/01/24 17:02:57
-
-- respond to "IAC WILL x" with "IAC DONT x"
-- respond to "IAC WONT x" with "IAC DONT x"
-- better dumplog format
- thanks to WATANABE Hirofumi <Hirofumi.Watanabe@jp.sony.com>
-
-=== Version 1.10
-
-2000/01/18 17:47:31
-
-- bug fix: write method
-- respond to "IAC WILL BINARY" with "IAC DO BINARY"
-
-=== Version 1.00
-
-1999/10/04 22:51:26
-
-- bug fix: waitfor(preprocess) method
- thanks to Shin-ichiro Hara <sinara@blade.nagaokaut.ac.jp>
-- add simple support for AO, DM, IP, NOP, SB, SE
-- COUTION! TimeOut --> TimeoutError
-
-=== Version 0.50
-
-1999/09/21 21:24:07
-
-- add write method
-
-=== Version 0.40
-
-1999/09/17 17:41:41
-
-- bug fix: preprocess method
-
-=== Version 0.30
-
-1999/09/14 23:09:05
-
-- change prompt check order.
- not IO::select([@sock], nil, nil, waittime) and prompt === line
- --> prompt === line and not IO::select([@sock], nil, nil, waittime)
-
-=== Version 0.24
-
-1999/09/13 22:28:33
-
-- Telnet#login
-if ommit password, then not require password prompt.
-
-=== Version 0.232
-
-1999/08/10 05:20:21
-
-- STATUS OUTPUT sample code typo. thanks to Tadayoshi Funaba <tadf@kt.rim.or.jp>
- host = Telnet.new({"Hosh" => "localhost"){|c| print c }
- --> host = Telnet.new({"Host" => "localhost"){|c| print c }
-
-=== Version 0.231
-
-1999/07/16 13:39:42
-
-- TRUE --> true, FALSE --> false
-
-=== Version 0.23
-
-1999/07/15 22:32:09
-
-- waitfor: if end of file reached, then return nil.
-
-=== Version 0.22
-
-1999/06/29 09:08:51
-
-- new, waitfor, cmd: {"Timeout" => false} # ignore timeout
-
-=== Version 0.21
-
-1999/06/28 18:18:55
-
-- waitfor: not rescue (EOFError)
-
-=== Version 0.20
-
-1999/06/04 06:24:58
-
-- waitfor: support for divided telnet command
-
-=== Version 0.181
-
-1999/05/22
-
-- bug fix: print method
-
-=== Version 0.18
-
-1999/05/14
-
-- respond to "IAC WON'T SGA" with "IAC DON'T SGA"
-- DON'T SGA : end of line --> CR + LF
-- bug fix: preprocess method
-
-=== Version 0.17
-
-1999/04/30
-
-- bug fix: $! + "\n" --> $!.to_s + "\n"
-
-=== Version 0.163
-
-1999/04/11
-
-- STDOUT.write(message) --> yield(message) if iterator?
-
-=== Version 0.162
-
-1999/03/17
-
-- add "Proxy" option
-- required timeout.rb
-
-=== Version 0.161
-
-1999/02/03
-
-- select --> IO::select
-
-=== Version 0.16
-
-1998/10/09
-
-- preprocess method change for the better
-- add binmode method.
-- change default Binmode. TRUE --> FALSE
-
-=== Version 0.15
-
-1998/10/04
-
-- add telnetmode method.
-
-=== Version 0.141
-
-1998/09/22
-
-- change default prompt. /[$%#>] $/ --> /[$%#>] \Z/
-
-=== Version 0.14
-
-1998/09/01
-
-- IAC WILL SGA send EOL --> CR+NULL
-- IAC WILL SGA IAC DO BIN send EOL --> CR
-- NONE send EOL --> LF
-- add Dump_log option.
-
-=== Version 0.13
-
-1998/08/25
-
-- add print method.
-
-=== Version 0.122
-
-1998/08/05
-
-- support for HP-UX 10.20 thanks to WATANABE Tetsuya <tetsu@jpn.hp.com>
-- socket.<< --> socket.write
-
-=== Version 0.121
-
-1998/07/15
-
-- string.+= --> string.concat
-
-=== Version 0.12
-
-1998/06/01
-
-- add timeout, waittime.
-
-=== Version 0.11
-
-1998/04/21
-
-- add realtime output.
-
-=== Version 0.10
-
-1998/04/13
-
-- first release.
-
-=end
-
-require "socket"
-require "delegate"
-require "timeout"
-
-class Telnet < SimpleDelegator
-
- IAC = 255.chr # "\377" # "\xff" # interpret as command:
- DONT = 254.chr # "\376" # "\xfe" # you are not to use option
- DO = 253.chr # "\375" # "\xfd" # please, you use option
- WONT = 252.chr # "\374" # "\xfc" # I won't use option
- WILL = 251.chr # "\373" # "\xfb" # I will use option
- SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation
- GA = 249.chr # "\371" # "\xf9" # you may reverse the line
- EL = 248.chr # "\370" # "\xf8" # erase the current line
- EC = 247.chr # "\367" # "\xf7" # erase the current character
- AYT = 246.chr # "\366" # "\xf6" # are you there
- AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish
- IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently
- BREAK = 243.chr # "\363" # "\xf3" # break
- DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning
- NOP = 241.chr # "\361" # "\xf1" # nop
- SE = 240.chr # "\360" # "\xf0" # end sub negotiation
- EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode)
- ABORT = 238.chr # "\356" # "\xee" # Abort process
- SUSP = 237.chr # "\355" # "\xed" # Suspend process
- EOF = 236.chr # "\354" # "\xec" # End of file
- SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls
-
- OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
- OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
- OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection
- OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
- OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation
- OPT_STATUS = 5.chr # "\005" # "\x05" # Status
- OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark
- OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo
- OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width
- OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size
- OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition
- OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops
- OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition
- OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
- OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops
- OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition
- OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition
- OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII
- OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout
- OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro
- OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal
- OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP
- OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output
- OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location
- OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type
- OPT_EOR = 25.chr # "\031" # "\x19" # End of Record
- OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification
- OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking
- OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number
- OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime
- OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD
- OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size
- OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed
- OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control
- OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode
- OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location
- OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option
- OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option
- OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option
- OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option
- OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List
-
- NULL = "\000"
- CR = "\015"
- LF = "\012"
- EOL = CR + LF
-v = $-v
-$-v = false
- VERSION = "1.20"
- RELEASE_DATE = "$Date: 2000/01/24 17:02:57 $"
-$-v = v
-
- def initialize(options)
- @options = options
- @options["Binmode"] = false unless @options.has_key?("Binmode")
- @options["Host"] = "localhost" unless @options.has_key?("Host")
- @options["Port"] = 23 unless @options.has_key?("Port")
- @options["Prompt"] = /[$%#>] \z/n unless @options.has_key?("Prompt")
- @options["Telnetmode"] = true unless @options.has_key?("Telnetmode")
- @options["Timeout"] = 10 unless @options.has_key?("Timeout")
- @options["Waittime"] = 0 unless @options.has_key?("Waittime")
-
- @telnet_option = { "SGA" => false, "BINARY" => false }
-
- if @options.has_key?("Output_log")
- @log = File.open(@options["Output_log"], 'a+')
- @log.sync = true
- @log.binmode
- end
-
- if @options.has_key?("Dump_log")
- @dumplog = File.open(@options["Dump_log"], 'a+')
- @dumplog.sync = true
- @dumplog.binmode
- def @dumplog.log_dump(dir, x)
- len = x.length
- addr = 0
- offset = 0
- while 0 < len
- if len < 16
- line = x[offset, len]
- else
- line = x[offset, 16]
- end
- hexvals = line.unpack('H*')[0]
- hexvals.concat ' ' * (32 - hexvals.length)
- hexvals = format "%s %s %s %s " * 4, *hexvals.unpack('a2' * 16)
- line.gsub! /[\000-\037\177-\377]/n, '.'
- printf "%s 0x%5.5x: %s%s\n", dir, addr, hexvals, line
- addr += 16
- offset += 16
- len -= 16
- end
- print "\n"
- end
- end
-
- if @options.has_key?("Proxy")
- if @options["Proxy"].kind_of?(Telnet)
- @sock = @options["Proxy"].sock
- elsif @options["Proxy"].kind_of?(TCPsocket)
- @sock = @options["Proxy"]
- else
- raise "Error; Proxy is Telnet or TCPSocket object."
- end
- else
- message = "Trying " + @options["Host"] + "...\n"
- yield(message) if iterator?
- @log.write(message) if @options.has_key?("Output_log")
- @dumplog.log_dump('#', message) if @options.has_key?("Dump_log")
-
- begin
- if @options["Timeout"] == false
- @sock = TCPsocket.open(@options["Host"], @options["Port"])
- else
- timeout(@options["Timeout"]){
- @sock = TCPsocket.open(@options["Host"], @options["Port"])
- }
- end
- rescue TimeoutError
- raise TimeoutError, "timed-out; opening of the host"
- rescue
- @log.write($!.to_s + "\n") if @options.has_key?("Output_log")
- @dumplog.log_dump('#', $!.to_s + "\n") if @options.has_key?("Dump_log")
- raise
- end
- @sock.sync = true
- @sock.binmode
-
- message = "Connected to " + @options["Host"] + ".\n"
- yield(message) if iterator?
- @log.write(message) if @options.has_key?("Output_log")
- @dumplog.log_dump('#', message) if @options.has_key?("Dump_log")
- end
-
- super(@sock)
- end # initialize
-
- attr :sock
-
- def telnetmode(mode = 'turn')
- if 'turn' == mode
- @options["Telnetmode"] = @options["Telnetmode"] ? false : true
- else
- @options["Telnetmode"] = mode ? true : false
- end
- end
-
- def binmode(mode = 'turn')
- if 'turn' == mode
- @options["Binmode"] = @options["Binmode"] ? false : true
- else
- @options["Binmode"] = mode ? true : false
- end
- end
-
- def preprocess(string)
- str = string.dup
-
- # combine CR+NULL into CR
- str.gsub!(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
-
- # combine EOL into "\n"
- str.gsub!(/#{EOL}/no, "\n") unless @options["Binmode"]
-
- str.gsub!(/#{IAC}(
- [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
- [#{DO}#{DONT}#{WILL}#{WONT}]
- [#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]|
- #{SB}[^#{IAC}]*#{IAC}#{SE}
- )/xno){
- if IAC == $1 # handle escaped IAC characters
- IAC
- elsif AYT == $1 # respond to "IAC AYT" (are you there)
- self.write("nobody here but us pigeons" + EOL)
- ''
- elsif DO[0] == $1[0] # respond to "IAC DO x"
- if OPT_BINARY[0] == $1[1]
- @telnet_option["BINARY"] = true
- self.write(IAC + WILL + OPT_BINARY)
- else
- self.write(IAC + WONT + $1[1..1])
- end
- ''
- elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x"
- self.write(IAC + WONT + $1[1..1])
- ''
- elsif WILL[0] == $1[0] # respond to "IAC WILL x"
- if OPT_BINARY[0] == $1[1]
- self.write(IAC + DO + OPT_BINARY)
- elsif OPT_ECHO[0] == $1[1]
- self.write(IAC + DO + OPT_ECHO)
- elsif OPT_SGA[0] == $1[1]
- @telnet_option["SGA"] = true
- self.write(IAC + DO + OPT_SGA)
- else
- self.write(IAC + DONT + $1[1..1])
- end
- ''
- elsif WONT[0] == $1[0] # respond to "IAC WON'T x"
- if OPT_ECHO[0] == $1[1]
- self.write(IAC + DONT + OPT_ECHO)
- elsif OPT_SGA[0] == $1[1]
- @telnet_option["SGA"] = false
- self.write(IAC + DONT + OPT_SGA)
- else
- self.write(IAC + DONT + $1[1..1])
- end
- ''
- else
- ''
- end
- }
-
- str
- end # preprocess
-
- def waitfor(options)
- time_out = @options["Timeout"]
- waittime = @options["Waittime"]
-
- if options.kind_of?(Hash)
- prompt = if options.has_key?("Match")
- options["Match"]
- elsif options.has_key?("Prompt")
- options["Prompt"]
- elsif options.has_key?("String")
- Regexp.new( Regexp.quote(options["String"]) )
- end
- time_out = options["Timeout"] if options.has_key?("Timeout")
- waittime = options["Waittime"] if options.has_key?("Waittime")
- else
- prompt = options
- end
-
- if time_out == false
- time_out = nil
- end
-
- line = ''
- buf = ''
- rest = ''
- until(prompt === line and not IO::select([@sock], nil, nil, waittime))
- unless IO::select([@sock], nil, nil, time_out)
- raise TimeoutError, "timed-out; wait for the next data"
- end
- begin
- c = @sock.sysread(1024 * 1024)
- @dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
- if @options["Telnetmode"]
- if Integer(c.rindex(/#{IAC}#{SE}/no)) <
- Integer(c.rindex(/#{IAC}#{SB}/no))
- buf = preprocess(rest + c[0 ... c.rindex(/#{IAC}#{SB}/no)])
- rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1]
- elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no)
- buf = preprocess(rest + c[0 ... pt])
- rest = c[pt .. -1]
- else
- buf = preprocess(c)
- rest = ''
- end
- end
- @log.print(buf) if @options.has_key?("Output_log")
- line.concat(buf)
- yield buf if iterator?
- rescue EOFError # End of file reached
- if line == ''
- line = nil
- yield nil if iterator?
- end
- break
- end
- end
- line
- end
-
- def write(string)
- length = string.length
- while 0 < length
- IO::select(nil, [@sock])
- @dumplog.log_dump('>', string[-length..-1]) if @options.has_key?("Dump_log")
- length -= @sock.syswrite(string[-length..-1])
- end
- end
-
- def print(string)
- str = string.dup + "\n"
-
- str.gsub!(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"]
-
- unless @options["Binmode"]
- if @telnet_option["BINARY"] and @telnet_option["SGA"]
- # IAC WILL SGA IAC DO BIN send EOL --> CR
- str.gsub!(/\n/n, CR)
- elsif @telnet_option["SGA"]
- # IAC WILL SGA send EOL --> CR+NULL
- str.gsub!(/\n/n, CR + NULL)
- else
- # NONE send EOL --> CR+LF
- str.gsub!(/\n/n, EOL)
- end
- end
-
- self.write(str)
- end
-
- def cmd(options)
- match = @options["Prompt"]
- time_out = @options["Timeout"]
-
- if options.kind_of?(Hash)
- string = options["String"]
- match = options["Match"] if options.has_key?("Match")
- time_out = options["Timeout"] if options.has_key?("Timeout")
- else
- string = options
- end
-
- self.print(string)
- if iterator?
- waitfor({"Prompt" => match, "Timeout" => time_out}){|c| yield c }
- else
- waitfor({"Prompt" => match, "Timeout" => time_out})
- end
- end
-
- def login(options, password = nil)
- if options.kind_of?(Hash)
- username = options["Name"]
- password = options["Password"]
- else
- username = options
- end
-
- if iterator?
- line = waitfor(/login[: ]*\z/n){|c| yield c }
- if password
- line.concat( cmd({"String" => username,
- "Match" => /Password[: ]*\z/n}){|c| yield c } )
- line.concat( cmd(password){|c| yield c } )
- else
- line.concat( cmd(username){|c| yield c } )
- end
- else
- line = waitfor(/login[: ]*\z/n)
- if password
- line.concat( cmd({"String" => username,
- "Match" => /Password[: ]*\z/n}) )
- line.concat( cmd(password) )
- else
- line.concat( cmd(username) )
- end
- end
- line
- end
-
-end
+Telnet = ::Net::Telnet