sisimai 4.25.17-java → 5.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +3 -3
  3. data/ANALYTICAL-PRECISION +2 -2
  4. data/Benchmarks.mk +3 -3
  5. data/CONTRIBUTING +1 -1
  6. data/ChangeLog.md +406 -407
  7. data/Developers.mk +5 -6
  8. data/Gemfile +1 -1
  9. data/Makefile +12 -12
  10. data/README-JA.md +142 -94
  11. data/README.md +282 -150
  12. data/Rakefile +9 -3
  13. data/Repository.mk +2 -3
  14. data/lib/sisimai/address.rb +118 -74
  15. data/lib/sisimai/arf.rb +84 -82
  16. data/lib/sisimai/datetime.rb +5 -52
  17. data/lib/sisimai/{data → fact}/json.rb +7 -9
  18. data/lib/sisimai/fact/yaml.rb +31 -0
  19. data/lib/sisimai/fact.rb +468 -0
  20. data/lib/sisimai/lhost/activehunter.rb +12 -14
  21. data/lib/sisimai/lhost/amavis.rb +11 -14
  22. data/lib/sisimai/lhost/amazonses.rb +37 -41
  23. data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
  24. data/lib/sisimai/lhost/aol.rb +12 -14
  25. data/lib/sisimai/lhost/apachejames.rb +19 -21
  26. data/lib/sisimai/lhost/barracuda.rb +10 -12
  27. data/lib/sisimai/lhost/bigfoot.rb +21 -21
  28. data/lib/sisimai/lhost/biglobe.rb +15 -16
  29. data/lib/sisimai/lhost/courier.rb +20 -20
  30. data/lib/sisimai/lhost/domino.rb +23 -19
  31. data/lib/sisimai/lhost/einsundeins.rb +20 -16
  32. data/lib/sisimai/lhost/exchange2003.rb +30 -29
  33. data/lib/sisimai/lhost/exchange2007.rb +70 -58
  34. data/lib/sisimai/lhost/exim.rb +175 -161
  35. data/lib/sisimai/lhost/ezweb.rb +31 -56
  36. data/lib/sisimai/lhost/facebook.rb +21 -33
  37. data/lib/sisimai/lhost/fml.rb +43 -48
  38. data/lib/sisimai/lhost/gmail.rb +29 -29
  39. data/lib/sisimai/lhost/gmx.rb +18 -17
  40. data/lib/sisimai/lhost/googlegroups.rb +9 -10
  41. data/lib/sisimai/lhost/gsuite.rb +21 -27
  42. data/lib/sisimai/lhost/imailserver.rb +25 -39
  43. data/lib/sisimai/lhost/interscanmss.rb +28 -31
  44. data/lib/sisimai/lhost/kddi.rb +22 -28
  45. data/lib/sisimai/lhost/mailfoundry.rb +11 -12
  46. data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
  47. data/lib/sisimai/lhost/mailru.rb +33 -27
  48. data/lib/sisimai/lhost/mcafee.rb +21 -31
  49. data/lib/sisimai/lhost/messagelabs.rb +17 -20
  50. data/lib/sisimai/lhost/messagingserver.rb +40 -37
  51. data/lib/sisimai/lhost/mfilter.rb +15 -16
  52. data/lib/sisimai/lhost/mxlogic.rb +24 -23
  53. data/lib/sisimai/lhost/notes.rb +17 -17
  54. data/lib/sisimai/lhost/office365.rb +63 -27
  55. data/lib/sisimai/lhost/opensmtpd.rb +12 -13
  56. data/lib/sisimai/lhost/outlook.rb +12 -15
  57. data/lib/sisimai/lhost/postfix.rb +179 -129
  58. data/lib/sisimai/lhost/powermta.rb +12 -14
  59. data/lib/sisimai/lhost/qmail.rb +44 -47
  60. data/lib/sisimai/lhost/receivingses.rb +15 -20
  61. data/lib/sisimai/lhost/sendgrid.rb +34 -32
  62. data/lib/sisimai/lhost/sendmail.rb +66 -53
  63. data/lib/sisimai/lhost/surfcontrol.rb +19 -19
  64. data/lib/sisimai/lhost/v5sendmail.rb +45 -39
  65. data/lib/sisimai/lhost/verizon.rb +35 -39
  66. data/lib/sisimai/lhost/x1.rb +18 -17
  67. data/lib/sisimai/lhost/x2.rb +17 -14
  68. data/lib/sisimai/lhost/x3.rb +19 -19
  69. data/lib/sisimai/lhost/x4.rb +72 -57
  70. data/lib/sisimai/lhost/x5.rb +17 -19
  71. data/lib/sisimai/lhost/x6.rb +41 -17
  72. data/lib/sisimai/lhost/yahoo.rb +17 -16
  73. data/lib/sisimai/lhost/yandex.rb +16 -20
  74. data/lib/sisimai/lhost/zoho.rb +16 -15
  75. data/lib/sisimai/lhost.rb +8 -10
  76. data/lib/sisimai/mail/maildir.rb +1 -3
  77. data/lib/sisimai/mail/mbox.rb +3 -4
  78. data/lib/sisimai/mail/memory.rb +0 -1
  79. data/lib/sisimai/mail/stdin.rb +1 -3
  80. data/lib/sisimai/mail.rb +3 -7
  81. data/lib/sisimai/mda.rb +28 -42
  82. data/lib/sisimai/message.rb +435 -325
  83. data/lib/sisimai/order.rb +5 -5
  84. data/lib/sisimai/reason/authfailure.rb +64 -0
  85. data/lib/sisimai/reason/badreputation.rb +53 -0
  86. data/lib/sisimai/reason/blocked.rb +94 -160
  87. data/lib/sisimai/reason/contenterror.rb +8 -9
  88. data/lib/sisimai/reason/delivered.rb +4 -6
  89. data/lib/sisimai/reason/exceedlimit.rb +10 -12
  90. data/lib/sisimai/reason/expired.rb +6 -8
  91. data/lib/sisimai/reason/feedback.rb +2 -3
  92. data/lib/sisimai/reason/filtered.rb +17 -19
  93. data/lib/sisimai/reason/hasmoved.rb +9 -10
  94. data/lib/sisimai/reason/hostunknown.rb +15 -15
  95. data/lib/sisimai/reason/mailboxfull.rb +10 -12
  96. data/lib/sisimai/reason/mailererror.rb +18 -20
  97. data/lib/sisimai/reason/mesgtoobig.rb +9 -11
  98. data/lib/sisimai/reason/networkerror.rb +5 -8
  99. data/lib/sisimai/reason/norelaying.rb +8 -11
  100. data/lib/sisimai/reason/notaccept.rb +13 -14
  101. data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
  102. data/lib/sisimai/reason/onhold.rb +6 -9
  103. data/lib/sisimai/reason/policyviolation.rb +14 -12
  104. data/lib/sisimai/reason/rejected.rb +26 -24
  105. data/lib/sisimai/reason/requireptr.rb +69 -0
  106. data/lib/sisimai/reason/securityerror.rb +33 -36
  107. data/lib/sisimai/reason/spamdetected.rb +114 -147
  108. data/lib/sisimai/reason/speeding.rb +49 -0
  109. data/lib/sisimai/reason/suspend.rb +11 -11
  110. data/lib/sisimai/reason/syntaxerror.rb +11 -10
  111. data/lib/sisimai/reason/systemerror.rb +7 -9
  112. data/lib/sisimai/reason/systemfull.rb +7 -8
  113. data/lib/sisimai/reason/toomanyconn.rb +9 -11
  114. data/lib/sisimai/reason/undefined.rb +2 -3
  115. data/lib/sisimai/reason/userunknown.rb +129 -146
  116. data/lib/sisimai/reason/vacation.rb +3 -4
  117. data/lib/sisimai/reason/virusdetected.rb +10 -11
  118. data/lib/sisimai/reason.rb +59 -64
  119. data/lib/sisimai/rfc1894.rb +55 -28
  120. data/lib/sisimai/rfc2045.rb +373 -0
  121. data/lib/sisimai/rfc3464.rb +250 -308
  122. data/lib/sisimai/rfc3834.rb +42 -45
  123. data/lib/sisimai/rfc5322.rb +75 -100
  124. data/lib/sisimai/rfc5965.rb +31 -0
  125. data/lib/sisimai/rhost/cox.rb +5 -6
  126. data/lib/sisimai/rhost/franceptt.rb +6 -8
  127. data/lib/sisimai/rhost/godaddy.rb +12 -12
  128. data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
  129. data/lib/sisimai/rhost/iua.rb +9 -10
  130. data/lib/sisimai/rhost/kddi.rb +6 -8
  131. data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
  132. data/lib/sisimai/rhost/mimecast.rb +42 -40
  133. data/lib/sisimai/rhost/nttdocomo.rb +13 -18
  134. data/lib/sisimai/rhost/spectrum.rb +10 -12
  135. data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
  136. data/lib/sisimai/rhost.rb +23 -31
  137. data/lib/sisimai/smtp/command.rb +59 -0
  138. data/lib/sisimai/smtp/error.rb +4 -7
  139. data/lib/sisimai/smtp/reply.rb +161 -74
  140. data/lib/sisimai/smtp/status.rb +504 -393
  141. data/lib/sisimai/smtp/transcript.rb +124 -0
  142. data/lib/sisimai/smtp.rb +0 -1
  143. data/lib/sisimai/string.rb +74 -5
  144. data/lib/sisimai/time.rb +1 -2
  145. data/lib/sisimai/version.rb +1 -1
  146. data/lib/sisimai.rb +35 -21
  147. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
  148. data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
  149. data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
  150. data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
  151. data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
  152. data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
  153. data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
  154. data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
  155. data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
  156. data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
  157. data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
  158. data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
  159. data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
  160. data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
  161. data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
  162. data/sisimai-java.gemspec +1 -1
  163. data/sisimai.gemspec +1 -1
  164. metadata +42 -23
  165. data/.rspec +0 -2
  166. data/lib/sisimai/data/yaml.rb +0 -33
  167. data/lib/sisimai/data.rb +0 -411
  168. data/lib/sisimai/mime.rb +0 -456
  169. data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
  170. /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::MailFoundry parses a bounce email which created by
