sisimai 4.22.3 → 4.22.4

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Benchmarks.mk +54 -0
  4. data/ChangeLog.md +23 -2
  5. data/Developers.mk +42 -35
  6. data/Makefile +10 -0
  7. data/README-JA.md +13 -13
  8. data/README.md +14 -14
  9. data/lib/sisimai.rb +12 -18
  10. data/lib/sisimai/address.rb +64 -82
  11. data/lib/sisimai/arf.rb +27 -42
  12. data/lib/sisimai/bite/email.rb +2 -4
  13. data/lib/sisimai/bite/email/activehunter.rb +12 -17
  14. data/lib/sisimai/bite/email/amazonses.rb +30 -48
  15. data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
  16. data/lib/sisimai/bite/email/aol.rb +27 -35
  17. data/lib/sisimai/bite/email/apachejames.rb +17 -28
  18. data/lib/sisimai/bite/email/bigfoot.rb +20 -33
  19. data/lib/sisimai/bite/email/biglobe.rb +15 -24
  20. data/lib/sisimai/bite/email/courier.rb +37 -61
  21. data/lib/sisimai/bite/email/domino.rb +19 -28
  22. data/lib/sisimai/bite/email/einsundeins.rb +20 -34
  23. data/lib/sisimai/bite/email/exchange2003.rb +25 -43
  24. data/lib/sisimai/bite/email/exchange2007.rb +15 -23
  25. data/lib/sisimai/bite/email/exim.rb +101 -120
  26. data/lib/sisimai/bite/email/ezweb.rb +28 -44
  27. data/lib/sisimai/bite/email/facebook.rb +26 -37
  28. data/lib/sisimai/bite/email/fml.rb +11 -20
  29. data/lib/sisimai/bite/email/gmx.rb +17 -27
  30. data/lib/sisimai/bite/email/google.rb +19 -29
  31. data/lib/sisimai/bite/email/gsuite.rb +39 -48
  32. data/lib/sisimai/bite/email/imailserver.rb +25 -39
  33. data/lib/sisimai/bite/email/interscanmss.rb +19 -26
  34. data/lib/sisimai/bite/email/kddi.rb +20 -33
  35. data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
  36. data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
  37. data/lib/sisimai/bite/email/mailru.rb +40 -59
  38. data/lib/sisimai/bite/email/mcafee.rb +21 -35
  39. data/lib/sisimai/bite/email/messagelabs.rb +23 -38
  40. data/lib/sisimai/bite/email/messagingserver.rb +15 -27
  41. data/lib/sisimai/bite/email/mfilter.rb +19 -28
  42. data/lib/sisimai/bite/email/mxlogic.rb +31 -49
  43. data/lib/sisimai/bite/email/notes.rb +16 -24
  44. data/lib/sisimai/bite/email/office365.rb +29 -38
  45. data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
  46. data/lib/sisimai/bite/email/outlook.rb +24 -36
  47. data/lib/sisimai/bite/email/postfix.rb +33 -42
  48. data/lib/sisimai/bite/email/qmail.rb +44 -59
  49. data/lib/sisimai/bite/email/receivingses.rb +28 -36
  50. data/lib/sisimai/bite/email/sendgrid.rb +28 -37
  51. data/lib/sisimai/bite/email/sendmail.rb +35 -51
  52. data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
  53. data/lib/sisimai/bite/email/userdefined.rb +17 -28
  54. data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
  55. data/lib/sisimai/bite/email/verizon.rb +31 -56
  56. data/lib/sisimai/bite/email/x1.rb +11 -18
  57. data/lib/sisimai/bite/email/x2.rb +11 -23
  58. data/lib/sisimai/bite/email/x3.rb +10 -19
  59. data/lib/sisimai/bite/email/x4.rb +46 -65
  60. data/lib/sisimai/bite/email/x5.rb +26 -37
  61. data/lib/sisimai/bite/email/yahoo.rb +11 -19
  62. data/lib/sisimai/bite/email/yandex.rb +19 -30
  63. data/lib/sisimai/bite/email/zoho.rb +21 -30
  64. data/lib/sisimai/bite/json.rb +1 -2
  65. data/lib/sisimai/bite/json/amazonses.rb +20 -25
  66. data/lib/sisimai/bite/json/sendgrid.rb +1 -1
  67. data/lib/sisimai/data.rb +36 -55
  68. data/lib/sisimai/data/json.rb +3 -3
  69. data/lib/sisimai/data/yaml.rb +1 -1
  70. data/lib/sisimai/datetime.rb +5 -21
  71. data/lib/sisimai/mail.rb +4 -6
  72. data/lib/sisimai/mail/maildir.rb +1 -1
  73. data/lib/sisimai/mda.rb +41 -44
  74. data/lib/sisimai/message.rb +2 -3
  75. data/lib/sisimai/message/email.rb +42 -52
  76. data/lib/sisimai/message/json.rb +7 -7
  77. data/lib/sisimai/mime.rb +25 -23
  78. data/lib/sisimai/order/email.rb +2 -2
  79. data/lib/sisimai/order/json.rb +2 -7
  80. data/lib/sisimai/reason.rb +41 -46
  81. data/lib/sisimai/reason/blocked.rb +60 -71
  82. data/lib/sisimai/reason/contenterror.rb +4 -8
  83. data/lib/sisimai/reason/delivered.rb +1 -3
  84. data/lib/sisimai/reason/exceedlimit.rb +10 -20
  85. data/lib/sisimai/reason/expired.rb +5 -9
  86. data/lib/sisimai/reason/feedback.rb +1 -3
  87. data/lib/sisimai/reason/filtered.rb +19 -38
  88. data/lib/sisimai/reason/hasmoved.rb +5 -8
  89. data/lib/sisimai/reason/hostunknown.rb +11 -18
  90. data/lib/sisimai/reason/mailboxfull.rb +14 -24
  91. data/lib/sisimai/reason/mailererror.rb +3 -5
  92. data/lib/sisimai/reason/mesgtoobig.rb +15 -25
  93. data/lib/sisimai/reason/networkerror.rb +8 -10
  94. data/lib/sisimai/reason/norelaying.rb +9 -14
  95. data/lib/sisimai/reason/notaccept.rb +9 -21
  96. data/lib/sisimai/reason/onhold.rb +3 -8
  97. data/lib/sisimai/reason/policyviolation.rb +8 -10
  98. data/lib/sisimai/reason/rejected.rb +36 -49
  99. data/lib/sisimai/reason/securityerror.rb +11 -13
  100. data/lib/sisimai/reason/spamdetected.rb +23 -37
  101. data/lib/sisimai/reason/suspend.rb +9 -10
  102. data/lib/sisimai/reason/syntaxerror.rb +3 -4
  103. data/lib/sisimai/reason/systemerror.rb +7 -9
  104. data/lib/sisimai/reason/systemfull.rb +2 -4
  105. data/lib/sisimai/reason/toomanyconn.rb +17 -30
  106. data/lib/sisimai/reason/undefined.rb +1 -3
  107. data/lib/sisimai/reason/userunknown.rb +28 -38
  108. data/lib/sisimai/reason/vacation.rb +4 -6
  109. data/lib/sisimai/reason/virusdetected.rb +4 -6
  110. data/lib/sisimai/rfc2606.rb +1 -2
  111. data/lib/sisimai/rfc3464.rb +87 -101
  112. data/lib/sisimai/rfc3834.rb +29 -39
  113. data/lib/sisimai/rfc5322.rb +17 -24
  114. data/lib/sisimai/rhost.rb +10 -7
  115. data/lib/sisimai/rhost/exchangeonline.rb +124 -255
  116. data/lib/sisimai/rhost/franceptt.rb +2 -2
  117. data/lib/sisimai/rhost/godaddy.rb +12 -25
  118. data/lib/sisimai/rhost/googleapps.rb +82 -183
  119. data/lib/sisimai/smtp.rb +4 -4
  120. data/lib/sisimai/smtp/error.rb +8 -8
  121. data/lib/sisimai/smtp/reply.rb +1 -1
  122. data/lib/sisimai/smtp/status.rb +1 -0
  123. data/lib/sisimai/string.rb +5 -7
  124. data/lib/sisimai/version.rb +1 -1
  125. data/set-of-emails/README.md +1 -1
  126. data/set-of-emails/maildir/bsd/README.md +50 -50
  127. data/sisimai-java.gemspec +1 -1
  128. data/sisimai.gemspec +1 -1
  129. metadata +5 -5
  130. data/lib/sisimai/skeleton.rb +0 -43
