rumbster 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +515 -0
 - data/README +56 -0
 - data/Rakefile +12 -0
 - data/lib/message_observers.rb +40 -0
 - data/lib/rumbster.rb +24 -0
 - data/lib/smtp_protocol.rb +42 -0
 - data/lib/smtp_states.rb +159 -0
 - data/test/message_observers_test.rb +102 -0
 - data/test/rumbster_test.rb +69 -0
 - data/test/smtp_protocol_test.rb +64 -0
 - data/test/smtp_states_test.rb +217 -0
 - data/vendor/tmail.rb +4 -0
 - data/vendor/tmail/.cvsignore +3 -0
 - data/vendor/tmail/Makefile +19 -0
 - data/vendor/tmail/address.rb +222 -0
 - data/vendor/tmail/base64.rb +52 -0
 - data/vendor/tmail/compat.rb +39 -0
 - data/vendor/tmail/config.rb +50 -0
 - data/vendor/tmail/encode.rb +447 -0
 - data/vendor/tmail/header.rb +895 -0
 - data/vendor/tmail/info.rb +14 -0
 - data/vendor/tmail/loader.rb +1 -0
 - data/vendor/tmail/mail.rb +869 -0
 - data/vendor/tmail/mailbox.rb +386 -0
 - data/vendor/tmail/mbox.rb +1 -0
 - data/vendor/tmail/net.rb +260 -0
 - data/vendor/tmail/obsolete.rb +122 -0
 - data/vendor/tmail/parser.rb +1475 -0
 - data/vendor/tmail/parser.y +372 -0
 - data/vendor/tmail/port.rb +356 -0
 - data/vendor/tmail/scanner.rb +22 -0
 - data/vendor/tmail/scanner_r.rb +243 -0
 - data/vendor/tmail/stringio.rb +256 -0
 - data/vendor/tmail/textutils.rb +197 -0
 - data/vendor/tmail/tmail.rb +1 -0
 - data/vendor/tmail/utils.rb +23 -0
 - metadata +88 -0
 
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'smtp_protocol'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class SmtpProtocolTest < Test::Unit::TestCase
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              def test_protocol_sets_protocol_property_on_each_state
         
     | 
| 
      
 9 
     | 
    
         
            +
                init_state = TestState.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                protocol = SmtpProtocol.new(:init, {:init => init_state})
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                assert_same protocol, init_state.protocol
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              def test_protocol_starts_in_the_initial_state
         
     | 
| 
      
 17 
     | 
    
         
            +
                init_state = TestState.new
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                protocol = SmtpProtocol.new(:init, {:init => init_state})
         
     | 
| 
      
 20 
     | 
    
         
            +
                protocol.serve(nil)
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert init_state.called
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def test_state_is_changed_when_a_new_state_is_set
         
     | 
| 
      
 26 
     | 
    
         
            +
                next_state = TestState.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                protocol = SmtpProtocol.new(:init, {:init => TestState.new, :next => next_state})
         
     | 
| 
      
 29 
     | 
    
         
            +
                protocol.state = :next
         
     | 
| 
      
 30 
     | 
    
         
            +
                protocol.serve(nil)
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert next_state.called
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
              
         
     | 
| 
      
 35 
     | 
    
         
            +
              def test_listeners_are_notified_when_a_new_message_is_received
         
     | 
| 
      
 36 
     | 
    
         
            +
                protocol = SmtpProtocol.new(:init, {:init => TestState.new})
         
     | 
| 
      
 37 
     | 
    
         
            +
                observer = TestObserver.new
         
     | 
| 
      
 38 
     | 
    
         
            +
                message = 'hi'
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                protocol.add_observer(observer)
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                protocol.new_message_received(message)
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                assert_same message, observer.received_message
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            class TestObserver
         
     | 
| 
      
 50 
     | 
    
         
            +
              attr_accessor :received_message
         
     | 
| 
      
 51 
     | 
    
         
            +
              
         
     | 
| 
      
 52 
     | 
    
         
            +
              def update(message)
         
     | 
