sisimai 4.24.1-java → 4.25.0-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sisimai might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/ANALYTICAL-PRECISION +16 -25
- data/ChangeLog.md +41 -0
- data/Developers.mk +2 -2
- data/README-JA.md +13 -13
- data/README.md +13 -13
- data/lib/sisimai.rb +3 -7
- data/lib/sisimai/address.rb +25 -41
- data/lib/sisimai/arf.rb +58 -59
- data/lib/sisimai/bite.rb +0 -1
- data/lib/sisimai/bite/email.rb +7 -7
- data/lib/sisimai/bite/email/activehunter.rb +4 -3
- data/lib/sisimai/bite/email/amavis.rb +133 -0
- data/lib/sisimai/bite/email/amazonses.rb +53 -87
- data/lib/sisimai/bite/email/amazonworkmail.rb +51 -57
- data/lib/sisimai/bite/email/aol.rb +50 -76
- data/lib/sisimai/bite/email/apachejames.rb +2 -2
- data/lib/sisimai/bite/email/bigfoot.rb +47 -74
- data/lib/sisimai/bite/email/biglobe.rb +8 -9
- data/lib/sisimai/bite/email/courier.rb +56 -101
- data/lib/sisimai/bite/email/domino.rb +7 -8
- data/lib/sisimai/bite/email/einsundeins.rb +4 -5
- data/lib/sisimai/bite/email/exchange2003.rb +21 -22
- data/lib/sisimai/bite/email/exchange2007.rb +26 -28
- data/lib/sisimai/bite/email/exim.rb +48 -47
- data/lib/sisimai/bite/email/ezweb.rb +24 -36
- data/lib/sisimai/bite/email/facebook.rb +54 -79
- data/lib/sisimai/bite/email/fml.rb +10 -10
- data/lib/sisimai/bite/email/gmx.rb +6 -6
- data/lib/sisimai/bite/email/google.rb +12 -13
- data/lib/sisimai/bite/email/gsuite.rb +80 -108
- data/lib/sisimai/bite/email/imailserver.rb +16 -16
- data/lib/sisimai/bite/email/interscanmss.rb +4 -6
- data/lib/sisimai/bite/email/kddi.rb +9 -11
- data/lib/sisimai/bite/email/mailfoundry.rb +2 -2
- data/lib/sisimai/bite/email/mailmarshalsmtp.rb +2 -2
- data/lib/sisimai/bite/email/mailru.rb +12 -13
- data/lib/sisimai/bite/email/mcafee.rb +31 -25
- data/lib/sisimai/bite/email/messagelabs.rb +48 -87
- data/lib/sisimai/bite/email/messagingserver.rb +9 -10
- data/lib/sisimai/bite/email/mfilter.rb +16 -16
- data/lib/sisimai/bite/email/mxlogic.rb +11 -11
- data/lib/sisimai/bite/email/notes.rb +5 -6
- data/lib/sisimai/bite/email/office365.rb +25 -42
- data/lib/sisimai/bite/email/opensmtpd.rb +8 -8
- data/lib/sisimai/bite/email/outlook.rb +49 -67
- data/lib/sisimai/bite/email/postfix.rb +78 -112
- data/lib/sisimai/bite/email/qmail.rb +23 -23
- data/lib/sisimai/bite/email/receivingses.rb +53 -86
- data/lib/sisimai/bite/email/sendgrid.rb +65 -84
- data/lib/sisimai/bite/email/sendmail.rb +89 -117
- data/lib/sisimai/bite/email/surfcontrol.rb +15 -18
- data/lib/sisimai/bite/email/userdefined.rb +1 -1
- data/lib/sisimai/bite/email/v5sendmail.rb +3 -4
- data/lib/sisimai/bite/email/verizon.rb +7 -8
- data/lib/sisimai/bite/email/x1.rb +2 -2
- data/lib/sisimai/bite/email/x2.rb +2 -2
- data/lib/sisimai/bite/email/x3.rb +3 -3
- data/lib/sisimai/bite/email/x4.rb +22 -22
- data/lib/sisimai/bite/email/x5.rb +40 -49
- data/lib/sisimai/bite/email/yahoo.rb +3 -3
- data/lib/sisimai/bite/email/yandex.rb +54 -82
- data/lib/sisimai/bite/email/zoho.rb +6 -6
- data/lib/sisimai/bite/json/amazonses.rb +20 -20
- data/lib/sisimai/bite/json/sendgrid.rb +2 -2
- data/lib/sisimai/data.rb +27 -40
- data/lib/sisimai/datetime.rb +146 -162
- data/lib/sisimai/mda.rb +30 -31
- data/lib/sisimai/message/email.rb +83 -123
- data/lib/sisimai/message/json.rb +2 -4
- data/lib/sisimai/mime.rb +31 -34
- data/lib/sisimai/order/email.rb +23 -22
- data/lib/sisimai/reason.rb +61 -61
- data/lib/sisimai/reason/blocked.rb +139 -135
- data/lib/sisimai/reason/contenterror.rb +11 -10
- data/lib/sisimai/reason/exceedlimit.rb +4 -4
- data/lib/sisimai/reason/expired.rb +20 -20
- data/lib/sisimai/reason/filtered.rb +19 -18
- data/lib/sisimai/reason/hasmoved.rb +3 -3
- data/lib/sisimai/reason/hostunknown.rb +19 -19
- data/lib/sisimai/reason/mailboxfull.rb +49 -49
- data/lib/sisimai/reason/mailererror.rb +16 -16
- data/lib/sisimai/reason/mesgtoobig.rb +17 -17
- data/lib/sisimai/reason/networkerror.rb +19 -19
- data/lib/sisimai/reason/norelaying.rb +16 -16
- data/lib/sisimai/reason/notaccept.rb +9 -10
- data/lib/sisimai/reason/onhold.rb +1 -1
- data/lib/sisimai/reason/policyviolation.rb +21 -20
- data/lib/sisimai/reason/rejected.rb +53 -53
- data/lib/sisimai/reason/securityerror.rb +29 -29
- data/lib/sisimai/reason/spamdetected.rb +127 -127
- data/lib/sisimai/reason/suspend.rb +17 -17
- data/lib/sisimai/reason/systemerror.rb +22 -21
- data/lib/sisimai/reason/systemfull.rb +6 -6
- data/lib/sisimai/reason/toomanyconn.rb +19 -18
- data/lib/sisimai/reason/userunknown.rb +122 -121
- data/lib/sisimai/reason/vacation.rb +8 -8
- data/lib/sisimai/reason/virusdetected.rb +8 -8
- data/lib/sisimai/rfc1894.rb +142 -0
- data/lib/sisimai/rfc3464.rb +70 -70
- data/lib/sisimai/rfc3834.rb +15 -15
- data/lib/sisimai/rfc5322.rb +20 -36
- data/lib/sisimai/rhost.rb +1 -0
- data/lib/sisimai/rhost/exchangeonline.rb +31 -33
- data/lib/sisimai/rhost/franceptt.rb +23 -23
- data/lib/sisimai/rhost/godaddy.rb +28 -28
- data/lib/sisimai/rhost/googleapps.rb +39 -41
- data/lib/sisimai/rhost/kddi.rb +3 -3
- data/lib/sisimai/rhost/tencentqq.rb +51 -0
- data/lib/sisimai/smtp/error.rb +14 -21
- data/lib/sisimai/smtp/reply.rb +14 -13
- data/lib/sisimai/smtp/status.rb +178 -179
- data/lib/sisimai/string.rb +13 -12
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/README.md +1 -5
- data/set-of-emails/maildir/bsd/arf-23.eml +49 -0
- data/set-of-emails/maildir/bsd/email-amavis-01.eml +78 -0
- data/set-of-emails/maildir/bsd/email-amavis-02.eml +78 -0
- data/set-of-emails/maildir/bsd/email-exchange2007-04.eml +146 -0
- data/set-of-emails/maildir/bsd/email-exim-60.eml +94 -0
- data/set-of-emails/maildir/bsd/email-ezweb-08.eml +49 -0
- data/set-of-emails/maildir/bsd/email-google-19.eml +67 -0
- data/set-of-emails/maildir/bsd/email-mcafee-05.eml +74 -0
- data/set-of-emails/maildir/bsd/email-messagingserver-12.eml +99 -0
- data/set-of-emails/maildir/bsd/email-postfix-46.eml +81 -0
- data/set-of-emails/maildir/bsd/email-postfix-47.eml +79 -0
- data/set-of-emails/maildir/bsd/email-postfix-48.eml +79 -0
- data/set-of-emails/maildir/bsd/email-postfix-49.eml +141 -0
- data/set-of-emails/maildir/bsd/email-postfix-50.eml +143 -0
- data/set-of-emails/maildir/bsd/email-postfix-51.eml +73 -0
- data/set-of-emails/maildir/bsd/email-postfix-52.eml +79 -0
- data/set-of-emails/maildir/bsd/email-postfix-53.eml +76 -0
- data/set-of-emails/maildir/bsd/email-postfix-54.eml +73 -0
- data/set-of-emails/maildir/bsd/email-postfix-55.eml +74 -0
- data/set-of-emails/maildir/bsd/email-postfix-56.eml +78 -0
- data/set-of-emails/maildir/bsd/email-qmail-10.eml +50 -0
- data/set-of-emails/maildir/bsd/email-x2-05.eml +38 -0
- data/set-of-emails/maildir/bsd/rhost-google-apps-02.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-tencentqq-01.eml +84 -0
- data/set-of-emails/maildir/bsd/rhost-tencentqq-02.eml +84 -0
- data/set-of-emails/maildir/bsd/rhost-tencentqq-03.eml +81 -0
- data/set-of-emails/maildir/dos/email-amavis-01.eml +78 -0
- data/set-of-emails/maildir/dos/email-apachejames-01.eml +1 -2
- data/set-of-emails/maildir/dos/email-messagelabs-01.eml +67 -50
- data/set-of-emails/maildir/dos/email-x4-01.eml +31 -76
- data/set-of-emails/maildir/dos/rhost-tencentqq-01.eml +84 -0
- data/set-of-emails/maildir/mac/email-amavis-01.eml +1 -4
- data/set-of-emails/maildir/mac/email-apachejames-01.eml +1 -9
- data/set-of-emails/maildir/mac/email-messagelabs-01.eml +1 -9
- data/set-of-emails/maildir/mac/email-x4-01.eml +1 -5
- data/set-of-emails/maildir/mac/rhost-tencentqq-01.eml +1 -4
- metadata +35 -4
- data/set-of-emails/logo/horizontalversions.png +0 -0
- data/set-of-emails/logo/icon.png +0 -0
@@ -17,15 +17,10 @@ module Sisimai
|
|
17
17
|
BorderLine = '__MIME_ENCODED_BOUNDARY__'
|
18
18
|
EndOfEmail = Sisimai::String.EOM
|
19
19
|
RFC822Head = Sisimai::RFC5322.HEADERFIELDS
|
20
|
-
RFC3834Set = Sisimai::RFC3834.headerlist
|
20
|
+
RFC3834Set = Sisimai::RFC3834.headerlist
|
21
21
|
HeaderList = %w[from to date subject content-type reply-to message-id
|
22
|
-
received content-transfer-encoding return-path x-mailer]
|
23
|
-
|
24
|
-
IgnoreList = { 'dkim-signature' => true }.freeze
|
25
|
-
Indicators = {
|
26
|
-
:begin => (1 << 1),
|
27
|
-
:endof => (1 << 2),
|
28
|
-
}.freeze
|
22
|
+
received content-transfer-encoding return-path x-mailer]
|
23
|
+
IsMultiple = { 'received' => true }
|
29
24
|
DefaultSet = Sisimai::Order::Email.another
|
30
25
|
SubjectTab = Sisimai::Order::Email.by('subject')
|
31
26
|
ExtHeaders = Sisimai::Order::Email.headers
|
@@ -56,8 +51,7 @@ module Sisimai
|
|
56
51
|
tobeloaded = Sisimai::Message::Email.load(methodargv)
|
57
52
|
|
58
53
|
# 1. Split email data to headers and a body part.
|
59
|
-
aftersplit = Sisimai::Message::Email.divideup(email)
|
60
|
-
return nil if aftersplit.empty?
|
54
|
+
return nil unless aftersplit = Sisimai::Message::Email.divideup(email)
|
61
55
|
|
62
56
|
# 2. Convert email headers from text to hash reference
|
63
57
|
headerargv = {
|
@@ -81,9 +75,7 @@ module Sisimai
|
|
81
75
|
'tryonfirst' => headerargv['tryonfirst'],
|
82
76
|
'tobeloaded' => tobeloaded,
|
83
77
|
}
|
84
|
-
bouncedata = Sisimai::Message::Email.parse(methodargv)
|
85
|
-
|
86
|
-
return nil unless bouncedata
|
78
|
+
return nil unless bouncedata = Sisimai::Message::Email.parse(methodargv)
|
87
79
|
return nil if bouncedata.empty?
|
88
80
|
processing['ds'] = bouncedata['ds']
|
89
81
|
processing['catch'] = bouncedata['catch']
|
@@ -153,48 +145,27 @@ module Sisimai
|
|
153
145
|
# @param [String] email Email data
|
154
146
|
# @return [Hash] Email data after split
|
155
147
|
def self.divideup(email)
|
156
|
-
return
|
148
|
+
return nil if email.empty?
|
157
149
|
|
150
|
+
block = { 'from' => '', 'header' => '', 'body' => '' }
|
158
151
|
email.scrub!('?')
|
159
152
|
email.gsub!(/\r\n/, "\n") if email.include?("\r\n")
|
160
153
|
email.gsub!(/[ \t]+$/, '') if email =~ /[ \t]+$/
|
161
154
|
|
162
|
-
|
163
|
-
return
|
164
|
-
|
165
|
-
readcursor = 0
|
166
|
-
aftersplit = { 'from' => '', 'header' => '', 'body' => '' }
|
155
|
+
(block['header'], block['body']) = email.split(/\n\n/, 2)
|
156
|
+
return nil unless block['header']
|
157
|
+
return nil unless block['body']
|
167
158
|
|
168
|
-
if
|
159
|
+
if block['header'][0, 5] == 'From '
|
169
160
|
# From MAILER-DAEMON Tue Feb 11 00:00:00 2014
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
# Split email data to headers and a body part.
|
175
|
-
while e = hasdivided.shift do
|
176
|
-
# Split email data to headers and a body part.
|
177
|
-
if readcursor & Indicators[:endof] > 0
|
178
|
-
# The body part of the email
|
179
|
-
aftersplit['body'] << e + "\n"
|
180
|
-
else
|
181
|
-
# The boundary for splitting headers and a body part does not
|
182
|
-
# appeare yet.
|
183
|
-
if e.empty?
|
184
|
-
# Blank line, it is a boundary of headers and a body part
|
185
|
-
readcursor |= Indicators[:endof] if readcursor & Indicators[:begin] > 0
|
186
|
-
else
|
187
|
-
# The header part of the email
|
188
|
-
aftersplit['header'] << e + "\n"
|
189
|
-
readcursor |= Indicators[:begin]
|
190
|
-
end
|
191
|
-
end
|
161
|
+
block['from'] = block['header'].split(/\n/, 2)[0].delete("\r")
|
162
|
+
else
|
163
|
+
# Set pseudo UNIX From line
|
164
|
+
block['from'] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
|
192
165
|
end
|
193
|
-
return {} if aftersplit['header'].empty?
|
194
|
-
return {} if aftersplit['body'].empty?
|
195
166
|
|
196
|
-
|
197
|
-
return
|
167
|
+
block['body'] << "\n"
|
168
|
+
return block
|
198
169
|
end
|
199
170
|
|
200
171
|
# Convert email headers from text to hash reference
|
@@ -205,6 +176,7 @@ module Sisimai
|
|
205
176
|
def self.headers(heads, argvs = {})
|
206
177
|
return nil unless heads
|
207
178
|
|
179
|
+
currheader = ''
|
208
180
|
allheaders = {}
|
209
181
|
structured = {}
|
210
182
|
extheaders = argvs['extheaders'] || []
|
@@ -214,50 +186,49 @@ module Sisimai
|
|
214
186
|
HeaderList.each { |e| structured[e] = nil }
|
215
187
|
HeaderList.each { |e| allheaders[e] = true }
|
216
188
|
RFC3834Set.each { |e| allheaders[e] = true }
|
217
|
-
|
189
|
+
IsMultiple.each_key { |e| structured[e] = [] }
|
218
190
|
extheaders.each_key { |e| allheaders[e] = true }
|
219
191
|
unless extrafield.empty?
|
220
|
-
extrafield.each { |e| allheaders[e
|
192
|
+
extrafield.each { |e| allheaders[e] = true }
|
221
193
|
end
|
222
194
|
|
223
195
|
while e = hasdivided.shift do
|
224
196
|
# Convert email headers to hash
|
225
|
-
if cv = e.match(/\A
|
226
|
-
#
|
227
|
-
|
228
|
-
rhs = cv[2]
|
197
|
+
if cv = e.match(/\A[ \t]+(.+)\z/)
|
198
|
+
# Continued (foled) header value from the previous line
|
199
|
+
next unless allheaders.key?(currheader)
|
229
200
|
|
230
|
-
|
201
|
+
# Header line continued from the previous line
|
202
|
+
if structured[currheader].is_a? Array
|
203
|
+
# Concatenate a header which have multi-lines such as 'Received'
|
204
|
+
structured[currheader][-1] << ' ' << cv[1]
|
205
|
+
else
|
206
|
+
structured[currheader] ||= ''
|
207
|
+
structured[currheader] << ' ' << cv[1]
|
208
|
+
end
|
209
|
+
else
|
210
|
+
# split the line into a header name and a header content
|
211
|
+
(lhs, rhs) = e.split(/:[ ]*/, 2)
|
212
|
+
currheader = lhs ? lhs.downcase : ''
|
231
213
|
next unless allheaders.key?(currheader)
|
232
214
|
|
233
|
-
if
|
215
|
+
if IsMultiple.key?(currheader)
|
234
216
|
# Such as 'Received' header, there are multiple headers in a single
|
235
217
|
# email message.
|
236
|
-
rhs = rhs.tr("\t", ' ').squeeze(' ')
|
218
|
+
#rhs = rhs.tr("\t", ' ').squeeze(' ')
|
219
|
+
rhs = rhs.tr("\t", ' ')
|
237
220
|
structured[currheader] << rhs
|
238
221
|
else
|
239
222
|
# Other headers except "Received" and so on
|
240
223
|
if extheaders[currheader]
|
241
224
|
# MTA specific header
|
242
|
-
extheaders[currheader].
|
225
|
+
extheaders[currheader].each do |r|
|
243
226
|
next if argvs['tryonfirst'].index(r)
|
244
227
|
argvs['tryonfirst'] << r
|
245
228
|
end
|
246
229
|
end
|
247
230
|
structured[currheader] = rhs
|
248
231
|
end
|
249
|
-
elsif cv = e.match(/\A[ \t]+(.+?)\z/)
|
250
|
-
# Ignore header?
|
251
|
-
next if IgnoreList[currheader]
|
252
|
-
|
253
|
-
# Header line continued from the previous line
|
254
|
-
if structured[currheader].is_a? Array
|
255
|
-
# Concatenate a header which have multi-lines such as 'Received'
|
256
|
-
structured[currheader][-1] << ' ' << cv[1]
|
257
|
-
else
|
258
|
-
structured[currheader] ||= ''
|
259
|
-
structured[currheader] << ' ' << cv[1]
|
260
|
-
end
|
261
232
|
end
|
262
233
|
end
|
263
234
|
return structured
|
@@ -294,72 +265,68 @@ module Sisimai
|
|
294
265
|
# 2. Convert from string to hash reference
|
295
266
|
heads = heads.scrub('?').gsub(/^[>]+[ ]/m, '')
|
296
267
|
|
297
|
-
takenapart = {}
|
298
|
-
hasdivided = heads.split("\n")
|
299
268
|
previousfn = '' # Previous field name
|
300
|
-
|
269
|
+
asciiarmor = {} # Header names which has MIME encoded value
|
270
|
+
headerpart = {} # Required headers in the original message part
|
271
|
+
hasdivided = heads.split("\n")
|
301
272
|
|
302
273
|
while e = hasdivided.shift do
|
303
274
|
# Header name as a key, The value of header as a value
|
304
|
-
if
|
305
|
-
#
|
306
|
-
lhs = cv[1].downcase
|
307
|
-
rhs = cv[2]
|
308
|
-
previousfn = ''
|
309
|
-
|
310
|
-
next unless RFC822Head.key?(lhs)
|
311
|
-
previousfn = lhs
|
312
|
-
takenapart[previousfn] = rhs unless takenapart[previousfn]
|
313
|
-
else
|
314
|
-
# Continued line from the previous line
|
315
|
-
next unless e.start_with?(' ', "\t")
|
275
|
+
if e.start_with?(' ', "\t")
|
276
|
+
# Continued (foled) header value from the previous line
|
316
277
|
next if previousfn.empty?
|
317
278
|
|
318
279
|
# Concatenate the line if it is the value of required header
|
319
280
|
if Sisimai::MIME.is_mimeencoded(e)
|
320
281
|
# The line is MIME-Encoded test
|
321
|
-
|
282
|
+
headerpart[previousfn] << if previousfn == 'subject'
|
322
283
|
# Subject: header
|
323
284
|
BorderLine + e
|
324
285
|
else
|
325
286
|
# Is not Subject header
|
326
287
|
e
|
327
288
|
end
|
328
|
-
|
289
|
+
asciiarmor[previousfn] = true
|
329
290
|
else
|
330
291
|
# ASCII Characters only: Not MIME-Encoded
|
331
|
-
|
332
|
-
|
292
|
+
headerpart[previousfn] << e.lstrip
|
293
|
+
asciiarmor[previousfn] ||= false
|
333
294
|
end
|
295
|
+
else
|
296
|
+
# Header name as a key, The value of header as a value
|
297
|
+
(lhs, rhs) = e.split(/:[ ]*/, 2)
|
298
|
+
next unless lhs
|
299
|
+
lhs.downcase!
|
300
|
+
previousfn = ''
|
301
|
+
|
302
|
+
next unless RFC822Head.key?(lhs)
|
303
|
+
previousfn = lhs
|
304
|
+
headerpart[previousfn] = rhs unless headerpart[previousfn]
|
334
305
|
end
|
335
306
|
end
|
307
|
+
return headerpart unless headerpart['subject']
|
336
308
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
#
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
v.split(BorderLine).each do |m|
|
351
|
-
# Insert value to the array if the string is MIME encoded text
|
352
|
-
r << m if Sisimai::MIME.is_mimeencoded(m)
|
353
|
-
end
|
354
|
-
else
|
355
|
-
# Subject line is not MIME encoded
|
356
|
-
r << v
|
309
|
+
# Convert MIME-Encoded subject
|
310
|
+
if Sisimai::String.is_8bit(headerpart['subject'])
|
311
|
+
# The value of ``Subject'' header is including multibyte character,
|
312
|
+
# is not MIME-Encoded text.
|
313
|
+
headerpart['subject'] = 'MULTIBYTE CHARACTERS HAVE BEEN REMOVED'
|
314
|
+
else
|
315
|
+
# MIME-Encoded subject field or ASCII characters only
|
316
|
+
r = []
|
317
|
+
if asciiarmor['subject']
|
318
|
+
# split the value of Subject by borderline
|
319
|
+
headerpart['subject'].split(BorderLine).each do |v|
|
320
|
+
# Insert value to the array if the string is MIME encoded text
|
321
|
+
r << v if Sisimai::MIME.is_mimeencoded(v)
|
357
322
|
end
|
358
|
-
|
323
|
+
else
|
324
|
+
# Subject line is not MIME encoded
|
325
|
+
r << headerpart['subject']
|
359
326
|
end
|
360
|
-
|
327
|
+
headerpart['subject'] = Sisimai::MIME.mimedecode(r)
|
361
328
|
end
|
362
|
-
return
|
329
|
+
return headerpart
|
363
330
|
end
|
364
331
|
|
365
332
|
# @abstract Parse bounce mail with each MTA module
|
@@ -441,10 +408,13 @@ module Sisimai
|
|
441
408
|
if mailheader['subject'].downcase =~ /\A[ \t]*fwd?:/
|
442
409
|
# Delete quoted strings, quote symbols(>)
|
443
410
|
bodystring = bodystring.gsub(/^[>]+[ ]/m, '').gsub(/^[>]$/m, '')
|
411
|
+
elsif Sisimai::MIME.is_mimeencoded(mailheader['subject'])
|
412
|
+
# Decode MIME-Encoded "Subject:" header
|
413
|
+
mailheader['subject'] = Sisimai::MIME.mimedecode(mailheader['subject'].split(/[ ]/))
|
414
|
+
mailheader['subject'].scrub!('?')
|
444
415
|
end
|
445
416
|
bodystring << EndOfEmail
|
446
417
|
haveloaded = {}
|
447
|
-
defaultset = DefaultSet.dup
|
448
418
|
scannedset = nil
|
449
419
|
|
450
420
|
catch :SCANNER do
|
@@ -469,19 +439,9 @@ module Sisimai
|
|
469
439
|
throw :SCANNER if scannedset
|
470
440
|
end
|
471
441
|
|
442
|
+
tryonfirst.concat(DefaultSet)
|
472
443
|
while r = tryonfirst.shift do
|
473
|
-
# Try MTA module candidates
|
474
|
-
# mail headers on first
|
475
|
-
next if haveloaded.key?(r)
|
476
|
-
require r.gsub('::', '/').downcase
|
477
|
-
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
478
|
-
haveloaded[r] = true
|
479
|
-
throw :SCANNER if scannedset
|
480
|
-
end
|
481
|
-
|
482
|
-
while r = defaultset.shift do
|
483
|
-
# MTA modules which does not have MTA specific header and did
|
484
|
-
# not match with any regular expressions of Subject header.
|
444
|
+
# Try MTA module candidates
|
485
445
|
next if haveloaded.key?(r)
|
486
446
|
require r.gsub('::', '/').downcase
|
487
447
|
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
data/lib/sisimai/message/json.rb
CHANGED
@@ -37,14 +37,12 @@ module Sisimai
|
|
37
37
|
|
38
38
|
# Rewrite message body for detecting the bounce reason
|
39
39
|
methodargv = { 'hook' => hookmethod, 'json' => argvs['data'] }
|
40
|
-
bouncedata = Sisimai::Message::JSON.parse(methodargv)
|
41
|
-
|
42
|
-
return nil unless bouncedata
|
40
|
+
return nil unless bouncedata = Sisimai::Message::JSON.parse(methodargv)
|
43
41
|
return nil if bouncedata.empty?
|
42
|
+
|
44
43
|
processing['ds'] = bouncedata['ds']
|
45
44
|
processing['catch'] = bouncedata['catch']
|
46
45
|
processing['rfc822'] = bouncedata['rfc822']
|
47
|
-
|
48
46
|
return processing
|
49
47
|
end
|
50
48
|
|
data/lib/sisimai/mime.rb
CHANGED
@@ -15,6 +15,14 @@ module Sisimai
|
|
15
15
|
:'only-charset' => %r/^[\s\t]+charset=['"]?(.+?)['"]?\b/,
|
16
16
|
:'html-message' => %r|^content-type:[ ]*text/html;|m,
|
17
17
|
}.freeze
|
18
|
+
AlsoAppend = %r{\A(?:text/rfc822-headers|message/)}.freeze
|
19
|
+
ThisFormat = %r/\A(?:Content-Transfer-Encoding:\s*.+\n)?Content-Type:\s*([^ ;]+)/.freeze
|
20
|
+
LeavesOnly = %r{\A(?>
|
21
|
+
text/(?:plain|html|rfc822-headers)
|
22
|
+
|message/(?:x?delivery-status|rfc822|partial|feedback-report)
|
23
|
+
|multipart/(?:report|alternative|mixed|related|partial)
|
24
|
+
)
|
25
|
+
}x.freeze
|
18
26
|
|
19
27
|
# Make MIME-Encoding and Content-Type related headers regurlar expression
|
20
28
|
# @return [Array] Regular expressions related to MIME encoding
|
@@ -27,17 +35,17 @@ module Sisimai
|
|
27
35
|
# @return [True,False] false: Not MIME encoded string
|
28
36
|
# true: MIME encoded string
|
29
37
|
def is_mimeencoded(argv1)
|
30
|
-
return
|
38
|
+
return nil unless argv1
|
31
39
|
|
32
|
-
argv1.delete
|
33
|
-
piece = []
|
40
|
+
text1 = argv1.delete('"')
|
34
41
|
mime1 = false
|
42
|
+
piece = []
|
35
43
|
|
36
|
-
if
|
44
|
+
if text1.include?(' ')
|
37
45
|
# Multiple MIME-Encoded strings in a line
|
38
|
-
piece =
|
46
|
+
piece = text1.split(' ')
|
39
47
|
else
|
40
|
-
piece <<
|
48
|
+
piece << text1
|
41
49
|
end
|
42
50
|
|
43
51
|
while e = piece.shift do
|
@@ -67,19 +75,17 @@ module Sisimai
|
|
67
75
|
characterset ||= cv[2]
|
68
76
|
encodingname ||= cv[3]
|
69
77
|
mimeencoded0 = cv[4]
|
70
|
-
decodedtext0 << cv[1]
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
79
|
+
decodedtext0 << cv[1]
|
80
|
+
decodedtext0 << if encodingname == 'B'
|
81
|
+
Base64.decode64(mimeencoded0)
|
82
|
+
else
|
83
|
+
mimeencoded0.unpack('M').first
|
84
|
+
end
|
85
|
+
decodedtext0[-1].gsub!(/\r\n/, '')
|
80
86
|
decodedtext0 << cv[5]
|
81
87
|
else
|
82
|
-
decodedtext0 << e
|
88
|
+
decodedtext0 << if decodedtext0.empty? then e else ' ' << e end
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
@@ -261,28 +267,19 @@ module Sisimai
|
|
261
267
|
return nil unless argv0
|
262
268
|
|
263
269
|
hasflatten = '' # Message body including only text/plain and message/*
|
264
|
-
alsoappend = %r{\A(?:text/rfc822-headers|message/)}
|
265
|
-
thisformat = %r/\A(?:Content-Transfer-Encoding:\s*.+\n)?Content-Type:\s*([^ ;]+)/
|
266
|
-
leavesonly = %r{\A(?>
|
267
|
-
text/(?:plain|html|rfc822-headers)
|
268
|
-
|message/(?:x?delivery-status|rfc822|partial|feedback-report)
|
269
|
-
|multipart/(?:report|alternative|mixed|related|partial)
|
270
|
-
)
|
271
|
-
}x
|
272
|
-
|
273
270
|
mimeformat = '' # MIME type string of this part
|
274
271
|
alternates = argv1.start_with?('multipart/alternative') ? true : false
|
275
272
|
|
276
273
|
# Get MIME type string from Content-Type: "..." field at the first line
|
277
274
|
# or the second line of the part.
|
278
|
-
if cv = argv0.match(
|
275
|
+
if cv = argv0.match(ThisFormat) then mimeformat = cv[1].downcase end
|
279
276
|
|
280
|
-
# Sisimai require only MIME types defined in
|
281
|
-
return '' unless mimeformat =~
|
277
|
+
# Sisimai require only MIME types defined in LeavesOnly variable
|
278
|
+
return '' unless mimeformat =~ LeavesOnly
|
282
279
|
return '' if alternates && mimeformat == 'text/html'
|
283
280
|
|
284
281
|
(upperchunk, lowerchunk) = argv0.split(/^$/m, 2)
|
285
|
-
upperchunk.
|
282
|
+
upperchunk.tr!("\n", ' ').squeeze(' ')
|
286
283
|
|
287
284
|
# Content-Description: Undelivered Message
|
288
285
|
# Content-Type: message/rfc822
|
@@ -297,12 +294,12 @@ module Sisimai
|
|
297
294
|
innerparts.shift if innerparts[0].empty?
|
298
295
|
while e = innerparts.shift do
|
299
296
|
# Find internal multipart/* blocks and decode
|
300
|
-
if cv = e.match(
|
297
|
+
if cv = e.match(ThisFormat)
|
301
298
|
# Found "Content-Type" field at the first or second line of this
|
302
299
|
# splitted part
|
303
300
|
nextformat = cv[1].downcase
|
304
301
|
|
305
|
-
next unless nextformat =~
|
302
|
+
next unless nextformat =~ LeavesOnly
|
306
303
|
next if nextformat == 'text/html'
|
307
304
|
|
308
305
|
hasflatten << Sisimai::MIME.breaksup(e, mimeformat)
|
@@ -340,12 +337,12 @@ module Sisimai
|
|
340
337
|
# Content-Transfer-Encoding: 8bit, binary, and so on
|
341
338
|
getdecoded = lowerchunk
|
342
339
|
end
|
343
|
-
getdecoded.gsub!(/\r\n/, "\n")
|
340
|
+
getdecoded.gsub!(/\r\n/, "\n") if getdecoded.include?("\r\n") # Convert CRLF to LF
|
344
341
|
|
345
|
-
if mimeformat =~
|
342
|
+
if mimeformat =~ AlsoAppend
|
346
343
|
# Append field when the value of Content-Type: begins with
|
347
344
|
# message/ or equals text/rfc822-headers.
|
348
|
-
upperchunk.sub!(/Content-Transfer-Encoding:.+\z/, '').
|
345
|
+
upperchunk.sub!(/Content-Transfer-Encoding:.+\z/, '').rstrip!
|
349
346
|
hasflatten << upperchunk
|
350
347
|
|
351
348
|
elsif mimeformat == 'text/html'
|