remailer 0.5.2 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +19 -0
- data/{README.rdoc → README.md} +12 -11
- data/Rakefile +21 -11
- data/VERSION +1 -1
- data/lib/remailer/abstract_connection.rb +36 -20
- data/lib/remailer/imap/client.rb +1 -1
- data/lib/remailer/interpreter.rb +40 -19
- data/lib/remailer/interpreter/state_proxy.rb +1 -1
- data/lib/remailer/smtp/client.rb +20 -26
- data/lib/remailer/smtp/client/interpreter.rb +85 -12
- data/lib/remailer/smtp/server.rb +9 -4
- data/lib/remailer/smtp/server/interpreter.rb +16 -15
- data/lib/remailer/smtp/server/transaction.rb +9 -2
- data/lib/remailer/socks5/client/interpreter.rb +18 -13
- data/remailer.gemspec +33 -23
- data/test/bin/exercise +115 -0
- data/test/config.example.yml +15 -0
- data/test/config.rb +41 -0
- data/test/helper.rb +42 -23
- data/test/unit/remailer_imap_client_interpreter_test.rb +2 -2
- data/test/unit/remailer_imap_client_test.rb +10 -12
- data/test/unit/remailer_interpreter_state_proxy_test.rb +14 -14
- data/test/unit/remailer_interpreter_test.rb +36 -28
- data/test/unit/remailer_smtp_client_interpreter_test.rb +80 -33
- data/test/unit/remailer_smtp_client_test.rb +53 -55
- data/test/unit/remailer_smtp_server_test.rb +24 -18
- data/test/unit/remailer_socks5_client_interpreter_test.rb +71 -10
- data/test/unit/remailer_test.rb +2 -2
- metadata +66 -24
- data/test/config.example.rb +0 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c66f7fc5cd78fcb8115342274f77169e4658cfb575d6b2609d2ae07bbd7278a0
|
4
|
+
data.tar.gz: 277347ffde8646bb32f6dc01cddca71be940c21fc46f5cfe32ecb4d02c849065
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6352a8dddf0f8cf1cd16cb810af0993a7bbd3386fe0ccc28c20fc9d891a9a9d4ae69e98b106f6d3a31933620364bb88f77217c2db1103400607333e9f5bcec71
|
7
|
+
data.tar.gz: 3b935c992a65b812b268cd616353886b104ba7c3cb97009c6234bae1e57d685d381c466219dd357542d6a424ddfe643f9648a8a644797f35806170e166cdfdd8
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2019 Scott Tadman, PostageApp Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/{README.rdoc → README.md}
RENAMED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# remailer
|
2
2
|
|
3
3
|
Client/Server Mail Networking Library for SMTP and IMAP
|
4
4
|
|
5
|
-
|
5
|
+
## Overview
|
6
6
|
|
7
7
|
This is an EventMachine Connection implementation of a high-performance
|
8
8
|
asynchronous SMTP client. Although EventMachine ships with a built-in SMTP
|
@@ -10,7 +10,7 @@ client, that version is limited to sending a single email per client,
|
|
10
10
|
and since establishing a client can be the majority of the time required
|
11
11
|
to send email, this limits throughput considerably.
|
12
12
|
|
13
|
-
|
13
|
+
## Use
|
14
14
|
|
15
15
|
The Remailer system consists of the Remailer::Connection class which works
|
16
16
|
within the EventMachine environment. To use it, create a client and then
|
@@ -21,7 +21,7 @@ make one or more requests to send email messages.
|
|
21
21
|
# messages to STDERR.
|
22
22
|
client = Remailer::SMTP::Client.open(
|
23
23
|
'smtp.google.com',
|
24
|
-
:
|
24
|
+
debug: STDERR
|
25
25
|
)
|
26
26
|
|
27
27
|
# Send a single email message through the client at the earliest
|
@@ -51,7 +51,7 @@ example is given here where the information is simply dumped on STDOUT:
|
|
51
51
|
|
52
52
|
client = Remailer::SMTP::Client.open(
|
53
53
|
'smtp.google.com',
|
54
|
-
:
|
54
|
+
debug: lambda { |type, message|
|
55
55
|
puts "#{type}> #{message.inspect}"
|
56
56
|
}
|
57
57
|
)
|
@@ -90,18 +90,19 @@ server. Success is defined as 250, errors vary:
|
|
90
90
|
|
91
91
|
A status code of nil is sent if the server timed out or the connection failed.
|
92
92
|
|
93
|
-
|
93
|
+
## Tests
|
94
94
|
|
95
|
-
In order to run tests, copy `test/config.example.
|
95
|
+
In order to run tests, copy `test/config.example.yml` to `test/config.yml` and
|
96
96
|
adjust as required. For obvious reasons, passwords to SMTP test accounts are
|
97
|
-
not included in the source code of this library.
|
97
|
+
not included in the source code of this library. Any Gmail-type account should
|
98
|
+
serve as a useful test target.
|
98
99
|
|
99
|
-
|
100
|
+
## Status
|
100
101
|
|
101
102
|
This software is currently experimental and is not recommended for production
|
102
103
|
use. Many of the internals may change significantly before a proper beta
|
103
104
|
release is made.
|
104
105
|
|
105
|
-
|
106
|
+
## Copyright
|
106
107
|
|
107
|
-
Copyright (c) 2010-
|
108
|
+
Copyright (c) 2010-2019 Scott Tadman, PostageApp Ltd.
|
data/Rakefile
CHANGED
@@ -1,29 +1,39 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
Bundler.require
|
7
|
+
|
4
8
|
begin
|
5
|
-
require '
|
6
|
-
|
9
|
+
require 'juwelier'
|
10
|
+
|
11
|
+
Juwelier::Tasks.new do |gem|
|
7
12
|
gem.name = "remailer"
|
8
13
|
gem.summary = %Q{Reactor-Ready SMTP Mailer}
|
9
|
-
gem.description = %Q{EventMachine SMTP
|
10
|
-
gem.email = "
|
11
|
-
gem.homepage = "http://github.com/
|
14
|
+
gem.description = %Q{EventMachine Mail Agent for SMTP and IMAP}
|
15
|
+
gem.email = "tadman@postageapp.com"
|
16
|
+
gem.homepage = "http://github.com/postageapp/remailer"
|
12
17
|
gem.authors = [ "Scott Tadman" ]
|
13
|
-
|
18
|
+
|
19
|
+
gem.files.exclude(
|
20
|
+
'.travis.yml',
|
21
|
+
'test/config.yml.enc'
|
22
|
+
)
|
14
23
|
end
|
15
|
-
|
24
|
+
|
25
|
+
Juwelier::GemcutterTasks.new
|
26
|
+
|
16
27
|
rescue LoadError
|
17
|
-
puts "
|
28
|
+
puts "Juwelier (or a dependency) not available. Install it with: gem install Juwelier"
|
18
29
|
end
|
19
30
|
|
20
31
|
require 'rake/testtask'
|
32
|
+
|
21
33
|
Rake::TestTask.new(:test) do |test|
|
22
34
|
test.libs << 'lib' << 'test'
|
23
35
|
test.pattern = 'test/**/*_test.rb'
|
24
36
|
test.verbose = true
|
25
37
|
end
|
26
38
|
|
27
|
-
task :
|
28
|
-
|
29
|
-
task :default => :test
|
39
|
+
task default: :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.1
|
@@ -83,7 +83,7 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
83
83
|
EventMachine.connect(host_name, host_port, self, options)
|
84
84
|
|
85
85
|
rescue EventMachine::ConnectionError => e
|
86
|
-
report_exception(e, options)
|
86
|
+
self.report_exception(e, options)
|
87
87
|
|
88
88
|
false
|
89
89
|
end
|
@@ -133,6 +133,14 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
133
133
|
@options = options
|
134
134
|
@hostname = @options[:hostname] || Socket.gethostname
|
135
135
|
@timeout = @options[:timeout] || self.class.default_timeout
|
136
|
+
@timed_out = false
|
137
|
+
|
138
|
+
@active_message = nil
|
139
|
+
@established = false
|
140
|
+
@connected = false
|
141
|
+
@closed = false
|
142
|
+
@unbound = false
|
143
|
+
@connecting_to_proxy = false
|
136
144
|
|
137
145
|
@messages = [ ]
|
138
146
|
|
@@ -151,9 +159,19 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
151
159
|
self.after_initialize
|
152
160
|
|
153
161
|
rescue Object => e
|
154
|
-
|
162
|
+
self.class.report_exception(e, @options)
|
163
|
+
|
164
|
+
STDERR.puts "#{e.class}: #{e}" rescue nil
|
155
165
|
end
|
156
|
-
|
166
|
+
|
167
|
+
def after_complete(&block)
|
168
|
+
if (block_given?)
|
169
|
+
@options[:after_complete] = block
|
170
|
+
elsif (@options[:after_complete])
|
171
|
+
@options[:after_complete].call
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
157
175
|
# Returns true if the connection requires TLS support, or false otherwise.
|
158
176
|
def use_tls?
|
159
177
|
!!@options[:use_tls]
|
@@ -166,9 +184,15 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
166
184
|
end
|
167
185
|
|
168
186
|
# Returns true if the connection has advertised authentication support, or
|
169
|
-
# false if not availble or could not be detected.
|
170
|
-
|
171
|
-
|
187
|
+
# false if not availble or could not be detected. If type is specified,
|
188
|
+
# returns true only if that type is supported, false otherwise.
|
189
|
+
def auth_support?(type = nil)
|
190
|
+
case (type)
|
191
|
+
when nil
|
192
|
+
!!@auth_support
|
193
|
+
else
|
194
|
+
!!(@auth_support&.include?(type))
|
195
|
+
end
|
172
196
|
end
|
173
197
|
|
174
198
|
# Returns true if the connection will be using a proxy to connect, false
|
@@ -229,11 +253,11 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
229
253
|
|
230
254
|
# This implements the EventMachine::Connection#receive_data method that
|
231
255
|
# is called each time new data is received from the socket.
|
232
|
-
def receive_data(data)
|
256
|
+
def receive_data(data = nil)
|
233
257
|
reset_timeout!
|
234
258
|
|
235
259
|
@buffer ||= ''
|
236
|
-
@buffer << data
|
260
|
+
@buffer << data if (data)
|
237
261
|
|
238
262
|
if (interpreter = @interpreter)
|
239
263
|
interpreter.process(@buffer) do |reply|
|
@@ -244,7 +268,10 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
244
268
|
end
|
245
269
|
|
246
270
|
rescue Object => e
|
247
|
-
|
271
|
+
self.class.report_exception(e, @options)
|
272
|
+
STDERR.puts("[#{e.class}] #{e}") rescue nil
|
273
|
+
|
274
|
+
raise e
|
248
275
|
end
|
249
276
|
|
250
277
|
def post_init
|
@@ -368,12 +395,6 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
368
395
|
def error?
|
369
396
|
!!@error
|
370
397
|
end
|
371
|
-
|
372
|
-
# EventMachine: Enables TLS support on the connection.
|
373
|
-
def start_tls
|
374
|
-
debug_notification(:tls, "Started")
|
375
|
-
super
|
376
|
-
end
|
377
398
|
|
378
399
|
# EventMachine: Closes down the connection.
|
379
400
|
def close_connection
|
@@ -399,11 +420,6 @@ class Remailer::AbstractConnection < EventMachine::Connection
|
|
399
420
|
|
400
421
|
reset_timeout!
|
401
422
|
end
|
402
|
-
|
403
|
-
# Switches to use the SOCKS5 interpreter for all subsequent communication
|
404
|
-
def use_socks5_interpreter!
|
405
|
-
@interpreter = Remailer::SOCKS5::Client::Interpreter.new(:delegate => self)
|
406
|
-
end
|
407
423
|
|
408
424
|
# -- Callbacks and Notifications ------------------------------------------
|
409
425
|
|
data/lib/remailer/imap/client.rb
CHANGED
@@ -192,7 +192,7 @@ class Remailer::IMAP::Client < Remailer::AbstractConnection
|
|
192
192
|
protected
|
193
193
|
# Switches to use the IMAP interpreter for all subsequent communication
|
194
194
|
def use_imap_interpreter!
|
195
|
-
@interpreter = Interpreter.new(:
|
195
|
+
@interpreter = Interpreter.new(delegate: self)
|
196
196
|
end
|
197
197
|
|
198
198
|
def next_tag
|
data/lib/remailer/interpreter.rb
CHANGED
@@ -19,7 +19,7 @@ class Remailer::Interpreter
|
|
19
19
|
|
20
20
|
# Defines the initial state for objects of this class.
|
21
21
|
def self.initial_state
|
22
|
-
@initial_state
|
22
|
+
@initial_state ||= :initialized
|
23
23
|
end
|
24
24
|
|
25
25
|
# Can be used to reassign the initial state for this class. May be easier
|
@@ -27,21 +27,37 @@ class Remailer::Interpreter
|
|
27
27
|
def self.initial_state=(state)
|
28
28
|
@initial_state = state
|
29
29
|
end
|
30
|
+
|
31
|
+
def self.config
|
32
|
+
{
|
33
|
+
states: @states,
|
34
|
+
default_interpreter: @default,
|
35
|
+
default_parser: @parser,
|
36
|
+
on_error_handler: @on_error
|
37
|
+
}
|
38
|
+
end
|
30
39
|
|
40
|
+
def self.states_default
|
41
|
+
{
|
42
|
+
:initialized => { },
|
43
|
+
:terminated => { }
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
31
47
|
# Returns the states that are defined as a has with their associated
|
32
48
|
# options. The default keys are :initialized and :terminated.
|
33
49
|
def self.states
|
34
50
|
@states ||=
|
35
|
-
|
36
|
-
when true
|
51
|
+
if (superclass.respond_to?(:states))
|
37
52
|
superclass.states.dup
|
38
53
|
else
|
39
|
-
|
40
|
-
:initialized => { },
|
41
|
-
:terminated => { }
|
42
|
-
}
|
54
|
+
self.states_default
|
43
55
|
end
|
44
56
|
end
|
57
|
+
|
58
|
+
def self.states_empty?
|
59
|
+
self.states == self.states_default
|
60
|
+
end
|
45
61
|
|
46
62
|
# Returns true if a given state is defined, false otherwise.
|
47
63
|
def self.state_defined?(state)
|
@@ -66,15 +82,15 @@ class Remailer::Interpreter
|
|
66
82
|
end
|
67
83
|
|
68
84
|
# This is a method to convert a spec and a block into a proper parser
|
69
|
-
# method. If spec is specified, it should be a
|
70
|
-
#
|
85
|
+
# method. If spec is specified, it should be a Integer, or a Regexp. A
|
86
|
+
# Integer defines a minimum size to process, useful for packed binary
|
71
87
|
# streams, while a Regexp defines a pattern that must match before the
|
72
88
|
# parser is engaged.
|
73
89
|
def self.create_parser_for_spec(spec, &block)
|
74
90
|
case (spec)
|
75
91
|
when nil
|
76
92
|
block
|
77
|
-
when
|
93
|
+
when Integer
|
78
94
|
lambda do |s|
|
79
95
|
if (s.length >= spec)
|
80
96
|
part = s.slice!(0, spec)
|
@@ -114,8 +130,7 @@ class Remailer::Interpreter
|
|
114
130
|
# Returns the parser used when no state-specific parser has been defined.
|
115
131
|
def self.default_parser
|
116
132
|
@parser ||=
|
117
|
-
|
118
|
-
when true
|
133
|
+
if (superclass.respond_to?(:default_parser))
|
119
134
|
superclass.default_parser
|
120
135
|
else
|
121
136
|
lambda { |s| _s = s.dup; s.replace(''); _s }
|
@@ -125,8 +140,7 @@ class Remailer::Interpreter
|
|
125
140
|
# Returns the current default_interpreter.
|
126
141
|
def self.default_interpreter
|
127
142
|
@default ||=
|
128
|
-
|
129
|
-
when true
|
143
|
+
if (superclass.respond_to?(:default_interpreter))
|
130
144
|
superclass.default_interpreter
|
131
145
|
else
|
132
146
|
nil
|
@@ -136,8 +150,7 @@ class Remailer::Interpreter
|
|
136
150
|
# Returns the defined error handler
|
137
151
|
def self.on_error_handler
|
138
152
|
@on_error ||=
|
139
|
-
|
140
|
-
when true
|
153
|
+
if (superclass.respond_to?(:on_error_handler))
|
141
154
|
superclass.on_error_handler
|
142
155
|
else
|
143
156
|
nil
|
@@ -155,6 +168,8 @@ class Remailer::Interpreter
|
|
155
168
|
# before the first state is entered.
|
156
169
|
def initialize(options = nil)
|
157
170
|
@delegate = (options and options[:delegate])
|
171
|
+
@state = nil
|
172
|
+
@error = nil
|
158
173
|
|
159
174
|
yield(self) if (block_given?)
|
160
175
|
|
@@ -212,8 +227,8 @@ class Remailer::Interpreter
|
|
212
227
|
yield(parsed) if (block_given?)
|
213
228
|
|
214
229
|
interpret(*parsed)
|
215
|
-
|
216
|
-
break if (s.empty?)
|
230
|
+
|
231
|
+
break if (s.empty? or self.finished?)
|
217
232
|
end
|
218
233
|
end
|
219
234
|
|
@@ -245,7 +260,7 @@ class Remailer::Interpreter
|
|
245
260
|
match_result = match_result.to_a
|
246
261
|
|
247
262
|
if (match_result.length > 1)
|
248
|
-
|
263
|
+
match_result.shift
|
249
264
|
args[0, 1] = match_result
|
250
265
|
else
|
251
266
|
args[0].sub!(match_result[0], '')
|
@@ -290,6 +305,12 @@ class Remailer::Interpreter
|
|
290
305
|
def will_interpret?(proc, args)
|
291
306
|
true
|
292
307
|
end
|
308
|
+
|
309
|
+
# Should return true if this interpreter no longer wants any data, false
|
310
|
+
# otherwise. Subclasses should implement their own behavior here.
|
311
|
+
def finished?
|
312
|
+
false
|
313
|
+
end
|
293
314
|
|
294
315
|
# Returns true if an error has been generated, false otherwise. The error
|
295
316
|
# content can be retrived by calling error.
|
@@ -14,7 +14,7 @@ class Remailer::Interpreter::StateProxy
|
|
14
14
|
|
15
15
|
# Defines a parser specification.
|
16
16
|
def parse(spec = nil, &block)
|
17
|
-
@options[:parser] = Remailer::Interpreter.
|
17
|
+
@options[:parser] = Remailer::Interpreter.create_parser_for_spec(spec, &block)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Defines a block that will execute when the state is entered.
|
data/lib/remailer/smtp/client.rb
CHANGED
@@ -60,6 +60,8 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
60
60
|
# Called by AbstractConnection at the end of the initialize procedure
|
61
61
|
def after_initialize
|
62
62
|
@protocol = :smtp
|
63
|
+
@error = nil
|
64
|
+
@tls_support = nil
|
63
65
|
|
64
66
|
if (using_proxy?)
|
65
67
|
proxy_connection_initiated!
|
@@ -69,6 +71,11 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
74
|
+
# Switches to use the SOCKS5 interpreter for all subsequent communication
|
75
|
+
def use_socks5_interpreter!
|
76
|
+
@interpreter = Remailer::SOCKS5::Client::Interpreter.new(delegate: self)
|
77
|
+
end
|
78
|
+
|
72
79
|
# Closes the connection after all of the queued messages have been sent.
|
73
80
|
def close_when_complete!
|
74
81
|
@options[:close] = true
|
@@ -83,10 +90,10 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
83
90
|
end
|
84
91
|
|
85
92
|
message = {
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
93
|
+
from: from,
|
94
|
+
to: to,
|
95
|
+
data: data,
|
96
|
+
callback: block
|
90
97
|
}
|
91
98
|
|
92
99
|
@messages << message
|
@@ -108,10 +115,10 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
108
115
|
end
|
109
116
|
|
110
117
|
message = {
|
111
|
-
:
|
112
|
-
:
|
113
|
-
:
|
114
|
-
:
|
118
|
+
from: from,
|
119
|
+
to: to,
|
120
|
+
test: true,
|
121
|
+
callback: block
|
115
122
|
}
|
116
123
|
|
117
124
|
@messages << message
|
@@ -146,23 +153,6 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
146
153
|
def unbound?
|
147
154
|
!!@unbound
|
148
155
|
end
|
149
|
-
|
150
|
-
# This implements the EventMachine::Connection#receive_data method that
|
151
|
-
# is called each time new data is received from the socket.
|
152
|
-
def receive_data(data)
|
153
|
-
reset_timeout!
|
154
|
-
|
155
|
-
@buffer ||= ''
|
156
|
-
@buffer << data
|
157
|
-
|
158
|
-
if (interpreter = @interpreter)
|
159
|
-
interpreter.process(@buffer) do |reply|
|
160
|
-
debug_notification(:receive, "[#{interpreter.label}] #{reply.inspect}")
|
161
|
-
end
|
162
|
-
else
|
163
|
-
error_notification(:out_of_band, "Receiving data before a protocol has been established.")
|
164
|
-
end
|
165
|
-
end
|
166
156
|
|
167
157
|
# Returns the current state of the active interpreter, or nil if no state
|
168
158
|
# is assigned.
|
@@ -227,7 +217,11 @@ class Remailer::SMTP::Client < Remailer::AbstractConnection
|
|
227
217
|
|
228
218
|
# Switches to use the SMTP interpreter for all subsequent communication
|
229
219
|
def use_smtp_interpreter!
|
230
|
-
@interpreter = Interpreter.new(:
|
220
|
+
@interpreter = Interpreter.new(delegate: self)
|
221
|
+
|
222
|
+
# Trigger processing using the new interpreter as some SMTP data might
|
223
|
+
# already be buffered by this point.
|
224
|
+
receive_data
|
231
225
|
end
|
232
226
|
|
233
227
|
# Callback receiver for when the proxy connection has been completed.
|