#! /usr/local/bin/ruby require 'socket' require 'timeout' class SMTPForward attr_accessor :filter, :error, :permanent, :code def initialize(filter, port = 10026, host = 'localhost') @filter = filter @host = host @port = port @error = '' @code = 0 @permanent = false end def begin begin smtp_connect l = smtp_gets if(l[0] / 100 != 2) then return [ l[0], l[1] ] end smtp_puts("ehlo #{$apphost}") l = smtp_gets if(l[0] / 100 != 2) then return [ l[0], l[1].to_a.join(', ') ] end if(@filter.xf) then xf = l[1].find { |e| e =~ /^XFORWARD/i } if(xf) then xl = 'xforward' xf.split(/ /)[1..-1].each do |v| if(@filter.xf[v]) then xl << " " + v + "=" + @filter.xf[v] end end if(xl != 'xforward') then smtp_puts(xl) l = smtp_gets if(l[0] / 100 != 2) then return [ l[0], l[1].to_a.join(', ') ] end end end end smtp_puts("mail from:<#{@filter.from}>") l = smtp_gets if(l[0] / 100 != 2) then return [ l[0], l[1].to_a.join(', ') ] end rescue SMTPFException => e return [ 451, "4.3.0 Queing error, #{e.to_s}" ] end end def rcpt_to(to) begin smtp_puts("rcpt to:<#{to}>") l = smtp_gets return [ l[0], l[1].to_a.join(', ') ] rescue SMTPFException => e return [ 451, "4.3.0 Queing error, #{e.to_s}" ] end end def data() begin smtp_puts("data") l = smtp_gets return [ l[0], l[1].to_a.join(', ') ] if(l[0] / 100 != 3) @filter.body.each do |l| smtp_puts(l.gsub(/^\./, '..')) end smtp_puts('.') l = smtp_gets rescue SMTPFException => e return [ 451, "4.3.0 Queing error, #{e.to_s}" ] end begin smtp_puts("quit") smtp_gets rescue Exception => e end @sock.close return l end private def smtp_connect begin Timeout.timeout(10) do @sock = TCPSocket.new(@host, @port) end rescue Timeout::Error => e raise SMTPFException, "timeout" rescue SystemCallError => e raise SMTPFException, e.to_s rescue Exception => e raise SMTPFException, "unexpected (#{e.to_s})" end end def smtp_gets c = 0 t = [] begin Timeout.timeout(10) do while(true) r = @sock.gets.chomp puts "X<< " + r if($ldebug) if(r !~ /^(\d{3})([ -])(.*)$/) then raise SMTPFException, "unrecognized response (#{r})" else c = $1.to_i t.push($3) break unless($2 == '-') end end end rescue Timeout::Error => e raise SMTPFException, "timeout" rescue SystemCallError => e raise SMTPFException, e.to_s rescue Exception => e raise SMTPFException, "unexpected (#{e.to_s})" end return [ c, (t.length == 1 ? t[0] : t) ] end def smtp_puts(r) begin Timeout.timeout(10) do puts "X>> " + r if($ldebug) @sock.print(r + "\r\n") end rescue Timeout::Error => e raise SMTPFException, "timeout" rescue SystemCallError => e raise SMTPFException, e.to_s rescue Exception => e raise SMTPFExcpeiton, "unexpected (#{e.to_s})" end end end class SMTPFException < SystemCallError attr_accessor :message def initialize(message) super(message) end end