diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/cgi.rb | 61 | ||||
-rw-r--r-- | lib/cgi/session.rb | 2 | ||||
-rw-r--r-- | lib/debug.rb | 314 | ||||
-rw-r--r-- | lib/net/telnet.rb | 749 | ||||
-rw-r--r-- | lib/telnet.rb | 742 | ||||
-rw-r--r-- | lib/thread.rb | 6 | ||||
-rw-r--r-- | lib/timeout.rb | 3 |
7 files changed, 992 insertions, 885 deletions
diff --git a/lib/cgi.rb b/lib/cgi.rb index b973904997..016c66c032 100644 --- a/lib/cgi.rb +++ b/lib/cgi.rb @@ -3,11 +3,12 @@ $Date$ == CGI SUPPORT LIBRARY -CGI.rb +cgi.rb -Version 1.10 +Version 1.20 -Copyright (C) 1999 Network Applied Communication Laboratory, Inc. +Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +Copyright (C) 2000 Information-technology Promotion Agancy, Japan Wakou Aoyama <wakou@fsinet.or.jp> @@ -182,7 +183,7 @@ class CGI EOL = CR + LF v = $-v $-v = false - VERSION = "1.10" + VERSION = "1.20" RELEASE_DATE = "$Date$" $-v = v @@ -237,7 +238,8 @@ $-v = v =end def CGI::escape(string) str = string.dup - str.gsub!(/[^a-zA-Z0-9_.-]/n){ sprintf("%%%02X", $&.unpack("C")[0]) } + str.gsub!(/ /n, '+') + str.gsub!(/([^a-zA-Z0-9_.-])/n){ sprintf("%%%02X", $1.unpack("C")[0]) } str end @@ -281,7 +283,16 @@ $-v = v when /\Aquot\z/ni then '"' when /\Agt\z/ni then '>' when /\Alt\z/ni then '<' - when /\A#(\d+)\z/n then Integer($1).chr + when /\A#(\d+)\z/n then + if Integer($1) < 256 + Integer($1).chr + else + if $KCODE[0] == ?u or $KCODE[0] == ?U + [Integer($1)].pack("U") + else + "#" + $1 + end + end when /\A#x([0-9a-f]+)\z/ni then $1.hex.chr end } @@ -594,7 +605,17 @@ convert string charset, and set language to "ja". @name = options["name"] @value = Array(options["value"]) - @path = options["path"] + # simple support for IE + if options["path"] + @path = options["path"] + elsif ENV["REQUEST_URI"] + @path = ENV["REQUEST_URI"].sub(/\?.*/n,'') + if ENV["PATH_INFO"] + @path = @path[0...@path.rindex(ENV["PATH_INFO"])] + end + else + @path = ENV["SCRIPT_NAME"] or "" + end @domain = options["domain"] @expires = options["expires"] @secure = options["secure"] == true ? true : false @@ -960,7 +981,7 @@ convert string charset, and set language to "ja". def nn_element_def(element) <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase) "<element.upcase" + attributes.collect{|name, value| - next if value == nil + next unless value " " + CGI::escapeHTML(name) + if true == value "" @@ -981,7 +1002,7 @@ convert string charset, and set language to "ja". def nOE_element_def(element) <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase) "<element.upcase" + attributes.collect{|name, value| - next if value == nil + next unless value " " + CGI::escapeHTML(name) + if true == value "" @@ -996,7 +1017,7 @@ convert string charset, and set language to "ja". def nO_element_def(element) <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase) "<element.upcase" + attributes.collect{|name, value| - next if value == nil + next unless value " " + CGI::escapeHTML(name) + if true == value "" @@ -1340,8 +1361,9 @@ convert string charset, and set language to "ja". { "TYPE" => "image", "SRC" => src, "NAME" => name, "ALT" => alt } else - name["TYPE"] = "image" - name + src["TYPE"] = "image" + src["SRC"] ||= "" + src end input(attributes) end @@ -1881,7 +1903,20 @@ end =begin -== HISTRY +== HISTORY + +=== Version 1.20 - wakou + +2000/04/03 18:31:42 + +- bug fix: CGI#image_button() can't get Hash option + thanks to Takashi Ikeda <ikeda@auc.co.jp> +- CGI::unescapeHTML() + simple support for "〹" +- CGI::Cookie::new() + simple support for IE +- CGI::escape() + ' ' replaced by '+' === Version 1.10 - wakou diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb index edbae8c850..5aa3a06053 100644 --- a/lib/cgi/session.rb +++ b/lib/cgi/session.rb @@ -1,3 +1,5 @@ +# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright (C) 2000 Information-technology Promotion Agancy, Japan require 'cgi' require 'final' diff --git a/lib/debug.rb b/lib/debug.rb index b9a1d5f1c5..8af0aab96d 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -1,3 +1,6 @@ +# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright (C) 2000 Information-technology Promotion Agancy, Japan + if $SAFE > 0 STDERR.print "-r debug.rb is not available in safe mode\n" exit 1 @@ -190,159 +193,158 @@ class DEBUGGER__ def debug_command(file, line, id, binding) MUTEX.lock - DEBUGGER__.set_last_thread(Thread.current) - frame_pos = 0 - binding_file = file - binding_line = line - previous_line = nil - if (ENV['EMACS'] == 't') - stdout.printf "\032\032%s:%d:\n", binding_file, binding_line - else - stdout.printf "%s:%d:%s", binding_file, binding_line, - line_at(binding_file, binding_line) - end - @frames[0] = [binding, file, line, id] - display_expressions(binding) - while input = readline("(rdb:%d) "%thnum(), true) - catch (:debug_error) do - if input == "" - input = DEBUG_LAST_CMD[0] - stdout.print input, "\n" + DEBUGGER__.set_last_thread(Thread.current) + frame_pos = 0 + binding_file = file + binding_line = line + previous_line = nil + if (ENV['EMACS'] == 't') + stdout.printf "\032\032%s:%d:\n", binding_file, binding_line + else + stdout.printf "%s:%d:%s", binding_file, binding_line, + line_at(binding_file, binding_line) + end + @frames[0] = [binding, file, line, id] + display_expressions(binding) + while input = readline("(rdb:%d) "%thnum(), true) + catch (:debug_error) do + if input == "" + input = DEBUG_LAST_CMD[0] + stdout.print input, "\n" + else + DEBUG_LAST_CMD[0] = input + end + + case input + when /^\s*b(?:reak)?\s+((?:.*?+:)?.+)$/ + pos = $1 + if pos.index(":") + file, pos = pos.split(":") + end + file = File.basename(file) + if pos =~ /^\d+$/ + pname = pos + pos = pos.to_i else - DEBUG_LAST_CMD[0] = input + pname = pos = pos.intern.id2name end - - case input - when /^\s*b(?:reak)?\s+((?:.*?+:)?.+)$/ - pos = $1 - if pos.index(":") - file, pos = pos.split(":") - end - file = File.basename(file) - if pos =~ /^\d+$/ - pname = pos - pos = pos.to_i - else - pname = pos = pos.intern.id2name - end - break_points.push [true, 0, file, pos] - stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, file, - pname - - when /^\s*wat(?:ch)?\s+(.+)$/ - exp = $1 - break_points.push [true, 1, exp] - stdout.printf "Set watchpoint %d\n", break_points.size, exp - - when /^\s*b(?:reak)?$/ - if break_points.find{|b| b[1] == 0} - n = 1 - stdout.print "breakpoints:\n" - for b in break_points - if b[0] and b[1] == 0 - stdout.printf " %d %s:%s\n", n, b[2], b[3] - end - n += 1 + break_points.push [true, 0, file, pos] + stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, file, pname + + when /^\s*wat(?:ch)?\s+(.+)$/ + exp = $1 + break_points.push [true, 1, exp] + stdout.printf "Set watchpoint %d\n", break_points.size, exp + + when /^\s*b(?:reak)?$/ + if break_points.find{|b| b[1] == 0} + n = 1 + stdout.print "breakpoints:\n" + for b in break_points + if b[0] and b[1] == 0 + stdout.printf " %d %s:%s\n", n, b[2], b[3] end + n += 1 end - if break_points.find{|b| b[1] == 1} - n = 1 - stdout.print "\n" - stdout.print "watchpoints:\n" - for b in break_points - if b[0] and b[1] == 1 - stdout.printf " %d %s\n", n, b[2] - end - n += 1 + end + if break_points.find{|b| b[1] == 1} + n = 1 + stdout.print "\n" + stdout.print "watchpoints:\n" + for b in break_points + if b[0] and b[1] == 1 + stdout.printf " %d %s\n", n, b[2] end + n += 1 end - if break_points.size == 0 - stdout.print "no breakpoints\n" - else - stdout.print "\n" - end + end + if break_points.size == 0 + stdout.print "no breakpoints\n" + else + stdout.print "\n" + end - when /^\s*del(?:ete)?(?:\s+(\d+))?$/ - pos = $1 - unless pos - input = readline("clear all breakpoints? (y/n) ", false) - if input == "y" - for b in break_points - b[0] = false - end + when /^\s*del(?:ete)?(?:\s+(\d+))?$/ + pos = $1 + unless pos + input = readline("clear all breakpoints? (y/n) ", false) + if input == "y" + for b in break_points + b[0] = false end + end + else + pos = pos.to_i + if break_points[pos-1] + break_points[pos-1][0] = false else - pos = pos.to_i - if break_points[pos-1] - break_points[pos-1][0] = false - else - stdout.printf "Breakpoint %d is not defined\n", pos - end + stdout.printf "Breakpoint %d is not defined\n", pos end + end - when /^\s*disp(?:lay)?\s+(.+)$/ - exp = $1 - display.push.push [true, exp] - stdout.printf " %d: %s = %s\n", display.size, exp, - eval(exp, binding) rescue "--" - - when /^\s*disp(?:lay)?$/ - display_expressions(binding) - - when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/ - pos = $1 - unless pos - input = readline("clear all expressions? (y/n) ", false) - if input == "y" - for d in display - d[0] = false - end - end - else - pos = pos.to_i - if display[pos-1] - display[pos-1][0] = false - else - stdout.printf "display expression %d is not defined\n", pos + when /^\s*disp(?:lay)?\s+(.+)$/ + exp = $1 + display.push.push [true, exp] + stdout.printf " %d: %s = %s\n", display.size, exp, + eval(exp, binding) rescue "--" + + when /^\s*disp(?:lay)?$/ + display_expressions(binding) + + when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/ + pos = $1 + unless pos + input = readline("clear all expressions? (y/n) ", false) + if input == "y" + for d in display + d[0] = false end end - - when /^\s*c(?:ont)?$/ - MUTEX.unlock - return - - when /^\s*s(?:tep)?(?:\s+(\d+))?$/ - if $1 - lev = $1.to_i + else + pos = pos.to_i + if display[pos-1] + display[pos-1][0] = false else - lev = 1 + stdout.printf "display expression %d is not defined\n", pos end - @stop_next = lev - return + end - when /^\s*n(?:ext)?(?:\s+(\d+))?$/ - if $1 - lev = $1.to_i - else - lev = 1 - end - @stop_next = lev - @no_step = @frames.size - frame_pos - return + when /^\s*c(?:ont)?$/ + MUTEX.unlock + return - when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ - display_frames(frame_pos) + when /^\s*s(?:tep)?(?:\s+(\d+))?$/ + if $1 + lev = $1.to_i + else + lev = 1 + end + @stop_next = lev + return - when /^\s*l(?:ist)?(?:\s+(.+))?$/ - if not $1 - b = previous_line ? previous_line + 10 : binding_line - 5 - e = b + 9 - elsif $1 == '-' - b = previous_line ? previous_line - 10 : binding_line - 5 - e = b + 9 - else - b, e = $1.split(/[-,]/) - if e + when /^\s*n(?:ext)?(?:\s+(\d+))?$/ + if $1 + lev = $1.to_i + else + lev = 1 + end + @stop_next = lev + @no_step = @frames.size - frame_pos + return + + when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ + display_frames(frame_pos) + + when /^\s*l(?:ist)?(?:\s+(.+))?$/ + if not $1 + b = previous_line ? previous_line + 10 : binding_line - 5 + e = b + 9 + elsif $1 == '-' + b = previous_line ? previous_line - 10 : binding_line - 5 + e = b + 9 + else + b, e = $1.split(/[-,]/) + if e b = b.to_i e = e.to_i else @@ -412,6 +414,9 @@ class DEBUGGER__ when /^\s*p\s+/ p debug_eval($', binding) + when /^\s*h(?:elp)?/ + debug_print_help() + else v = debug_eval(input, binding) p v unless (v == nil) @@ -420,6 +425,45 @@ class DEBUGGER__ end end + def debug_print_help + print <<EOHELP +Debugger help v.-0.002b +Commands + b[reak] [file or method:]<line> set breakpoint to some position + wat[ch] <expression> set watchpoint to some expression + b[reak] list breakpoints + del[ele][ nnn] delete some or all breakpoints + disp[lay] <expression> add expression into display expression list + undisp[lay][ nnn] delete one particular or all display expressions + c[ont] run until program ends or hit breakpoint + s[tep][ nnn] step (into methods) one line or till line nnn + n[ext][ nnn] go over one line or till line nnn + w[here] display frames + f[rame] alias for where + l[ist][ (-|nn-mm)] list program, - lists backwards + nn-mm lists given lines + up[ nn] move to higher frame + down[ nn] move to lower frame + fin[ish] return to outer frame + q[uit] exit from debugger + v[ar] g[lobal] show global variables + v[ar] l[ocal] show local variables + v[ar] i[nstance] <object> show instance variables of object + v[ar] c[onst] <object> show constants of object + m[ethod] i[nstance] <obj> show methods of object + m[ethod] <class or module> show instance methods of class or module + th[read] l[ist] list all threads + th[read] c[ur[rent]] show current threads + th[read] <nnn> stop thread nnn + th[read] stop <nnn> alias for th[read] <nnn> + th[read] c[ur[rent]] <nnn> alias for th[read] <nnn> + th[read] resume <nnn> run thread nnn + p expression evaluate expression and print its value + h[elp] print this help + <everything else> evaluate +EOHELP + end + def display_expressions(binding) n = 1 for d in display diff --git a/lib/net/telnet.rb b/lib/net/telnet.rb new file mode 100644 index 0000000000..4acaaadd3a --- /dev/null +++ b/lib/net/telnet.rb @@ -0,0 +1,749 @@ +=begin +$Date$ + +== SIMPLE TELNET CLIENT LIBRARY + +net/telnet.rb + +Version 1.30 + +Wakou Aoyama <wakou@fsinet.or.jp> + + +=== MAKE NEW TELNET OBJECT + + host = Net::Telnet::new({ + "Binmode" => false, # default: false + "Host" => "localhost", # default: "localhost" + "Output_log" => "output_log", # default: nil (no output) + "Dump_log" => "dump_log", # default: nil (no 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 = Net::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 = Net::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 = Net::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.30 + +2000/04/03 18:27:02 + +- telnet.rb --> net/telnet.rb + +=== 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" + +module Net + 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.30" + RELEASE_DATE = "$Date$" + $-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 +end 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 diff --git a/lib/thread.rb b/lib/thread.rb index 9edda48abe..75822b91be 100644 --- a/lib/thread.rb +++ b/lib/thread.rb @@ -1,7 +1,10 @@ # # thread.rb - thread support classes # $Date$ -# by Yukihiro Matsumoto <matz@caelum.co.jp> +# by Yukihiro Matsumoto <matz@netlab.co.jp> +# +# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright (C) 2000 Information-technology Promotion Agancy, Japan # unless defined? Thread @@ -71,6 +74,7 @@ class Mutex retry end Thread.critical = false + t.run if t self end diff --git a/lib/timeout.rb b/lib/timeout.rb index b6bda6cece..ab55e73ed6 100644 --- a/lib/timeout.rb +++ b/lib/timeout.rb @@ -1,6 +1,9 @@ # # timeout.rb -- execution timeout # +# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright (C) 2000 Information-technology Promotion Agancy, Japan +# #= SYNOPSIS # # require 'timeout' |