eventmachine 0.12.0-i386-mswin32

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.
Files changed (104) hide show
  1. data/COPYING +60 -0
  2. data/DEFERRABLES +138 -0
  3. data/EPOLL +141 -0
  4. data/GNU +281 -0
  5. data/KEYBOARD +38 -0
  6. data/LEGAL +25 -0
  7. data/LIGHTWEIGHT_CONCURRENCY +72 -0
  8. data/PURE_RUBY +77 -0
  9. data/README +74 -0
  10. data/RELEASE_NOTES +96 -0
  11. data/SMTP +9 -0
  12. data/SPAWNED_PROCESSES +93 -0
  13. data/TODO +10 -0
  14. data/ext/Makefile +180 -0
  15. data/ext/binder.cpp +126 -0
  16. data/ext/binder.h +48 -0
  17. data/ext/cmain.cpp +527 -0
  18. data/ext/cplusplus.cpp +172 -0
  19. data/ext/ed.cpp +1442 -0
  20. data/ext/ed.h +351 -0
  21. data/ext/em.cpp +1781 -0
  22. data/ext/em.h +167 -0
  23. data/ext/emwin.cpp +300 -0
  24. data/ext/emwin.h +94 -0
  25. data/ext/epoll.cpp +26 -0
  26. data/ext/epoll.h +25 -0
  27. data/ext/eventmachine.h +83 -0
  28. data/ext/eventmachine_cpp.h +94 -0
  29. data/ext/extconf.rb +203 -0
  30. data/ext/files.cpp +94 -0
  31. data/ext/files.h +65 -0
  32. data/ext/kb.cpp +368 -0
  33. data/ext/mkmf.log +129 -0
  34. data/ext/page.cpp +107 -0
  35. data/ext/page.h +51 -0
  36. data/ext/pipe.cpp +327 -0
  37. data/ext/project.h +119 -0
  38. data/ext/rubyeventmachine-i386-mswin32.def +2 -0
  39. data/ext/rubyeventmachine-i386-mswin32.exp +0 -0
  40. data/ext/rubyeventmachine-i386-mswin32.lib +0 -0
  41. data/ext/rubyeventmachine-i386-mswin32.pdb +0 -0
  42. data/ext/rubyeventmachine.so +0 -0
  43. data/ext/rubymain.cpp +630 -0
  44. data/ext/sigs.cpp +89 -0
  45. data/ext/sigs.h +32 -0
  46. data/ext/ssl.cpp +408 -0
  47. data/ext/ssl.h +86 -0
  48. data/ext/vc60.pdb +0 -0
  49. data/lib/em/deferrable.rb +208 -0
  50. data/lib/em/eventable.rb +39 -0
  51. data/lib/em/future.rb +62 -0
  52. data/lib/em/messages.rb +66 -0
  53. data/lib/em/processes.rb +68 -0
  54. data/lib/em/spawnable.rb +88 -0
  55. data/lib/em/streamer.rb +112 -0
  56. data/lib/eventmachine.rb +1621 -0
  57. data/lib/eventmachine_version.rb +31 -0
  58. data/lib/evma.rb +32 -0
  59. data/lib/evma/callback.rb +32 -0
  60. data/lib/evma/container.rb +75 -0
  61. data/lib/evma/factory.rb +77 -0
  62. data/lib/evma/protocol.rb +87 -0
  63. data/lib/evma/reactor.rb +48 -0
  64. data/lib/jeventmachine.rb +106 -0
  65. data/lib/pr_eventmachine.rb +1011 -0
  66. data/lib/protocols/buftok.rb +127 -0
  67. data/lib/protocols/header_and_content.rb +123 -0
  68. data/lib/protocols/httpcli2.rb +784 -0
  69. data/lib/protocols/httpclient.rb +253 -0
  70. data/lib/protocols/line_and_text.rb +122 -0
  71. data/lib/protocols/linetext2.rb +145 -0
  72. data/lib/protocols/saslauth.rb +179 -0
  73. data/lib/protocols/smtpclient.rb +308 -0
  74. data/lib/protocols/smtpserver.rb +543 -0
  75. data/lib/protocols/stomp.rb +127 -0
  76. data/lib/protocols/tcptest.rb +57 -0
  77. data/lib/rubyeventmachine.so +0 -0
  78. data/tests/test_basic.rb +142 -0
  79. data/tests/test_defer.rb +63 -0
  80. data/tests/test_epoll.rb +168 -0
  81. data/tests/test_errors.rb +82 -0
  82. data/tests/test_eventables.rb +78 -0
  83. data/tests/test_exc.rb +58 -0
  84. data/tests/test_futures.rb +214 -0
  85. data/tests/test_hc.rb +221 -0
  86. data/tests/test_httpclient.rb +194 -0
  87. data/tests/test_httpclient2.rb +133 -0
  88. data/tests/test_kb.rb +61 -0
  89. data/tests/test_ltp.rb +190 -0
  90. data/tests/test_ltp2.rb +261 -0
  91. data/tests/test_next_tick.rb +58 -0
  92. data/tests/test_processes.rb +56 -0
  93. data/tests/test_pure.rb +128 -0
  94. data/tests/test_running.rb +47 -0
  95. data/tests/test_sasl.rb +73 -0
  96. data/tests/test_send_file.rb +238 -0
  97. data/tests/test_servers.rb +90 -0
  98. data/tests/test_smtpclient.rb +81 -0
  99. data/tests/test_smtpserver.rb +93 -0
  100. data/tests/test_spawn.rb +329 -0
  101. data/tests/test_timers.rb +138 -0
  102. data/tests/test_ud.rb +43 -0
  103. data/tests/testem.rb +5 -0
  104. metadata +170 -0
