rumbster 1.0.0 → 1.0.1

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 (44) hide show
  1. data/.autotest +1 -0
  2. data/Gemfile +11 -0
  3. data/Gemfile.lock +34 -0
  4. data/LICENSE.txt +202 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +50 -8
  7. data/VERSION +1 -0
  8. data/lib/message_observers.rb +3 -3
  9. data/lib/rumbster.rb +0 -0
  10. data/lib/smtp_protocol.rb +7 -7
  11. data/lib/smtp_states.rb +24 -58
  12. data/rumbster.gemspec +70 -0
  13. data/test/{message_observers_test.rb → test_message_observers.rb} +1 -1
  14. data/test/{rumbster_test.rb → test_rumbster.rb} +1 -1
  15. data/test/{smtp_protocol_test.rb → test_smtp_protocol.rb} +2 -19
  16. data/test/{smtp_states_test.rb → test_smtp_states.rb} +31 -87
  17. metadata +128 -76
  18. data/COPYING +0 -515
  19. data/README +0 -56
  20. data/vendor/tmail.rb +0 -4
  21. data/vendor/tmail/.cvsignore +0 -3
  22. data/vendor/tmail/Makefile +0 -19
  23. data/vendor/tmail/address.rb +0 -222
  24. data/vendor/tmail/base64.rb +0 -52
  25. data/vendor/tmail/compat.rb +0 -39
  26. data/vendor/tmail/config.rb +0 -50
  27. data/vendor/tmail/encode.rb +0 -447
  28. data/vendor/tmail/header.rb +0 -895
  29. data/vendor/tmail/info.rb +0 -14
  30. data/vendor/tmail/loader.rb +0 -1
  31. data/vendor/tmail/mail.rb +0 -869
  32. data/vendor/tmail/mailbox.rb +0 -386
  33. data/vendor/tmail/mbox.rb +0 -1
  34. data/vendor/tmail/net.rb +0 -260
  35. data/vendor/tmail/obsolete.rb +0 -122
  36. data/vendor/tmail/parser.rb +0 -1475
  37. data/vendor/tmail/parser.y +0 -372
  38. data/vendor/tmail/port.rb +0 -356
  39. data/vendor/tmail/scanner.rb +0 -22
  40. data/vendor/tmail/scanner_r.rb +0 -243
  41. data/vendor/tmail/stringio.rb +0 -256
  42. data/vendor/tmail/textutils.rb +0 -197
  43. data/vendor/tmail/tmail.rb +0 -1
  44. data/vendor/tmail/utils.rb +0 -23