3
- # MailFoundry. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::MailFoundry parses a bounce email which created by MailFoundry. Methods in the
3
+ # module are called from only Sisimai::Message.
4
4
  module MailFoundry
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MailFoundry.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
9
+ Boundaries = ['Content-Type: message/rfc822'].freeze
11
10
  StartingOf = {
12
11
  message: ['Unable to deliver message to:'],
13
12
  error: ['Delivery failed for the following reason:'],
@@ -18,20 +17,20 @@ module Sisimai::Lhost
18
17
  # @param [String] mbody Message body of a bounce email
19
18
  # @return [Hash] Bounce data list and message/rfc822 part
20
19
  # @return [Nil] it failed to parse or the arguments are missing
21
- def make(mhead, mbody)
20
+ def inquire(mhead, mbody)
22
21
  return nil unless mhead['subject'] == 'Message delivery has failed'
23
22
  return nil unless mhead['received'].any? { |a| a.include?('(MAILFOUNDRY) id ') }
24
23
 
25
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
26
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
27
- bodyslices = emailsteak[0].split("\n")
25
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
26
+ bodyslices = emailparts[0].split("\n")
28
27
  readcursor = 0 # (Integer) Points the current cursor position
29
28
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
30
29
  v = nil
31
30
 
32
31
  while e = bodyslices.shift do
33
- # Read error messages and delivery status lines from the head of the email
34
- # to the previous line of the beginning of the original message.
32
+ # Read error messages and delivery status lines from the head of the email to the previous
33
+ # line of the beginning of the original message.
35
34
  if readcursor == 0
36
35
  # Beginning of the bounce message or delivery status part
37
36
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -46,14 +45,14 @@ module Sisimai::Lhost
46
45
  # This has been a permanent failure. No further delivery attempts will be made.
47
46
  v = dscontents[-1]
48
47
 
49
- if cv = e.match(/\AUnable to deliver message to: [<]([^ ]+[@][^ ]+)[>]\z/)
48
+ if e.start_with?('Unable to deliver message to: <') && e.index('@') > 1
50
49
  # Unable to deliver message to: <kijitora@example.org>
51
50
  if v['recipient']
52
51
  # There are multiple recipient addresses in the message body.
53
52
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
54
53
  v = dscontents[-1]
55
54
  end
56
- v['recipient'] = cv[1]
55
+ v['recipient'] = e[e.index('<'), e.size]
57
56
  recipients += 1
58
57
  else
59
58
  # Error message
@@ -74,7 +73,7 @@ module Sisimai::Lhost
74
73
  return nil unless recipients > 0
75
74
 
76
75
  dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
77
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
76
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
78
77
  end
79
78
  def description; return 'MailFoundry'; end
80
79
  end
@@ -1,14 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created
3
- # by Trustwave Secure Email Gateway: formerly MailMarshal SMTP. Methods in
4
- # the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::MailMarshalSMTP parses a bounce email which created by Trustwave Secure Email
3
+ # Gateway: formerly MailMarshal SMTP. Methods in the module are called from only Sisimai::Message.
5
4
  module MailMarshalSMTP
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MailMarshalSMTP.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r/^[ \t]*[+]+[ \t]*/.freeze
9
+ Boundaries = ['+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++']
12
10
  StartingOf = {
13
11
  message: ['Your message:'],
14
12
  error: ['Could not be delivered because of'],
@@ -20,26 +18,19 @@ module Sisimai::Lhost
20
18
  # @param [String] mbody Message body of a bounce email
21
19
  # @return [Hash] Bounce data list and message/rfc822 part
22
20
  # @return [Nil] it failed to parse or the arguments are missing
23
- def make(mhead, mbody)
21
+ def inquire(mhead, mbody)
24
22
  return nil unless mhead['subject'].start_with?('Undeliverable Mail: "')
25
23
 
26
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
27
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
28
- bodyslices = emailsteak[0].split("\n")
25
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
26
+ bodyslices = emailparts[0].split("\n")
29
27
  readcursor = 0 # (Integer) Points the current cursor position
30
28
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
31
29
  endoferror = false # (Boolean) Flag for the end of error message
32
30
  regularexp = nil
31
+ q = Sisimai::RFC2045.boundary(mhead['content-type'], 1); Boundaries << q if q
33
32
  v = nil
34
33
 
35
- boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
36
- regularexp = if boundary00.size > 0
37
- # Convert to regular expression
38
- Regexp.new('\A' << Regexp.escape(boundary00) << '\z')
39
- else
40
- regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
41
- end
42
-
43
34
  while e = bodyslices.shift do
44
35
  # Read error messages and delivery status lines from the head of the email
45
36
  # to the previous line of the beginning of the original message.
@@ -61,7 +52,7 @@ module Sisimai::Lhost
61
52
  # dummyuser@blabla.xxxxxxxxxxxx.com
62
53
  v = dscontents[-1]
63
54
 
64
- if cv = e.match(/\A[ ]{4}([^ ]+[@][^ ]+)\z/)
55
+ if e.start_with?(' ') && e.index('@') > 1
65
56
  # The following recipients were affected:
66
57
  # dummyuser@blabla.xxxxxxxxxxxx.com
67
58
  if v['recipient']
@@ -69,7 +60,7 @@ module Sisimai::Lhost
69
60
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
70
61
  v = dscontents[-1]
71
62
  end
72
- v['recipient'] = cv[1]
63
+ v['recipient'] = e[4, e.size]
73
64
  recipients += 1
74
65
  else
75
66
  # Get error message lines
@@ -93,24 +84,29 @@ module Sisimai::Lhost
93
84
  # Reporting-MTA: <relay.xxxxxxxxxxxx.com>
94
85
  # MessageName: <B549996730000.000000000001.0003.mml>
95
86
  # Last-Attempt-Date: <16:21:07 seg, 22 Dezembro 2014>
96
- if cv = e.match(/\AOriginal Sender:[ \t]+[<](.+)[>]\z/)
87
+ p1 = e.index('<')
88
+ p2 = e.index('>')
89
+ if e.start_with?('Original Sender: ')
97
90
  # Original Sender: <originalsender@example.com>
98
- # Use this line instead of "From" header of the original
99
- # message.
100
- emailsteak[1] << ('From: ' << cv[1] << "\n")
91
+ # Use this line instead of "From" header of the original message.
92
+ emailparts[1] << ('From: ' << e[p1 + 1, p2 - p1 - 1] << "\n")
101
93
 
102
- elsif cv = e.match(/\ASender-MTA:[ \t]+[<](.+)[>]\z/)
94
+ elsif e.start_with?('Sender-MTA: ')
103
95
  # Sender-MTA: <10.11.12.13>
104
- v['lhost'] = cv[1]
96
+ v['lhost'] = e[p1 + 1, p2 - p1 - 1]
105
97
 
106
- elsif cv = e.match(/\AReporting-MTA:[ \t]+[<](.+)[>]\z/)
98
+ elsif e.start_with?('Reporting-MTA: ')
107
99
  # Reporting-MTA: <relay.xxxxxxxxxxxx.com>
108
- v['rhost'] = cv[1]
100
+ v['rhost'] = e[p1 + 1, p2 - p1 - 1]
109
101
 
110
- elsif cv = e.match(/\A\s+(From|Subject):\s*(.+)\z/)
102
+ elsif e.include?(' From:') || e.include?(' Subject:')
111
103
  # From: originalsender@example.com
112
104
  # Subject: ...
113
- emailsteak[1] << sprintf("%s: %s\n", cv[1], cv[2])
105
+ p1 = e.index(' From:') || e.index(' Subject:')
106
+ p2 = e.index(':')
107
+ cf = e[p1 + 1, p2 - p1 - 1]
108
+ cv = Sisimai::String.sweep(e[p2 + 1, e.size])
109
+ emailparts[1] << sprintf("%s: %s\n", cf, cv)
114
110
  end
115
111
  end
116
112
  end
@@ -118,7 +114,7 @@ module Sisimai::Lhost
118
114
  return nil unless recipients > 0
119
115
 
120
116
  dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
121
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
117
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
122
118
  end
123
119
  def description; return 'Trustwave Secure Email Gateway'; end
124
120
  end
@@ -1,14 +1,13 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::MailRu parses a bounce email which created by @mail.ru. Methods in the module are
3
+ # called from only Sisimai::Message.
4
4
  module MailRu
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MailRu.pm
7
6
  # Based on Sisimai::Lhost::Exim
8
7
  require 'sisimai/lhost'
9
8
 
10
9
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r|^------ This is a copy of the message, including all the headers[.] ------|.freeze
10
+ Boundaries = ['------ This is a copy of the message, including all the headers. ------'].freeze
12
11
  StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
13
12
  ReCommands = [
14
13
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
@@ -50,30 +49,32 @@ module Sisimai::Lhost
50
49
  # @param [String] mbody Message body of a bounce email
51
50
  # @return [Hash] Bounce data list and message/rfc822 part
52
51
  # @return [Nil] it failed to parse or the arguments are missing
53
- def make(mhead, mbody)
54
- return nil unless mhead['from'] =~ /[<]?mailer-daemon[@].*mail[.]ru[>]?/i
55
- return nil unless mhead['message-id'].end_with?('.mail.ru>', 'smailru.net>')
56
- return nil unless mhead['subject'] =~ %r{(?:
57
- Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
58
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
59
- |Delivery[ ]Status[ ]Notification
60
- |Mail[ ]failure
61
- |Message[ ]frozen
62
- |error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
63
- )
64
- }x
52
+ def inquire(mhead, mbody)
53
+ mfrom = mhead['from'].downcase
54
+ msgid = mhead['message-id'] ? mhead['message-id'].downcase : ''
55
+ match = 0
56
+ match += 1 if mfrom.include?('mailer-daemon@') && mfrom.include?('mail.ru')
57
+ match += 1 if msgid.end_with?('.mail.ru>', 'smailru.net>')
58
+ match += 1 if [
59
+ 'Delivery Status Notification',
60
+ 'Mail delivery failed',
61
+ 'Mail failure',
62
+ 'Message frozen',
63
+ 'Warning: message ',
64
+ 'error(s) in forwarding or filtering'].any? { |a| mhead['subject'].include?(a) }
65
+ return nil unless match > 2
65
66
 
66
67
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
67
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
68
- bodyslices = emailsteak[0].split("\n")
68
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
69
+ bodyslices = emailparts[0].split("\n")
69
70
  readcursor = 0 # (Integer) Points the current cursor position
70
71
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
71
72
  localhost0 = '' # (String) Local MTA
72
73
  v = nil
73
74
 
74
75
  while e = bodyslices.shift do
75
- # Read error messages and delivery status lines from the head of the email
76
- # to the previous line of the beginning of the original message.
76
+ # Read error messages and delivery status lines from the head of the email to the previous
77
+ # line of the beginning of the original message.
77
78
  if readcursor == 0
78
79
  # Beginning of the bounce message or delivery status part
79
80
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -102,14 +103,14 @@ module Sisimai::Lhost
102
103
  # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
103
104
  v = dscontents[-1]
104
105
 
105
- if cv = e.match(/\A[ \t]+([^ \t]+[@][^ \t]+[.][a-zA-Z]+)\z/)
106
+ if e.start_with?(' ') && e.include?(' ') == false && e.index('@') > 1
106
107
  # kijitora@example.jp
107
108
  if v['recipient']
108
109
  # There are multiple recipient addresses in the message body.
109
110
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
110
111
  v = dscontents[-1]
111
112
  end
112
- v['recipient'] = cv[1]
113
+ v['recipient'] = e[2, e.size]
113
114
  recipients += 1
114
115
 
115
116
  elsif dscontents.size == recipients
@@ -120,7 +121,7 @@ module Sisimai::Lhost
120
121
  else
121
122
  # Error message when email address above does not include '@'
122
123
  # and domain part.
123
- next unless e.start_with?(' ', "\t")
124
+ next unless e.start_with?(' ')
124
125
  v['alterrors'] ||= ''
125
126
  v['alterrors'] << e + ' '
126
127
  end
@@ -147,7 +148,9 @@ module Sisimai::Lhost
147
148
  unless mhead['received'].empty?
148
149
  # Get the name of local MTA
149
150
  # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
150
- if cv = mhead['received'][-1].match(/from[ \t]([^ ]+)/) then localhost0 = cv[1] end
151
+ p1 = mhead['received'][-1].index('from ') || -1
152
+ p2 = mhead['received'][-1].index(' ', p1 + 5) || -1
153
+ localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5] if p1 > -1
151
154
  end
152
155
 
153
156
  dscontents.each do |e|
@@ -164,12 +167,15 @@ module Sisimai::Lhost
164
167
  e.delete('alterrors')
165
168
  end
166
169
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
167
- e['diagnosis'].sub!(/\b__.+\z/, '')
170
+ p1 = e['diagnosis'].rindex('__') || -1
171
+ e['diagnosis'] = e['diagnosis'][0, p1 - 1] if p1 > 2
168
172
 
169
173
  unless e['rhost']
170
174
  # Get the remote host name
171
175
  # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
172
- if cv = e['diagnosis'].match(/host[ ]+([^ \t]+)[ ]\[.+\]:[ ]/) then e['rhost'] = cv[1] end
176
+ p1 = e['diagnosis'].index('host ') || -1
177
+ p2 = e['diagnosis'].index(' ', p1 + 5) || -1
178
+ e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
173
179
 
174
180
  unless e['rhost']
175
181
  # Get localhost and remote host name from Received header.
@@ -208,7 +214,7 @@ module Sisimai::Lhost
208
214
  e['command'] ||= ''
209
215
  end
210
216
 
211
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
217
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
212
218
  end
213
219
  def description; return '@mail.ru: https://mail.ru'; end
214
220
  end
@@ -1,49 +1,39 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::McAfee parses a bounce email which created by McAfee
3
- # Email Appliance. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::McAfee parses a bounce email which created by McAfee Email Appliance. Methods in
3
+ # the module are called from only Sisimai::Message.
4
4
  module McAfee
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/McAfee.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
9
+ Boundaries = ['Content-Type: message/rfc822'].freeze
11
10
  StartingOf = { message: ['--- The following addresses had delivery problems ---'] }.freeze
12
- ReFailures = {
13
- 'userunknown' => %r{(?:
14
- [ ]User[ ][(].+[@].+[)][ ]unknown[.][ ]
15
- |550[ ]Unknown[ ]user[ ][^ ]+[@][^ ]+
16
- |550[ ][<].+?[@].+?[>][.]+[ ]User[ ]not[ ]exist
17
- |No[ ]such[ ]user
18
- )
19
- }x,
20
- }.freeze
11
+ MessagesOf = { 'userunknown' => [' User not exist', ' unknown.', '550 Unknown user ', 'No such user'] }.freeze
21
12
 
22
13
  # Parse bounce messages from McAfee Email Appliance
23
14
  # @param [Hash] mhead Message headers of a bounce email
24
15
  # @param [String] mbody Message body of a bounce email
25
16
  # @return [Hash] Bounce data list and message/rfc822 part
26
17
  # @return [Nil] it failed to parse or the arguments are missing
27
- def make(mhead, mbody)
18
+ def inquire(mhead, mbody)
28
19
  # X-NAI-Header: Modified by McAfee Email and Web Security Virtual Appliance
29
20
  return nil unless mhead['x-nai-header']
30
21
  return nil unless mhead['x-nai-header'].start_with?('Modified by McAfee ')
31
22
  return nil unless mhead['subject'] == 'Delivery Status'
32
23
 
33
- require 'sisimai/rfc1894'
34
24
  fieldtable = Sisimai::RFC1894.FIELDTABLE
35
25
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
36
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
37
- bodyslices = emailsteak[0].split("\n")
26
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
27
+ bodyslices = emailparts[0].split("\n")
38
28
  readslices = ['']
39
29
  readcursor = 0 # (Integer) Points the current cursor position
40
30
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
41
- diagnostic = '' # (String) Alternative diagnostic message
31
+ issuedcode = '' # (String) Alternative diagnostic message
42
32
  v = nil
43
33
 
44
34
  while e = bodyslices.shift do
45
- # Read error messages and delivery status lines from the head of the email
46
- # to the previous line of the beginning of the original message.
35
+ # Read error messages and delivery status lines from the head of the email to the previous
36
+ # line of the beginning of the original message.
47
37
  readslices << e # Save the current line for the next loop
48
38
 
49
39
  if readcursor == 0
@@ -65,15 +55,15 @@ module Sisimai::Lhost
65
55
  #
66
56
  v = dscontents[-1]
67
57
 
68
- if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>][ \t]+[(](.+)[)]\z/)
58
+ if Sisimai::String.aligned(e, ['<', '@', '>', '(', ')'])
69
59
  # <kijitora@example.co.jp> (Unknown user kijitora@example.co.jp)