| 
      
 53 
     | 
    
         
            +
                @received_message = message
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            class TestState
         
     | 
| 
      
 58 
     | 
    
         
            +
              attr_accessor :called, :protocol
         
     | 
| 
      
 59 
     | 
    
         
            +
              
         
     | 
| 
      
 60 
     | 
    
         
            +
              def serve(io)
         
     | 
| 
      
 61 
     | 
    
         
            +
                @called = true
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
              
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,217 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'stringio'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smtp_protocol'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class SmtpStatesTest < Test::Unit::TestCase
         
     | 
| 
      
 8 
     | 
    
         
            +
             
         
     | 
| 
      
 9 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 10 
     | 
    
         
            +
                buffer = ''
         
     | 
| 
      
 11 
     | 
    
         
            +
                @server_stream = StringIO.new(buffer)
         
     | 
| 
      
 12 
     | 
    
         
            +
                @client_stream = StringIO.new(buffer)    
         
     | 
| 
      
 13 
     | 
    
         
            +
                @protocol = TestProtocol.new
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
         
     | 
| 
      
 16 
     | 
    
         
            +
              def test_greeting_is_returned_upon_initial_client_connection
         
     | 
| 
      
 17 
     | 
    
         
            +
                init_state = InitState.new(@protocol)
         
     | 
| 
      
 18 
     | 
    
         
            +
                init_state.serve(@server_stream)
         
     | 
| 
      
 19 
     | 
    
         
            +
                   
         
     | 
| 
      
 20 
     | 
    
         
            +
                assert_equal "220 ruby ESMTP\n", @client_stream.readline
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
              
         
     | 
| 
      
 23 
     | 
    
         
            +
              def test_initial_state_passes_protocol_connect_as_the_next_state_in_the_chain
         
     | 
| 
      
 24 
     | 
    
         
            +
                init_state = InitState.new(@protocol)
         
     | 
| 
      
 25 
     | 
    
         
            +
                init_state.serve(@server_stream)
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                assert_equal :connect, @protocol.state
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
              def test_initial_state_passes_protocol_the_same_io_as_it_received
         
     | 
| 
      
 31 
     | 
    
         
            +
                init_state = InitState.new(@protocol)
         
     | 
| 
      
 32 
     | 
    
         
            +
                init_state.serve(@server_stream)
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                assert_same @server_stream, @protocol.io
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
              def test_initial_state_raises_not_initialized_when_protocol_is_not_set
         
     | 
| 
      
 38 
     | 
    
         
            +
                init_state = InitState.new
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                assert_raise NotInitializedError do 
         
     | 
| 
      
 41 
     | 
    
         
            +
                  init_state.serve(@server_stream)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
                 
         
     | 
| 
      
 45 
     | 
    
         
            +
              def test_helo_is_accepted_while_in_connect_state
         
     | 
| 
      
 46 
     | 
    
         
            +
                @client_stream.puts "HELO test.client"
         
     | 
| 
      
 47 
     | 
    
         
            +
                connect_state = ConnectState.new(@protocol)
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                connect_state.serve(@server_stream)
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                assert_equal "250 ruby\n", @client_stream.readline
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              def test_connect_state_passes_protocol_connected_as_the_next_state_in_the_chain
         
     | 
| 
      
 55 
     | 
    
         
            +
                @client_stream.puts "HELO test.client"
         
     | 
| 
      
 56 
     | 
    
         
            +
                connect_state = ConnectState.new(@protocol)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                connect_state.serve(@server_stream)
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                assert_equal :connected, @protocol.state
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
              
         
     | 
| 
      
 63 
     | 
    
         
            +
              def test_connect_state_passes_protocol_the_same_io_as_it_received
         
     | 
| 
      
 64 
     | 
    
         
            +
                @client_stream.puts "HELO test.client"
         
     | 
| 
      
 65 
     | 
    
         
            +
                connect_state = ConnectState.new(@protocol)
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                connect_state.serve(@server_stream)
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
                assert_same @server_stream, @protocol.io
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
              def test_connect_state_raises_not_initialized_when_protocol_is_not_set
         
     | 
