=begin = net/protocol.rb written by Minero Aoki This library is distributed under the terms of the Ruby license. You can freely distribute/modify this library. =end require 'socket' module Net Version = '1.1.12' =begin == Net::Protocol the abstruct class for Internet protocol === Super Class Object === Class Methods : new( address = 'localhost', port = nil ) This method Creates a new protocol object. : start( address = 'localhost', port = nil, *args ) : start( address = 'localhost', port = nil, *args ){|proto| .... } This method creates a new Protocol object and start session. If you call this method with block, Protocol object give itself to block and finish session when block returns. : Proxy( address, port ) This method creates a proxy class of its protocol. Arguments are address/port of proxy host. === Methods : address the address of connecting server (FQDN). : port connecting port number : start( *args ) This method start protocol. If you call this method when the protocol is already started, this only returns false without doing anything. '*args' are specified in subclasses. : finish This method ends protocol. If you call this method before protocol starts, it only return false without doing anything. : active? true if session have been started =end class Protocol Version = ::Net::Version class << self def start( address = 'localhost', port = nil, *args ) instance = new( address, port ) if iterator? then instance.start( *args ) { yield instance } else instance.start *args instance end end def Proxy( p_addr, p_port ) klass = Class.new( self ) klass.module_eval %- def initialize( addr, port ) @proxyaddr = '#{p_addr}' @proxyport = '#{p_port}' super @proxyaddr, @proxyport @address = addr @port = port end def connect( addr = nil, port = nil ) super @proxyaddr, @proxyport end private :connect attr_reader :proxyaddr, :proxyport - def klass.proxy? true end klass end def proxy? false end private def protocol_param( name, val ) module_eval %- def self.#{name.id2name} #{val} end - end end # # sub-class requirements # # protocol_param command_type # protocol_param port # # private method do_start (optional) # private method do_finish (optional) # protocol_param :port, 'nil' protocol_param :command_type, 'nil' protocol_param :socket_type, '::Net::Socket' def initialize( addr = nil, port = nil ) @address = addr || 'localhost' @port = port || type.port @active = false @pipe = nil @command = nil @socket = nil end attr_reader :address, :port, :command, :socket def start( *args ) return false if active? begin connect do_start *args @active = true yield if iterator? ensure finish if iterator? end end def finish ret = active? do_finish disconnect @active = false ret end def active? @active end def set_pipe( arg ) # un-documented @pipe = arg end private def do_start end def do_finish @command.quit end def connect( addr = @address, port = @port ) @socket = type.socket_type.open( addr, port, @pipe ) @command = type.command_type.new( @socket ) end def disconnect @command = nil if @socket and not @socket.closed? then @socket.close end @socket = nil end end Session = Protocol class Command def initialize( sock ) @socket = sock @error_occured = false @last_reply = nil @critical = false end attr_reader :socket, :error_occured, :last_reply attr_writer :socket # abstract quit private # abstract get_reply() def check_reply( *oks ) @last_reply = get_reply reply_must( @last_reply, *oks ) end def reply_must( rep, *oks ) oks.each do |i| if i === rep then return rep end end @error_occured = true rep.error! @socket.sending end def getok( line, ok = SuccessCode ) @socket.writeline line check_reply ok end def critical return if @critical @critical = true r = yield @critical = false r end def critical? @critical end def begin_critical ret = @critical @critical = true not ret end def end_critical @critical = false end end class Response def initialize( ctype, cno, msg ) @code_type = ctype @code = cno @message = msg super() end attr_reader :code_type, :code, :message alias msg message def error!( sending ) raise @code_type.error_type, sprintf( < 512 end end end def each_crlf_line2( mid ) buf = @wbuf beg = pos = nil buf << "\n" unless /\n|\r/o === buf[-1,1] beg = 0 while true do pos = buf.index( TERMEXP, beg ) break unless pos __send__ mid, buf[ beg, pos - beg ] << CRLF beg = pos + $&.size end end def do_write_beg @writtensize = 0 @sending = '' @wbuf = '' end def do_write_do( arg ) if @pipe or @sending.size < 128 then @sending << Net.quote( arg ) else @sending << '...' unless @sending[-1] == ?. end s = @socket.write( arg ) @writtensize += s s end def do_write_fin if @pipe then @pipe << 'write "' @pipe << @sending @pipe << "\"\n" end @socket.flush @writtensize end def pipeoff @prepipe = @pipe @pipe = nil @prepipe end def pipeon @pipe = @prepipe @prepipe = nil @pipe end end def Net.quote( str ) str = str.gsub( "\n", '\\n' ) str.gsub!( "\r", '\\r' ) str.gsub!( "\t", '\\t' ) str end end # module Net