70
60
  if v['recipient']
71
61
  # There are multiple recipient addresses in the message body.
72
62
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
73
63
  v = dscontents[-1]
74
64
  end
75
- v['recipient'] = cv[1]
76
- diagnostic = cv[2]
65
+ v['recipient'] = Sisimai::Address.s3s4(e[e.index('<'), e.index('>')])
66
+ issuedcode = e[e.index('(') + 1, e.size]
77
67
  recipients += 1
78
68
 
79
69
  elsif f = Sisimai::RFC1894.match(e)
@@ -82,8 +72,8 @@ module Sisimai::Lhost
82
72
  unless o
83
73
  # Fallback code for empty value or invalid formatted value
84
74
  # - Original-Recipient: <kijitora@example.co.jp>
85
- if cv = e.match(/\AOriginal-Recipient:[ ]*([^ ]+)\z/)
86
- v['alias'] = Sisimai::Address.s3s4(cv[1])
75
+ if e.start_with?('Original-Recipient: ')
76
+ v['alias'] = Sisimai::Address.s3s4(e[e.index(':') + 1, e.size])
87
77
  end
88
78
  next
89
79
  end
@@ -93,24 +83,24 @@ module Sisimai::Lhost
93
83
  else
94
84
  # Continued line of the value of Diagnostic-Code field