@@ -6,27 +6,21 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Sendmail.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :from => %r/\AMail Delivery Subsystem/,
11
- :subject => %r/(?:see transcript for details\z|\AWarning: )/,
12
- }.freeze
13
- # Error text regular expressions which defined in sendmail/savemail.c
14
- # savemail.c:1040|if (printheader && !putline(" ----- Transcript of session follows -----\n",
15
- # savemail.c:1041| mci))
16
- # savemail.c:1042| goto writeerr;
17
- #
18
- Re1 = {
19
- :begin => %r/\A[ \t]+[-]+ Transcript of session follows [-]+\z/,
20
- :error => %r/\A[.]+ while talking to .+[:]\z/,
21
- :rfc822 => %r{\AContent-Type:[ ]*(?:message/rfc822|text/rfc822-headers)\z},
22
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
23
- }.freeze
24
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ # Error text regular expressions which defined in sendmail/savemail.c
12
+ # savemail.c:1040|if (printheader && !putline(" ----- Transcript of session follows -----\n",
13
+ # savemail.c:1041| mci))
14
+ # savemail.c:1042| goto writeerr;
15
+ #
16
+ rfc822: ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'],
17
+ message: [' ----- Transcript of session follows -----'],
18
+ error: ['... while talking to '],
19
+ }.freeze
25
20
 