| 
      
 73 
     | 
    
         
            +
                connect_state = ConnectState.new
         
     | 
| 
      
 74 
     | 
    
         
            +
                
         
     | 
| 
      
 75 
     | 
    
         
            +
                assert_raise NotInitializedError do
         
     | 
| 
      
 76 
     | 
    
         
            +
                  connect_state.serve(@server_stream)
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
              def test_from_okayed_while_in_connected_state
         
     | 
| 
      
 81 
     | 
    
         
            +
                @client_stream.puts "MAIL FROM:<adam@esterlines.com>"
         
     | 
| 
      
 82 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 85 
     | 
    
         
            +
                
         
     | 
| 
      
 86 
     | 
    
         
            +
                assert_equal "250 ok\n", @client_stream.readline
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
              
         
     | 
| 
      
 89 
     | 
    
         
            +
              def test_connected_state_passes_protocol_connected_as_the_next_state_when_client_sends_from_request
         
     | 
| 
      
 90 
     | 
    
         
            +
                @client_stream.puts "MAIL FROM:<junk@junkster.com>"
         
     | 
| 
      
 91 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 94 
     | 
    
         
            +
                
         
     | 
| 
      
 95 
     | 
    
         
            +
                assert_equal :connected, @protocol.state
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
              
         
     | 
| 
      
 98 
     | 
    
         
            +
              def test_rcpt_okayed_while_in_connected_state
         
     | 
| 
      
 99 
     | 
    
         
            +
                @client_stream.puts "RCPT TO:<junk@junkster.com>"    
         
     | 
| 
      
 100 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 103 
     | 
    
         
            +
                
         
     | 
| 
      
 104 
     | 
    
         
            +
                assert_equal "250 ok\n", @client_stream.readline
         
     | 
| 
      
 105 
     | 
    
         
            +
              end
         
     | 
| 
      
 106 
     | 
    
         
            +
              
         
     | 
| 
      
 107 
     | 
    
         
            +
              def test_connected_state_passes_protocol_connected_as_the_next_state_when_client_sends_rcpt_request
         
     | 
| 
      
 108 
     | 
    
         
            +
                @client_stream.puts "RCPT TO:<foo@foo.com>"    
         
     | 
| 
      
 109 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 112 
     | 
    
         
            +
                
         
     | 
| 
      
 113 
     | 
    
         
            +
                assert_equal :connected, @protocol.state
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
              
         
     | 
| 
      
 116 
     | 
    
         
            +
              def test_connected_state_passes_protocol_the_same_io_as_it_received
         
     | 
| 
      
 117 
     | 
    
         
            +
                @client_stream.puts "MAIL FROM:<foo@foo.com>"
         
     | 
| 
      
 118 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 121 
     | 
    
         
            +
                
         
     | 
| 
      
 122 
     | 
    
         
            +
                assert_same @server_stream, @protocol.io
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
              
         
     | 
| 
      
 125 
     | 
    
         
            +
              def test_data_request_given_the_go_ahead_while_in_connected_state
         
     | 
| 
      
 126 
     | 
    
         
            +
                @client_stream.puts "DATA"
         
     | 
| 
      
 127 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 130 
     | 
    
         
            +
                
         
     | 
| 
      
 131 
     | 
    
         
            +
                assert_equal "354 go ahead\n", @client_stream.readline
         
     | 
| 
      
 132 
     | 
    
         
            +
              end
         
     | 
| 
      
 133 
     | 
    
         
            +
              
         
     | 
| 
      
 134 
     | 
    
         
            +
              def test_connected_state_passes_protocol_read_mail_as_the_next_state_when_client_sends_data_request
         
     | 
| 
      
 135 
     | 
    
         
            +
                @client_stream.puts "DATA"
         
     | 
| 
      
 136 
     | 
    
         
            +
                connected_state = ConnectedState.new(@protocol)
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                connected_state.serve(@server_stream)
         
     | 