@@ -1,372 +0,0 @@
1
- #
2
- # parser.y
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
- class TMail::Parser
12
-
13
- options no_result_var
14
-
15
- rule
16
-
17
- content : DATETIME datetime { val[1] }
18
- | RECEIVED received { val[1] }
19
- | MADDRESS addrs_TOP { val[1] }
20
- | RETPATH retpath { val[1] }
21
- | KEYWORDS keys { val[1] }
22
- | ENCRYPTED enc { val[1] }
23
- | MIMEVERSION version { val[1] }
24
- | CTYPE ctype { val[1] }
25
- | CENCODING cencode { val[1] }
26
- | CDISPOSITION cdisp { val[1] }
27
- | ADDRESS addr_TOP { val[1] }
28
- | MAILBOX mbox { val[1] }
29
-
30
- datetime : day DIGIT ATOM DIGIT hour zone
31
- # 0 1 2 3 4 5
32
- # date month year
33
- {
34
- t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0)
35
- (t + val[4] - val[5]).localtime
36
- }
37
-
38
- day : /* none */
39
- | ATOM ','
40
-
41
- hour : DIGIT ':' DIGIT
42
- {
43
- (val[0].to_i * 60 * 60) +
44
- (val[2].to_i * 60)
45
- }
46
- | DIGIT ':' DIGIT ':' DIGIT
47
- {
48
- (val[0].to_i * 60 * 60) +
49
- (val[2].to_i * 60) +
50
- (val[4].to_i)
51
- }
52
-
53
- zone : ATOM
54
- {
55
- timezone_string_to_unixtime(val[0])
56
- }
57
-
58
- received : from by via with id for received_datetime
59
- {
60
- val
61
- }
62
-
63
- from : /* none */
64
- | FROM received_domain
65
- {
66
- val[1]
67
- }
68
-
69
- by : /* none */
70
- | BY received_domain
71
- {
72
- val[1]
73
- }
74
-
75
- received_domain
76
- : domain
77
- {
78
- join_domain(val[0])
79
- }
80
- | domain '@' domain
81
- {
82
- join_domain(val[2])
83
- }
84
- | domain DOMLIT
85
- {
86
- join_domain(val[0])
87
- }
88
-
89
- via : /* none */
90
- | VIA ATOM
91
- {
92
- val[1]
93
- }
94
-
95
- with : /* none */
96
- {
97
- []
98
- }
99
- | with WITH ATOM
100
- {
101
- val[0].push val[2]
102
- val[0]
103
- }
104
-
105
- id : /* none */
106
- | ID msgid
107
- {
108
- val[1]
109
- }
110
- | ID ATOM
111
- {
112
- val[1]
113
- }
114
-
115
- for : /* none */
116
- | FOR received_addrspec
117
- {
118
- val[1]
119
- }
120
-
121
- received_addrspec
122
- : routeaddr
123
- {
124
- val[0].spec
125
- }
126
- | spec
127
- {
128
- val[0].spec
129
- }
130
-
131
- received_datetime
132
- : /* none */
133
- | ';' datetime
134
- {
135
- val[1]
136
- }
137
-
138
- addrs_TOP : addrs
139
- | group_bare
140
- | addrs commas group_bare
141
-
142
- addr_TOP : mbox
143
- | group
144
- | group_bare
145
-
146
- retpath : addrs_TOP
147
- | '<' '>' { [ Address.new(nil, nil) ] }
148
-
149
- addrs : addr { val }
150
- | addrs commas addr { val[0].push val[2]; val[0] }
151
-
152
- addr : mbox
153
- | group
154
-
155
- mboxes : mbox
156
- {
157
- val
158
- }
159
- | mboxes commas mbox
160
- {
161
- val[0].push val[2]
162
- val[0]
163
- }
164
-
165
- mbox : spec
166
- | routeaddr
167
- | addr_phrase routeaddr
168
- {
169
- val[1].phrase = Decoder.decode(val[0])
170
- val[1]
171
- }
172
-
173
- group : group_bare ';'
174
-
175
- group_bare: addr_phrase ':' mboxes
176
- {
177
- AddressGroup.new(val[0], val[2])
178
- }
179
- | addr_phrase ':' { AddressGroup.new(val[0], []) }
180
-
181
- addr_phrase
182
- : local_head { val[0].join('.') }
183
- | addr_phrase local_head { val[0] << ' ' << val[1].join('.') }
184
-
185
- routeaddr : '<' routes spec '>'
186
- {
187
- val[2].routes.replace val[1]
188
- val[2]
189
- }
190
- | '<' spec '>'
191
- {
192
- val[1]
193
- }
194
-
195
- routes : at_domains ':'
196
-
197
- at_domains: '@' domain { [ val[1].join('.') ] }
198
- | at_domains ',' '@' domain { val[0].push val[3].join('.'); val[0] }
199
-
200
- spec : local '@' domain { Address.new( val[0], val[2] ) }
201
- | local { Address.new( val[0], nil ) }
202
-
203
- local: local_head
204
- | local_head '.' { val[0].push ''; val[0] }
205
-
206
- local_head: word
207
- { val }
208
- | local_head dots word
209
- {
210
- val[1].times do
211
- val[0].push ''
212
- end
213
- val[0].push val[2]
214
- val[0]
215
- }
216
-
217
- domain : domword
218
- { val }
219
- | domain dots domword
220
- {
221
- val[1].times do
222
- val[0].push ''
223
- end
224
- val[0].push val[2]
225
- val[0]
226
- }
227
-
228
- dots : '.' { 0 }
229
- | '.' '.' { 1 }
230
-
231
- word : atom
232
- | QUOTED
233
- | DIGIT
234
-
235
- domword : atom
236
- | DOMLIT
237
- | DIGIT
238
-
239
- commas : ','
240
- | commas ','
241
-
242
- msgid : '<' spec '>'
243
- {
244
- val[1] = val[1].spec
245
- val.join('')
246
- }
247
-
248
- keys : phrase { val }
249
- | keys ',' phrase { val[0].push val[2]; val[0] }
250
-
251
- phrase : word
252
- | phrase word { val[0] << ' ' << val[1] }
253
-
254
- enc : word
255
- {
256
- val.push nil
257
- val
258
- }
259
- | word word
260
- {
261
- val
262
- }
263
-
264
- version : DIGIT '.' DIGIT
265
- {
266
- [ val[0].to_i, val[2].to_i ]
267
- }
268
-
269
- ctype : TOKEN '/' TOKEN params opt_semicolon
270
- {
271
- [ val[0].downcase, val[2].downcase, decode_params(val[3]) ]
272
- }
273
- | TOKEN params opt_semicolon
274
- {
275
- [ val[0].downcase, nil, decode_params(val[1]) ]
276
- }
277
-
278
- params : /* none */
279
- {
280
- {}
281
- }
282
- | params ';' TOKEN '=' value
283
- {
284
- val[0][ val[2].downcase ] = val[4]
285
- val[0]
286
- }
287
-
288
- value : TOKEN
289
- | QUOTED
290
-
291
- cencode : TOKEN
292
- {
293
- val[0].downcase
294
- }
295
-
296
- cdisp : TOKEN params opt_semicolon
297
- {
298
- [ val[0].downcase, decode_params(val[1]) ]
299
- }
300
-
301
- opt_semicolon
302
- :
303
- | ';'
304
-
305
- atom : ATOM
306
- | FROM
307
- | BY
308
- | VIA
309
- | WITH
310
- | ID
311
- | FOR
312
-
313
- end
314
-
315
-
316
- ---- header
317
- #
318
- # parser.rb
319
- #
320
- # Copyright (c) 1998-2004 Minero Aoki
321
- #
322
- # This program is free software.
323
- # You can distribute/modify this program under the terms of
324
- # the GNU Lesser General Public License version 2.1.
325
- #
326
-
327
- require 'tmail/scanner'
328
- require 'tmail/textutils'
329
-
330
- ---- inner
331
-
332
- include TextUtils
333
-
334
- def self.parse( ident, str, cmt = nil )
335
- new.parse(ident, str, cmt)
336
- end
337
-
338
- MAILP_DEBUG = false
339
-
340
- def initialize
341
- self.debug = MAILP_DEBUG
342
- end
343
-
344
- def debug=( flag )
345
- @yydebug = flag && Racc_debug_parser
346
- @scanner_debug = flag
347
- end
348
-
349
- def debug
350
- @yydebug
351
- end
352
-
353
- def parse( ident, str, comments = nil )
354
- @scanner = Scanner.new(str, ident, comments)
355
- @scanner.debug = @scanner_debug
356
- @first = [ident, ident]
357
- result = yyparse(self, :parse_in)
358
- comments.map! {|c| to_kcode(c) } if comments
359
- result
360
- end
361
-
362
- private
363
-
364
- def parse_in( &block )
365
- yield @first
366
- @scanner.scan(&block)
367
- end
368
-
369
- def on_error( t, val, vstack )
370
- raise SyntaxError, "parse error on token #{racc_token2str t}"
371
- end
372
-
data/vendor/tmail/port.rb DELETED
@@ -1,356 +0,0 @@
1
- #
2
- # port.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/stringio'
12
-
13
- module TMail
14
-
15
- class Port
16
- def reproducible?
17
- false
18
- end
19
- end
20
-
21
-
22
- ###
23
- ### FilePort
24
- ###
25
-
26
- class FilePort < Port
27
-
28
- def initialize(fname)
29
- @path = File.expand_path(fname)
30
- super()
31
- end
32
-
33
- attr_reader :path
34
- alias filename path
35
-
36
- alias ident path
37
-
38
- def ==(other)
39
- other.respond_to?(:path) and @path == other.path
40
- end
41
-
42
- alias eql? ==
43
-
44
- def hash
45
- @path.hash
46
- end
47
-
48
- def inspect
49
- "#<#{self.class} #{@path}>"
50
- end
51
-
52
- def reproducible?
53
- true
54
- end
55
-
56
- def size
57
- File.size(@path)
58
- end
59
-
60
-
61
- def ropen(&block)
62
- File.open(@path, &block)
63
- end
64
-
65
- def wopen(&block)
66
- File.open(@path, 'w', &block)
67
- end
68
-
69
- def aopen(&block)
70
- File.open(@path, 'a', &block)
71
- end
72
-
73
-
74
- def read_all
75
- ropen {|f|
76
- return f.read
77
- }
78
- end
79
-
80
-
81
- def remove
82
- File.unlink @path
83
- end
84
-
85
- def move_to(port)
86
- begin
87
- File.link @path, port.path
88
- rescue Errno::EXDEV
89
- copy_to port
90
- end
91
- File.unlink @path
92
- end
93
-
94
- alias mv move_to
95
-
96
- def copy_to(port)
97
- if port.is_a?(FilePort)
98
- copy_file @path, port.path
99
- else
100
- File.open(@path) {|r|
101
- port.wopen {|w|
102
- while s = r.sysread(4096)
103
- w.write << s
104
- end
105
- }
106
- }
107
- end
108
- end
109
-
110
- alias cp copy_to
111
-
112
- private
113
-
114
- def copy_file(src, dest)
115
- File.open(src, 'rb') {|r|
116
- File.open(dest, 'wb') {|w|
117
- while str = r.read(2048)
118
- w.write str
119
- end
120
- }
121
- }
122
- end
123
-
124
- end
125
-
126
-
127
- module MailFlags
128
-
129
- def seen=(b)
130
- set_status 'S', b
131
- end
132
-
133
- def seen?
134
- get_status 'S'
135
- end
136
-
137
- def replied=(b)
138
- set_status 'R', b
139
- end
140
-
141
- def replied?
142
- get_status 'R'
143
- end
144
-
145
- def flagged=(b)
146
- set_status 'F', b
147
- end
148
-
149
- def flagged?
150
- get_status 'F'
151
- end
152
-
153
- private
154
-
155
- def procinfostr(str, tag, true_p)
156
- a = str.upcase.split(//)
157
- a.push true_p ? tag : nil
158
- a.delete tag unless true_p
159
- a.compact.sort.join('').squeeze
160
- end
161
-
162
- end
163
-
164
-
165
- class MhPort < FilePort
166
-
167
- include MailFlags
168
-
169
- private
170
-
171
- def set_status(tag, flag)
172
- begin
173
- tmpfile = "#{@path}.tmailtmp.#{$$}"
174
- File.open(tmpfile, 'w') {|f|
175
- write_status f, tag, flag
176
- }
177
- File.unlink @path
178
- File.link tmpfile, @path
179
- ensure
180
- File.unlink tmpfile
181
- end
182
- end
183
-
184
- def write_status(f, tag, flag)
185
- stat = ''
186
- File.open(@path) {|r|
187
- while line = r.gets
188
- if line.strip.empty?
189
- break
190
- elsif m = /\AX-TMail-Status:/i.match(line)
191
- stat = m.post_match.strip
192
- else
193
- f.print line
194
- end
195
- end
196
-
197
- s = procinfostr(stat, tag, flag)
198
- f.puts 'X-TMail-Status: ' + s unless s.empty?
199
- f.puts
200
-
201
- while s = r.read(2048)
202
- f.write s
203
- end
204
- }
205
- end
206
-
207
- def get_status(tag)
208
- File.foreach(@path) {|line|
209
- return false if line.strip.empty?
210
- if m = /\AX-TMail-Status:/i.match(line)
211
- return m.post_match.strip.include?(tag[0])
212
- end
213
- }
214
- false
215
- end
216
-
217
- end
218
-
219
-
220
- class MaildirPort < FilePort
221
-
222
- def move_to_new
223
- new = replace_dir(@path, 'new')
224
- File.rename @path, new
225
- @path = new
226
- end
227
-
228
- def move_to_cur
229
- new = replace_dir(@path, 'cur')
230
- File.rename @path, new
231
- @path = new
232
- end
233
-
234
- def replace_dir(path, dir)
235
- "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}"
236
- end
237
- private :replace_dir
238
-
239
-
240
- include MailFlags
241
-
242
- private
243
-
244
- MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/
245
-
246
- def set_status(tag, flag)
247
- if m = MAIL_FILE.match(File.basename(@path))
248
- s, uniq, type, info, = m.to_a
249
- return if type and type != '2' # do not change anything
250
- newname = File.dirname(@path) + '/' +
251
- uniq + ':2,' + procinfostr(info.to_s, tag, flag)
252
- else
253
- newname = @path + ':2,' + tag
254
- end
255
-
256
- File.link @path, newname
257
- File.unlink @path
258
- @path = newname
259
- end
260
-
261
- def get_status(tag)
262
- m = MAIL_FILE.match(File.basename(@path)) or return false
263
- m[2] == '2' and m[3].to_s.include?(tag[0])
264
- end
265
-
266
- end
267
-
268
-
269
- ###
270
- ### StringPort
271
- ###
272
-
273
- class StringPort < Port
274
-
275
- def initialize(str = '')
276
- @buffer = str
277
- super()
278
- end
279
-
280
- def string
281
- @buffer
282
- end
283
-
284
- def to_s
285
- @buffer.dup
286
- end
287
-
288
- alias read_all to_s
289
-
290
- def size
291
- @buffer.size
292
- end
293
-
294
- def ==(other)
295
- other.is_a?(StringPort) and @buffer.equal?(other.string)
296
- end
297
-
298
- alias eql? ==
299
-
300
- def hash
301
- @buffer.object_id.hash
302
- end
303
-
304
- def inspect
305
- "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>"
306
- end
307
-
308
- def reproducible?
309
- true
310
- end
311
-
312
- def ropen(&block)
313
- # FIXME: Should we raise ENOENT?
314
- raise Errno::ENOENT, "#{inspect} is already removed" unless @buffer
315
- StringInput.open(@buffer, &block)
316
- end
317
-
318
- def wopen(&block)
319
- @buffer = ''
320
- StringOutput.new(@buffer, &block)
321
- end
322
-
323
- def aopen(&block)
324
- @buffer ||= ''
325
- StringOutput.new(@buffer, &block)
326
- end
327
-
328
- def remove
329
- @buffer = nil
330
- end
331
-
332
- alias rm remove
333
-
334
- def copy_to(port)
335
- port.wopen {|f|
336
- f.write @buffer
337
- }
338
- end
339
-
340
- alias cp copy_to
341
-
342
- def move_to(port)
343
- if port.is_a?(StringPort)
344
- tmp = @buffer
345
- port.instance_eval {
346
- @buffer = tmp
347
- }
348
- else
349
- copy_to port
350
- end
351
- remove
352
- end
353
-
354
- end
355
-
356
- end # module TMail