internet_message 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.
@@ -0,0 +1,49 @@
1
+ require __FILE__.sub(/\/spec\//, '/lib/').sub(/_spec\.rb\z/,'')
2
+
3
+ describe 'InternetMessage::Received.parse' do
4
+ subject{InternetMessage::Received.parse(src)}
5
+ context 'with normal value' do
6
+ let(:src){<<EOS}
7
+ from smtp.example.com (localhost [127.0.0.1])
8
+ by smtp.example.net (Postfix) with ESMTP id 0ECC2108362
9
+ for <tommy@example.net>; Thu, 1 Feb 2007 02:05:10 +0900 (JST)
10
+ EOS
11
+ it 'return InternetMessage::Received' do
12
+ subject.from.should == 'smtp.example.com'
13
+ subject.by.should == 'smtp.example.net'
14
+ subject.via.should be_nil
15
+ subject.with.should == 'ESMTP'
16
+ subject.id.should == '0ECC2108362'
17
+ subject.for.should == InternetMessage::Address.new('tommy', 'example.net')
18
+ subject.date.should == DateTime.new(2007,2,1,2,5,10,'+0900')
19
+ end
20
+ end
21
+ context 'with invalid "by"' do
22
+ let(:src){'from 223.128.78.240 by ; Wed, 31 Jan 2007 17:57:43 +0100'}
23
+ it 'return InternetMessage::Received' do
24
+ subject.from.should == '223.128.78.240'
25
+ subject.by.should == nil
26
+ subject.via.should be_nil
27
+ subject.with.should == nil
28
+ subject.id.should == nil
29
+ subject.for.should == nil
30
+ subject.date.should == DateTime.new(2007,1,31,17,57,43,'+0100')
31
+ end
32
+ end
33
+ context 'with invalid "for", "date"' do
34
+ let(:src){<<EOS}
35
+ from Infomarks Corporation (http://www.infomarks.co.jp/)
36
+ by version 2.0.1.a with id UCT00000
37
+ for <5-subscribers>;
38
+ EOS
39
+ it 'return InternetMessage::Received' do
40
+ subject.from.should == 'Infomarks'
41
+ subject.by.should == 'version'
42
+ subject.via.should be_nil
43
+ subject.with.should == 'id'
44
+ subject.id.should == nil
45
+ subject.for.should == nil
46
+ subject.date.should == nil
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,59 @@
1
+ require __FILE__.sub(/\/spec\//, '/lib/').sub(/_spec\.rb\z/,'')
2
+
3
+ describe InternetMessage::Tokenizer do
4
+ subject{InternetMessage::Tokenizer.new(src)}
5
+ describe '#tokenize' do
6
+ def token(type, value)
7
+ InternetMessage::Token.new(type, value)
8
+ end
9
+
10
+ let(:src){' "hoge\"fuga\\\\hero" < hoge.fuga@ example.com(a)> (foo(bar)) '}
11
+ it 'returns Array of Token' do
12
+ ret = subject.tokenize
13
+ ret.shift.should == token(:WSP, ' ')
14
+ ret.shift.should == token(:QUOTED, 'hoge"fuga\\hero')
15
+ ret.shift.should == token(:WSP, ' ')
16
+ ret.shift.should == token(:CHAR, '<')
17
+ ret.shift.should == token(:WSP, ' ')
18
+ ret.shift.should == token(:TOKEN, 'hoge.fuga')
19
+ ret.shift.should == token(:CHAR, '@')
20
+ ret.shift.should == token(:WSP, ' ')
21
+ ret.shift.should == token(:TOKEN, 'example.com')
22
+ ret.shift.should == token(:COMMENT, ['a'])
23
+ ret.shift.should == token(:CHAR, '>')
24
+ ret.shift.should == token(:WSP, ' ')
25
+ ret.shift.should == token(:COMMENT, ['foo', ['bar']])
26
+ ret.shift.should == token(:WSP, ' ')
27
+ end
28
+ end
29
+
30
+ describe '#scan_comment' do
31
+ context 'with one level comment' do
32
+ let(:src){'(hoge fuga)'}
33
+ it 'return comment string' do
34
+ subject.scan_comment.should == ['hoge fuga']
35
+ end
36
+ end
37
+
38
+ context 'with "\)"' do
39
+ let(:src){'(hoge\))'}
40
+ it 'treat as not special char' do
41
+ subject.scan_comment.should == ['hoge)']
42
+ end
43
+ end
44
+
45
+ context 'with nested comment' do
46
+ let(:src){'(hoge (fuga (hage) moge) )'}
47
+ it 'return comment string' do
48
+ subject.scan_comment.should == ['hoge ', ['fuga ', ['hage'], ' moge'], ' ']
49
+ end
50
+ end
51
+
52
+ context 'with unclosed comment' do
53
+ let(:src){'(hoge (fuga)'}
54
+ it 'return comment' do
55
+ subject.scan_comment.should == ['hoge ', ['fuga']]
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,573 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "#{File.dirname __FILE__}/../lib/internet_message"
3
+
4
+ describe 'InternetMessage' do
5
+ subject{InternetMessage.new(src)}
6
+ context 'with simple message' do
7
+ let(:src){<<EOS}
8
+ Return-Path: <hoge@example.com>
9
+ Received: from example.net (localhost) by example.com
10
+ with SMTP id HOGEHOGE; Tue, 6 Sep 2011 19:49:44 +0900
11
+ Received: from example.org (localhost) by example.net
12
+ with SMTP id FUGAFUGA; Tue, 6 Sep 2011 19:49:43 +0900
13
+ Resent-Date: Tue, 6 Sep 2011 19:49:42 +0900
14
+ Resent-From: hoge@example.com
15
+ Resent-Sender: fuga@example.net
16
+ Resent-To: test@example.jp, test2@example.test
17
+ Resent-Cc: test3@example.net
18
+ Resent-Bcc:test4@example.org
19
+ Resent-Message-Id: <hoge.fuga@example.com>
20
+ From: TOMITA Masahiro <tommy@tmtm.org>
21
+ Sender: TOMITA Masahiro <tommy@tmtm.org>
22
+ Reply-To: hogehogera <hoge@example.com>, fugafuga <fuga@example.com>
23
+ To: hogehogera <hoge@example.com>, fugafuga <fuga@example.com>
24
+ Cc: fugafuga <fuga@example.com>
25
+ Bcc: fugafuga <fuga@example.com>
26
+ Subject: test
27
+ Content-Type: Text/Plain; charset=UTF-8
28
+ Date: Sun, 4 Sep 2011 23:14:45 +0900 (JST)
29
+ Message-Id: <20101203223001.5C9523E3A70@note.tmtm.org>
30
+ In-Reply-To: <a.b@example.net> <c.d@example.com>
31
+ References: <a.b@example.net> <c.d@example.com>
32
+ Comments: This is comment message.
33
+ Keywords: hoge, fuga, foo, bar
34
+ Mime-Version: 1.0
35
+ Content-Transfer-Encoding: 7bit
36
+ Content-Id: <a.b@example.com>
37
+ Content-Description: Description of Contents
38
+ Content-Disposition: inline; filename="hoge.txt"
39
+
40
+ body test
41
+ EOS
42
+ it '#fields is Array of HeaderFields' do
43
+ subject.fields.map(&:name).should == [
44
+ 'return-path',
45
+ 'received',
46
+ 'received',
47
+ 'resent-date',
48
+ 'resent-from',
49
+ 'resent-sender',
50
+ 'resent-to',
51
+ 'resent-cc',
52
+ 'resent-bcc',
53
+ 'resent-message-id',
54
+ 'from',
55
+ 'sender',
56
+ 'reply-to',
57
+ 'to',
58
+ 'cc',
59
+ 'bcc',
60
+ 'subject',
61
+ 'content-type',
62
+ 'date',
63
+ 'message-id',
64
+ 'in-reply-to',
65
+ 'references',
66
+ 'comments',
67
+ 'keywords',
68
+ 'mime-version',
69
+ 'content-transfer-encoding',
70
+ 'content-id',
71
+ 'content-description',
72
+ 'content-disposition',
73
+ ]
74
+ end
75
+ it '#date returns DateTime' do
76
+ subject.date.should == DateTime.new(2011, 9, 4, 23, 14, 45, '+0900')
77
+ end
78
+ it '#from returns InternetMessage::Mailbox' do
79
+ subject.from.should == InternetMessage::Mailbox.new('tommy', 'tmtm.org', 'TOMITA Masahiro')
80
+ end
81
+ it '#sender returns InternetMessage::Mailbox' do
82
+ subject.sender.should == InternetMessage::Mailbox.new('tommy', 'tmtm.org', 'TOMITA Masahiro')
83
+ end
84
+ it '#reply_to returns Array of InternetMessage::Mailbox' do
85
+ subject.reply_to.should be_kind_of Array
86
+ subject.reply_to.size.should == 2
87
+ subject.reply_to.each{|a| a.should be_kind_of InternetMessage::Mailbox}
88
+ end
89
+ it '#to returns Array of InternetMessage::Mailbox' do
90
+ subject.to.should be_kind_of Array
91
+ subject.to.size.should == 2
92
+ subject.to.each{|a| a.should be_kind_of InternetMessage::Mailbox}
93
+ end
94
+ it '#cc returns Array of InternetMessage::Mailbox' do
95
+ subject.cc.should be_kind_of Array
96
+ subject.cc.size.should == 1
97
+ subject.cc.each{|a| a.should be_kind_of InternetMessage::Mailbox}
98
+ end
99
+ it '#bcc returns Array of InternetMessage::Mailbox' do
100
+ subject.bcc.should be_kind_of Array
101
+ subject.bcc.size.should == 1
102
+ subject.bcc.each{|a| a.should be_kind_of InternetMessage::Mailbox}
103
+ end
104
+ it '#message_id returns InternetMessage::MessageId' do
105
+ subject.message_id.should == InternetMessage::MessageId.new('20101203223001.5C9523E3A70@note.tmtm.org')
106
+ end
107
+ it '#in_reply_to returns Array of InternetMessage::MessageId' do
108
+ subject.in_reply_to.should == [
109
+ InternetMessage::MessageId.new('a.b@example.net'),
110
+ InternetMessage::MessageId.new('c.d@example.com')
111
+ ]
112
+ end
113
+ it '#references returns Array of InternetMessage::MessageId' do
114
+ subject.references.should == [
115
+ InternetMessage::MessageId.new('a.b@example.net'),
116
+ InternetMessage::MessageId.new('c.d@example.com')
117
+ ]
118
+ end
119
+ it '#subject returns String' do
120
+ subject.subject.should == 'test'
121
+ end
122
+ it '#comments returns Array of String' do
123
+ subject.comments.should == ['This is comment message.']
124
+ end
125
+ it '#keywords returns Array of String' do
126
+ subject.keywords.should == ['hoge', 'fuga', 'foo', 'bar']
127
+ end
128
+ it '#resent_date returns Resent-Date in latest trace block as DateTime' do
129
+ subject.resent_date.should == DateTime.new(2011, 9, 6, 19, 49, 42, '+0900')
130
+ end
131
+ it '#resent_from returns Resent-From in latest trace block as InternetMessage::Mailbox' do
132
+ subject.resent_from.should == InternetMessage::Mailbox.new('hoge', 'example.com')
133
+ end
134
+ it '#resent_sender returns Resent-Sender in latest trace block as InternetMessage::Mailbox' do
135
+ subject.resent_sender.should == InternetMessage::Mailbox.new('fuga', 'example.net')
136
+ end
137
+ it '#resent_to returns Resent-To in latest trace block as InternetMessage::Mailbox' do
138
+ subject.resent_to.should be_kind_of Array
139
+ subject.resent_to.size.should == 2
140
+ subject.resent_to.each{|a| a.should be_kind_of InternetMessage::Mailbox}
141
+ end
142
+ it '#resent_cc returns Resent-Cc in latest trace block as InternetMessage::Mailbox' do
143
+ subject.resent_cc.should be_kind_of Array
144
+ subject.resent_cc.size.should == 1
145
+ subject.resent_cc.each{|a| a.should be_kind_of InternetMessage::Mailbox}
146
+ end
147
+ it '#resent_bcc returns Resent-Bcc in latest trace block as InternetMessage::Mailbox' do
148
+ subject.resent_bcc.should be_kind_of Array
149
+ subject.resent_bcc.size.should == 1
150
+ subject.resent_bcc.each{|a| a.should be_kind_of InternetMessage::Mailbox}
151
+ end
152
+ it '#resent_message_id returns Resent-Message-Id in latest trace block as InternetMessage::MessageId' do
153
+ subject.resent_message_id.should == InternetMessage::MessageId.new('hoge.fuga@example.com')
154
+ end
155
+ it '#return_path returns Return-Path in latest trace block as InernetMessage::Address' do
156
+ subject.return_path.should == InternetMessage::Address.new('hoge', 'example.com')
157
+ end
158
+ it '#received return Received in latest trace block as Array of InternetMessage::Received' do
159
+ subject.received.should be_kind_of Array
160
+ subject.received.size.should == 2
161
+ subject.received.each{|a| a.should be_kind_of InternetMessage::Received}
162
+ end
163
+ it '#mime_version returns String' do
164
+ subject.mime_version.should == '1.0'
165
+ end
166
+ it '#content_type returns ContentType' do
167
+ subject.content_type.should == InternetMessage::ContentType.new('text', 'plain', 'charset'=>'UTF-8')
168
+ end
169
+ it '#content_transfer_encoding returns String' do
170
+ subject.content_transfer_encoding.should == '7bit'
171
+ end
172
+ it '#content_id returns Content-Id as InternetMessage::MessageId' do
173
+ subject.content_id.should == InternetMessage::MessageId.new('a.b@example.com')
174
+ end
175
+ it '#content_description returns String' do
176
+ subject.content_description.should == 'Description of Contents'
177
+ end
178
+ it '#content_disposition return ContentDisposition' do
179
+ subject.content_disposition.should == InternetMessage::ContentDisposition.new('inline', 'filename'=>'hoge.txt')
180
+ end
181
+ it '#type returns String' do
182
+ subject.type.should == 'text'
183
+ end
184
+ it '#subtype returns String' do
185
+ subject.subtype.should == 'plain'
186
+ end
187
+ it '#charset returns String' do
188
+ subject.charset.should == 'UTF-8'
189
+ end
190
+ it '#body returns String' do
191
+ subject.body.should == "body test\n"
192
+ subject.body.encoding.should == Encoding::UTF_8
193
+ end
194
+ it '#preamble returns nil' do
195
+ subject.preamble.should == nil
196
+ end
197
+ it '#epilogue returns nil' do
198
+ subject.epilogue.should == nil
199
+ end
200
+ it '#parts returns []' do
201
+ subject.parts.should == []
202
+ end
203
+ it '#message returns nil' do
204
+ subject.message.should == nil
205
+ end
206
+ end
207
+
208
+ context 'with empty field value' do
209
+ let(:src){<<EOS}
210
+ Return-Path:
211
+ Received:
212
+ Received:
213
+ Resent-Date:
214
+ Resent-From:
215
+ Resent-Sender:
216
+ Resent-To:
217
+ Resent-Cc:
218
+ Resent-Bcc:
219
+ Resent-Message-Id:
220
+ From:
221
+ Sender:
222
+ Reply-To:
223
+ To:
224
+ Cc:
225
+ Bcc:
226
+ Subject:
227
+ Content-Type:
228
+ Date:
229
+ Message-Id:
230
+ In-Reply-To:
231
+ References:
232
+ Comments:
233
+ Keywords:
234
+ Mime-Version:
235
+ Content-Transfer-Encoding:
236
+ Content-Id:
237
+ Content-Description:
238
+ Content-Disposition:
239
+
240
+ body test
241
+ EOS
242
+ its(:date){should be_nil}
243
+ its(:from){should be_nil}
244
+ its(:sender){should be_nil}
245
+ its(:reply_to){should == []}
246
+ its(:to){should == []}
247
+ its(:cc){should == []}
248
+ its(:bcc){should == []}
249
+ its(:message_id){should be_nil}
250
+ its(:in_reply_to){should == []}
251
+ its(:references){should == []}
252
+ its(:subject){should == ''}
253
+ its(:comments){should == ['']}
254
+ its(:keywords){should == []}
255
+ its(:resent_date){should be_nil}
256
+ its(:resent_from){should be_nil}
257
+ its(:resent_sender){should be_nil}
258
+ its(:resent_to){should == []}
259
+ its(:resent_cc){should == []}
260
+ its(:resent_bcc){should == []}
261
+ its(:resent_message_id){should be_nil}
262
+ its(:return_path){should be_nil}
263
+ its(:received){should == []}
264
+ its(:mime_version){should be_nil}
265
+ its(:content_type){should be_nil}
266
+ its(:content_transfer_encoding){should be_nil}
267
+ its(:content_id){should == nil}
268
+ its(:content_description){should == ''}
269
+ its(:content_disposition){should be_nil}
270
+ its(:type){should == 'text'}
271
+ its(:subtype){should == 'plain'}
272
+ its(:charset){should == 'us-ascii'}
273
+ its(:body){should == "body test\n"}
274
+ its(:preamble){should be_nil}
275
+ its(:epilogue){should be_nil}
276
+ its(:parts){should == []}
277
+ its(:message){should be_nil}
278
+ end
279
+
280
+ context 'with empty header' do
281
+ let(:src){<<EOS}
282
+
283
+ body test
284
+ EOS
285
+ its(:date){should be_nil}
286
+ its(:from){should be_nil}
287
+ its(:sender){should be_nil}
288
+ its(:reply_to){should == []}
289
+ its(:to){should == []}
290
+ its(:cc){should == []}
291
+ its(:bcc){should == []}
292
+ its(:message_id){should be_nil}
293
+ its(:in_reply_to){should == []}
294
+ its(:references){should == []}
295
+ its(:subject){should be_nil}
296
+ its(:comments){should == []}
297
+ its(:keywords){should == []}
298
+ its(:resent_date){should be_nil}
299
+ its(:resent_from){should be_nil}
300
+ its(:resent_sender){should be_nil}
301
+ its(:resent_to){should == []}
302
+ its(:resent_cc){should == []}
303
+ its(:resent_bcc){should == []}
304
+ its(:resent_message_id){should be_nil}
305
+ its(:return_path){should be_nil}
306
+ its(:received){should == []}
307
+ its(:mime_version){should be_nil}
308
+ its(:content_type){should be_nil}
309
+ its(:content_transfer_encoding){should be_nil}
310
+ its(:content_id){should == nil}
311
+ its(:content_description){should be_nil}
312
+ its(:content_disposition){should be_nil}
313
+ its(:type){should == 'text'}
314
+ its(:subtype){should == 'plain'}
315
+ its(:charset){should == 'us-ascii'}
316
+ its(:body){should == "body test\n"}
317
+ its(:preamble){should be_nil}
318
+ its(:epilogue){should be_nil}
319
+ its(:parts){should == []}
320
+ its(:message){should be_nil}
321
+ end
322
+
323
+ context 'with multipart message' do
324
+ let(:src){<<EOS}
325
+ Content-Type: Multipart/Mixed; Boundary="abcdefgABCDEFG"
326
+
327
+ this is preamble.
328
+ --abcdefgABCDEFG
329
+ Content-Type: text/plain
330
+
331
+ body1
332
+ --abcdefgABCDEFG
333
+ Content-Type: text/plain
334
+
335
+ body2
336
+
337
+ --abcdefgABCDEFG--
338
+ this is epilogue.
339
+ EOS
340
+ it '#preamble returns preamble as String' do
341
+ subject.preamble.should == 'this is preamble.'
342
+ end
343
+ it '#epilogue returns epilogue as String' do
344
+ subject.epilogue.should == "this is epilogue.\n"
345
+ end
346
+ it '#parts returns Array of InternetMessage' do
347
+ subject.parts.size.should == 2
348
+ subject.parts[0].body.should == 'body1'
349
+ subject.parts[1].body.should == "body2\n"
350
+ end
351
+ end
352
+
353
+ context 'with base64 encoding' do
354
+ let(:src){<<EOS}
355
+ Content-Transfer-Encoding: Base64
356
+
357
+ MDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla
358
+ EOS
359
+ it '#body returns decoded body' do
360
+ subject.body.should == '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
361
+ end
362
+ end
363
+
364
+ context 'with quoted-printable encoding' do
365
+ let(:src){<<EOS}
366
+ Content-Transfer-Encoding: Quoted-Printable
367
+
368
+ 0123456789=
369
+ ABCDEFGHIJKLMNO=
370
+ =50=51=52=53=54=55=56=57=58=59=5A=
371
+ EOS
372
+ it '#body returns decoded body' do
373
+ subject.body.should == '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
374
+ end
375
+ end
376
+
377
+ context 'with :decode_mime_header=>true' do
378
+ subject{InternetMessage.new(src, :decode_mime_header=>true)}
379
+ context 'for ascii header' do
380
+ let(:src){<<EOS}
381
+ From: TOMITA Masahiro <tommy@tmtm.org>
382
+ To: TOMITA Masahiro <tommy@tmtm.org>
383
+ Subject: test aiueo
384
+ Content-Description: test aiueo
385
+ Comments: test aiueo
386
+ Keywords: abc, def, ghi
387
+ EOS
388
+ it 'parse header' do
389
+ subject.from.display_name.should == 'TOMITA Masahiro'
390
+ subject.to.first.display_name.should == 'TOMITA Masahiro'
391
+ subject.subject.should == 'test aiueo'
392
+ subject.content_description.should == 'test aiueo'
393
+ subject.comments.should == ['test aiueo']
394
+ subject.keywords.should == ['abc', 'def', 'ghi']
395
+ end
396
+ end
397
+ context 'for encoded header' do
398
+ let(:src){<<EOS}
399
+ From: =?ISO-2022-JP?B?GyRCJEgkXyQ/JF4kNSRSJG0bKEI=?= <tommy@tmtm.org>
400
+ To: =?ISO-2022-JP?B?GyRCJEgkXyQ/JF4kNSRSJG0bKEI=?= <tommy@tmtm.org>
401
+ Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIGyhCIBskQiQiJCQkJiQoJCobKEI=?=
402
+ Content-Description: =?ISO-2022-JP?B?GyRCJUYlOSVIGyhCIBskQiQiJCQkJiQoJCobKEI=?=
403
+ Comments: =?ISO-2022-JP?B?GyRCJUYlOSVIGyhCIBskQiQiJCQkJiQoJCobKEI=?=
404
+ Keywords: =?UTF-8?B?44GC?=, =?UTF-8?B?44GE?=, =?UTF-8?B?44GG?=
405
+ EOS
406
+ it 'decode mime header' do
407
+ subject.from.display_name.should == 'とみたまさひろ'
408
+ subject.to.first.display_name.should == 'とみたまさひろ'
409
+ subject.subject.should == 'テスト あいうえお'
410
+ subject.content_description.should == 'テスト あいうえお'
411
+ subject.comments.should == ['テスト あいうえお']
412
+ subject.keywords.should == ['あ', 'い', 'う']
413
+ end
414
+ end
415
+ end
416
+
417
+ context 'with RFC2231' do
418
+ subject{InternetMessage.new(src)}
419
+ context 'splited parameter' do
420
+ let(:src){<<EOS}
421
+ Content-Disposition: attachment;
422
+ filename*0="hoge";
423
+ filename*1="hoge.txt"
424
+ EOS
425
+ it 'parameter is decoded' do
426
+ subject.content_disposition.attribute['filename'].should == 'hogehoge.txt'
427
+ end
428
+ end
429
+ context 'extended parameter' do
430
+ let(:src){<<EOS}
431
+ Content-Disposition: attachment;
432
+ filename*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A
433
+ EOS
434
+ it 'parameter is decoded' do
435
+ subject.content_disposition.attribute['filename'].should == 'This is ***fun***'
436
+ end
437
+ end
438
+ context 'complex parameter' do
439
+ let(:src){<<EOS}
440
+ Content-Type: application/x-stuff;
441
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
442
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
443
+ title*2="isn't it!"
444
+ EOS
445
+ it 'parameter is decoded' do
446
+ subject.content_type.attribute['title'].should == "This is even more ***fun*** isn't it!"
447
+ end
448
+ end
449
+ end
450
+
451
+ context 'with message/* type' do
452
+ let(:src){<<EOS}
453
+ Content-Type: message/rfc822
454
+
455
+ From: TOMITA Masahiro <tommy@tmtm.org>
456
+ Subject: test
457
+
458
+ body
459
+ EOS
460
+ it '.message returns InternetMessage' do
461
+ m = subject.message
462
+ m.from.should == InternetMessage::Mailbox.new('tommy', 'tmtm.org', 'TOMITA Masahiro')
463
+ m.subject.should == 'test'
464
+ m.body.should == "body\n"
465
+ end
466
+ end
467
+ end
468
+
469
+ describe 'InternetMessage.decode_mime_header_str' do
470
+ subject{InternetMessage.decode_mime_header_str(src)}
471
+ context 'with "=?ISO-8859-1?Q?a?="' do
472
+ let(:src){'=?ISO-8859-1?Q?a?='}
473
+ it{should == 'a'}
474
+ end
475
+ context 'with "=?ISO-8859-1?Q?a?= b"' do
476
+ let(:src){'=?ISO-8859-1?Q?a?= b'}
477
+ it{should == 'a b'}
478
+ end
479
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="' do
480
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?='}
481
+ it{should == 'ab'}
482
+ end
483
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="' do
484
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?='}
485
+ it{should == 'ab'}
486
+ end
487
+ context 'with "=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?="' do
488
+ let(:src){"=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?="}
489
+ it{should == 'ab'}
490
+ end
491
+ context 'with "=?ISO-8859-1?Q?a_b?="' do
492
+ let(:src){'=?ISO-8859-1?Q?a_b?='}
493
+ it{should == 'a b'}
494
+ end
495
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="' do
496
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?='}
497
+ it{should == 'a b'}
498
+ end
499
+ end
500
+
501
+ describe 'InternetMessage.decode_mime_header_words' do
502
+ subject{InternetMessage.decode_mime_header_words(InternetMessage::Tokenizer.new(src).tokenize)}
503
+ context 'with "=?ISO-8859-1?Q?a?="' do
504
+ let(:src){'=?ISO-8859-1?Q?a?='}
505
+ it{should == 'a'}
506
+ end
507
+ context 'with "=?ISO-8859-1?Q?a?= b"' do
508
+ let(:src){'=?ISO-8859-1?Q?a?= b'}
509
+ it{should == 'a b'}
510
+ end
511
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="' do
512
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?='}
513
+ it{should == 'ab'}
514
+ end
515
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="' do
516
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?='}
517
+ it{should == 'ab'}
518
+ end
519
+ context 'with "=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?="' do
520
+ let(:src){"=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?="}
521
+ it{should == 'ab'}
522
+ end
523
+ context 'with "=?ISO-8859-1?Q?a_b?="' do
524
+ let(:src){'=?ISO-8859-1?Q?a_b?='}
525
+ it{should == 'a b'}
526
+ end
527
+ context 'with "=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="' do
528
+ let(:src){'=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?='}
529
+ it{should == 'a b'}
530
+ end
531
+ end
532
+
533
+ describe InternetMessage::TraceBlockList do
534
+ let(:return_path){double :name=>'return-path'}
535
+ let(:received){double :name=>'received'}
536
+ let(:resent){double :name=>'resent-from'}
537
+ context 'with one block' do
538
+ before do
539
+ subject.push return_path
540
+ subject.push received
541
+ subject.push received
542
+ subject.push received
543
+ subject.clean
544
+ end
545
+ its('blocks.size'){should == 1}
546
+ its('blocks.first'){should == [return_path, received, received, received]}
547
+ end
548
+ context 'with many block' do
549
+ before do
550
+ subject.push return_path
551
+ subject.push received
552
+ subject.push return_path
553
+ subject.push received
554
+ subject.push received
555
+ subject.clean
556
+ end
557
+ its('blocks.size'){should == 2}
558
+ it{subject.blocks.first.should == [return_path, received]}
559
+ it{subject.blocks[1].should == [return_path, received, received]}
560
+ end
561
+ context 'with many block without Return-Path' do
562
+ before do
563
+ subject.push received
564
+ subject.push resent
565
+ subject.push received
566
+ subject.push received
567
+ subject.clean
568
+ end
569
+ its('blocks.size'){should == 2}
570
+ it{subject.blocks.first.should == [received, resent]}
571
+ it{subject.blocks[1].should == [received, received]}
572
+ end
573
+ end