| 
      
 139 
     | 
    
         
            +
                
         
     | 
| 
      
 140 
     | 
    
         
            +
                assert_equal :read_mail, @protocol.state
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
              
         
     | 
| 
      
 143 
     | 
    
         
            +
              def test_connected_state_raises_not_initialized_when_protocol_is_not_set
         
     | 
| 
      
 144 
     | 
    
         
            +
                connected_state = ConnectedState.new
         
     | 
| 
      
 145 
     | 
    
         
            +
                
         
     | 
| 
      
 146 
     | 
    
         
            +
                assert_raise NotInitializedError do
         
     | 
| 
      
 147 
     | 
    
         
            +
                  connected_state.serve(@server_stream)
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
              
         
     | 
| 
      
 151 
     | 
    
         
            +
              def test_read_mail_state_reads_until_a_single_dot_is_found_on_a_line_then_returns_an_ok_message
         
     | 
| 
      
 152 
     | 
    
         
            +
                @client_stream.puts "To: junk@junk.com\nFrom: junk2@junk2.com\n\nHi\n.\n"
         
     | 
| 
      
 153 
     | 
    
         
            +
                read_mail_state = ReadMailState.new(@protocol)
         
     | 
| 
      
 154 
     | 
    
         
            +
                
         
     | 
| 
      
 155 
     | 
    
         
            +
                read_mail_state.serve(@server_stream)
         
     | 
| 
      
 156 
     | 
    
         
            +
                
         
     | 
| 
      
 157 
     | 
    
         
            +
                assert_equal "250 ok\n", @client_stream.readline
         
     | 
| 
      
 158 
     | 
    
         
            +
              end
         
     | 
| 
      
 159 
     | 
    
         
            +
              
         
     | 
| 
      
 160 
     | 
    
         
            +
              def test_read_mail_state_passes_read_message_to_protocol
         
     | 
| 
      
 161 
     | 
    
         
            +
                message = "To: junk@junk.com\nFrom: junk2@junk2.com\n\nHi\n"
         
     | 
| 
      
 162 
     | 
    
         
            +
                @client_stream.puts "#{message}.\n"
         
     | 
| 
      
 163 
     | 
    
         
            +
                read_mail_state = ReadMailState.new(@protocol)
         
     | 
| 
      
 164 
     | 
    
         
            +
                
         
     | 
| 
      
 165 
     | 
    
         
            +
                read_mail_state.serve(@server_stream)
         
     | 
| 
      
 166 
     | 
    
         
            +
                
         
     | 
| 
      
 167 
     | 
    
         
            +
                assert_equal message, @protocol.new_message
         
     | 
| 
      
 168 
     | 
    
         
            +
              end
         
     | 
| 
      
 169 
     | 
    
         
            +
              
         
     | 
| 
      
 170 
     | 
    
         
            +
              def test_read_mail_state_passes_protocol_quit_as_the_next_state_when_mail_message_is_read
         
     | 
| 
      
 171 
     | 
    
         
            +
                @client_stream.puts "To: junk@junk.com\nFrom: junk2@junk2.com\n\nHi\n.\n"
         
     | 
| 
      
 172 
     | 
    
         
            +
                read_mail_state = ReadMailState.new(@protocol)
         
     | 
| 
      
 173 
     | 
    
         
            +
                
         
     | 
| 
      
 174 
     | 
    
         
            +
                read_mail_state.serve(@server_stream)
         
     | 
| 
      
 175 
     | 
    
         
            +
                
         
     | 
| 
      
 176 
     | 
    
         
            +
                assert_equal :quit, @protocol.state
         
     | 
| 
      
 177 
     | 
    
         
            +
              end
         
     | 
| 
      
 178 
     | 
    
         
            +
              
         
     | 
| 
      
 179 
     | 
    
         
            +
              def test_read_mail_state_raises_not_initialized_when_protocol_is_not_set
         
     | 
| 
      
 180 
     | 
    
         
            +
                read_mail_state = ReadMailState.new
         
     | 