26
21
  def description; return 'V8Sendmail: /usr/sbin/sendmail'; end
27
22
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
28
23
  def headerlist; return []; end
29
- def pattern; return Re0; end
30
24
 
31
25
  # Parse bounce messages from Sendmail
32
26
  # @param [Hash] mhead Message headers of a bounce email
@@ -42,12 +36,12 @@ module Sisimai::Bite::Email
42
36
  def scan(mhead, mbody)
43
37
  return nil unless mhead
44
38
  return nil unless mbody
45
- return nil unless mhead['subject'] =~ Re0[:subject]
46
39
 
47
- unless mhead['subject'] =~ /\A[ \t]*Fwd?:/i
40
+ return nil unless mhead['subject'] =~ /(?:see transcript for details\z|\AWarning: )/
41
+ unless mhead['subject'].downcase =~ /\A[ \t]*fwd?:/
48
42
  # Fwd: Returned mail: see transcript for details
49
43
  # Do not execute this code if the bounce mail is a forwarded message.
50
- return nil unless mhead['from'] =~ Re0[:from]
44
+ return nil unless mhead['from'].start_with?('Mail Delivery Subsystem')
51
45
  end
52
46
 
53
47
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -68,14 +62,14 @@ module Sisimai::Bite::Email
68
62
  anotherset = {} # Another error information
69
63
  v = nil
70
64
 
71
- hasdivided.each do |e|
65
+ while e = hasdivided.shift do
72
66
  # Save the current line for the next loop
73
67
  havepassed << e
74
68
  p = havepassed[-2]
75
69
 
76
70
  if readcursor.zero?
77
71
  # Beginning of the bounce message or delivery status part
78
- if e =~ Re1[:begin]
72
+ if e.start_with?(StartingOf[:message][0])
79
73
  readcursor |= Indicators[:deliverystatus]
80
74
  next
81
75
  end
@@ -83,7 +77,7 @@ module Sisimai::Bite::Email
83
77
 
84
78
  if (readcursor & Indicators[:'message-rfc822']).zero?
85
79
  # Beginning of the original message part
86
- if e =~ Re1[:rfc822]
80
+ if e.start_with?(StartingOf[:rfc822][0], StartingOf[:rfc822][1])
87
81
  readcursor |= Indicators[:'message-rfc822']
88
82
  next
89
83
  end
@@ -97,7 +91,6 @@ module Sisimai::Bite::Email
97
91
  next
98
92
  end
99
93
  rfc822list << e
100
-
101
94
  else
102
95
  # Before "message/rfc822"
103
96
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -113,7 +106,7 @@ module Sisimai::Bite::Email
113
106
  # Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
114
107
  v = dscontents[-1]
115
108
 
