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.
- data/lib/internet_message/address.rb +35 -0
- data/lib/internet_message/content_attribute.rb +54 -0
- data/lib/internet_message/content_disposition.rb +37 -0
- data/lib/internet_message/content_type.rb +38 -0
- data/lib/internet_message/group.rb +49 -0
- data/lib/internet_message/header_field.rb +129 -0
- data/lib/internet_message/mailbox.rb +102 -0
- data/lib/internet_message/message_id.rb +47 -0
- data/lib/internet_message/received.rb +59 -0
- data/lib/internet_message/tokenizer.rb +61 -0
- data/lib/internet_message.rb +457 -0
- data/spec/internet_message/address_spec.rb +34 -0
- data/spec/internet_message/group_spec.rb +60 -0
- data/spec/internet_message/mailbox_spec.rb +138 -0
- data/spec/internet_message/received_spec.rb +49 -0
- data/spec/internet_message/tokenizer_spec.rb +59 -0
- data/spec/internet_message_spec.rb +573 -0
- metadata +74 -0
|
@@ -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
|