95
85
  next unless readslices[-2].start_with?('Diagnostic-Code:')
96
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
97
- v['diagnosis'] << ' ' << cv[1]
86
+ next unless e.start_with?(' ')
87
+ v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
98
88
  readslices[-1] = 'Diagnostic-Code: ' << e
99
89
  end
100
90
  end
101
91
  return nil unless recipients > 0
102
92
 
103
93
  dscontents.each do |e|
104
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || diagnostic)
105
- ReFailures.each_key do |r|
94
+ e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'] || issuedcode)
95
+ MessagesOf.each_key do |r|
106
96
  # Verify each regular expression of session errors
107
- next unless e['diagnosis'] =~ ReFailures[r]
97
+ next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
108
98
  e['reason'] = r
109
99
  break
110
100
  end
111
101
  end
112
102
 
113
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
103
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
114
104
  end
115
105
  def description; return 'McAfee Email Appliance'; end
116
106
  end
@@ -1,18 +1,16 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::MessageLabs parses a bounce email which created by
3
- # Symantec.cloud: formerly MessageLabs. Methods in the module are called
4
- # from only Sisimai::Message.
2
+ # Sisimai::Lhost::MessageLabs parses a bounce email which created by Symantec.cloud: formerly MessageLabs.
3
+ # Methods in the module are called from only Sisimai::Message.
5
4
  module MessageLabs
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MessageLabs.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r|^Content-Type:[ ]text/rfc822-headers|.freeze
9
+ Boundaries = ['Content-Type: text/rfc822-headers'].freeze
12
10
  StartingOf = { message: ['Content-Type: message/delivery-status'] }.freeze