@@ -0,0 +1,543 @@
1
+ # $Id: smtpserver.rb 668 2008-01-04 23:00:34Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+
27
+ #require 'base64'
28
+
29
+ module EventMachine
30
+ module Protocols
31
+
32
+
33
+ =begin
34
+ This is a protocol handler for the server side of SMTP.
35
+ It's NOT a complete SMTP server obeying all the semantics of servers conforming to
36
+ RFC2821. Rather, it uses overridable method stubs to communicate protocol states
37
+ and data to user code. User code is responsible for doing the right things with the
38
+ data in order to get complete and correct SMTP server behavior.
39
+
40
+ Useful paragraphs in RFC-2821:
41
+ 4.3.2: Concise list of command-reply sequences, in essence a text representation
42
+ of the command state-machine.
43
+
44
+ STARTTLS is defined in RFC2487.
45
+ Observe that there are important rules governing whether a publicly-referenced server
46
+ (meaning one whose Internet address appears in public MX records) may require the
47
+ non-optional use of TLS.
48
+ Non-optional TLS does not apply to EHLO, NOOP, QUIT or STARTTLS.
49
+
50
+ =end
51
+
52
+ class SmtpServer < EventMachine::Connection
53
+ include Protocols::LineText2
54
+
55
+ HeloRegex = /\AHELO\s*/i
56
+ EhloRegex = /\AEHLO\s*/i
57
+ QuitRegex = /\AQUIT/i
58
+ MailFromRegex = /\AMAIL FROM:\s*/i
59
+ RcptToRegex = /\ARCPT TO:\s*/i
60
+ DataRegex = /\ADATA/i
61
+ NoopRegex = /\ANOOP/i
62
+ RsetRegex = /\ARSET/i
63
+ VrfyRegex = /\AVRFY\s+/i
64
+ ExpnRegex = /\AEXPN\s+/i
65
+ HelpRegex = /\AHELP/i
66
+ StarttlsRegex = /\ASTARTTLS/i
67
+ AuthRegex = /\AAUTH\s+/i
68
+
69
+
70
+ # Class variable containing default parameters that can be overridden
71
+ # in application code.
72
+ # Individual objects of this class will make an instance-local copy of
73
+ # the class variable, so that they can be reconfigured on a per-instance
74
+ # basis.
75
+ #
76
+ # Chunksize is the number of data lines we'll buffer before
77
+ # sending them to the application. TODO, make this user-configurable.
78
+ #
79
+ @@parms = {
80
+ :chunksize => 4000,
81
+ :verbose => false
82
+ }
83
+ def self.parms= parms={}
84
+ @@parms.merge!(parms)
85
+ end
86
+
87
+
88
+
89
+ def initialize *args
90
+ super
91
+ @parms = @@parms
92
+ init_protocol_state
93
+ end
94
+
95
+ def parms= parms={}
96
+ @parms.merge!(parms)
97
+ end
98
+
99
+ # In SMTP, the server talks first. But by a (perhaps flawed) axiom in EM,
100
+ # #post_init will execute BEFORE the block passed to #start_server, for any
101
+ # given accepted connection. Since in this class we'll probably be getting
102
+ # a lot of initialization parameters, we want the guts of post_init to
103
+ # run AFTER the application has initialized the connection object. So we
104
+ # use a spawn to schedule the post_init to run later.
105
+ # It's a little weird, I admit. A reasonable alternative would be to set
106
+ # parameters as a class variable and to do that before accepting any connections.
107
+ #
108
+ # OBSOLETE, now we have @@parms. But the spawn is nice to keep as an illustration.
109
+ #
110
+ def post_init
111
+ #send_data "220 #{get_server_greeting}\r\n" (ORIGINAL)
112
+ #(EM.spawn {|x| x.send_data "220 #{x.get_server_greeting}\r\n"}).notify(self)
113
+ (EM.spawn {|x| x.send_server_greeting}).notify(self)
114
+ end
115
+
116
+ def send_server_greeting
117
+ send_data "220 #{get_server_greeting}\r\n"
118
+ end
119
+
120
+ def receive_line ln
121
+ @@parms[:verbose] and $>.puts ">>> #{ln}"
122
+ if @state.include?(:data)
123
+ process_data_line ln
124
+ elsif ln =~ EhloRegex
125
+ process_ehlo $'.dup
126
+ elsif ln =~ HeloRegex
127
+ process_helo $'.dup
128
+ elsif ln =~ MailFromRegex
129
+ process_mail_from $'.dup
130
+ elsif ln =~ RcptToRegex
131
+ process_rcpt_to $'.dup
132
+ elsif ln =~ DataRegex
133
+ process_data
134
+ elsif ln =~ RsetRegex
135
+ process_rset
136
+ elsif ln =~ VrfyRegex
137
+ process_vrfy
138
+ elsif ln =~ ExpnRegex
139
+ process_expn
140
+ elsif ln =~ HelpRegex
141
+ process_help
142
+ elsif ln =~ NoopRegex
143
+ process_noop
144
+ elsif ln =~ QuitRegex
145
+ process_quit
146
+ elsif ln =~ StarttlsRegex
147
+ process_starttls
148
+ elsif ln =~ AuthRegex
149
+ process_auth $'.dup
150
+ else
151
+ process_unknown
152
+ end
153
+ end
154
+
155
+
156
+
157
+ #--
158
+ # This is called at several points to restore the protocol state
159
+ # to a pre-transaction state. In essence, we "forget" having seen
160
+ # any valid command except EHLO and STARTTLS.
161
+ # We also have to callback user code, in case they're keeping track
162
+ # of senders, recipients, and whatnot.
163
+ #
164
+ # We try to follow the convention of avoiding the verb "receive" for
165
+ # internal method names except receive_line (which we inherit), and
166
+ # using only receive_xxx for user-overridable stubs.
167
+ #
168
+ # init_protocol_state is called when we initialize the connection as
169
+ # well as during reset_protocol_state. It does NOT call the user
170
+ # override method. This enables us to promise the users that they
171
+ # won't see the overridable fire except after EHLO and RSET, and
172
+ # after a message has been received. Although the latter may be wrong.
173
+ # The standard may allow multiple DATA segments with the same set of
174
+ # senders and recipients.
175
+ #
176
+ def reset_protocol_state
177
+ init_protocol_state
178
+ s,@state = @state,[]
179
+ @state << :starttls if s.include?(:starttls)
180
+ @state << :ehlo if s.include?(:ehlo)
181
+ receive_transaction
182
+ end
183
+ def init_protocol_state
184
+ @state ||= []
185
+ end
186
+
187
+
188
+ #--
189
+ # EHLO/HELO is always legal, per the standard. On success
190
+ # it always clears buffers and initiates a mail "transaction."
191
+ # Which means that a MAIL FROM must follow.
192
+ #
193
+ # Per the standard, an EHLO/HELO or a RSET "initiates" an email
194
+ # transaction. Thereafter, MAIL FROM must be received before
195
+ # RCPT TO, before DATA. Not sure what this specific ordering
196
+ # achieves semantically, but it does make it easier to
197
+ # implement. We also support user-specified requirements for
198
+ # STARTTLS and AUTH. We make it impossible to proceed to MAIL FROM
199
+ # without fulfilling tls and/or auth, if the user specified either
200
+ # or both as required. We need to check the extension standard
201
+ # for auth to see if a credential is discarded after a RSET along
202
+ # with all the rest of the state. We'll behave as if it is.
203
+ # Now clearly, we can't discard tls after its been negotiated
204
+ # without dropping the connection, so that flag doesn't get cleared.
205
+ #
206
+ def process_ehlo domain
207
+ if receive_ehlo_domain domain
208
+ send_data "250-#{get_server_domain}\r\n"
209
+ if @@parms[:starttls]
210
+ send_data "250-STARTTLS\r\n"
211
+ end
212
+ if @@parms[:auth]
213
+ send_data "250-AUTH PLAIN LOGIN\r\n"
214
+ end
215
+ send_data "250-NO-SOLICITING\r\n"
216
+ # TODO, size needs to be configurable.
217
+ send_data "250 SIZE 20000000\r\n"
218
+ reset_protocol_state
219
+ @state << :ehlo
220
+ else
221
+ send_data "550 Requested action not taken\r\n"
222
+ end
223
+ end
224
+
225
+ def process_helo domain
226
+ if receive_ehlo_domain domain.dup
227
+ send_data "250 #{get_server_domain}\r\n"
228
+ reset_protocol_state
229
+ @state << :ehlo
230
+ else
231
+ send_data "550 Requested action not taken\r\n"
232
+ end
233
+ end
234
+
235
+ def process_quit
236
+ send_data "221 Ok\r\n"
237
+ close_connection_after_writing
238
+ end
239
+
240
+ def process_noop
241
+ send_data "250 Ok\r\n"
242
+ end
243
+
244
+ def process_unknown
245
+ send_data "500 Unknown command\r\n"
246
+ end
247
+
248
+ #--
249
+ # So far, only AUTH PLAIN is supported but we should do at least LOGIN as well.
250
+ # TODO, support clients that send AUTH PLAIN with no parameter, expecting a 3xx
251
+ # response and a continuation of the auth conversation.
252
+ #
253
+ def process_auth str
254
+ if @state.include?(:auth)
255
+ send_data "503 auth already issued\r\n"
256
+ elsif str =~ /\APLAIN\s+/i
257
+ plain = ($'.dup).unpack("m").first # Base64::decode64($'.dup)
258
+ discard,user,psw = plain.split("\000")
259
+ if receive_plain_auth user,psw
260
+ send_data "235 authentication ok\r\n"
261
+ @state << :auth
262
+ else
263
+ send_data "535 invalid authentication\r\n"
264
+ end
265
+ #elsif str =~ /\ALOGIN\s+/i
266
+ else
267
+ send_data "504 auth mechanism not available\r\n"
268
+ end
269
+ end
270
+
271
+ #--
272
+ # Unusually, we can deal with a Deferrable returned from the user application.
273
+ # This was added to deal with a special case in a particular application, but
274
+ # it would be a nice idea to add it to the other user-code callbacks.
275
+ #
276
+ def process_data
277
+ unless @state.include?(:rcpt)
278
+ send_data "503 Operation sequence error\r\n"
279
+ else
280
+ succeeded = proc {
281
+ send_data "354 Send it\r\n"
282
+ @state << :data
283
+ @databuffer = []
284
+ }
285
+ failed = proc {
286
+ send_data "550 Operation failed\r\n"
287
+ }
288
+
289
+ d = receive_data_command
290
+
291
+ if d.respond_to?(:callback)
292
+ d.callback &succeeded
293
+ d.errback &failed
294
+ else
295
+ (d ? succeeded : failed).call
296
+ end
297
+ end
298
+ end
299
+
300
+ def process_rset
301
+ reset_protocol_state
302
+ receive_reset
303
+ send_data "250 Ok\r\n"
304
+ end
305
+
306
+ def unbind
307
+ connection_ended
308
+ end
309
+
310
+ #--
311
+ # STARTTLS may not be issued before EHLO, or unless the user has chosen
312
+ # to support it.
313
+ # TODO, must support user-supplied certificates.
314
+ #
315
+ def process_starttls
316
+ if @@parms[:starttls]
317
+ if @state.include?(:starttls)
318
+ send_data "503 TLS Already negotiated\r\n"
319
+ elsif ! @state.include?(:ehlo)
320
+ send_data "503 EHLO required before STARTTLS\r\n"
321
+ else
322
+ send_data "220 Start TLS negotiation\r\n"
323
+ start_tls
324
+ @state << :starttls
325
+ end
326
+ else
327
+ process_unknown
328
+ end
329
+ end
330
+
331
+
332
+ #--
333
+ # Requiring TLS is touchy, cf RFC2784.
334
+ # Requiring AUTH seems to be much more reasonable.
335
+ # We don't currently support any notion of deriving an authentication from the TLS
336
+ # negotiation, although that would certainly be reasonable.
337
+ # We DON'T allow MAIL FROM to be given twice.
338
+ # We DON'T enforce all the various rules for validating the sender or
339
+ # the reverse-path (like whether it should be null), and notifying the reverse
340
+ # path in case of delivery problems. All of that is left to the calling application.
341
+ #
342
+ def process_mail_from sender
343
+ if (@@parms[:starttls]==:required and !@state.include?(:starttls))
344
+ send_data "550 This server requires STARTTLS before MAIL FROM\r\n"
345
+ elsif (@@parms[:auth]==:required and !@state.include?(:auth))
346
+ send_data "550 This server requires authentication before MAIL FROM\r\n"
347
+ elsif @state.include?(:mail_from)
348
+ send_data "503 MAIL already given\r\n"
349
+ else
350
+ unless receive_sender sender
351
+ send_data "550 sender is unacceptable\r\n"
352
+ else
353
+ send_data "250 Ok\r\n"
354
+ @state << :mail_from
355
+ end
356
+ end
357
+ end
358
+
359
+ #--
360
+ # Since we require :mail_from to have been seen before we process RCPT TO,
361
+ # we don't need to repeat the tests for TLS and AUTH.
362
+ # Note that we don't remember or do anything else with the recipients.
363
+ # All of that is on the user code.
364
+ # TODO: we should enforce user-definable limits on the total number of
365
+ # recipients per transaction.
366
+ # We might want to make sure that a given recipient is only seen once, but
367
+ # for now we'll let that be the user's problem.
368
+ #
369
+ # User-written code can return a deferrable from receive_recipient.
370
+ #
371
+ def process_rcpt_to rcpt
372
+ unless @state.include?(:mail_from)
373
+ send_data "503 MAIL is required before RCPT\r\n"
374
+ else
375
+ succeeded = proc {
376
+ send_data "250 Ok\r\n"
377
+ @state << :rcpt unless @state.include?(:rcpt)
378
+ }
379
+ failed = proc {
380
+ send_data "550 recipient is unacceptable\r\n"
381
+ }
382
+
383
+ d = receive_recipient rcpt
384
+
385
+ if d.respond_to?(:set_deferred_status)
386
+ d.callback &succeeded
387
+ d.errback &failed
388
+ else
389
+ (d ? succeeded : failed).call
390
+ end
391
+
392
+ =begin
393
+ unless receive_recipient rcpt
394
+ send_data "550 recipient is unacceptable\r\n"
395
+ else
396
+ send_data "250 Ok\r\n"
397
+ @state << :rcpt unless @state.include?(:rcpt)
398
+ end
399
+ =end
400
+ end
401
+ end
402
+
403
+
404
+ # Send the incoming data to the application one chunk at a time, rather than
405
+ # one line at a time. That lets the application be a little more flexible about
406
+ # storing to disk, etc.
407
+ # Since we clear the chunk array every time we submit it, the caller needs to be
408
+ # aware to do things like dup it if he wants to keep it around across calls.
409
+ #
410
+ # DON'T reset the transaction upon disposition of the incoming message.
411
+ # This means another DATA command can be accepted with the same sender and recipients.
412
+ # If the client wants to reset, he can call RSET.
413
+ # Not sure whether the standard requires a transaction-reset at this point, but it
414
+ # appears not to.
415
+ #
416
+ # User-written code can return a Deferrable as a response from receive_message.
417
+ #
418
+ def process_data_line ln
419
+ if ln == "."
420
+ if @databuffer.length > 0
421
+ receive_data_chunk @databuffer
422
+ @databuffer.clear
423
+ end
424
+
425
+
426
+ succeeded = proc {
427
+ send_data "250 Message accepted\r\n"
428
+ }
429
+ failed = proc {
430
+ send_data "550 Message rejected\r\n"
431
+ }
432
+
433
+ d = receive_message
434
+
435
+ if d.respond_to?(:set_deferred_status)
436
+ d.callback &succeeded
437
+ d.errback &failed
438
+ else
439
+ (d ? succeeded : failed).call
440
+ end
441
+
442
+ @state.delete :data
443
+ else
444
+ # slice off leading . if any
445
+ ln.slice!(0...1) if ln[0] == 46
446
+ @databuffer << ln
447
+ if @databuffer.length > @@parms[:chunksize]
448
+ receive_data_chunk @databuffer
449
+ @databuffer.clear
450
+ end
451
+ end
452
+ end
453
+
454
+
455
+ #------------------------------------------
456
+ # Everything from here on can be overridden in user code.
457
+
458
+ # The greeting returned in the initial connection message to the client.
459
+ def get_server_greeting
460
+ "EventMachine SMTP Server"
461
+ end
462
+ # The domain name returned in the first line of the response to a
463
+ # successful EHLO or HELO command.
464
+ def get_server_domain
465
+ "Ok EventMachine SMTP Server"
466
+ end
467
+
468
+ # A false response from this user-overridable method will cause a
469
+ # 550 error to be returned to the remote client.
470
+ #
471
+ def receive_ehlo_domain domain
472
+ true
473
+ end
474
+
475
+ # Return true or false to indicate that the authentication is acceptable.
476
+ def receive_plain_auth user, password
477
+ true
478
+ end
479
+
480
+ # Receives the argument of the MAIL FROM command. Return false to
481
+ # indicate to the remote client that the sender is not accepted.
482
+ # This can only be successfully called once per transaction.
483
+ #
484
+ def receive_sender sender
485
+ true
486
+ end
487
+
488
+ # Receives the argument of a RCPT TO command. Can be given multiple
489
+ # times per transaction. Return false to reject the recipient.
490
+ #
491
+ def receive_recipient rcpt
492
+ true
493
+ end
494
+
495
+ # Sent when the remote peer issues the RSET command.
496
+ # Since RSET is not allowed to fail (according to the protocol),
497
+ # we ignore any return value from user overrides of this method.
498
+ #
499
+ def receive_reset
500
+ end
501
+
502
+ # Sent when the remote peer has ended the connection.
503
+ #
504
+ def connection_ended
505
+ end
506
+
507
+ # Called when the remote peer sends the DATA command.
508
+ # Returning false will cause us to send a 550 error to the peer.
509
+ # This can be useful for dealing with problems that arise from processing
510
+ # the whole set of sender and recipients.
511
+ #
512
+ def receive_data_command
513
+ true
514
+ end
515
+
516
+ # Sent when data from the remote peer is available. The size can be controlled
517
+ # by setting the :chunksize parameter. This call can be made multiple times.
518
+ # The goal is to strike a balance between sending the data to the application one
519
+ # line at a time, and holding all of a very large message in memory.
520
+ #
521
+ def receive_data_chunk data
522
+ @smtps_msg_size ||= 0
523
+ @smtps_msg_size += data.join.length
524
+ STDERR.write "<#{@smtps_msg_size}>"
525
+ end
526
+
527
+ # Sent after a message has been completely received. User code
528
+ # must return true or false to indicate whether the message has
529
+ # been accepted for delivery.
530
+ def receive_message
531
+ @@parms[:verbose] and $>.puts "Received complete message"
532
+ true
533
+ end
534
+
535
+ # This is called when the protocol state is reset. It happens
536
+ # when the remote client calls EHLO/HELO or RSET.
537
+ def receive_transaction
538
+ end
539
+ end
540
+ end
541
+ end
542
+
543
+