sisimai 4.22.3-java → 4.22.4-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 +1 -1
- data/Benchmarks.mk +54 -0
- data/ChangeLog.md +23 -2
- data/Developers.mk +42 -35
- data/Makefile +10 -0
- data/README-JA.md +13 -13
- data/README.md +14 -14
- data/lib/sisimai.rb +12 -18
- data/lib/sisimai/address.rb +64 -82
- data/lib/sisimai/arf.rb +27 -42
- data/lib/sisimai/bite/email.rb +2 -4
- data/lib/sisimai/bite/email/activehunter.rb +12 -17
- data/lib/sisimai/bite/email/amazonses.rb +30 -48
- data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
- data/lib/sisimai/bite/email/aol.rb +27 -35
- data/lib/sisimai/bite/email/apachejames.rb +17 -28
- data/lib/sisimai/bite/email/bigfoot.rb +20 -33
- data/lib/sisimai/bite/email/biglobe.rb +15 -24
- data/lib/sisimai/bite/email/courier.rb +37 -61
- data/lib/sisimai/bite/email/domino.rb +19 -28
- data/lib/sisimai/bite/email/einsundeins.rb +20 -34
- data/lib/sisimai/bite/email/exchange2003.rb +25 -43
- data/lib/sisimai/bite/email/exchange2007.rb +15 -23
- data/lib/sisimai/bite/email/exim.rb +101 -120
- data/lib/sisimai/bite/email/ezweb.rb +28 -44
- data/lib/sisimai/bite/email/facebook.rb +26 -37
- data/lib/sisimai/bite/email/fml.rb +11 -20
- data/lib/sisimai/bite/email/gmx.rb +17 -27
- data/lib/sisimai/bite/email/google.rb +19 -29
- data/lib/sisimai/bite/email/gsuite.rb +39 -48
- data/lib/sisimai/bite/email/imailserver.rb +25 -39
- data/lib/sisimai/bite/email/interscanmss.rb +19 -26
- data/lib/sisimai/bite/email/kddi.rb +20 -33
- data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
- data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
- data/lib/sisimai/bite/email/mailru.rb +40 -59
- data/lib/sisimai/bite/email/mcafee.rb +21 -35
- data/lib/sisimai/bite/email/messagelabs.rb +23 -38
- data/lib/sisimai/bite/email/messagingserver.rb +15 -27
- data/lib/sisimai/bite/email/mfilter.rb +19 -28
- data/lib/sisimai/bite/email/mxlogic.rb +31 -49
- data/lib/sisimai/bite/email/notes.rb +16 -24
- data/lib/sisimai/bite/email/office365.rb +29 -38
- data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
- data/lib/sisimai/bite/email/outlook.rb +24 -36
- data/lib/sisimai/bite/email/postfix.rb +33 -42
- data/lib/sisimai/bite/email/qmail.rb +44 -59
- data/lib/sisimai/bite/email/receivingses.rb +28 -36
- data/lib/sisimai/bite/email/sendgrid.rb +28 -37
- data/lib/sisimai/bite/email/sendmail.rb +35 -51
- data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
- data/lib/sisimai/bite/email/userdefined.rb +17 -28
- data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
- data/lib/sisimai/bite/email/verizon.rb +31 -56
- data/lib/sisimai/bite/email/x1.rb +11 -18
- data/lib/sisimai/bite/email/x2.rb +11 -23
- data/lib/sisimai/bite/email/x3.rb +10 -19
- data/lib/sisimai/bite/email/x4.rb +46 -65
- data/lib/sisimai/bite/email/x5.rb +26 -37
- data/lib/sisimai/bite/email/yahoo.rb +11 -19
- data/lib/sisimai/bite/email/yandex.rb +19 -30
- data/lib/sisimai/bite/email/zoho.rb +21 -30
- data/lib/sisimai/bite/json.rb +1 -2
- data/lib/sisimai/bite/json/amazonses.rb +20 -25
- data/lib/sisimai/bite/json/sendgrid.rb +1 -1
- data/lib/sisimai/data.rb +36 -55
- data/lib/sisimai/data/json.rb +3 -3
- data/lib/sisimai/data/yaml.rb +1 -1
- data/lib/sisimai/datetime.rb +5 -21
- data/lib/sisimai/mail.rb +4 -6
- data/lib/sisimai/mail/maildir.rb +1 -1
- data/lib/sisimai/mda.rb +41 -44
- data/lib/sisimai/message.rb +2 -3
- data/lib/sisimai/message/email.rb +42 -52
- data/lib/sisimai/message/json.rb +7 -7
- data/lib/sisimai/mime.rb +25 -23
- data/lib/sisimai/order/email.rb +2 -2
- data/lib/sisimai/order/json.rb +2 -7
- data/lib/sisimai/reason.rb +41 -46
- data/lib/sisimai/reason/blocked.rb +60 -71
- data/lib/sisimai/reason/contenterror.rb +4 -8
- data/lib/sisimai/reason/delivered.rb +1 -3
- data/lib/sisimai/reason/exceedlimit.rb +10 -20
- data/lib/sisimai/reason/expired.rb +5 -9
- data/lib/sisimai/reason/feedback.rb +1 -3
- data/lib/sisimai/reason/filtered.rb +19 -38
- data/lib/sisimai/reason/hasmoved.rb +5 -8
- data/lib/sisimai/reason/hostunknown.rb +11 -18
- data/lib/sisimai/reason/mailboxfull.rb +14 -24
- data/lib/sisimai/reason/mailererror.rb +3 -5
- data/lib/sisimai/reason/mesgtoobig.rb +15 -25
- data/lib/sisimai/reason/networkerror.rb +8 -10
- data/lib/sisimai/reason/norelaying.rb +9 -14
- data/lib/sisimai/reason/notaccept.rb +9 -21
- data/lib/sisimai/reason/onhold.rb +3 -8
- data/lib/sisimai/reason/policyviolation.rb +8 -10
- data/lib/sisimai/reason/rejected.rb +36 -49
- data/lib/sisimai/reason/securityerror.rb +11 -13
- data/lib/sisimai/reason/spamdetected.rb +23 -37
- data/lib/sisimai/reason/suspend.rb +9 -10
- data/lib/sisimai/reason/syntaxerror.rb +3 -4
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +2 -4
- data/lib/sisimai/reason/toomanyconn.rb +17 -30
- data/lib/sisimai/reason/undefined.rb +1 -3
- data/lib/sisimai/reason/userunknown.rb +28 -38
- data/lib/sisimai/reason/vacation.rb +4 -6
- data/lib/sisimai/reason/virusdetected.rb +4 -6
- data/lib/sisimai/rfc2606.rb +1 -2
- data/lib/sisimai/rfc3464.rb +87 -101
- data/lib/sisimai/rfc3834.rb +29 -39
- data/lib/sisimai/rfc5322.rb +17 -24
- data/lib/sisimai/rhost.rb +10 -7
- data/lib/sisimai/rhost/exchangeonline.rb +124 -255
- data/lib/sisimai/rhost/franceptt.rb +2 -2
- data/lib/sisimai/rhost/godaddy.rb +12 -25
- data/lib/sisimai/rhost/googleapps.rb +82 -183
- data/lib/sisimai/smtp.rb +4 -4
- data/lib/sisimai/smtp/error.rb +8 -8
- data/lib/sisimai/smtp/reply.rb +1 -1
- data/lib/sisimai/smtp/status.rb +1 -0
- data/lib/sisimai/string.rb +5 -7
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/README.md +1 -1
- data/set-of-emails/maildir/bsd/README.md +50 -50
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +4 -4
- data/lib/sisimai/skeleton.rb +0 -43
data/lib/sisimai/data/json.rb
CHANGED
@@ -13,13 +13,13 @@ module Sisimai
|
|
13
13
|
return nil unless argvs
|
14
14
|
return nil unless argvs.is_a? Sisimai::Data
|
15
15
|
|
16
|
-
if RUBY_PLATFORM
|
16
|
+
if RUBY_PLATFORM.include?('java')
|
17
17
|
# java-based ruby environment like JRuby.
|
18
18
|
begin
|
19
19
|
require 'jrjackson'
|
20
20
|
jsonstring = JrJackson::Json.dump(argvs.damn)
|
21
21
|
rescue StandardError => ce
|
22
|
-
warn '***warning: Failed to JrJackson::Json.dump: '
|
22
|
+
warn '***warning: Failed to JrJackson::Json.dump: ' << ce.to_s
|
23
23
|
end
|
24
24
|
else
|
25
25
|
# MRI
|
@@ -27,7 +27,7 @@ module Sisimai
|
|
27
27
|
require 'oj'
|
28
28
|
jsonstring = Oj.dump(argvs.damn, :mode => :compat)
|
29
29
|
rescue StandardError => ce
|
30
|
-
warn '***warning: Failed to Oj.dump: '
|
30
|
+
warn '***warning: Failed to Oj.dump: ' << ce.to_s
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
data/lib/sisimai/data/yaml.rb
CHANGED
data/lib/sisimai/datetime.rb
CHANGED
@@ -34,20 +34,17 @@ module Sisimai
|
|
34
34
|
}.freeze
|
35
35
|
|
36
36
|
MonthName = {
|
37
|
-
full: %w
|
38
|
-
abbr: %w
|
37
|
+
full: %w[January February March April May June July August September October November December],
|
38
|
+
abbr: %w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec],
|
39
39
|
}.freeze
|
40
40
|
|
41
41
|
DayOfWeek = {
|
42
|
-
full: %w
|
43
|
-
abbr: %w
|
42
|
+
full: %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday],
|
43
|
+
abbr: %w[Sun Mon Tue Wed Thu Fri Sat],
|
44
44
|
}.freeze
|
45
45
|
|
46
46
|
HourName = {
|
47
|
-
full: [
|
48
|
-
'Midnight', 1, 2, 3, 4, 5, 'Morning', 7, 8, 9, 10, 11,
|
49
|
-
'Noon', 13, 14, 15, 16, 17, 'Evening', 19, 20, 21, 22, 23,
|
50
|
-
],
|
47
|
+
full: %w[Midnight 1 2 3 4 5 Morning 7 8 9 10 11 Noon 13 14 15 16 17 Evening 19 20 21 22 23],
|
51
48
|
abbr: [0..23],
|
52
49
|
}.freeze
|
53
50
|
|
@@ -207,10 +204,8 @@ module Sisimai
|
|
207
204
|
m = MathematicalConstant[cr[2].to_sym].to_f
|
208
205
|
u = cr[3] || 'd'
|
209
206
|
getseconds = n * m * TimeUnit[u.to_sym].to_f
|
210
|
-
|
211
207
|
else
|
212
208
|
getseconds = 0
|
213
|
-
|
214
209
|
end
|
215
210
|
|
216
211
|
return getseconds
|
@@ -313,15 +308,12 @@ module Sisimai
|
|
313
308
|
elsif MonthName[:abbr].include?(p)
|
314
309
|
# Month name abbr.; Apr, May, ...
|
315
310
|
v[:M] = p
|
316
|
-
|
317
311
|
end
|
318
|
-
|
319
312
|
elsif p =~ /\A\d{1,4}\z/
|
320
313
|
# Year or Day; 2005, 31, 04, 1, ...
|
321
314
|
if p.to_i > 31
|
322
315
|
# The piece is the value of an year
|
323
316
|
v[:Y] = p
|
324
|
-
|
325
317
|
else
|
326
318
|
# The piece is the value of a day
|
327
319
|
if v[:d]
|
@@ -332,23 +324,19 @@ module Sisimai
|
|
332
324
|
v[:d] = p
|
333
325
|
end
|
334
326
|
end
|
335
|
-
|
336
327
|
elsif cr = p.match(/\A([0-2]\d):([0-5]\d):([0-5]\d)\z/) ||
|
337
328
|
p.match(/\A(\d{1,2})[-:](\d{1,2})[-:](\d{1,2})\z/)
|
338
329
|
# Time; 12:34:56, 03:14:15, ...
|
339
330
|
# Arrival-Date: 2014-03-26 00-01-19
|
340
|
-
|
341
331
|
if cr[1].to_i < 24 && cr[2].to_i < 60 && cr[3].to_i < 60
|
342
332
|
# Valid time format, maybe...
|
343
333
|
v[:T] = sprintf('%02d:%02d:%02d', cr[1].to_i, cr[2].to_i, cr[3].to_i)
|
344
334
|
end
|
345
|
-
|
346
335
|
elsif cr = p.match(/\A([0-2]\d):([0-5]\d)\z/)
|
347
336
|
# Time; 12:34 => 12:34:00
|
348
337
|
if cr[1].to_i < 24 && cr[2].to_i < 60
|
349
338
|
v[:T] = sprintf('%02d:%02d:00', cr[1].to_i, cr[2].to_i)
|
350
339
|
end
|
351
|
-
|
352
340
|
elsif cr = p.match(/\A(\d\d?):(\d\d?)\z/)
|
353
341
|
# Time: 1:4 => 01:04:00
|
354
342
|
v[:T] = sprintf('%02d:%02d:00', cr[1].to_i, cr[2].to_i)
|
@@ -356,7 +344,6 @@ module Sisimai
|
|
356
344
|
elsif p =~ /\A[APap][Mm]\z/
|
357
345
|
# AM or PM
|
358
346
|
afternoon1 = 1
|
359
|
-
|
360
347
|
else
|
361
348
|
# Timezone offset and others
|
362
349
|
if p =~ /\A[-+][01]\d{3}\z/
|
@@ -366,7 +353,6 @@ module Sisimai
|
|
366
353
|
elsif p =~ /\A[(]?[A-Z]{2,5}[)]?\z/
|
367
354
|
# Timezone abbreviation; JST, GMT, UTC, ...
|
368
355
|
v[:z] ||= abbr2tz(p) || '+0000'
|
369
|
-
|
370
356
|
else
|
371
357
|
# Other date format
|
372
358
|
if cr = p.match(%r|\A(\d{4})[-/](\d{1,2})[-/](\d{1,2})\z|)
|
@@ -384,7 +370,6 @@ module Sisimai
|
|
384
370
|
if cr[4].to_i < 24 && cr[5].to_i < 60 && cr[6].to_i < 60
|
385
371
|
v[:T] = sprintf('%02d:%02d:%02d', cr[4].to_i, cr[5].to_i, cr[6].to_i)
|
386
372
|
end
|
387
|
-
|
388
373
|
elsif cr = p.match(%r|\A(\d{1,2})/(\d{1,2})/(\d{1,2})\z|)
|
389
374
|
# 4/29/01 11:34:45 PM
|
390
375
|
v[:M] = MonthName[:abbr][cr[1].to_i - 1]
|
@@ -484,7 +469,6 @@ module Sisimai
|
|
484
469
|
|
485
470
|
elsif argv1 =~ /\A[A-Za-z]+\z/
|
486
471
|
return tz2second(TimeZoneAbbr[argv1.to_sym])
|
487
|
-
|
488
472
|
else
|
489
473
|
return nil
|
490
474
|
end
|
data/lib/sisimai/mail.rb
CHANGED
@@ -24,7 +24,7 @@ module Sisimai
|
|
24
24
|
# Path to mail or '<STDIN>' ?
|
25
25
|
if argv1 == '<STDIN>'
|
26
26
|
# Sisimai::Mail.new('<STDIN>')
|
27
|
-
classname =
|
27
|
+
classname = self.class.to_s << '::STDIN'
|
28
28
|
parameter['type'] = 'stdin'
|
29
29
|
parameter['path'] = $stdin
|
30
30
|
else
|
@@ -33,23 +33,21 @@ module Sisimai
|
|
33
33
|
|
34
34
|
if mediatype == 'file'
|
35
35
|
# The argument is a file, it is an mbox or email file in Maildir/
|
36
|
-
classname =
|
36
|
+
classname = self.class.to_s << '::Mbox'
|
37
37
|
parameter['type'] = 'mailbox'
|
38
38
|
|
39
39
|
elsif mediatype == 'directory'
|
40
40
|
# The agument is not a file, it is a Maildir/
|
41
|
-
classname =
|
41
|
+
classname = self.class.to_s << '::Maildir'
|
42
42
|
parameter['type'] = 'maildir'
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
46
45
|
elsif argv1.is_a?(IO)
|
47
46
|
# Read from STDIN
|
48
47
|
# The argument neither a mailbox nor a Maildir/.
|
49
|
-
classname =
|
48
|
+
classname = self.class.to_s << '::STDIN'
|
50
49
|
parameter['type'] = 'stdin'
|
51
50
|
end
|
52
|
-
|
53
51
|
return nil unless classname
|
54
52
|
|
55
53
|
classpath = classname.gsub('::', '/').downcase
|
data/lib/sisimai/mail/maildir.rb
CHANGED
data/lib/sisimai/mda.rb
CHANGED
@@ -3,10 +3,7 @@ module Sisimai
|
|
3
3
|
module MDA
|
4
4
|
# Imported from p5-Sisimail/lib/Sisimai/MDA.pm
|
5
5
|
class << self
|
6
|
-
|
7
|
-
:from => %r/\A(?:Mail Delivery Subsystem|MAILER-DAEMON|postmaster)/i,
|
8
|
-
}.freeze
|
9
|
-
Re1 = {
|
6
|
+
AgentNames = {
|
10
7
|
# dovecot/src/deliver/deliver.c
|
11
8
|
# 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
|
12
9
|
# 12: "Your message to <%t> was automatically rejected:%n%r"
|
@@ -17,66 +14,68 @@ module Sisimai
|
|
17
14
|
:'vpopmail' => %r/\Avdelivermail: /,
|
18
15
|
:'vmailmgr' => %r/\Avdeliver: /,
|
19
16
|
}.freeze
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
MarkingsOf = {
|
18
|
+
message: %r{\A(?>
|
19
|
+
Your[ ]message[ ]to[ ].+[ ]was[ ]automatically[ ]rejected:\z
|
20
|
+
|(?:mail[.]local|procmail|maildrop|vdelivermail|vdeliver):[ ]
|
21
|
+
)
|
22
|
+
}x
|
23
|
+
}.freeze
|
25
24
|
|
26
25
|
# dovecot/src/deliver/mail-send.c:94
|
27
|
-
|
26
|
+
ReFailures = {
|
28
27
|
:'dovecot' => {
|
29
|
-
:userunknown => %r/\
|
28
|
+
:userunknown => %r/\Amailbox doesn't exist: /,
|
30
29
|
:mailboxfull => %r{\A(?:
|
31
|
-
|
32
|
-
|
|
33
|
-
|
|
30
|
+
quota[ ]exceeded # Dovecot 1.2 dovecot/src/plugins/quota/quota.c
|
31
|
+
|quota[ ]exceeded[ ][(]mailbox[ ]for[ ]user[ ]is[ ]full[)] # dovecot/src/plugins/quota/quota.c
|
32
|
+
|not[ ]enough[ ]disk[ ]space
|
34
33
|
)
|
35
|
-
}
|
34
|
+
}x,
|
36
35
|
},
|
37
36
|
:'mail.local' => {
|
38
37
|
:userunknown => %r{[:][ ](?:
|
39
38
|
unknown[ ]user[:]
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
|user[ ]unknown
|
40
|
+
|invalid[ ]mailbox[ ]path
|
41
|
+
|user[ ]missing[ ]home[ ]directory
|
43
42
|
)
|
44
|
-
}
|
43
|
+
}x,
|
45
44
|
:mailboxfull => %r{(?:
|
46
|
-
|
47
|
-
|
|
45
|
+
disc[ ]quota[ ]exceeded
|
46
|
+
|mailbox[ ]full[ ]or[ ]quota[ ]exceeded
|
48
47
|
)
|
49
|
-
}
|
50
|
-
:systemerror => %r/
|
48
|
+
}x,
|
49
|
+
:systemerror => %r/temporary file write error/,
|
51
50
|
},
|
52
51
|
:'procmail' => {
|
53
|
-
:mailboxfull => %r/
|
54
|
-
:systemfull => %r/
|
52
|
+
:mailboxfull => %r/quota exceeded while writing/,
|
53
|
+
:systemfull => %r/no space left to finish writing/,
|
55
54
|
},
|
56
55
|
:'maildrop' => {
|
57
56
|
:userunknown => %r{(?:
|
58
|
-
|
57
|
+
invalid[ ]user[ ]specified[.]
|
59
58
|
|Cannot[ ]find[ ]system[ ]user
|
60
59
|
)
|
61
|
-
}
|
62
|
-
:mailboxfull => %r/maildir over quota[.]\z
|
60
|
+
}x,
|
61
|
+
:mailboxfull => %r/maildir over quota[.]\z/,
|
63
62
|
},
|
64
63
|
:'vpopmail' => {
|
65
|
-
:userunknown => %r/
|
64
|
+
:userunknown => %r/sorry, no mailbox here by that name[.]/,
|
66
65
|
:filtered => %r{(?:
|
67
66
|
account[ ]is[ ]locked[ ]email[ ]bounced
|
68
67
|
|user[ ]does[ ]not[ ]exist,[ ]but[ ]will[ ]deliver[ ]to[ ]
|
69
68
|
)
|
70
|
-
}
|
71
|
-
:mailboxfull => %r/(?:domain|user) is over quota
|
69
|
+
}x,
|
70
|
+
:mailboxfull => %r/(?:domain|user) is over quota/,
|
72
71
|
},
|
73
72
|
:'vmailmgr' => {
|
74
73
|
:userunknown => %r{(?>
|
75
|
-
|
76
|
-
|
|
74
|
+
invalid[ ]or[ ]unknown[ ](?:base[ ]user[ ]or[ ]domain|virtual[ ]user)
|
75
|
+
|user[ ]name[ ]does[ ]not[ ]refer[ ]to[ ]a[ ]virtual[ ]user/
|
77
76
|
)
|
78
|
-
}
|
79
|
-
:mailboxfull => %r/
|
77
|
+
}x,
|
78
|
+
:mailboxfull => %r/delivery failed due to system quota violation/,
|
80
79
|
},
|
81
80
|
}.freeze
|
82
81
|
|
@@ -96,8 +95,7 @@ module Sisimai
|
|
96
95
|
return nil unless mbody
|
97
96
|
return nil if mhead.keys.size.zero?
|
98
97
|
return nil if mbody.empty?
|
99
|
-
|
100
|
-
return nil unless mhead['from'] =~ Re0[:from]
|
98
|
+
return nil unless mhead['from'].downcase.start_with?('mail delivery subsystem','mailer-daemon', 'postmaster')
|
101
99
|
|
102
100
|
agentname0 = '' # [String] MDA name
|
103
101
|
reasonname = '' # [String] Error reason
|
@@ -105,16 +103,16 @@ module Sisimai
|
|
105
103
|
hasdivided = mbody.split("\n")
|
106
104
|
linebuffer = []
|
107
105
|
|
108
|
-
hasdivided.
|
106
|
+
while e = hasdivided.shift do
|
109
107
|
# Check each line with each MDA's symbol regular expression.
|
110
108
|
if agentname0 == ''
|
111
109
|
# Try to match with each regular expression
|
112
110
|
next unless e.size > 0
|
113
|
-
next unless e =~
|
111
|
+
next unless e =~ MarkingsOf[:message]
|
114
112
|
|
115
|
-
|
113
|
+
AgentNames.each_key do |f|
|
116
114
|
# Detect the agent name from the line
|
117
|
-
next unless e =~
|
115
|
+
next unless e =~ AgentNames[f]
|
118
116
|
agentname0 = f.to_s
|
119
117
|
break
|
120
118
|
end
|
@@ -124,15 +122,14 @@ module Sisimai
|
|
124
122
|
linebuffer << e
|
125
123
|
break unless e.size > 0
|
126
124
|
end
|
127
|
-
|
128
125
|
return nil unless agentname0.size > 0
|
129
126
|
return nil unless linebuffer.size > 0
|
130
127
|
|
131
|
-
|
128
|
+
ReFailures[agentname0.to_sym].each_key do |e|
|
132
129
|
# Detect an error reason from message patterns of the MDA.
|
133
130
|
linebuffer.each do |f|
|
134
131
|
# Try to match with each regular expression
|
135
|
-
next unless f =~
|
132
|
+
next unless f.downcase =~ ReFailures[agentname0.to_sym][e]
|
136
133
|
reasonname = e.to_s
|
137
134
|
bouncemesg = f
|
138
135
|
break
|
data/lib/sisimai/message.rb
CHANGED
@@ -50,10 +50,9 @@ module Sisimai
|
|
50
50
|
# Sisimai::Message::JSON
|
51
51
|
return nil unless email.is_a? Hash
|
52
52
|
child = 'Sisimai::Message::JSON'
|
53
|
-
|
54
53
|
else
|
55
54
|
# Unsupported value in "input"
|
56
|
-
warn ' ***warning: Unsupported value in "input": '
|
55
|
+
warn ' ***warning: Unsupported value in "input": ' << input.to_s
|
57
56
|
return nil
|
58
57
|
end
|
59
58
|
|
@@ -66,7 +65,7 @@ module Sisimai
|
|
66
65
|
begin
|
67
66
|
require child.gsub('::', '/').downcase
|
68
67
|
rescue LoadError => ce
|
69
|
-
warn ' ***warning: Failed to load module: '
|
68
|
+
warn ' ***warning: Failed to load module: ' << ce.to_s
|
70
69
|
return nil
|
71
70
|
end
|
72
71
|
|
@@ -16,13 +16,12 @@ module Sisimai
|
|
16
16
|
@@ToBeLoaded = []
|
17
17
|
@@TryOnFirst = []
|
18
18
|
|
19
|
+
BorderLine = '__MIME_ENCODED_BOUNDARY__'
|
19
20
|
EndOfEmail = Sisimai::String.EOM
|
20
21
|
RFC822Head = Sisimai::RFC5322.HEADERFIELDS
|
21
22
|
RFC3834Set = Sisimai::RFC3834.headerlist.map(&:downcase)
|
22
|
-
HeaderList = [
|
23
|
-
|
24
|
-
'received', 'content-transfer-encoding', 'return-path', 'x-mailer',
|
25
|
-
].freeze
|
23
|
+
HeaderList = %w[from to date subject content-type reply-to message-id
|
24
|
+
received content-transfer-encoding return-path x-mailer].freeze
|
26
25
|
MultiHeads = { 'received' => true }.freeze
|
27
26
|
IgnoreList = { 'dkim-signature' => true }.freeze
|
28
27
|
Indicators = {
|
@@ -64,10 +63,11 @@ module Sisimai
|
|
64
63
|
return nil if aftersplit.empty?
|
65
64
|
|
66
65
|
# 2. Convert email headers from text to hash reference
|
67
|
-
headerargv = {
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
headerargv = {
|
67
|
+
'extheaders' => ExtHeaders,
|
68
|
+
'tryonfirst' => [],
|
69
|
+
'extrafield' => argvs['field'] || [],
|
70
|
+
}
|
71
71
|
processing['from'] = aftersplit['from']
|
72
72
|
processing['header'] = Sisimai::Message::Email.headers(aftersplit['header'], headerargv)
|
73
73
|
|
@@ -115,7 +115,7 @@ module Sisimai
|
|
115
115
|
modulelist = []
|
116
116
|
tobeloaded = []
|
117
117
|
|
118
|
-
%w
|
118
|
+
%w[load order].each do |e|
|
119
119
|
# The order of MTA modules specified by user
|
120
120
|
next unless argvs.key?(e)
|
121
121
|
next unless argvs[e].is_a? Array
|
@@ -130,7 +130,7 @@ module Sisimai
|
|
130
130
|
begin
|
131
131
|
require v.to_s.gsub('::', '/').downcase
|
132
132
|
rescue LoadError
|
133
|
-
warn ' ***warning: Failed to load '
|
133
|
+
warn ' ***warning: Failed to load ' << v
|
134
134
|
next
|
135
135
|
end
|
136
136
|
|
@@ -159,7 +159,7 @@ module Sisimai
|
|
159
159
|
return {} if email.empty?
|
160
160
|
|
161
161
|
email = email.scrub('?')
|
162
|
-
email = email.gsub(/\r\n/, "\n") if email
|
162
|
+
email = email.gsub(/\r\n/, "\n") if email.include?("\r\n")
|
163
163
|
email = email.gsub(/[ \t]+$/, '') if email =~ /[ \t]+$/
|
164
164
|
|
165
165
|
hasdivided = email.split("\n")
|
@@ -167,7 +167,6 @@ module Sisimai
|
|
167
167
|
|
168
168
|
readcursor = 0
|
169
169
|
aftersplit = { 'from' => '', 'header' => '', 'body' => '' }
|
170
|
-
pseudofrom = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
|
171
170
|
|
172
171
|
if hasdivided[0][0, 5] == 'From '
|
173
172
|
# From MAILER-DAEMON Tue Feb 11 00:00:00 2014
|
@@ -176,22 +175,20 @@ module Sisimai
|
|
176
175
|
end
|
177
176
|
|
178
177
|
# Split email data to headers and a body part.
|
179
|
-
hasdivided.
|
178
|
+
while e = hasdivided.shift do
|
180
179
|
# Split email data to headers and a body part.
|
181
180
|
if readcursor & Indicators[:endof] > 0
|
182
181
|
# The body part of the email
|
183
|
-
aftersplit['body']
|
184
|
-
|
182
|
+
aftersplit['body'] << e + "\n"
|
185
183
|
else
|
186
184
|
# The boundary for splitting headers and a body part does not
|
187
185
|
# appeare yet.
|
188
186
|
if e.empty?
|
189
187
|
# Blank line, it is a boundary of headers and a body part
|
190
188
|
readcursor |= Indicators[:endof] if readcursor & Indicators[:begin] > 0
|
191
|
-
|
192
189
|
else
|
193
190
|
# The header part of the email
|
194
|
-
aftersplit['header']
|
191
|
+
aftersplit['header'] << e + "\n"
|
195
192
|
readcursor |= Indicators[:begin]
|
196
193
|
end
|
197
194
|
end
|
@@ -199,7 +196,7 @@ module Sisimai
|
|
199
196
|
return {} if aftersplit['header'].empty?
|
200
197
|
return {} if aftersplit['body'].empty?
|
201
198
|
|
202
|
-
aftersplit['from'] =
|
199
|
+
aftersplit['from'] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014' if aftersplit['from'].empty?
|
203
200
|
return aftersplit
|
204
201
|
end
|
205
202
|
|
@@ -211,11 +208,11 @@ module Sisimai
|
|
211
208
|
def self.headers(heads, argvs = {})
|
212
209
|
return nil unless heads
|
213
210
|
|
214
|
-
currheader = ''
|
215
211
|
allheaders = {}
|
216
212
|
structured = {}
|
217
213
|
extheaders = argvs['extheaders'] || []
|
218
214
|
extrafield = argvs['extrafield'] || []
|
215
|
+
hasdivided = heads.split("\n")
|
219
216
|
|
220
217
|
HeaderList.each { |e| structured[e] = nil }
|
221
218
|
HeaderList.each { |e| allheaders[e] = true }
|
@@ -226,7 +223,7 @@ module Sisimai
|
|
226
223
|
extrafield.each { |e| allheaders[e.downcase] = true }
|
227
224
|
end
|
228
225
|
|
229
|
-
|
226
|
+
while e = hasdivided.shift do
|
230
227
|
# Convert email headers to hash
|
231
228
|
if cv = e.match(/\A([^ ]+?)[:][ ]*(.*?)\z/)
|
232
229
|
# split the line into a header name and a header content
|
@@ -242,7 +239,6 @@ module Sisimai
|
|
242
239
|
rhs = rhs.tr("\t", ' ')
|
243
240
|
rhs = rhs.squeeze(' ')
|
244
241
|
structured[currheader] << rhs
|
245
|
-
|
246
242
|
else
|
247
243
|
# Other headers except "Received" and so on
|
248
244
|
if extheaders[currheader]
|
@@ -254,7 +250,6 @@ module Sisimai
|
|
254
250
|
end
|
255
251
|
structured[currheader] = rhs
|
256
252
|
end
|
257
|
-
|
258
253
|
elsif cv = e.match(/\A[ \t]+(.+?)\z/)
|
259
254
|
# Ignore header?
|
260
255
|
next if IgnoreList[currheader]
|
@@ -262,11 +257,10 @@ module Sisimai
|
|
262
257
|
# Header line continued from the previous line
|
263
258
|
if structured[currheader].is_a? Array
|
264
259
|
# Concatenate a header which have multi-lines such as 'Received'
|
265
|
-
structured[currheader][-1]
|
266
|
-
|
260
|
+
structured[currheader][-1] << ' ' << cv[1]
|
267
261
|
else
|
268
262
|
structured[currheader] ||= ''
|
269
|
-
structured[currheader]
|
263
|
+
structured[currheader] << ' ' << cv[1]
|
270
264
|
end
|
271
265
|
end
|
272
266
|
end
|
@@ -309,10 +303,9 @@ module Sisimai
|
|
309
303
|
takenapart = {}
|
310
304
|
hasdivided = heads.split("\n")
|
311
305
|
previousfn = '' # Previous field name
|
312
|
-
borderline = '__MIME_ENCODED_BOUNDARY__'
|
313
306
|
mimeborder = {}
|
314
307
|
|
315
|
-
hasdivided.
|
308
|
+
while e = hasdivided.shift do
|
316
309
|
# Header name as a key, The value of header as a value
|
317
310
|
if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*(.*)\z/)
|
318
311
|
# Header
|
@@ -323,28 +316,26 @@ module Sisimai
|
|
323
316
|
next unless RFC822Head.key?(lhs)
|
324
317
|
previousfn = lhs
|
325
318
|
takenapart[previousfn] = rhs unless takenapart[previousfn]
|
326
|
-
|
327
319
|
else
|
328
320
|
# Continued line from the previous line
|
329
|
-
next unless e
|
321
|
+
next unless e.start_with?(' ', "\t")
|
330
322
|
next if previousfn.empty?
|
331
323
|
|
332
324
|
# Concatenate the line if it is the value of required header
|
333
325
|
if Sisimai::MIME.is_mimeencoded(e)
|
334
326
|
# The line is MIME-Encoded test
|
335
|
-
takenapart[previousfn]
|
327
|
+
takenapart[previousfn] << if previousfn == 'subject'
|
336
328
|
# Subject: header
|
337
|
-
|
329
|
+
BorderLine + e
|
338
330
|
else
|
339
331
|
# Is not Subject header
|
340
332
|
e
|
341
333
|
end
|
342
334
|
mimeborder[previousfn] = true
|
343
|
-
|
344
335
|
else
|
345
336
|
# ASCII Characters only: Not MIME-Encoded
|
346
337
|
e = e.lstrip
|
347
|
-
takenapart[previousfn]
|
338
|
+
takenapart[previousfn] << e
|
348
339
|
mimeborder[previousfn] ||= false
|
349
340
|
end
|
350
341
|
end
|
@@ -358,13 +349,12 @@ module Sisimai
|
|
358
349
|
# The value of ``Subject'' header is including multibyte character,
|
359
350
|
# is not MIME-Encoded text.
|
360
351
|
v = 'MULTIBYTE CHARACTERS HAVE BEEN REMOVED'
|
361
|
-
|
362
352
|
else
|
363
353
|
# MIME-Encoded subject field or ASCII characters only
|
364
354
|
r = []
|
365
355
|
if mimeborder['subject']
|
366
356
|
# split the value of Subject by borderline
|
367
|
-
v.split(
|
357
|
+
v.split(BorderLine).each do |m|
|
368
358
|
# Insert value to the array if the string is MIME encoded text
|
369
359
|
r << m if Sisimai::MIME.is_mimeencoded(m)
|
370
360
|
end
|
@@ -412,7 +402,7 @@ module Sisimai
|
|
412
402
|
mesgformat = (mailheader['content-type'] || '').downcase
|
413
403
|
ctencoding = (mailheader['content-transfer-encoding'] || '').downcase
|
414
404
|
|
415
|
-
if mesgformat
|
405
|
+
if mesgformat.start_with?('text/plain', 'text/html')
|
416
406
|
# Content-Type: text/plain; charset=UTF-8
|
417
407
|
if ctencoding == 'base64' || ctencoding == 'quoted-printable'
|
418
408
|
# Content-Transfer-Encoding: base64
|
@@ -426,23 +416,23 @@ module Sisimai
|
|
426
416
|
end
|
427
417
|
end
|
428
418
|
|
429
|
-
if mesgformat
|
419
|
+
if mesgformat.start_with?('text/html;')
|
430
420
|
# Content-Type: text/html;...
|
431
421
|
bodystring = Sisimai::String.to_plain(bodystring, true)
|
432
422
|
end
|
433
|
-
|
434
423
|
else
|
435
424
|
# NOT text/plain
|
436
|
-
|
425
|
+
lowercased = bodystring.downcase
|
426
|
+
if lowercased =~ ReEncoding[:'quoted-print']
|
437
427
|
# Content-Transfer-Encoding: quoted-printable
|
438
428
|
bodystring = Sisimai::MIME.qprintd(bodystring, mailheader)
|
439
429
|
end
|
440
430
|
|
441
|
-
if
|
442
|
-
cv =
|
431
|
+
if lowercased =~ ReEncoding[:'7bit-encoded'] &&
|
432
|
+
cv = lowercased.match(ReEncoding[:'some-iso2022'])
|
443
433
|
# Content-Transfer-Encoding: 7bit
|
444
434
|
# Content-Type: text/plain; charset=ISO-2022-JP
|
445
|
-
|
435
|
+
if ! cv[1].include?('us-ascii') && ! cv[1].include?('utf-8')
|
446
436
|
bodystring = Sisimai::String.to_utf8(bodystring, cv[1])
|
447
437
|
end
|
448
438
|
end
|
@@ -460,7 +450,7 @@ module Sisimai
|
|
460
450
|
}
|
461
451
|
havecaught = hookmethod.call(p)
|
462
452
|
rescue StandardError => ce
|
463
|
-
warn
|
453
|
+
warn ' ***warning: Something is wrong in hook method :' << ce.to_s
|
464
454
|
end
|
465
455
|
end
|
466
456
|
|
@@ -468,17 +458,17 @@ module Sisimai
|
|
468
458
|
# Check whether or not the message is a bounce mail.
|
469
459
|
# Pre-Process email body if it is a forwarded bounce message.
|
470
460
|
# Get the original text when the subject begins from 'fwd:' or 'fw:'
|
471
|
-
if mailheader['subject'] =~ /\A[ \t]*fwd?:/
|
461
|
+
if mailheader['subject'].downcase =~ /\A[ \t]*fwd?:/
|
472
462
|
# Delete quoted strings, quote symbols(>)
|
473
463
|
bodystring = bodystring.gsub(/^[>]+[ ]/m, '')
|
474
464
|
bodystring = bodystring.gsub(/^[>]$/m, '')
|
475
465
|
end
|
476
|
-
bodystring
|
477
|
-
haveloaded
|
478
|
-
scannedset
|
466
|
+
bodystring << EndOfEmail
|
467
|
+
haveloaded = {}
|
468
|
+
scannedset = nil
|
479
469
|
|
480
470
|
catch :SCANNER do
|
481
|
-
|
471
|
+
while true
|
482
472
|
# 1. Sisimai::ARF
|
483
473
|
# 2. User-Defined Module
|
484
474
|
# 3. MTA Module Candidates to be tried on first
|
@@ -498,7 +488,7 @@ module Sisimai
|
|
498
488
|
begin
|
499
489
|
require r.gsub('::', '/').downcase
|
500
490
|
rescue LoadError => ce
|
501
|
-
warn ' ***warning: Failed to load '
|
491
|
+
warn ' ***warning: Failed to load ' << ce.to_s
|
502
492
|
next
|
503
493
|
end
|
504
494
|
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
@@ -513,7 +503,7 @@ module Sisimai
|
|
513
503
|
begin
|
514
504
|
require r.gsub('::', '/').downcase
|
515
505
|
rescue LoadError => ce
|
516
|
-
warn ' ***warning: '
|
506
|
+
warn ' ***warning: ' << ce.to_s
|
517
507
|
next
|
518
508
|
end
|
519
509
|
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
@@ -531,10 +521,9 @@ module Sisimai
|
|
531
521
|
haveloaded[r] = true
|
532
522
|
throw :SCANNER if scannedset
|
533
523
|
rescue => ce
|
534
|
-
warn ' ***warning: '
|
524
|
+
warn ' ***warning: ' << ce.to_s
|
535
525
|
next
|
536
526
|
end
|
537
|
-
|
538
527
|
end
|
539
528
|
|
540
529
|
# When the all of Sisimai::Bite::Email::* modules did not return
|
@@ -560,3 +549,4 @@ module Sisimai
|
|
560
549
|
end
|
561
550
|
end
|
562
551
|
end
|
552
|
+
|