116
- if cv = e.match(/\A[Ff]inal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
109
+ if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
117
110
  # Final-Recipient: RFC822; userunknown@example.jp
118
111
  if v['recipient']
119
112
  # There are multiple recipient addresses in the message body.
@@ -123,43 +116,40 @@ module Sisimai::Bite::Email
123
116
  v['recipient'] = cv[1]
124
117
  recipients += 1
125
118
 
126
- elsif cv = e.match(/\A[Xx]-[Aa]ctual-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
119
+ elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
127
120
  # X-Actual-Recipient: RFC822; kijitora@example.co.jp
128
121
  v['alias'] = cv[1]
129
122
 
130
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
123
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
131
124
  # Action: failed
132
125
  v['action'] = cv[1].downcase
133
126
 
134
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
127
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
135
128
  # Status: 5.1.1
136
129
  # Status:5.2.0
137
130
  # Status: 5.1.0 (permanent failure)
138
131
  v['status'] = cv[1]
139
132
 
140
- elsif cv = e.match(/\A[Rr]emote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
133
+ elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
141
134
  # Remote-MTA: DNS; mx.example.jp
142
135
  v['rhost'] = cv[1].downcase
143
136
  v['rhost'] = '' if v['rhost'] =~ /\A\s+\z/ # Remote-MTA: DNS;
144
137
 
145
- elsif cv = e.match(/\A[Ll]ast-[Aa]ttempt-[Dd]ate:[ ]*(.+)\z/)
138
+ elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
146
139
  # Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
147
140
  v['date'] = cv[1]
148
-
149
141
  else
150
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
142
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
151
143
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
152
144
  v['spec'] = cv[1].upcase
153
145
  v['diagnosis'] = cv[2]
154
146
 
155
- elsif p =~ /\A[Dd]iagnostic-[Cc]ode:[ ]*/ && cv = e.match(/\A[ \t]+(.+)\z/)
147
+ elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
156
148
  # Continued line of the value of Diagnostic-Code header
157
- v['diagnosis'] ||= ''
158
- v['diagnosis'] += ' ' + cv[1]
159
- havepassed[-1] = 'Diagnostic-Code: ' + e
149
+ v['diagnosis'] << ' ' << cv[1]
150
+ havepassed[-1] = 'Diagnostic-Code: ' << e
160
151
  end
161
152
  end
162
-
163
153
  else
164
154
  # ----- Transcript of session follows -----
165
155
  # ... while talking to mta.example.org.:
@@ -178,13 +168,13 @@ module Sisimai::Bite::Email
178
168
  # <<< Response
179
169
  esmtpreply = cv[1]
180
170
 
181
- elsif cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
171
+ elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
182
172
  # Reporting-MTA: dns; mx.example.jp
183
173
  next if connheader['rhost'].size > 0
184
174
  connheader['rhost'] = cv[1].downcase
185
175
  connvalues += 1
186
176
 
187
- elsif cv = e.match(/\A[Rr]eceived-[Ff]rom-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
177
+ elsif cv = e.match(/\AReceived-From-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
188
178
  # Received-From-MTA: DNS; x1x2x3x4.dhcp.example.ne.jp
189
179
  next if connheader['lhost']
190
180
 
@@ -192,16 +182,15 @@ module Sisimai::Bite::Email
192
182
  connheader['lhost'] = cv[1].downcase
193
183
  connvalues += 1
194
184
 
195
- elsif cv = e.match(/\A[Aa]rrival-[Dd]ate:[ ]*(.+)\z/)
185
+ elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
196
186
  # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
197
187
  next if connheader['date'].size > 0
198
188
  connheader['date'] = cv[1]
199
189
  connvalues += 1
200
-
201
190
  else
202
191
  # Detect SMTP session error or connection error
203
192
  next if sessionerr
204
- if e =~ Re1[:error]
193
+ if e.start_with?(StartingOf[:error][0])
205
194
  # ----- Transcript of session follows -----
206
195
  # ... while talking to mta.example.org.:
207
196
  sessionerr = true
@@ -212,7 +201,6 @@ module Sisimai::Bite::Email
212
201
  # <kijitora@example.co.jp>... Deferred: Name server: example.co.jp.: host name lookup failure
213
202
  anotherset['recipient'] = cv[1]
214
203
  anotherset['diagnosis'] = cv[2]
215
-
216
204
  else
217
205
  # ----- Transcript of session follows -----
218
206
  # Message could not be delivered for too long
@@ -225,13 +213,13 @@ module Sisimai::Bite::Email
225
213
  # 554 5.3.0 unknown mailer error 255
226
214
  anotherset['status'] = cv[1]
227
215
  anotherset['diagnosis'] ||= ''
228
- anotherset['diagnosis'] += ' ' + e
216
+ anotherset['diagnosis'] << ' ' << e
229
217
 
230
- elsif e =~ /\A(?:Message|Warning:) /
218
+ elsif e.start_with?('Message ', 'Warning: ')
231
219
  # Message could not be delivered for too long
232
220
  # Warning: message still undelivered after 4 hours
233
221
  anotherset['diagnosis'] ||= ''
234
- anotherset['diagnosis'] += ' ' + e
222
+ anotherset['diagnosis'] << ' ' << e
235
223
  end
236
224
  end
237
225
  end
@@ -239,8 +227,8 @@ module Sisimai::Bite::Email
239
227
  end
240
228
  end
241
229
  return nil if recipients.zero?
242
- require 'sisimai/string'
243
230
 
231
+ require 'sisimai/string'
244
232
  dscontents.map do |e|
245
233
  # Set default values if each value is empty.
246
234
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -255,11 +243,7 @@ module Sisimai::Bite::Email
255
243
  # Copy alternative error message
256
244
  e['diagnosis'] = anotherset['diagnosis'] if e['diagnosis'] =~ /\A[ \t]+\z/
257
245
  e['diagnosis'] = anotherset['diagnosis'] unless e['diagnosis']
258
-
259
- if e['diagnosis'] =~ /\A\d+\z/
260
- # Override the value of diagnostic code message
261
- e['diagnosis'] = anotherset['diagnosis']
262
- end
246
+ e['diagnosis'] = anotherset['diagnosis'] if e['diagnosis'] =~ /\A\d+\z/
263
247
  end
264
248
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
265
249
 
@@ -7,17 +7,11 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/SurfControl.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :'from' => %r/ [(]Mail Delivery System[)]\z/,
12
- :'x-mailer' => %r/\ASurfControl E-mail Filter\z/,
13
- }.freeze
14
- Re1 = {
15
- :begin => %r/\AYour message could not be sent[.]\z/,
16
- :error => %r/\AFailed to send to identified host,\z/,
17
- :rfc822 => %r|\AContent-Type: message/rfc822\z|,
18
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
19
- }.freeze
20
10
  Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ message: ['Your message could not be sent.'],
13
+ rfc822: ['Content-Type: message/rfc822'],
14
+ }.freeze
21
15
 
22
16
  def description; return 'WebSense SurfControl'; end
23
17
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -25,7 +19,6 @@ module Sisimai::Bite::Email
25
19
  # X-SEF-Processed: 0_0_0_000__2010_04_29_23_34_45
26
20
  # X-Mailer: SurfControl E-mail Filter
27
21
  def headerlist; return ['X-SEF-Processed', 'X-Mailer']; end
28
- def pattern; return Re0; end
29
22
 
30
23
  # Parse bounce messages from SurfControl
31
24
  # @param [Hash] mhead Message headers of a bounce email
@@ -41,9 +34,11 @@ module Sisimai::Bite::Email
41
34
  def scan(mhead, mbody)
42
35
  return nil unless mhead
43
36
  return nil unless mbody
37
+
38
+ # :'from' => %r/ [(]Mail Delivery System[)]\z/,
44
39
  return nil unless mhead['x-sef-processed']
45
40
  return nil unless mhead['x-mailer']
46
- return nil unless mhead['x-mailer'] =~ Re0[:'x-mailer']
41
+ return nil unless mhead['x-mailer'] == 'SurfControl E-mail Filter'
47
42
 
48
43
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
49
44
  hasdivided = mbody.split("\n")
@@ -54,14 +49,14 @@ module Sisimai::Bite::Email
54
49
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
55
50
  v = nil
56
51
 
57
- hasdivided.each do |e|
52
+ while e = hasdivided.shift do
58
53
  # Save the current line for the next loop
59
54
  havepassed << e
60
55
  p = havepassed[-2]
61
56
 
62
57
  if readcursor.zero?
63
58
  # Beginning of the bounce message or delivery status part
64
- if e =~ Re1[:begin]
59
+ if e == StartingOf[:message][0]
65
60
  readcursor |= Indicators[:deliverystatus]
66
61
  next
67
62
  end
@@ -69,7 +64,7 @@ module Sisimai::Bite::Email
69
64
 
70
65
  if (readcursor & Indicators[:'message-rfc822']).zero?
71
66
  # Beginning of the original message part
72
- if e =~ Re1[:rfc822]
67
+ if e == StartingOf[:rfc822][0]
73
68
  readcursor |= Indicators[:'message-rfc822']
74
69
  next
75
70
  end
@@ -83,7 +78,6 @@ module Sisimai::Bite::Email
83
78
  next
84
79
  end
85
80
  rfc822list << e
86
-
87
81
  else
88
82
  # Before "message/rfc822"
89
83
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -118,25 +112,23 @@ module Sisimai::Bite::Email
118
112
  # kijitora@example.com: [192.0.2.5], 550 kijitora@example.com... No such user
119
113
  v['rhost'] = cv[1]
120
114
  v['diagnosis'] = cv[2]
121
-
122
115
  else
123
116
  # Fallback, parse RFC3464 headers.
124
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
117
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
125
118
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
126
119
  v['spec'] = cv[1].upcase
127
120
  v['diagnosis'] = cv[2]
128
121
 
129
- elsif p =~ /\A[Dd]iagnostic-[Cc]ode:[ ]*/ && cv = e.match(/\A[ ]+(.+)\z/)
122
+ elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ ]+(.+)\z/)
130
123
  # Continued line of the value of Diagnostic-Code header
131
- v['diagnosis'] ||= ''
132
- v['diagnosis'] += ' ' + cv[1]
133
- havepassed[-1] = 'Diagnostic-Code: ' + e
124
+ v['diagnosis'] << ' ' << cv[1]
125
+ havepassed[-1] = 'Diagnostic-Code: ' << e
134
126
 
135
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
127
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
136
128
  # Action: failed
137
129
  v['action'] = cv[1].downcase
138
130
 
139
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
131
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
140
132
  # Status: 5.0.-
141
133
  v['status'] = cv[1]
142
134
  end
@@ -144,8 +136,8 @@ module Sisimai::Bite::Email
144
136
  end
145
137
  end
146
138
  return nil if recipients.zero?
147
- require 'sisimai/string'
148
139
 
140
+ require 'sisimai/string'
149
141
  dscontents.map do |e|
150
142
  e['agent'] = self.smtpagent
151
143
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -6,31 +6,22 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/UserDefined.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- # Re0 is a regular expression to match with message headers which are
10
- # given as the first argument of scan() method.
11
- Re0 = {
12
- :from => %r/\AMail Sysmet/,
13
- :subject => %r/\AError Mail Report/,
14
- }.freeze
15
-
16
- # Re1 is delimiter set of these sections:
17
- # begin: The first line of a bounce message to be parsed.
18
- # error: The first line of an error message to get an error reason, recipient
19
- # addresses, or other bounce information.
20
- # rfc822: The first line of the original message.
21
- # endof: Fixed string ``__END_OF_EMAIL_MESSAGE__''
22
- Re1 = {
23
- :begin => %r/\A[ \t]+[-]+ Transcript of session follows [-]+\z/,
24
- :error => %r/\A[.]+ while talking to .+[:]\z/,
25
- :rfc822 => %r{\AContent-Type:[ ]*(?:message/rfc822|text/rfc822-headers)\z},
26
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
27
- }.freeze
28
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ MarkingsOf = {
11
+ # MarkingsOf is a delimiter set of these sections:
12
+ # message: The first line of a bounce message to be parsed.
13
+ # error: The first line of an error message to get an error reason, recipient
14
+ # addresses, or other bounce information.
15
+ # rfc822: The first line of the original message.
16
+ # endof: Fixed string ``__END_OF_EMAIL_MESSAGE__''
17
+ message: %r/\A[ \t]+[-]+ Transcript of session follows [-]+\z/,
18
+ error: %r/\A[.]+ while talking to .+[:]\z/,
19
+ rfc822: %r{\AContent-Type:[ ]*(?:message/rfc822|text/rfc822-headers)\z},
20
+ }.freeze
29
21
 
30
22
  def description; return 'Module description'; end
31
23
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
32
24
  def headerlist; return ['X-Some-UserDefined-Header']; end
33
- def pattern; return Re0; end
34
25
 
35
26
  # @abstract Template for User-Defined MTA module
36
27
  # @param [Hash] mhead Message headers of a bounce email
@@ -47,14 +38,14 @@ module Sisimai::Bite::Email
47
38
  return nil unless mhead
48
39
  return nil unless mbody
49
40
 
50
- match = 0
51
41
  # 1. Check some value in mhead using regular expression or "==" operator
52
42
  # whether the bounce message should be parsed by this module or not.
53
43
  # - Matched 1 or more values: Proceed to the step 2.
54
44
  # - Did not matched: return nil
55
45
  #
56
- match += 1 if mhead['subject'] =~ Re0[:subject]
57
- match += 1 if mhead['from'] =~ Re0[:from]
46
+ match = 0
47
+ match += 1 if mhead['subject'].start_with?('Error Mail Report')
48
+ match += 1 if mhead['from'].include?('Mail System')
58
49
  match += 1 if mhead['x-some-userdefined-header']
59
50
  return nil if match.zero?
60
51
 
@@ -67,10 +58,10 @@ module Sisimai::Bite::Email
67
58
  readcursor = 0 # (Integer) Points the current cursor position
68
59
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
69
60
 
70
- hasdivided.each do |e|
61
+ while e = hasdivided.shift do
71
62
  if readcursor.zero?
72
63
  # Beginning of the bounce message or delivery status part
73
- if e =~ Re1[:begin]
64
+ if e =~ MarkingsOf[:message]
74
65
  readcursor |= Indicators[:deliverystatus]
75
66
  next
76
67
  end
@@ -78,7 +69,7 @@ module Sisimai::Bite::Email
78
69
 
79
70
  if (readcursor & Indicators[:'message-rfc822']).zero?
80
71
  # Beginning of the original message part
81
- if e =~ Re1[:rfc822]
72
+ if e =~ MarkingsOf[:rfc822]
82
73
  readcursor |= Indicators[:'message-rfc822']
83
74
  next
84
75
  end
@@ -92,12 +83,10 @@ module Sisimai::Bite::Email
92
83
  next
93
84
  end
94
85
  rfc822list << e
95
-
96
86
  else
97
87
  # Before "message/rfc822"
98
88
  next if (readcursor & Indicators[:deliverystatus]).zero?
99
89
  next if e.empty?
100
-
101
90
  end
102
91
  end
103
92
 
@@ -7,42 +7,36 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/V5sendmail.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :from => %r/\AMail Delivery Subsystem/,
12
- :subject => %r/\AReturned mail: [A-Z]/,
13
- }.freeze
14
- # Error text regular expressions which defined in src/savemail.c
15
- # savemail.c:485| (void) fflush(stdout);
16
- # savemail.c:486| p = queuename(e->e_parent, 'x');
17
- # savemail.c:487| if ((xfile = fopen(p, "r")) == NULL)
18
- # savemail.c:488| {
19
- # savemail.c:489| syserr("Cannot open %s", p);
20
- # savemail.c:490| fprintf(fp, " ----- Transcript of session is unavailable -----\n");
21
- # savemail.c:491| }
22
- # savemail.c:492| else
23
- # savemail.c:493| {
24
- # savemail.c:494| fprintf(fp, " ----- Transcript of session follows -----\n");
25
- # savemail.c:495| if (e->e_xfp != NULL)
26
- # savemail.c:496| (void) fflush(e->e_xfp);
27
- # savemail.c:497| while (fgets(buf, sizeof buf, xfile) != NULL)
28
- # savemail.c:498| putline(buf, fp, m);
29
- # savemail.c:499| (void) fclose(xfile);
30
- Re1 = {
31
- :begin => %r/\A[ \t]+[-]+ Transcript of session follows [-]+\z/,
32
- :error => %r/\A[.]+ while talking to .+[:]\z/,
33
- :rfc822 => %r{\A[ \t]+-----[ ](?:
10
+ Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = { message: ['----- Transcript of session follows -----'] };
12
+ MarkingsOf = {
13
+ # Error text regular expressions which defined in src/savemail.c
14
+ # savemail.c:485| (void) fflush(stdout);
15
+ # savemail.c:486| p = queuename(e->e_parent, 'x');
16
+ # savemail.c:487| if ((xfile = fopen(p, "r")) == NULL)
17
+ # savemail.c:488| {
18
+ # savemail.c:489| syserr("Cannot open %s", p);
19
+ # savemail.c:490| fprintf(fp, " ----- Transcript of session is unavailable -----\n");
20
+ # savemail.c:491| }
21
+ # savemail.c:492| else
22
+ # savemail.c:493| {
23
+ # savemail.c:494| fprintf(fp, " ----- Transcript of session follows -----\n");
24
+ # savemail.c:495| if (e->e_xfp != NULL)
25
+ # savemail.c:496| (void) fflush(e->e_xfp);
26
+ # savemail.c:497| while (fgets(buf, sizeof buf, xfile) != NULL)
27
+ # savemail.c:498| putline(buf, fp, m);
28
+ # savemail.c:499| (void) fclose(xfile);
29
+ error: %r/\A[.]+ while talking to .+[:]\z/,
30
+ rfc822: %r{\A[ \t]+-----[ ](?:
34
31
  Unsent[ ]message[ ]follows
35
32
  |No[ ]message[ ]was[ ]collected
36
33
  )[ ]-----
37
34
  }x,
38
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
39
35
  }.freeze
40
- Indicators = Sisimai::Bite::Email.INDICATORS
41
36
 
42
37
  def description; return 'Sendmail version 5'; end
43
38
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
44
39
  def headerlist; return []; end
45
- def pattern; return Re0; end
46
40
 
47
41
  # Parse bounce messages from Sendmail version 5
48
42
  # @param [Hash] mhead Message headers of a bounce email
@@ -58,7 +52,9 @@ module Sisimai::Bite::Email
58
52
  def scan(mhead, mbody)
59
53
  return nil unless mhead
60
54
  return nil unless mbody
61
- return nil unless mhead['subject'] =~ Re0[:subject]
55
+
56
+ # :from => %r/\AMail Delivery Subsystem/,
57
+ return nil unless mhead['subject'] =~ /\AReturned mail: [A-Z]/
62
58
 
63
59
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
64
60
  hasdivided = mbody.split("\n")
@@ -72,10 +68,10 @@ module Sisimai::Bite::Email
72
68
  errorindex = -1 # (Integer)
73
69
  v = nil
74
70
 
75
- hasdivided.each do |e|
71
+ while e = hasdivided.shift do
76
72
  if readcursor.zero?
77
73
  # Beginning of the bounce message or delivery status part
78
- if e =~ Re1[:begin]
74
+ if e.include?(StartingOf[:message][0])
79
75
  readcursor |= Indicators[:deliverystatus]
80
76
  next
81
77
  end
@@ -83,7 +79,7 @@ module Sisimai::Bite::Email
83
79
 
84
80
  if (readcursor & Indicators[:'message-rfc822']).zero?
85
81
  # Beginning of the original message part
86
- if e =~ Re1[:rfc822]
82
+ if e =~ MarkingsOf[:rfc822]
87
83
  readcursor |= Indicators[:'message-rfc822']
88
84
  next
89
85
  end
@@ -97,7 +93,6 @@ module Sisimai::Bite::Email
97
93
  next
98
94
  end
99
95
  rfc822list << e
100
-
101
96
  else
102
97
  # Before "message/rfc822"
103
98
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -121,11 +116,8 @@ module Sisimai::Bite::Email
121
116
  v['recipient'] = cv[1]
122
117
  v['diagnosis'] = cv[2]
123
118
 
124
- if responding[recipients]
125
- # Concatenate the response of the server and error message
126
- v['diagnosis'] ||= ''
127
- v['diagnosis'] += ': ' + responding[recipients]
128
- end
119
+ # Concatenate the response of the server and error message
120
+ v['diagnosis'] << ': ' << responding[recipients] if responding[recipients]
129
121
  recipients += 1
130
122
 
131
123
  elsif cv = e.match(/\A[>]{3}[ ]*([A-Z]{4})[ ]*/)
@@ -137,12 +129,11 @@ module Sisimai::Bite::Email
137
129
  # <<< 501 <shironeko@example.co.jp>... no access from mail server [192.0.2.55] which is an open relay.
138
130
  # <<< 550 Requested User Mailbox not found. No such user here.
139
131
  responding[recipients] = cv[1]
140
-
141
132
  else
142
133
  # Detect SMTP session error or connection error
143
134
  next if v['sessionerr']
144
135
 
145
- if e =~ Re1[:error]
136
+ if e =~ MarkingsOf[:error]
146
137
  # ----- Transcript of session follows -----
147
138
  # ... while talking to mta.example.org.:
148
139
  v['sessionerr'] = true
@@ -170,14 +161,14 @@ module Sisimai::Bite::Email
170
161
  end
171
162
  end
172
163
  return nil if recipients.zero?
173
- require 'sisimai/string'
174
164
 
165
+ require 'sisimai/string'
175
166
  dscontents.map do |e|
176
167
  errorindex += 1
177
168
  e['agent'] = self.smtpagent
178
169
  e['command'] = commandset[errorindex] || ''
179
170
 
180
- e['diagnosis'] ||= if anotherset['diagnosis'] && anotherset['diagnosis'].size > 0
171
+ e['diagnosis'] ||= if anotherset['diagnosis'].to_s.size > 0
181
172
  # Copy alternative error message
182
173
  anotherset['diagnosis']
183
174
  else