| 
      
 181 
     | 
    
         
            +
                
         
     | 
| 
      
 182 
     | 
    
         
            +
                assert_raise NotInitializedError do
         
     | 
| 
      
 183 
     | 
    
         
            +
                  read_mail_state.serve(@server_stream)
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
              
         
     | 
| 
      
 187 
     | 
    
         
            +
              def test_quit_state_reads_client_quit_and_says_goodbye
         
     | 
| 
      
 188 
     | 
    
         
            +
                @client_stream.puts "QUIT"
         
     | 
| 
      
 189 
     | 
    
         
            +
                quit_state = QuitState.new(@protocol)
         
     | 
| 
      
 190 
     | 
    
         
            +
                
         
     | 
| 
      
 191 
     | 
    
         
            +
                quit_state.serve(@server_stream)
         
     | 
| 
      
 192 
     | 
    
         
            +
                
         
     | 
| 
      
 193 
     | 
    
         
            +
                assert_equal "221 ruby goodbye\n", @client_stream.readline
         
     | 
| 
      
 194 
     | 
    
         
            +
              end
         
     | 
| 
      
 195 
     | 
    
         
            +
              
         
     | 
| 
      
 196 
     | 
    
         
            +
              def test_quit_state_raises_not_initialized_when_protocol_is_not_set
         
     | 
| 
      
 197 
     | 
    
         
            +
                quit_state = QuitState.new
         
     | 
| 
      
 198 
     | 
    
         
            +
                
         
     | 
| 
      
 199 
     | 
    
         
            +
                assert_raise NotInitializedError do
         
     | 
| 
      
 200 
     | 
    
         
            +
                  quit_state.serve(@server_stream)
         
     | 
| 
      
 201 
     | 
    
         
            +
                end
         
     | 
| 
      
 202 
     | 
    
         
            +
              end
         
     | 
| 
      
 203 
     | 
    
         
            +
              
         
     | 
| 
      
 204 
     | 
    
         
            +
            end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            class TestProtocol
         
     | 
| 
      
 207 
     | 
    
         
            +
              attr_accessor :state, :io
         
     | 
| 
      
 208 
     | 
    
         
            +
              attr_reader :new_message
         
     | 
| 
      
 209 
     | 
    
         
            +
              
         
     | 
| 
      
 210 
     | 
    
         
            +
              def serve (io)
         
     | 
| 
      
 211 
     | 
    
         
            +
                @io = io
         
     | 
| 
      
 212 
     | 
    
         
            +
              end
         
     | 
| 
      
 213 
     | 
    
         
            +
              
         
     | 
| 
      
 214 
     | 
    
         
            +
              def new_message_received(message)
         
     | 
| 
      
 215 
     | 
    
         
            +
                @new_message = message
         
     | 
| 
      
 216 
     | 
    
         
            +
              end
         
     | 
| 
      
 217 
     | 
    
         
            +
            end
         
     | 
    
        data/vendor/tmail.rb
    ADDED
    
    
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # lib/tmail/Makefile
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            debug:
         
     | 
| 
      
 6 
     | 
    
         
            +
            	rm -f parser.rb
         
     | 
| 
      
 7 
     | 
    
         
            +
            	make parser.rb DEBUG=true
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            parser.rb: parser.y
         
     | 
| 
      
 10 
     | 
    
         
            +
            	if [ "$(DEBUG)" = true ]; then \
         
     | 
| 
      
 11 
     | 
    
         
            +
            	    racc -v -g -o$@ parser.y ;\
         
     | 
| 
      
 12 
     | 
    
         
            +
            	else \
         
     | 
| 
      
 13 
     | 
    
         
            +
            	    racc -E -o$@ parser.y ;\
         
     | 
| 
      
 14 
     | 
    
         
            +
            	fi
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            clean:
         
     | 
| 
      
 17 
     | 
    
         
            +
            	rm -f parser.rb parser.output
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            distclean: clean
         
     | 
