sisimai 4.16.0-java → 4.17.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.

Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/ANALYTICAL-PRECISION +7 -7
  4. data/Changes +15 -0
  5. data/Makefile +1 -1
  6. data/README.md +30 -28
  7. data/lib/sisimai.rb +20 -1
  8. data/lib/sisimai/address.rb +28 -9
  9. data/lib/sisimai/arf.rb +37 -46
  10. data/lib/sisimai/data.rb +67 -43
  11. data/lib/sisimai/datetime.rb +210 -210
  12. data/lib/sisimai/mda.rb +30 -30
  13. data/lib/sisimai/message.rb +3 -5
  14. data/lib/sisimai/msp/de/einsundeins.rb +14 -42
  15. data/lib/sisimai/msp/de/gmx.rb +17 -44
  16. data/lib/sisimai/msp/jp/biglobe.rb +15 -44
  17. data/lib/sisimai/msp/jp/ezweb.rb +20 -50
  18. data/lib/sisimai/msp/jp/kddi.rb +16 -43
  19. data/lib/sisimai/msp/ru/mailru.rb +20 -48
  20. data/lib/sisimai/msp/ru/yandex.rb +16 -50
  21. data/lib/sisimai/msp/uk/messagelabs.rb +17 -51
  22. data/lib/sisimai/msp/us/amazonses.rb +18 -40
  23. data/lib/sisimai/msp/us/amazonworkmail.rb +17 -35
  24. data/lib/sisimai/msp/us/aol.rb +17 -41
  25. data/lib/sisimai/msp/us/bigfoot.rb +15 -48
  26. data/lib/sisimai/msp/us/facebook.rb +63 -90
  27. data/lib/sisimai/msp/us/google.rb +15 -44
  28. data/lib/sisimai/msp/us/office365.rb +21 -46
  29. data/lib/sisimai/msp/us/outlook.rb +17 -50
  30. data/lib/sisimai/msp/us/receivingses.rb +20 -43
  31. data/lib/sisimai/msp/us/sendgrid.rb +13 -37
  32. data/lib/sisimai/msp/us/verizon.rb +30 -74
  33. data/lib/sisimai/msp/us/yahoo.rb +12 -40
  34. data/lib/sisimai/msp/us/zoho.rb +14 -42
  35. data/lib/sisimai/mta/activehunter.rb +11 -40
  36. data/lib/sisimai/mta/apachejames.rb +18 -40
  37. data/lib/sisimai/mta/courier.rb +20 -57
  38. data/lib/sisimai/mta/domino.rb +24 -56
  39. data/lib/sisimai/mta/exchange.rb +26 -54
  40. data/lib/sisimai/mta/exim.rb +20 -39
  41. data/lib/sisimai/mta/imailserver.rb +26 -71
  42. data/lib/sisimai/mta/interscanmss.rb +26 -44
  43. data/lib/sisimai/mta/mailfoundry.rb +12 -42
  44. data/lib/sisimai/mta/mailmarshalsmtp.rb +13 -43
  45. data/lib/sisimai/mta/mcafee.rb +17 -46
  46. data/lib/sisimai/mta/messagingserver.rb +14 -47
  47. data/lib/sisimai/mta/mfilter.rb +12 -35
  48. data/lib/sisimai/mta/mxlogic.rb +18 -42
  49. data/lib/sisimai/mta/notes.rb +22 -45
  50. data/lib/sisimai/mta/opensmtpd.rb +18 -48
  51. data/lib/sisimai/mta/postfix.rb +15 -45
  52. data/lib/sisimai/mta/qmail.rb +32 -60
  53. data/lib/sisimai/mta/sendmail.rb +13 -38
  54. data/lib/sisimai/mta/surfcontrol.rb +15 -44
  55. data/lib/sisimai/mta/userdefined.rb +14 -30
  56. data/lib/sisimai/mta/v5sendmail.rb +18 -40
  57. data/lib/sisimai/mta/x1.rb +12 -41
  58. data/lib/sisimai/mta/x2.rb +12 -41
  59. data/lib/sisimai/mta/x3.rb +12 -39
  60. data/lib/sisimai/mta/x4.rb +33 -66
  61. data/lib/sisimai/mta/x5.rb +15 -42
  62. data/lib/sisimai/reason.rb +8 -71
  63. data/lib/sisimai/reason/blocked.rb +3 -0
  64. data/lib/sisimai/reason/contenterror.rb +3 -0
  65. data/lib/sisimai/reason/delivered.rb +27 -0
  66. data/lib/sisimai/reason/exceedlimit.rb +3 -0
  67. data/lib/sisimai/reason/expired.rb +3 -0
  68. data/lib/sisimai/reason/feedback.rb +18 -0
  69. data/lib/sisimai/reason/filtered.rb +4 -0
  70. data/lib/sisimai/reason/hasmoved.rb +3 -0
  71. data/lib/sisimai/reason/hostunknown.rb +3 -0
  72. data/lib/sisimai/reason/mailboxfull.rb +3 -0
  73. data/lib/sisimai/reason/mailererror.rb +3 -0
  74. data/lib/sisimai/reason/mesgtoobig.rb +3 -0
  75. data/lib/sisimai/reason/networkerror.rb +3 -0
  76. data/lib/sisimai/reason/norelaying.rb +3 -0
  77. data/lib/sisimai/reason/notaccept.rb +3 -0
  78. data/lib/sisimai/reason/onhold.rb +3 -0
  79. data/lib/sisimai/reason/rejected.rb +3 -0
  80. data/lib/sisimai/reason/securityerror.rb +3 -0
  81. data/lib/sisimai/reason/spamdetected.rb +3 -0
  82. data/lib/sisimai/reason/suspend.rb +3 -0
  83. data/lib/sisimai/reason/syntaxerror.rb +41 -0
  84. data/lib/sisimai/reason/systemerror.rb +3 -0
  85. data/lib/sisimai/reason/systemfull.rb +3 -0
  86. data/lib/sisimai/reason/toomanyconn.rb +3 -0
  87. data/lib/sisimai/reason/undefined.rb +18 -0
  88. data/lib/sisimai/reason/userunknown.rb +3 -0
  89. data/lib/sisimai/reason/vacation.rb +18 -0
  90. data/lib/sisimai/rfc3464.rb +15 -40
  91. data/lib/sisimai/rfc3834.rb +1 -10
  92. data/lib/sisimai/rfc5322.rb +57 -19
  93. data/lib/sisimai/rhost/googleapps.rb +82 -82
  94. data/lib/sisimai/smtp/reply.rb +2 -1
  95. data/lib/sisimai/smtp/status.rb +154 -152
  96. data/lib/sisimai/string.rb +2 -3
  97. data/lib/sisimai/version.rb +1 -1
  98. data/set-of-emails/maildir/bsd/rfc3464-29.eml +60 -0
  99. data/set-of-emails/maildir/bsd/us-amazonworkmail-06.eml +156 -0
  100. data/set-of-emails/maildir/bsd/us-amazonworkmail-07.eml +158 -0
  101. data/set-of-emails/maildir/bsd/us-google-15.eml +97 -0
  102. data/set-of-emails/maildir/bsd/us-google-16.eml +99 -0
  103. data/set-of-emails/maildir/bsd/us-google-17.eml +104 -0
  104. data/set-of-emails/maildir/dos/apachejames-01.eml +4 -4
  105. data/set-of-emails/maildir/dos/us-amazonworkmail-01.eml +156 -0
  106. data/set-of-emails/maildir/dos/us-office365-01.eml +102 -0
  107. data/set-of-emails/maildir/mac/apachejames-01.eml +1 -9
  108. data/set-of-emails/maildir/mac/us-amazonworkmail-01.eml +1 -7
  109. data/set-of-emails/maildir/mac/us-office365-01.eml +1 -4
  110. metadata +17 -2