13
- ReFailures = {
14
- 'userunknown' => %r/(?:542 .+ Rejected|No such user)/,
15
- 'securityerror' => %r/Please turn on SMTP Authentication in your mail client/,
11
+ MessagesOf = {
12
+ 'userunknown' => ['542 ', ' Rejected', 'No such user'],
13
+ 'securityerror' => ['Please turn on SMTP Authentication in your mail client'],
16
14
  }.freeze
17
15
 
18
16
  # Parse bounce messages from Symantec.cloud(MessageLabs)
@@ -20,7 +18,7 @@ module Sisimai::Lhost
20
18
  # @param [String] mbody Message body of a bounce email
21
19
  # @return [Hash] Bounce data list and message/rfc822 part
22
20
  # @return [Nil] it failed to parse or the arguments are missing
23
- def make(mhead, mbody)
21
+ def inquire(mhead, mbody)
24
22
  # X-Msg-Ref: server-11.tower-143.messagelabs.com!1419367175!36473369!1
25
23
  # X-Originating-IP: [10.245.230.38]
26
24
  # X-StarScan-Received:
@@ -30,13 +28,12 @@ module Sisimai::Lhost
30
28
  return nil unless mhead['from'].include?('MAILER-DAEMON@messagelabs.com')
31
29
  return nil unless mhead['subject'].start_with?('Mail Delivery Failure')
32
30
 
33
- require 'sisimai/rfc1894'
34
31
  fieldtable = Sisimai::RFC1894.FIELDTABLE
35
32
  permessage = {} # (Hash) Store values of each Per-Message field
36
33
 
37
34
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
38
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
39
- bodyslices = emailsteak[0].split("\n")
35
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
36
+ bodyslices = emailparts[0].split("\n")
40
37
  readslices = ['']
41
38
  readcursor = 0 # (Integer) Points the current cursor position
42
39
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
@@ -44,8 +41,8 @@ module Sisimai::Lhost
44
41
  v = nil
45
42
 
46
43
  while e = bodyslices.shift do
47
- # Read error messages and delivery status lines from the head of the email
48
- # to the previous line of the beginning of the original message.
44
+ # Read error messages and delivery status lines from the head of the email to the previous
45
+ # line of the beginning of the original message.
49
46
  readslices << e # Save the current line for the next loop
50
47
 
51
48
  if readcursor == 0
@@ -86,14 +83,14 @@ module Sisimai::Lhost
86
83
  next unless fieldtable[o[0]]
87
84
  v[fieldtable[o[0]]] = o[2]
88
85
 
89
- next unless f == 1
86
+ next unless f
90
87
  permessage[fieldtable[o[0]]] = o[2]
91
88
  end
92
89
  else
93
90
  # Continued line of the value of Diagnostic-Code field
94
91
  next unless readslices[-2].start_with?('Diagnostic-Code:')
95
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
96
- v['diagnosis'] << ' ' << cv[1]
92
+ next unless e.start_with?(' ')
93
+ v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
97
94
  readslices[-1] = 'Diagnostic-Code: ' << e
98
95
  end
99
96
  end
@@ -106,15 +103,15 @@ module Sisimai::Lhost
106
103
  e['command'] = commandset.shift || ''
107
104
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
108
105
 
109
- ReFailures.each_key do |r|
106
+ MessagesOf.each_key do |r|
110
107
  # Verify each regular expression of session errors
111
- next unless e['diagnosis'] =~ ReFailures[r]
108
+ next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
112
109
  e['reason'] = r
113
110
  break
114
111
  end
115
112
  end
116
113
 
117
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
114
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
118
115
  end
119
116
  def description; return 'Symantec.cloud http://www.messagelabs.com'; end
120
117
  end