| 
         @@ -0,0 +1,222 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # address.rb
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright (c) 1998-2004 Minero Aoki
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # This program is free software.
         
     | 
| 
      
 7 
     | 
    
         
            +
            # You can distribute/modify this program under the terms of
         
     | 
| 
      
 8 
     | 
    
         
            +
            # the GNU Lesser General Public License version 2.1.
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            require 'tmail/encode'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'tmail/parser'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            module TMail
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              class Address
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                include TextUtils
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def Address.parse(str)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Parser.parse :ADDRESS, str
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def address_group?
         
     | 
| 
      
 25 
     | 
    
         
            +
                  false
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def initialize(local, domain)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  if domain
         
     | 
| 
      
 30 
     | 
    
         
            +
                    domain.each do |s|
         
     | 
| 
      
 31 
     | 
    
         
            +
                      raise SyntaxError, 'empty word in domain' if s.empty?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @local = local
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @domain = domain
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @name   = nil
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @routes = []
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                attr_reader :name
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def name=(str)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @name = str
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @name = nil if str and str.empty?
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                alias phrase  name
         
     | 
| 
      
 48 
     | 
    
         
            +
                alias phrase= name=
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                attr_reader :routes
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 53 
     | 
    
         
            +
                  "#<#{self.class} #{address()}>"
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def local
         
     | 
| 
      
 57 
     | 
    
         
            +
                  return nil unless @local
         
     | 
| 
      
 58 
     | 
    
         
            +
                  return '""' if @local.size == 1 and @local[0].empty?
         
     | 
| 
      
 59 
     | 
    
         
            +
                  @local.map {|i| quote_atom(i) }.join('.')
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def domain
         
     | 
| 
      
 63 
     | 
    
         
            +
                  return nil unless @domain
         
     | 
| 
      
 64 
     | 
    
         
            +
                  join_domain(@domain)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def spec
         
     | 
| 
      
 68 
     | 
    
         
            +
                  s = self.local
         
     | 
| 
      
 69 
     | 
    
         
            +
                  d = self.domain
         
     | 
| 
      
 70 
     | 
    
         
            +
                  if s and d
         
     | 
| 
      
 71 
     | 
    
         
            +
                    s + '@' + d
         
     | 
| 
      
 72 
     | 
    
         
            +
                  else
         
     | 
| 
      
 73 
     | 
    
         
            +
                    s
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                alias address  spec
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def ==(other)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  other.respond_to? :spec and self.spec == other.spec
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                alias eql? ==
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def hash
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @local.hash ^ @domain.hash
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                def dup
         
     | 
| 
      
 91 
     | 
    
         
            +
                  obj = self.class.new(@local.dup, @domain.dup)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  obj.name = @name.dup if @name
         
     | 
| 
      
 93 
     | 
    
         
            +
                  obj.routes.replace @routes
         
     | 
| 
      
 94 
     | 
    
         
            +
                  obj
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                include StrategyInterface
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                def accept(strategy, dummy1 = nil, dummy2 = nil)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  unless @local
         
     | 
| 
      
 101 
     | 
    
         
            +
                    strategy.meta '<>'   # empty return-path
         
     | 
| 
      
 102 
     | 
    
         
            +
                    return
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  spec_p = (not @name and @routes.empty?)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  if @name
         
     | 
| 
      
 107 
     | 
    
         
            +
                    strategy.phrase @name
         
     | 
| 
      
 108 
     | 
    
         
            +
                    strategy.space
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
                  tmp = spec_p ? '' : '<'
         
     | 
| 
      
 111 
     | 
    
         
            +
                  unless @routes.empty?
         
     | 
| 
      
 112 
     | 
    
         
            +
                    tmp << @routes.map {|i| '@' + i }.join(',') << ':'
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                  tmp << self.spec
         
     | 
| 
      
 115 
     | 
    
         
            +
                  tmp << '>' unless spec_p
         
     | 
| 
      
 116 
     | 
    
         
            +
                  strategy.meta tmp
         
     | 
