sisimai 4.16.0 → 4.17.0

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
@@ -21,8 +21,6 @@ module Sisimai
21
21
  :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
22
22
  }
23
23
  Indicators = Sisimai::MTA.INDICATORS
24
- LongFields = Sisimai::RFC5322.LONGFIELDS
25
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
26
24
 
27
25
  def description; return 'Digital Arts m-FILTER'; end
28
26
  def smtpagent; return 'm-FILTER'; end
@@ -47,11 +45,10 @@ module Sisimai
47
45
  return nil unless mhead['x-mailer'] =~ Re0[:'x-mailer']
48
46
  return nil unless mhead['subject'] =~ Re0[:'subject']
49
47
 
50
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
48
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
51
49
  hasdivided = mbody.split("\n")
52
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
53
- rfc822part = '' # (String) message/rfc822-headers part
54
- previousfn = '' # (String) Previous field name
50
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
51
+ blanklines = 0 # (Integer) The number of blank lines
55
52
  readcursor = 0 # (Integer) Points the current cursor position
56
53
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
57
54
  markingset = { 'diagnosis' => false, 'command' => false }
@@ -60,7 +57,7 @@ module Sisimai
60
57
  hasdivided.each do |e|
61
58
  if readcursor == 0
62
59
  # Beginning of the bounce message or delivery status part
63
- readcursor |= Indicators[:'deliverystatus'] if e =~ Re1[:begin]
60
+ readcursor |= Indicators[:deliverystatus] if e =~ Re1[:begin]
64
61
  end
65
62
 
66
63
  if readcursor & Indicators[:'message-rfc822'] == 0
@@ -73,30 +70,16 @@ module Sisimai
73
70
 
74
71
  if readcursor & Indicators[:'message-rfc822'] > 0
75
72
  # After "message/rfc822"
76
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
77
- # Get required headers only
78
- lhs = cv[1].downcase
79
- previousfn = ''
80
- next unless RFC822Head.key?(lhs)
81
-
82
- previousfn = lhs
83
- rfc822part += e + "\n"
84
-
85
- elsif e =~ /\A[ \t]+/
86
- # Continued line from the previous line
87
- next if rfc822next[previousfn]
88
- rfc822part += e + "\n" if LongFields.key?(previousfn)
89
-
90
- else
91
- # Check the end of headers in rfc822 part
92
- next unless LongFields.key?(previousfn)
93
- next unless e.empty?
94
- rfc822next[previousfn] = true
73
+ if e.empty?
74
+ blanklines += 1
75
+ break if blanklines > 1
76
+ next
95
77
  end
78
+ rfc822list << e
96
79
 
97
80
  else
98
81
  # Before "message/rfc822"
99
- next if readcursor & Indicators[:'deliverystatus'] == 0
82
+ next if readcursor & Indicators[:deliverystatus] == 0
100
83
  next if e.empty?
101
84
 
102
85
  # このメールは「m-FILTER」が自動的に生成して送信しています。
@@ -152,14 +135,10 @@ module Sisimai
152
135
  end
153
136
  end
154
137
  end
155
-
156
138
  return nil if recipients == 0
157
139
  require 'sisimai/string'
158
- require 'sisimai/smtp/status'
159
140
 
160
141
  dscontents.map do |e|
161
- e['agent'] = Sisimai::MTA::MFILTER.smtpagent
162
-
163
142
  if mhead['received'].size > 0
164
143
  # Get localhost and remote host name from Received header.
165
144
  rheads = mhead['received']
@@ -172,14 +151,12 @@ module Sisimai
172
151
  e['rhost'] = ee
173
152
  end
174
153
  end
175
-
176
154
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
177
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
178
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
179
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
155
+ e['agent'] = Sisimai::MTA::MFILTER.smtpagent
180
156
  e.each_key { |a| e[a] ||= '' }
181
157
  end
182
158
 
159
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
183
160
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
184
161
  end
185
162
 
@@ -28,12 +28,11 @@ module Sisimai
28
28
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
29
29
  %r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
30
30
  ]