@@ -78,11 +78,11 @@ module Sisimai
78
78
  # find exim/ -type f -exec grep 'message = US' {} /dev/null \;
79
79
  ReFailure = {
80
80
  # route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
81
- 'userunknown' => %r/user[ ]not[ ]found/x,
81
+ userunknown: %r/user[ ]not[ ]found/x,
82
82
  # transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
83
83
  # routers/dnslookup.c:331| addr->message = US"all relevant MX records point to non-existent hosts";
84
84
  # route.c:1826| uschar *message = US"Unrouteable address";
85
- 'hostunknown' => %r{(?>
85
+ hostunknown: %r{(?>
86
86
  all[ ](?:
87
87
  host[ ]address[ ]lookups[ ]failed[ ]permanently
88
88
  |relevant[ ]MX[ ]records[ ]point[ ]to[ ]non[-]existent[ ]hosts
@@ -93,10 +93,10 @@ module Sisimai
93
93
  # transports/appendfile.c:2567| addr->user_message = US"mailbox is full";
94
94
  # transports/appendfile.c:3049| addr->message = string_sprintf("mailbox is full "
95
95
  # transports/appendfile.c:3050| "(quota exceeded while writing to file %s)", filename);
96
- 'mailboxfull' => %r/(?:mailbox[ ]is[ ]full:?|error:[ ]quota[ ]exceed)/x,
96
+ mailboxfull: %r/(?:mailbox[ ]is[ ]full:?|error:[ ]quota[ ]exceed)/x,
97
97
  # routers/dnslookup.c:328| addr->message = US"an MX or SRV record indicated no SMTP service";
98
98
  # transports/smtp.c:3502| addr->message = US"no host found for existing SMTP connection";
99
- 'notaccept' => %r{(?:
99
+ notaccept: %r{(?:
100
100
  an[ ]MX[ ]or[ ]SRV[ ]record[ ]indicated[ ]no[ ]SMTP[ ]service
101
101
  |no[ ]host[ ]found[ ]for[ ]existing[ ]SMTP[ ]connection
102
102
  )
@@ -104,14 +104,14 @@ module Sisimai
104
104
  # deliver.c:5614| addr->message = US"delivery to file forbidden";
105
105
  # deliver.c:5624| addr->message = US"delivery to pipe forbidden";
106
106
  # transports/pipe.c:1156| addr->user_message = US"local delivery failed";
107
- 'systemerror' => %r{(?>
107
+ systemerror: %r{(?>
108
108
  delivery[ ]to[ ](?:file|pipe)[ ]forbidden
109
109
  |local[ ]delivery[ ]failed
110
110
  |LMTP[ ]error[ ]after[ ]
111
111
  )
112
112
  }x,
113
113
  # deliver.c:5425| new->message = US"Too many \"Received\" headers - suspected mail loop";
114
- 'contenterror' => %r/Too[ ]many[ ]["]Received["][ ]headers/x,
114
+ contenterror: %r/Too[ ]many[ ]["]Received["][ ]headers/x,
115
115
  }
116
116
 
117
117
  # retry.c:902| addr->message = (addr->message == NULL)? US"retry timeout exceeded" :
@@ -132,10 +132,7 @@ module Sisimai
132
132
  |Message[ ].+[ ](?:has[ ]been[ ]frozen|was[ ]frozen[ ]on[ ]arrival[ ]by[ ])
133
133
  )
134
134
  }x
135
-
136
135
  Indicators = Sisimai::MTA.INDICATORS
137
- LongFields = Sisimai::RFC5322.LONGFIELDS
138
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
139
136
 
140
137
  def description; return 'Exim'; end
141
138
  def smtpagent; return 'Exim'; end
@@ -160,11 +157,10 @@ module Sisimai
160
157
  return nil unless mhead['from'] =~ Re0[:from]
161
158
  return nil unless mhead['subject'] =~ Re0[:subject]
162
159
 
163
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
160
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
164
161
  hasdivided = mbody.split("\n")
165
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
166
- rfc822part = '' # (String) message/rfc822-headers part
167
- previousfn = '' # (String) Previous field name
162
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
163
+ blanklines = 0 # (Integer) The number of blank lines
168
164
  readcursor = 0 # (Integer) Points the current cursor position
169
165
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
170
166
  localhost0 = '' # (String) Local MTA
@@ -184,7 +180,7 @@ module Sisimai
184
180
  if readcursor == 0
185
181
  # Beginning of the bounce message or delivery status part
186
182
  if e =~ Re1[:begin]
187
- readcursor |= Indicators[:'deliverystatus']
183
+ readcursor |= Indicators[:deliverystatus]
188
184
  next unless e =~ Re1[:frozen]
189
185
  end
190
186
  end
@@ -199,30 +195,16 @@ module Sisimai
199
195
 
200
196
  if readcursor & Indicators[:'message-rfc822'] > 0
201
197
  # After "message/rfc822"
202
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
203
- # Get required headers only
204
- lhs = cv[1].downcase
205
- previousfn = ''
206
- next unless RFC822Head.key?(lhs)
207
-
208
- previousfn = lhs
209
- rfc822part += e + "\n"
210
-
211
- elsif e =~ /\A[ \t]+/
212
- # Continued line from the previous line
213
- next if rfc822next[previousfn]
214
- rfc822part += e + "\n" if LongFields.key?(previousfn)
215
-
216
- else
217
- # Check the end of headers in rfc822 part
218
- next unless LongFields.key?(previousfn)
219
- next unless e.empty?
220
- rfc822next[previousfn] = true
198
+ if e.empty?
199
+ blanklines += 1
200
+ break if blanklines > 1
201
+ next
221
202
  end
203
+ rfc822list << e
222
204
 
223
205
  else
224
206
  # Before "message/rfc822"
225
- next if readcursor & Indicators[:'deliverystatus'] == 0
207
+ next if readcursor & Indicators[:deliverystatus] == 0
226
208
  next if e.empty?
227
209
 
228
210
  # This message was created automatically by mail delivery software.
@@ -239,8 +221,7 @@ module Sisimai
239
221
  # deliver.c:6811| "recipients. This is a permanent error. The following address(es) failed:\n");
240
222
  v['softbounce'] = 0
241
223
 
242
- elsif cv = e.match(/\A[ ][ ]+([^ \t]+[@][^ \t]+[.][a-zA-Z]+)(:.+)?\z/) ||
243
- cv = e.match(Re1[:alias])
224
+ elsif cv = e.match(/\A[ ][ ]+([^ \t]+[@][^ \t]+[.][a-zA-Z]+)(:.+)?\z/) || e.match(Re1[:alias])
244
225
  # kijitora@example.jp
245
226
  # sabineko@example.jp: forced freeze
246
227
  #
@@ -256,7 +237,7 @@ module Sisimai
256
237
  recipients += 1
257
238
 
258
239
  elsif cv = e.match(/\A[ ]+[(]generated[ ]from[ ](.+)[)]\z/) ||
259
- cv = e.match(/\A[ ]+generated[ ]by[ ]([^ \t]+[@][^ \t]+)/)
240
+ e.match(/\A[ ]+generated[ ]by[ ]([^ \t]+[@][^ \t]+)/)
260
241
  # (generated from kijitora@example.jp)
261
242
  # pipe to |/bin/echo "Some pipe output"
262
243
  # generated by userx@myhost.test.ex
@@ -457,7 +438,7 @@ module Sisimai
457
438
  ReFailure.each_key do |r|
458
439
  # Check each regular expression
459
440
  next unless e['diagnosis'] =~ ReFailure[r]
460
- e['reason'] = r
441
+ e['reason'] = r.to_s
461
442
  break
462
443
  end
463
444
 
@@ -535,10 +516,10 @@ module Sisimai
535
516
  end
536
517
  end
537
518
  e['status'] ||= sv
538
- e['action'] ||= 'failed' if e['status'] =~ /\A[45]/
539
519
  e.each_key { |a| e[a] ||= '' }
540
520
  end
541
521
 
522
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
542
523
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
543
524
  end
544
525
 
@@ -9,8 +9,8 @@ module Sisimai
9
9
  require 'sisimai/rfc5322'
10
10
 
11
11
  Re0 = {
12
- :'x-mailer' => %r/\A[<]SMTP32 v[\d.]+[>]\z/,
13
- :'subject' => %r/\AUndeliverable Mail\z/,
12
+ :'x-mailer' => %r/\A[<]SMTP32 v[\d.]+[>][ ]*\z/,
13
+ :'subject' => %r/\AUndeliverable Mail[ ]*\z/,
14
14
  }
15
15
  Re1 = {
16
16
  :begin => %r/\A\z/, # Blank line
@@ -19,41 +19,25 @@ module Sisimai
19
19
  :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
20
20
  }
21
21
  ReSMTP = {
22
- 'conn' => %r{(?:
22
+ conn: %r{(?:
23
23
  SMTP[ ]connection[ ]failed,
24
24
  |Unexpected[ ]connection[ ]response[ ]from[ ]server:
25
25
  )
26
26
  },
27
- 'ehlo' => %r|Unexpected response to EHLO/HELO:|,
28
- 'mail' => %r|Server response to MAIL FROM:|,
29
- 'rcpt' => %r|Additional RCPT TO generated following response:|,
30
- 'data' => %r|DATA command generated response:|,
27
+ ehlo: %r|Unexpected response to EHLO/HELO:|,
28
+ mail: %r|Server response to MAIL FROM:|,
29
+ rcpt: %r|Additional RCPT TO generated following response:|,
30
+ data: %r|DATA command generated response:|,
31
31
  }
32
32
  ReFailure = {
33
- 'hostunknown' => %r{
34
- Unknown[ ]host
35
- },
36
- 'userunknown' => %r{\A(?:
37
- Unknown[ ]user
38
- |Invalid[ ]final[ ]delivery[ ]userid # Filtered ?
39
- )
40
- }x,
41
- 'mailboxfull' => %r{
42
- \AUser[ ]mailbox[ ]exceeds[ ]allowed[ ]size
43
- }x,
44
- 'securityerr' => %r{
45
- \ARequested[ ]action[ ]not[ ]taken:[ ]virus[ ]detected
46
- }x,
47
- 'undefined' => %r{
48
- \Aundeliverable[ ]to[ ]
49
- }x,
50
- 'expired' => %r{
51
- \ADelivery[ ]failed[ ]\d+[ ]attempts
52
- }x,
33
+ hostunknown: %r/Unknown[ ]host/x,
34
+ userunknown: %r/\A(?:Unknown[ ]user|Invalid[ ]final[ ]delivery[ ]userid)/x,
35
+ mailboxfull: %r/\AUser[ ]mailbox[ ]exceeds[ ]allowed[ ]size/x,
36
+ securityerr: %r/\ARequested[ ]action[ ]not[ ]taken:[ ]virus[ ]detected/x,
37
+ undefined: %r/\Aundeliverable[ ]to[ ]/x,
38
+ expired: %r/\ADelivery[ ]failed[ ]\d+[ ]attempts/x,
53
39
  }
54
40
  Indicators = Sisimai::MTA.INDICATORS
55
- LongFields = Sisimai::RFC5322.LONGFIELDS
56
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
57
41
 
58
42
  def description; return 'IPSWITCH IMail Server'; end
59
43
  def smtpagent; return 'IMailServer'; end
@@ -80,11 +64,10 @@ module Sisimai
80
64
  match += 1 if mhead['x-mailer'] && mhead['x-mailer'] =~ Re0[:'x-mailer']
81
65
  return nil if match == 0
82
66
 
83
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
67
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
84
68
  hasdivided = mbody.split("\n")
85
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
86
- rfc822part = '' # (String) message/rfc822-headers part
87
- previousfn = '' # (String) Previous field name
69
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
70
+ blanklines = 0 # (Integer) The number of blank lines
88
71
  readcursor = 0 # (Integer) Points the current cursor position
89
72
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
90
73
  v = nil
@@ -93,7 +76,7 @@ module Sisimai
93
76
  if readcursor == 0
94
77
  # Beginning of the bounce message or delivery status part
95
78
  if e =~ Re1[:begin]
96
- readcursor |= Indicators[:'deliverystatus']
79
+ readcursor |= Indicators[:deliverystatus]
97
80
  next
98
81
  end
99
82
  end
@@ -108,26 +91,12 @@ module Sisimai
108
91
 
109
92
  if readcursor & Indicators[:'message-rfc822'] > 0
110
93
  # After "message/rfc822"
111
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
112
- # Get required headers only
113
- lhs = cv[1].downcase
114
- previousfn = ''
115
- next unless RFC822Head.key?(lhs)
116
-
117
- previousfn = lhs
118
- rfc822part += e + "\n"
119
-
120
- elsif e =~ /\A[ \t]+/
121
- # Continued line from the previous line
122
- next if rfc822next[previousfn]
123
- rfc822part += e + "\n" if LongFields.key?(previousfn)
124
-
125
- else
126
- # Check the end of headers in rfc822 part
127
- next unless LongFields.key?(previousfn)
128
- next unless e.empty?
129
- rfc822next[previousfn] = true
94
+ if e.empty?
95
+ blanklines += 1
96
+ break if blanklines > 1
97
+ next
130
98
  end
99
+ rfc822list << e
131
100
 
132
101
  else
133
102
  # Before "message/rfc822"
@@ -138,7 +107,7 @@ module Sisimai
138
107
  # Original message follows.
139
108
  v = dscontents[-1]
140
109
 
141
- if cv = e.match(/\A(.+)[ ](.+)[:][ \t]*([^ ]+[@][^ ]+)\z/)
110
+ if cv = e.match(/\A(.+)[ ](.+)[:][ \t]*([^ ]+[@][^ ]+)/)
142
111
  # Unknown user: kijitora@example.com
143
112
  if v['recipient']
144
113
  # There are multiple recipient addresses in the message body.
@@ -169,23 +138,12 @@ module Sisimai
169
138
  end
170
139
  end
171
140
  end
172
-
173
141
  return nil if recipients == 0
174
142
  require 'sisimai/string'
175
- require 'sisimai/smtp/status'
176
143
 
177
144
  dscontents.map do |e|
178
- # Set default values if each value is empty.
179
145
  e['agent'] = Sisimai::MTA::IMailServer.smtpagent
180
146
 
181
- if mhead['received'].size > 0
182
- # Get localhost and remote host name from Received header.
183
- r0 = mhead['received']
184
- %w|lhost rhost|.each { |a| e[a] ||= '' }
185
- e['lhost'] = Sisimai::RFC5322.received(r0[0]).shift if e['lhost'].empty?
186
- e['rhost'] = Sisimai::RFC5322.received(r0[-1]).pop if e['rhost'].empty?
187
- end
188
-
189
147
  if e['alterrors'] && e['alterrors'].size > 0
190
148
  # Copy alternative error message
191
149
  if e['diagnosis']
@@ -201,23 +159,20 @@ module Sisimai
201
159
  ReSMTP.each_key do |r|
202
160
  # Detect SMTP command from the message
203
161
  next unless e['diagnosis'] =~ ReSMTP[r]
204
- e['command'] = r.upcase
162
+ e['command'] = r.to_s.upcase
205
163
  break
206
164
  end
207
165
 
208
166
  ReFailure.each_key do |r|
209
167
  # Verify each regular expression of session errors
210
168
  next unless e['diagnosis'] =~ ReFailure[r]
211
- e['reason'] = r
169
+ e['reason'] = r.to_s
212
170
  break
213
171
  end
214
-
215
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
216
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
217
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
218
172
  e.each_key { |a| e[a] ||= '' }
219
173
  end
220
174
 
175
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
221
176
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
222
177
  end
223
178
 
@@ -26,8 +26,6 @@ module Sisimai
26
26
  :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
27
27
  }
28
28
  Indicators = Sisimai::MTA.INDICATORS
29
- LongFields = Sisimai::RFC5322.LONGFIELDS
30
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
31
29
 
32
30
  def description; return 'Trend Micro InterScan Messaging Security Suite'; end
33
31
  def smtpagent; return 'InterScanMSS'; end
@@ -54,11 +52,10 @@ module Sisimai
54
52
  match += 1 if Re0[:subject].find { |a| mhead['subject'] == a }
55
53
  return nil if match == 0
56
54
 
57
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
55
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
58
56
  hasdivided = mbody.split("\n")
59
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
60
- rfc822part = '' # (String) message/rfc822-headers part
61
- previousfn = '' # (String) Previous field name
57
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
58
+ blanklines = 0 # (Integer) The number of blank lines
62
59
  readcursor = 0 # (Integer) Points the current cursor position
63
60
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
64
61
  v = nil
@@ -67,7 +64,7 @@ module Sisimai
67
64
  if readcursor == 0
68
65
  # Beginning of the bounce message or delivery status part
69
66
  if e =~ Re1[:begin]
70
- readcursor |= Indicators[:'deliverystatus']
67
+ readcursor |= Indicators[:deliverystatus]
71
68
  next
72
69
  end
73
70
  end
@@ -82,30 +79,16 @@ module Sisimai
82
79
 
83
80
  if readcursor & Indicators[:'message-rfc822'] > 0
84
81
  # After "message/rfc822"
85
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
86
- # Get required headers only
87
- lhs = cv[1].downcase
88
- previousfn = ''
89
- next unless RFC822Head.key?(lhs)
90
-
91
- previousfn = lhs
92
- rfc822part += e + "\n"
93
-
94
- elsif e =~ /\A[ \t]+/
95
- # Continued line from the previous line
96
- next if rfc822next[previousfn]
97
- rfc822part += e + "\n" if LongFields.key?(previousfn)
98
-
99
- else
100
- # Check the end of headers in rfc822 part
101
- next unless LongFields.key?(previousfn)
102
- next unless e.empty?
103
- rfc822next[previousfn] = true
82
+ if e.empty?
83
+ blanklines += 1
84
+ break if blanklines > 1
85
+ next
104
86
  end
87
+ rfc822list << e
105
88
 
106
89
  else
107
90
  # Before "message/rfc822"
108
- next if readcursor & Indicators[:'deliverystatus'] == 0
91
+ next if readcursor & Indicators[:deliverystatus] == 0
109
92
  next if e.empty?
110
93
 
111
94
  # Sent <<< RCPT TO:<kijitora@example.co.jp>
@@ -113,16 +96,15 @@ module Sisimai
113
96
  v = dscontents[-1]
114
97
 
115
98
  if cv = e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]\z/) ||
116
- cv = e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]/)
99
+ e.match(/\A.+[<>]{3}[ \t]+.+[<]([^ ]+[@][^ ]+)[>]/)
117
100
  # Sent <<< RCPT TO:<kijitora@example.co.jp>
118
101
  # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
119
- cr = cv[1]
120
- if v['recipient'] && cr != v['recipient']
102
+ if v['recipient'] && cv[1] != v['recipient']
121
103
  # There are multiple recipient addresses in the message body.
122
104
  dscontents << Sisimai::MTA.DELIVERYSTATUS
123
105
  v = dscontents[-1]
124
106
  end
125
- v['recipient'] = cr
107
+ v['recipient'] = cv[1]
126
108
  recipients = dscontents.size
127
109
  end
128
110
 
@@ -133,30 +115,30 @@ module Sisimai
133
115
  elsif cv = e.match(/\AReceived[ ]+[>]{3}[ ]+(\d{3}[ ]+.+)\z/)
134
116
  # Received >>> 550 5.1.1 <kijitora@example.co.jp>... user unknown
135
117
  v['diagnosis'] = cv[1]
118
+
119
+ else
120
+ # Error message in non-English
121
+ if cv = e.match(/[ ][>]{3}[ ]([A-Z]{4})/)
122
+ # >>> RCPT TO ...
123
+ v['command'] = cv[1]
124
+
125
+ elsif cv = e.match(/[ ][<]{3}[ ](.+)/)
126
+ # <<< 550 5.1.1 User unknown
127
+ v['diagnosis'] = cv[1]
128
+ end
136
129
  end
137
130
  end
138
131
  end
139
-
140
132
  return nil if recipients == 0
141
133
  require 'sisimai/string'
142
- require 'sisimai/smtp/status'
143
134
 
144
135
  dscontents.map do |e|
145
- e['agent'] = Sisimai::MTA::InterScanMSS.smtpagent
146
- if mhead['received'].size > 0
147
- # Get localhost and remote host name from Received header.
148
- r0 = mhead['received']
149
- %w|lhost rhost|.each { |a| e[a] ||= '' }
150
- e['lhost'] = Sisimai::RFC5322.received(r0[0]).shift if e['lhost'].empty?
151
- e['rhost'] = Sisimai::RFC5322.received(r0[-1]).pop if e['rhost'].empty?
152
- end
136
+ e['agent'] = Sisimai::MTA::InterScanMSS.smtpagent
153
137
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
154
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
155
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
156
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
157
138
  e.each_key { |a| e[a] ||= '' }
158
139
  end
159
140
 
141
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
160
142
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
161
143
  end
162
144