| 
      
 117 
     | 
    
         
            +
                  strategy.lwsp ''
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
              class AddressGroup
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                def address_group?
         
     | 
| 
      
 128 
     | 
    
         
            +
                  true
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                def initialize(name, addrs)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @addresses = addrs
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                attr_reader :name
         
     | 
| 
      
 137 
     | 
    
         
            +
                
         
     | 
| 
      
 138 
     | 
    
         
            +
                def ==(other)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  other.respond_to? :to_a and @addresses == other.to_a
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                alias eql? ==
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                def hash
         
     | 
| 
      
 145 
     | 
    
         
            +
                  map {|i| i.hash }.hash
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                def [](idx)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  @addresses[idx]
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                def size
         
     | 
| 
      
 153 
     | 
    
         
            +
                  @addresses.size
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                def empty?
         
     | 
| 
      
 157 
     | 
    
         
            +
                  @addresses.empty?
         
     | 
| 
      
 158 
     | 
    
         
            +
                end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                def each(&block)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  @addresses.each(&block)
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                def to_a
         
     | 
| 
      
 165 
     | 
    
         
            +
                  @addresses.dup
         
     | 
| 
      
 166 
     | 
    
         
            +
                end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                alias to_ary to_a
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                def include?(a)
         
     | 
| 
      
 171 
     | 
    
         
            +
                  @addresses.include? a
         
     | 
| 
      
 172 
     | 
    
         
            +
                end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                def flatten
         
     | 
| 
      
 175 
     | 
    
         
            +
                  set = []
         
     | 
| 
      
 176 
     | 
    
         
            +
                  @addresses.each do |a|
         
     | 
| 
      
 177 
     | 
    
         
            +
                    if a.respond_to? :flatten
         
     | 
| 
      
 178 
     | 
    
         
            +
                      set.concat a.flatten
         
     | 
| 
      
 179 
     | 
    
         
            +
                    else
         
     | 
| 
      
 180 
     | 
    
         
            +
                      set.push a
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 183 
     | 
    
         
            +
                  set
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                def each_address(&block)
         
     | 
| 
      
 187 
     | 
    
         
            +
                  flatten.each(&block)
         
     | 
| 
      
 188 
     | 
    
         
            +
                end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                def add(a)
         
     | 
| 
      
 191 
     | 
    
         
            +
                  @addresses.push a
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                alias push add
         
     | 
| 
      
 195 
     | 
    
         
            +
                
         
     | 
| 
      
 196 
     | 
    
         
            +
                def delete(a)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  @addresses.delete a
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                include StrategyInterface
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                def accept(strategy, dummy1 = nil, dummy2 = nil)
         
     | 
| 
      
 203 
     | 
    
         
            +
                  strategy.phrase @name
         
     | 
| 
      
 204 
     | 
    
         
            +
                  strategy.meta ':'
         
     | 
| 
      
 205 
     | 
    
         
            +
                  strategy.space
         
     | 
| 
      
 206 
     | 
    
         
            +
                  first = true
         
     | 
| 
      
 207 
     | 
    
         
            +
                  each do |mbox|
         
     | 
| 
      
 208 
     | 
    
         
            +
                    if first
         
     | 
| 
      
 209 
     | 
    
         
            +
                      first = false
         
     | 
| 
      
 210 
     | 
    
         
            +
                    else
         
     | 
| 
      
 211 
     | 
    
         
            +
                      strategy.meta ','
         
     | 
| 
      
 212 
     | 
    
         
            +
                    end
         
     | 
| 
      
 213 
     | 
    
         
            +
                    strategy.space
         
     | 
| 
      
 214 
     | 
    
         
            +
                    mbox.accept strategy
         
     | 
| 
      
 215 
     | 
    
         
            +
                  end
         
     | 
| 
      
 216 
     | 
    
         
            +
                  strategy.meta ';'
         
     | 
| 
      
 217 
     | 
    
         
            +
                  strategy.lwsp ''
         
     | 
| 
      
 218 
     | 
    
         
            +
                end
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
              end
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            end   # module TMail
         
     |