31
-
32
31
  ReFailure = {
33
- 'userunknown' => %r{
32
+ userunknown: %r{
34
33
  user[ ]not[ ]found
35
34
  }x,
36
- 'hostunknown' => %r{(?>
35
+ hostunknown: %r{(?>
37
36
  all[ ](?:
38
37
  host[ ]address[ ]lookups[ ]failed[ ]permanently
39
38
  |relevant[ ]MX[ ]records[ ]point[ ]to[ ]non[-]existent[ ]hosts
@@ -41,27 +40,26 @@ module Sisimai
41
40
  |Unrouteable[ ]address
42
41
  )
43
42
  }x,
44
- 'mailboxfull' => %r{(?:
43
+ mailboxfull: %r{(?:
45
44
  mailbox[ ]is[ ]full:?
46
45
  |error:[ ]quota[ ]exceed
47
46
  )
48
47
  }x,
49
- 'notaccept' => %r{(?:
48
+ notaccept: %r{(?:
50
49
  an[ ]MX[ ]or[ ]SRV[ ]record[ ]indicated[ ]no[ ]SMTP[ ]service
51
50
  |no[ ]host[ ]found[ ]for[ ]existing[ ]SMTP[ ]connection
52
51
  )
53
52
  }x,
54
- 'systemerror' => %r{(?>
53
+ systemerror: %r{(?>
55
54
  delivery[ ]to[ ](?:file|pipe)[ ]forbidden
56
55
  |local[ ]delivery[ ]failed
57
56
  |LMTP[ ]error[ ]after[ ]
58
57
  )
59
58
  }x,
60
- 'contenterror' => %r{
59
+ contenterror: %r{
61
60
  Too[ ]many[ ]["]Received["][ ]headers
62
61
  }x,
63
62
  }
64
-
65
63
  ReDelayed = %r{(?:
66
64
  retry[ ]timeout[ ]exceeded
67
65
  |No[ ]action[ ]is[ ]required[ ]on[ ]your[ ]part
@@ -72,8 +70,6 @@ module Sisimai
72
70
  )
73
71
  }x
74
72
  Indicators = Sisimai::MTA.INDICATORS
75
- LongFields = Sisimai::RFC5322.LONGFIELDS
76
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
77
73
 
78
74
  def description; return 'McAfee SaaS'; end
79
75
  def smtpagent; return 'MXLogic'; end
@@ -106,11 +102,10 @@ module Sisimai
106
102
  match += 1 if mhead['from'] =~ Re0[:from]
107
103
  return nil if match == 0
108
104
 
109
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
105
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
110
106
  hasdivided = mbody.split("\n")
111
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
112
- rfc822part = '' # (String) message/rfc822-headers part
113
- previousfn = '' # (String) Previous field name
107
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
108
+ blanklines = 0 # (Integer) The number of blank lines
114
109
  readcursor = 0 # (Integer) Points the current cursor position
115
110
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
116
111
  localhost0 = '' # (String) Local MTA
@@ -120,7 +115,7 @@ module Sisimai
120
115
  if readcursor == 0
121
116
  # Beginning of the bounce message or delivery status part
122
117
  if e =~ Re1[:begin]
123
- readcursor |= Indicators[:'deliverystatus']
118
+ readcursor |= Indicators[:deliverystatus]
124
119
  next
125
120
  end
126
121
  end
@@ -135,30 +130,16 @@ module Sisimai
135
130
 
136
131
  if readcursor & Indicators[:'message-rfc822'] > 0
137
132
  # After "message/rfc822"
138
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
139
- # Get required headers only
140
- lhs = cv[1].downcase
141
- previousfn = ''
142
- next unless RFC822Head.key?(lhs)
143
-
144
- previousfn = lhs
145
- rfc822part += e + "\n"
146
-
147
- elsif e =~ /\A[ \t]+/
148
- # Continued line from the previous line
149
- next if rfc822next[previousfn]
150
- rfc822part += e + "\n" if LongFields.key?(previousfn)
151
-
152
- else
153
- # Check the end of headers in rfc822 part
154
- next unless LongFields.key?(previousfn)
155
- next unless e.empty?
156
- rfc822next[previousfn] = true
133
+ if e.empty?
134
+ blanklines += 1
135
+ break if blanklines > 1
136
+ next
157
137
  end
138
+ rfc822list << e
158
139
 
159
140
  else
160
141
  # Before "message/rfc822"
161
- next if readcursor & Indicators[:'deliverystatus'] == 0
142
+ next if readcursor & Indicators[:deliverystatus] == 0
162
143
  next if e.empty?
163
144
 
164
145
  # This message was created automatically by mail delivery software.
@@ -208,8 +189,6 @@ module Sisimai
208
189
  end
209
190
 
210
191
  require 'sisimai/string'
211
- require 'sisimai/smtp/status'
212
-
213
192
  dscontents.map do |e|
214
193
  e['agent'] = Sisimai::MTA::MXLogic.smtpagent
215
194
  e['lhost'] = localhost0
@@ -256,7 +235,7 @@ module Sisimai
256
235
  ReFailure.each_key do |r|
257
236
  # Check each regular expression
258
237
  next unless e['diagnosis'] =~ ReFailure[r]
259
- e['reason'] = r
238
+ e['reason'] = r.to_s
260
239
  break
261
240
  end
262
241
 
@@ -266,13 +245,10 @@ module Sisimai
266
245
  end
267
246
  end
268
247
  end
269
-
270
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
271
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
272
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
273
248
  e.each_key { |a| e[a] ||= '' }
274
249
  end
275
250
 
251
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
276
252
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
277
253
  end
278
254
 
@@ -17,16 +17,14 @@ module Sisimai
17
17
  :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
18
18
  }
19
19
  ReFailure = {
20
- 'userunknown' => %r{(?:
20
+ userunknown: %r{(?:
21
21
  User[ ]not[ ]listed[ ]in[ ]public[ ]Name[ ][&][ ]Address[ ]Book
22
22
  |ディレクトリのリストにありません
23
23
  )
24
24
  }x,
25
- 'networkerror' => %r/Message has exceeded maximum hop count/,
25
+ networkerror: %r/Message has exceeded maximum hop count/,
26
26
  }
27
27
  Indicators = Sisimai::MTA.INDICATORS
28
- LongFields = Sisimai::RFC5322.LONGFIELDS
29
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
30
28
 
31
29
  def description; return 'Lotus Notes'; end
32
30
  def smtpagent; return 'Notes'; end
@@ -49,11 +47,10 @@ module Sisimai
49
47
  return nil unless mbody
50
48
  return nil unless mhead['subject'] =~ Re0[:subject]
51
49
 
52
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
50
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
53
51
  hasdivided = mbody.split("\n")
54
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
55
- rfc822part = '' # (String) message/rfc822-headers part
56
- previousfn = '' # (String) Previous field name
52
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
53
+ blanklines = 0 # (Integer) The number of blank lines
57
54
  readcursor = 0 # (Integer) Points the current cursor position
58
55
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
59
56
  characters = '' # (String) Character set name of the bounce mail
@@ -65,7 +62,7 @@ module Sisimai
65
62
  if readcursor == 0
66
63
  # Beginning of the bounce message or delivery status part
67
64
  if e =~ Re1[:begin]
68
- readcursor |= Indicators[:'deliverystatus']
65
+ readcursor |= Indicators[:deliverystatus]
69
66
  next
70
67
  end
71
68
  end
@@ -88,30 +85,16 @@ module Sisimai
88
85
 
89
86
  if readcursor & Indicators[:'message-rfc822'] > 0
90
87
  # After "message/rfc822"
91
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
92
- # Get required headers only
93
- lhs = cv[1].downcase
94
- previousfn = ''
95
- next unless RFC822Head.key?(lhs)
96
-
97
- previousfn = lhs
98
- rfc822part += e + "\n"
99
-
100
- elsif e =~ /\A[ \t]+/
101
- # Continued line from the previous line
102
- next if rfc822next[previousfn]
103
- rfc822part += e + "\n" if LongFields.key?(previousfn)
104
-
105
- else
106
- # Check the end of headers in rfc822 part
107
- next unless LongFields.key?(previousfn)
108
- next unless e.empty?
109
- rfc822next[previousfn] = true
88
+ if e.empty?
89
+ blanklines += 1
90
+ break if blanklines > 1
91
+ next
110
92
  end
93
+ rfc822list << e
111
94
 
112
95
  else
113
96
  # Before "message/rfc822"
114
- next if readcursor & Indicators[:'deliverystatus'] == 0
97
+ next if readcursor & Indicators[:deliverystatus] == 0
115
98
 
116
99
  # ------- Failure Reasons --------
117
100
  #
@@ -161,9 +144,12 @@ module Sisimai
161
144
 
162
145
  if recipients == 0
163
146
  # Fallback: Get the recpient address from RFC822 part
164
- if cv = rfc822part.match(/^To:[ ]*(.+)$/m)
165
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
166
- recipients += 1 if v['recipient'].size > 0
147
+ rfc822list.each do |e|
148
+ if cv = e.match(/^To:[ ]*(.+)$/m)
149
+ v['recipient'] = Sisimai::Address.s3s4(cv[1])
150
+ recipients += 1 if v['recipient'].size > 0
151
+ break
152
+ end
167
153
  end
168
154
  end
169
155
 
@@ -172,31 +158,22 @@ module Sisimai
172
158
  require 'sisimai/smtp/status'
173
159
 
174
160
  dscontents.map do |e|
175
- e['agent'] = Sisimai::MTA::Notes.smtpagent
176
-
177
- if mhead['received'].size > 0
178
- # Get localhost and remote host name from Received header.
179
- r0 = mhead['received']
180
- %w|lhost rhost|.each { |a| e[a] ||= '' }
181
- e['lhost'] = Sisimai::RFC5322.received(r0[0]).shift if e['lhost'].empty?
182
- e['rhost'] = Sisimai::RFC5322.received(r0[-1]).pop if e['rhost'].empty?
183
- end
161
+ e['agent'] = Sisimai::MTA::Notes.smtpagent
184
162
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
185
163
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
186
164
 
187
165
  ReFailure.each_key do |r|
188
166
  # Check each regular expression of Notes error messages
189
167
  next unless e['diagnosis'] =~ ReFailure[r]
190
- e['reason'] = r
191
- pseudostatus = Sisimai::SMTP::Status.code(r)
168
+ e['reason'] = r.to_s
169
+ pseudostatus = Sisimai::SMTP::Status.code(r.to_s)
192
170
  e['status'] = pseudostatus if pseudostatus.size > 0
193
171
  break
194
172
  end
195
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
196
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
197
173
  e.each_key { |a| e[a] ||= '' }
198
174
  end
199
175
 
176
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
200
177
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
201
178
  end
202
179
 
@@ -44,22 +44,22 @@ module Sisimai
44
44
  :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
45
45
  }
46
46
  ReFailure = {
47
- 'expired' => %r{
47
+ expired: %r{
48
48
  # smtpd/queue.c:221| envelope_set_errormsg(&evp, "Envelope expired");
49
49
  Envelope[ ]expired
50
50
  }x,
51
- 'hostunknown' => %r{(?:
51
+ hostunknown: %r{(?:
52
52
  # smtpd/mta.c:976| relay->failstr = "Invalid domain name";
53
53
  Invalid[ ]domain[ ]name
54
54
  # smtpd/mta.c:980| relay->failstr = "Domain does not exist";
55
55
  |Domain[ ]does[ ]not[ ]exist
56
56
  )
57
57
  }x,
58
- 'notaccept' => %r{
58
+ notaccept: %r{
59
59
  # smtp/mta.c:1085| relay->failstr = "Destination seem to reject all mails";
60
60
  Destination[ ]seem[ ]to[ ]reject[ ]all[ ]mails
61
61
  }x,
62
- 'networkerror' => %r{(?>
62
+ networkerror: %r{(?>
63
63
  # smtpd/mta.c:972| relay->failstr = "Temporary failure in MX lookup";
64
64
  Address[ ]family[ ]mismatch[ ]on[ ]destination[ ]MXs
65
65
  |All[ ]routes[ ]to[ ]destination[ ]blocked
@@ -74,14 +74,12 @@ module Sisimai
74
74
  |Temporary[ ]failure[ ]in[ ]MX[ ]lookup
75
75
  )
76
76
  }x,
77
- 'securityerror' => %r{
77
+ securityerror: %r{
78
78
  # smtpd/mta.c:1013| relay->failstr = "Could not retrieve credentials";
79
79
  Could[ ]not[ ]retrieve[ ]credentials
80
80
  }x,
81
81
  }
82
82
  Indicators = Sisimai::MTA.INDICATORS
83
- LongFields = Sisimai::RFC5322.LONGFIELDS
84
- RFC822Head = Sisimai::RFC5322.HEADERFIELDS
85
83
 
86
84
  def description; return 'OpenSMTPD'; end
87
85
  def smtpagent; return 'OpenSMTPD'; end
@@ -106,11 +104,10 @@ module Sisimai
106
104
  return nil unless mhead['from'] =~ Re0[:from]
107
105
  return nil unless mhead['received'].find { |a| a =~ Re0[:received] }
108
106
 
109
- dscontents = []; dscontents << Sisimai::MTA.DELIVERYSTATUS
107
+ dscontents = [Sisimai::MTA.DELIVERYSTATUS]
110
108
  hasdivided = mbody.split("\n")
111
- rfc822next = { 'from' => false, 'to' => false, 'subject' => false }
112
- rfc822part = '' # (String) message/rfc822-headers part
113
- previousfn = '' # (String) Previous field name
109
+ rfc822list = [] # (Array) Each line in message/rfc822 part string
110
+ blanklines = 0 # (Integer) The number of blank lines
114
111
  readcursor = 0 # (Integer) Points the current cursor position
115
112
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
116
113
  v = nil
@@ -119,7 +116,7 @@ module Sisimai
119
116
  if readcursor == 0
120
117
  # Beginning of the bounce message or delivery status part
121
118
  if e =~ Re1[:begin]
122
- readcursor |= Indicators[:'deliverystatus']
119
+ readcursor |= Indicators[:deliverystatus]
123
120
  next
124
121
  end
125
122
  end
@@ -134,30 +131,16 @@ module Sisimai
134
131
 
135
132
  if readcursor & Indicators[:'message-rfc822'] > 0
136
133
  # After "message/rfc822"
137
- if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
138
- # Get required headers only
139
- lhs = cv[1].downcase
140
- previousfn = ''
141
- next unless RFC822Head.key?(lhs)
142
-
143
- previousfn = lhs
144
- rfc822part += e + "\n"
145
-
146
- elsif e =~ /\A[ \t]+/
147
- # Continued line from the previous line
148
- next if rfc822next[previousfn]
149
- rfc822part += e + "\n" if LongFields.key?(previousfn)
150
-
151
- else
152
- # Check the end of headers in rfc822 part
153
- next unless LongFields.key?(previousfn)
154
- next unless e.empty?
155
- rfc822next[previousfn] = true
134
+ if e.empty?
135
+ blanklines += 1
136
+ break if blanklines > 1
137
+ next
156
138
  end
139
+ rfc822list << e
157
140
 
158
141
  else
159
142
  # Before "message/rfc822"
160
- next if readcursor & Indicators[:'deliverystatus'] == 0
143
+ next if readcursor & Indicators[:deliverystatus] == 0
161
144
  next if e.empty?
162
145
 
163
146
  # Hi!
@@ -185,36 +168,23 @@ module Sisimai
185
168
  end
186
169
  end
187
170
  end
188
-
189
171
  return nil if recipients == 0
190
172
  require 'sisimai/string'
191
- require 'sisimai/smtp/status'
192
173
 
193
174
  dscontents.map do |e|
194
- e['agent'] = Sisimai::MTA::OpenSMTPD.smtpagent
195
-
196
- if mhead['received'].size > 0
197
- # Get localhost and remote host name from Received header.
198
- r0 = mhead['received']
199
- %w|lhost rhost|.each { |a| e[a] ||= '' }
200
- e['lhost'] = Sisimai::RFC5322.received(r0[0]).shift if e['lhost'].empty?
201
- e['rhost'] = Sisimai::RFC5322.received(r0[-1]).pop if e['rhost'].empty?
202
- end
175
+ e['agent'] = Sisimai::MTA::OpenSMTPD.smtpagent
203
176
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
204
177
 
205
178
  ReFailure.each_key do |r|
206
179
  # Verify each regular expression of session errors
207
180
  next unless e['diagnosis'] =~ ReFailure[r]
208
- e['reason'] = r
181
+ e['reason'] = r.to_s
209
182
  break
210
183
  end
211
-
212
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
213
- e['spec'] = e['reason'] == 'mailererror' ? 'X-UNIX' : 'SMTP'
214
- e['action'] = 'failed' if e['status'] =~ /\A[45]/
215
184
  e.each_key { |a| e[a] ||= '' }
216
185
  end
217
186
 
187
+ rfc822part = Sisimai::RFC5322.weedout(rfc822list)
218
188
  return { 'ds' => dscontents, 'rfc822' => rfc822part }
219
189
  end
220
190