* Makefile.am (EXTRA_DIST): Added aproxy.rb.
[riece] / lisp / aproxy.rb
1 # aproxy.rb --- async proxy between an IRC server and a client
2 # Copyright (C) 1998-2005 Daiki Ueno
3
4 # Author: Daiki Ueno <ueno@unixuser.org>
5 # Created: 1998-09-28
6 # Keywords: IRC, riece
7
8 # This file is part of Riece.
9
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2, or (at your option)
13 # any later version.
14
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
18 # GNU General Public License for more details.
19
20 # You should have received a copy of the GNU General Public License
21 # along with GNU Emacs; see the file COPYING.  If not, write to the
22 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 # Boston, MA 02111-1307, USA.
24
25 require 'io/nonblock'
26 require 'socket'
27
28 class AProxy
29   def initialize(host, port, size, back)
30     @host = host
31     @port = port
32     @size = size
33     @back = File.new(back, 'a') if back
34   end
35
36   def start
37     $stdout.nonblock = true
38     trap('STOP', 'IGNORE')
39     trap('TSTP', 'IGNORE')
40     socket = TCPSocket.new(@host, @port)
41     @out.write("NOTICE CONNECTED #{$$}\r\n")
42     wfds_in = []
43     buf = ''
44     loop do
45       rfds, wfds, = select([socket, $stdin], wfds_in)
46       unless wfds.empty?
47         if buf.length > @size
48           s = buf.slice!(0 ... @size)
49           @back.write(s) if @back
50         end
51         begin
52           until buf.empty?
53             len = $stdout.syswrite(buf)
54             buf.slice!(0 .. len)
55           end
56           wfds_in.clear
57         rescue Errno::EAGAIN
58         end
59       end
60       if rfds.include?(socket)
61         line = socket.gets("\r\n")
62         break unless line
63         if line =~ /\A(?::\S+\s+)?PING\s+(.*)\r\n/i
64           socket.write("PONG #{$1}\r\n")
65         else
66           wfds_in = [$stdout]
67           buf << line
68         end
69       end
70       if rfds.include?($stdin)
71         line = $stdin.gets("\r\n")
72         break unless line
73         socket.write(line)
74       end
75     end
76     socket.close
77   end
78 end
79
80 if $0 == __FILE__
81   require 'optparse'
82
83   opt_size, opt_back = nil, nil
84   opts = OptionParser.new do |opts|
85     opts.banner = <<"End"
86 Usage: #{$0} [OPTIONS] host port
87 End
88     opts.on('-s', '--size SIZE', 'Size of buffer.') do |size|
89       opt_size = size.to_i
90     end
91     opts.on('-b', '--back BACK', 'Send outdated messages to BACK.') do |back|
92       opt_back = back
93     end
94     opts.on_tail('--help', '-h', 'Show this message.') do
95       $stdout.print(opts.to_s)
96       exit(0)
97     end
98   end
99   begin
100     opts.parse!(ARGV)
101   rescue OptionParser::ParseError
102     $stderr.print(opts.to_s)
103     exit(1)
104   end
105
106   AProxy.new(ARGV.shift, ARGV.shift, opt_size, opt_back).start
107 end