sisimai 4.25.16-java → 5.0.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rake-test.yml +55 -0
  3. data/.travis.yml +3 -3
  4. data/ANALYTICAL-PRECISION +2 -2
  5. data/Benchmarks.mk +3 -3
  6. data/CONTRIBUTING +1 -1
  7. data/ChangeLog.md +451 -393
  8. data/Developers.mk +5 -6
  9. data/Gemfile +1 -1
  10. data/Makefile +15 -15
  11. data/README-JA.md +323 -149
  12. data/README.md +319 -149
  13. data/Rakefile +9 -3
  14. data/Repository.mk +2 -3
  15. data/lib/sisimai/address.rb +118 -74
  16. data/lib/sisimai/arf.rb +84 -82
  17. data/lib/sisimai/datetime.rb +5 -52
  18. data/lib/sisimai/{data → fact}/json.rb +7 -9
  19. data/lib/sisimai/fact/yaml.rb +31 -0
  20. data/lib/sisimai/fact.rb +506 -0
  21. data/lib/sisimai/lhost/activehunter.rb +12 -14
  22. data/lib/sisimai/lhost/amavis.rb +11 -14
  23. data/lib/sisimai/lhost/amazonses.rb +37 -42
  24. data/lib/sisimai/lhost/amazonworkmail.rb +15 -19
  25. data/lib/sisimai/lhost/aol.rb +12 -15
  26. data/lib/sisimai/lhost/apachejames.rb +19 -21
  27. data/lib/sisimai/lhost/barracuda.rb +10 -12
  28. data/lib/sisimai/lhost/bigfoot.rb +21 -22
  29. data/lib/sisimai/lhost/biglobe.rb +15 -16
  30. data/lib/sisimai/lhost/courier.rb +20 -20
  31. data/lib/sisimai/lhost/domino.rb +23 -20
  32. data/lib/sisimai/lhost/einsundeins.rb +23 -18
  33. data/lib/sisimai/lhost/exchange2003.rb +30 -29
  34. data/lib/sisimai/lhost/exchange2007.rb +70 -58
  35. data/lib/sisimai/lhost/exim.rb +179 -174
  36. data/lib/sisimai/lhost/ezweb.rb +31 -56
  37. data/lib/sisimai/lhost/facebook.rb +21 -34
  38. data/lib/sisimai/lhost/fml.rb +43 -48
  39. data/lib/sisimai/lhost/gmail.rb +29 -29
  40. data/lib/sisimai/lhost/gmx.rb +18 -17
  41. data/lib/sisimai/lhost/googlegroups.rb +11 -11
  42. data/lib/sisimai/lhost/gsuite.rb +21 -28
  43. data/lib/sisimai/lhost/imailserver.rb +25 -39
  44. data/lib/sisimai/lhost/interscanmss.rb +28 -31
  45. data/lib/sisimai/lhost/kddi.rb +22 -28
  46. data/lib/sisimai/lhost/mailfoundry.rb +11 -12
  47. data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
  48. data/lib/sisimai/lhost/mailru.rb +37 -40
  49. data/lib/sisimai/lhost/mcafee.rb +21 -31
  50. data/lib/sisimai/lhost/messagelabs.rb +17 -21
  51. data/lib/sisimai/lhost/messagingserver.rb +40 -37
  52. data/lib/sisimai/lhost/mfilter.rb +16 -17
  53. data/lib/sisimai/lhost/mxlogic.rb +24 -33
  54. data/lib/sisimai/lhost/notes.rb +17 -17
  55. data/lib/sisimai/lhost/office365.rb +64 -28
  56. data/lib/sisimai/lhost/opensmtpd.rb +12 -13
  57. data/lib/sisimai/lhost/outlook.rb +12 -16
  58. data/lib/sisimai/lhost/postfix.rb +179 -130
  59. data/lib/sisimai/lhost/powermta.rb +12 -14
  60. data/lib/sisimai/lhost/qmail.rb +44 -47
  61. data/lib/sisimai/lhost/receivingses.rb +15 -21
  62. data/lib/sisimai/lhost/sendgrid.rb +34 -34
  63. data/lib/sisimai/lhost/sendmail.rb +65 -53
  64. data/lib/sisimai/lhost/surfcontrol.rb +19 -19
  65. data/lib/sisimai/lhost/v5sendmail.rb +45 -39
  66. data/lib/sisimai/lhost/verizon.rb +35 -39
  67. data/lib/sisimai/lhost/x1.rb +18 -17
  68. data/lib/sisimai/lhost/x2.rb +17 -14
  69. data/lib/sisimai/lhost/x3.rb +19 -19
  70. data/lib/sisimai/lhost/x4.rb +72 -57
  71. data/lib/sisimai/lhost/x5.rb +17 -19
  72. data/lib/sisimai/lhost/x6.rb +41 -17
  73. data/lib/sisimai/lhost/yahoo.rb +17 -16
  74. data/lib/sisimai/lhost/yandex.rb +16 -21
  75. data/lib/sisimai/lhost/zoho.rb +16 -15
  76. data/lib/sisimai/lhost.rb +8 -10
  77. data/lib/sisimai/mail/maildir.rb +1 -3
  78. data/lib/sisimai/mail/mbox.rb +3 -4
  79. data/lib/sisimai/mail/memory.rb +0 -1
  80. data/lib/sisimai/mail/stdin.rb +1 -3
  81. data/lib/sisimai/mail.rb +3 -7
  82. data/lib/sisimai/mda.rb +28 -42
  83. data/lib/sisimai/message.rb +444 -326
  84. data/lib/sisimai/order.rb +5 -5
  85. data/lib/sisimai/reason/authfailure.rb +65 -0
  86. data/lib/sisimai/reason/badreputation.rb +53 -0
  87. data/lib/sisimai/reason/blocked.rb +96 -160
  88. data/lib/sisimai/reason/contenterror.rb +8 -9
  89. data/lib/sisimai/reason/delivered.rb +4 -6
  90. data/lib/sisimai/reason/exceedlimit.rb +10 -12
  91. data/lib/sisimai/reason/expired.rb +7 -8
  92. data/lib/sisimai/reason/feedback.rb +2 -3
  93. data/lib/sisimai/reason/filtered.rb +17 -19
  94. data/lib/sisimai/reason/hasmoved.rb +9 -10
  95. data/lib/sisimai/reason/hostunknown.rb +15 -15
  96. data/lib/sisimai/reason/mailboxfull.rb +11 -12
  97. data/lib/sisimai/reason/mailererror.rb +18 -20
  98. data/lib/sisimai/reason/mesgtoobig.rb +9 -11
  99. data/lib/sisimai/reason/networkerror.rb +5 -8
  100. data/lib/sisimai/reason/norelaying.rb +8 -11
  101. data/lib/sisimai/reason/notaccept.rb +13 -14
  102. data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
  103. data/lib/sisimai/reason/onhold.rb +6 -9
  104. data/lib/sisimai/reason/policyviolation.rb +14 -12
  105. data/lib/sisimai/reason/rejected.rb +26 -24
  106. data/lib/sisimai/reason/requireptr.rb +69 -0
  107. data/lib/sisimai/reason/securityerror.rb +34 -36
  108. data/lib/sisimai/reason/spamdetected.rb +115 -147
  109. data/lib/sisimai/reason/speeding.rb +49 -0
  110. data/lib/sisimai/reason/suspend.rb +12 -11
  111. data/lib/sisimai/reason/syntaxerror.rb +11 -10
  112. data/lib/sisimai/reason/systemerror.rb +7 -9
  113. data/lib/sisimai/reason/systemfull.rb +7 -8
  114. data/lib/sisimai/reason/toomanyconn.rb +9 -11
  115. data/lib/sisimai/reason/undefined.rb +2 -3
  116. data/lib/sisimai/reason/userunknown.rb +129 -146
  117. data/lib/sisimai/reason/vacation.rb +3 -4
  118. data/lib/sisimai/reason/virusdetected.rb +10 -11
  119. data/lib/sisimai/reason.rb +59 -64
  120. data/lib/sisimai/rfc1894.rb +55 -28
  121. data/lib/sisimai/rfc2045.rb +373 -0
  122. data/lib/sisimai/rfc3464.rb +250 -308
  123. data/lib/sisimai/rfc3834.rb +42 -45
  124. data/lib/sisimai/rfc5322.rb +177 -146
  125. data/lib/sisimai/rfc5965.rb +31 -0
  126. data/lib/sisimai/rhost/cox.rb +5 -6
  127. data/lib/sisimai/rhost/franceptt.rb +6 -8
  128. data/lib/sisimai/rhost/godaddy.rb +12 -12
  129. data/lib/sisimai/rhost/google.rb +530 -0
  130. data/lib/sisimai/rhost/iua.rb +9 -10
  131. data/lib/sisimai/rhost/kddi.rb +6 -8
  132. data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
  133. data/lib/sisimai/rhost/mimecast.rb +51 -42
  134. data/lib/sisimai/rhost/nttdocomo.rb +12 -12
  135. data/lib/sisimai/rhost/spectrum.rb +10 -12
  136. data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
  137. data/lib/sisimai/rhost.rb +23 -31
  138. data/lib/sisimai/smtp/command.rb +59 -0
  139. data/lib/sisimai/smtp/error.rb +4 -7
  140. data/lib/sisimai/smtp/reply.rb +161 -74
  141. data/lib/sisimai/smtp/status.rb +507 -393
  142. data/lib/sisimai/smtp/transcript.rb +124 -0
  143. data/lib/sisimai/smtp.rb +0 -1
  144. data/lib/sisimai/string.rb +74 -5
  145. data/lib/sisimai/time.rb +1 -2
  146. data/lib/sisimai/version.rb +1 -1
  147. data/lib/sisimai.rb +46 -31
  148. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
  149. data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
  150. data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
  151. data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
  152. data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
  153. data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
  154. data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
  155. data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
  156. data/set-of-emails/maildir/bsd/lhost-sendmail-60.eml +85 -0
  157. data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
  158. data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
  159. data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
  160. data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
  161. data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
  162. data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
  163. data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
  164. data/sisimai-java.gemspec +1 -1
  165. data/sisimai.gemspec +1 -1
  166. metadata +48 -26
  167. data/.rspec +0 -2
  168. data/lib/sisimai/data/yaml.rb +0 -33
  169. data/lib/sisimai/data.rb +0 -411
  170. data/lib/sisimai/mime.rb +0 -456
  171. data/lib/sisimai/rhost/googleapps.rb +0 -261
  172. /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  179. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  180. /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::Barracuda parses a bounce email which created by Barracuda.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Barracuda parses a bounce email which created by Barracuda. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Barracuda
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Barracuda.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]text/rfc822-headers|.freeze
9
+ Boundaries = ['Content-Type: text/rfc822-headers'].freeze
11
10
  StartingOf = { message: ['Your message to:'] }.freeze
12
11
 
13
12
  # Parse bounce messages from Barracuda
@@ -16,24 +15,23 @@ module Sisimai::Lhost
16
15
  # @return [Hash] Bounce data list and message/rfc822 part
17
16
  # @return [Nil] it failed to parse or the arguments are missing
18
17
  # @since v4.25.6
19
- def make(mhead, mbody)
18
+ def inquire(mhead, mbody)
20
19
  # Subject: **Message you sent blocked by our bulk email filter**
21
20
  return nil unless mhead['subject'].to_s.end_with?('our bulk email filter**')
22
21
 
23
- require 'sisimai/rfc1894'
24
22
  fieldtable = Sisimai::RFC1894.FIELDTABLE
25
23
  permessage = {} # (Hash) Store values of each Per-Message field
26
24
 
27
25
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
28
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
29
- bodyslices = emailsteak[0].split("\n")
26
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
27
+ bodyslices = emailparts[0].split("\n")
30
28
  readcursor = 0 # (Integer) Points the current cursor position
31
29
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
32
30
  v = nil
33
31
 
34
32
  while e = bodyslices.shift do
35
- # Read error messages and delivery status lines from the head of the email
36
- # to the previous line of the beginning of the original message.
33
+ # Read error messages and delivery status lines from the head of the email to the previous
34
+ # line of the beginning of the original message.
37
35
  if readcursor == 0
38
36
  # Beginning of the bounce message or message/delivery-status part
39
37
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -72,7 +70,7 @@ module Sisimai::Lhost
72
70
  next unless fieldtable[o[0]]
73
71
  v[fieldtable[o[0]]] = o[2]
74
72
 
75
- next unless f == 1
73
+ next unless f
76
74
  permessage[fieldtable[o[0]]] = o[2]
77
75
  end
78
76
  end
@@ -85,7 +83,7 @@ module Sisimai::Lhost
85
83
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].to_s.tr("\n", ' '))
86
84
  end
87
85
 
88
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
86
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
89
87
  end
90
88
  def description; return 'Barracuda: https://www.barracuda.com'; end
91
89
  end
@@ -1,49 +1,49 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Bigfoot parses a bounce email which created by Bigfoot.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Bigfoot parses a bounce email which created by Bigfoot. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Bigfoot
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Bigfoot.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/partial|.freeze
11
- MarkingsOf = { message: %r/\A[ \t]+[-]+[ \t]*Transcript of session follows/ }.freeze
9
+ Boundaries = ['Content-Type: message/partial'].freeze
10
+ MarkingsOf = { message: ' ----- Transcript of session follows -----' }.freeze
12
11
 
13
12
  # Parse bounce messages from Bigfoot
14
13
  # @param [Hash] mhead Message headers of a bounce email
15
14
  # @param [String] mbody Message body of a bounce email
16
15
  # @return [Hash] Bounce data list and message/rfc822 part
17
16
  # @return [Nil] it failed to parse or the arguments are missing
18
- def make(mhead, mbody)
17
+ def inquire(mhead, mbody)
19
18
  # :subject => %r/\AReturned mail: /,
20
19
  match = 0
21
20
  match += 1 if mhead['from'].include?('@bigfoot.com>')
22
21
  match += 1 if mhead['received'].any? { |a| a.include?('.bigfoot.com') }
23
22
  return nil unless match > 0
24
23
 
24
+ require 'sisimai/smtp/command'
25
25
  require 'sisimai/rfc1894'
26
26
  fieldtable = Sisimai::RFC1894.FIELDTABLE
27
27
  permessage = {} # (Hash) Store values of each Per-Message field
28
28
 
29
29
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
30
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
31
- bodyslices = emailsteak[0].split("\n")
30
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
31
+ bodyslices = emailparts[0].split("\n")
32
32
  readslices = ['']
33
33
  readcursor = 0 # (Integer) Points the current cursor position
34
34
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
35
- commandtxt = '' # (String) SMTP Command name begin with the string '>>>'
35
+ thecommand = '' # (String) SMTP Command name begin with the string '>>>'
36
36
  esmtpreply = '' # (String) Reply from remote server on SMTP session
37
37
  v = nil
38
38
 
39
39
  while e = bodyslices.shift do
40
- # Read error messages and delivery status lines from the head of the email
41
- # to the previous line of the beginning of the original message.
40
+ # Read error messages and delivery status lines from the head of the email to the previous
41
+ # line of the beginning of the original message.
42
42
  readslices << e # Save the current line for the next loop
43
43
 
44
44
  if readcursor == 0
45
45
  # Beginning of the bounce message or message/delivery-status part
46
- readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
46
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(MarkingsOf[:message])
47
47
  next
48
48
  end
49
49
  next if (readcursor & Indicators[:deliverystatus]) == 0
@@ -79,7 +79,7 @@ module Sisimai::Lhost
79
79
  next unless fieldtable[o[0]]
80
80
  v[fieldtable[o[0]]] = o[2]
81
81
 
82
- next unless f == 1
82
+ next unless f
83
83
  permessage[fieldtable[o[0]]] = o[2]
84
84
  end
85
85
  else
@@ -88,18 +88,18 @@ module Sisimai::Lhost
88
88
  # ----- Transcript of session follows -----
89
89
  # >>> RCPT TO:<destinaion@example.net>
90
90
  # <<< 553 Invalid recipient destinaion@example.net (Mode: normal)
91
- if cv = e.match(/\A[>]{3}[ ]+([A-Z]{4})[ ]?/)
91
+ if e.start_with?('>>> ')
92
92
  # >>> DATA
93
- commandtxt = cv[1]
94
- elsif cv = e.match(/\A[<]{3}[ ]+(.+)\z/)
93
+ thecommand = Sisimai::SMTP::Command.find(e)
94
+ elsif e.start_with?('<<< ')
95
95
  # <<< Response
96
- esmtpreply = cv[1]
96
+ esmtpreply = e[4, e.size - 4]
97
97
  end
98
98
  else
99
99
  # Continued line of the value of Diagnostic-Code field
100
100
  next unless readslices[-2].start_with?('Diagnostic-Code:')
101
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
102
- v['diagnosis'] << ' ' << cv[1]
101
+ next unless e.start_with?(' ')
102
+ v['diagnosis'] << ' ' << Sisimai::String.sweep(e[1, e.size])
103
103
  readslices[-1] = 'Diagnostic-Code: ' << e
104
104
  end
105
105
  end
@@ -108,16 +108,15 @@ module Sisimai::Lhost
108
108
 
109
109
  dscontents.each do |e|
110
110
  # Set default values if each value is empty.
111
- e['lhost'] ||= permessage['rhost']
112
111
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
113
112
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
114
- e['command'] = commandtxt
113
+ e['command'] = thecommand || ''
115
114
  if e['command'].empty?
116
115
  e['command'] = 'EHLO' unless esmtpreply.empty?
117
116
  end
118
117
  end
119
118
 
120
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
119
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
121
120
  end
122
121
  def description; return 'Bigfoot: http://www.bigfoot.com'; end
123
122
  end
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Biglobe parses a bounce email which created by BIGLOBE.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Biglobe parses a bounce email which created by BIGLOBE. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Biglobe
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Biglobe.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: [' ----- The following addresses had delivery problems -----'],
13
12
  error: [' ----- Non-delivered information -----'],
@@ -22,20 +21,21 @@ module Sisimai::Lhost
22
21
  # @param [String] mbody Message body of a bounce email
23
22
  # @return [Hash] Bounce data list and message/rfc822 part
24
23
  # @return [Nil] it failed to parse or the arguments are missing
25
- def make(mhead, mbody)
26
- return nil unless mhead['from'] =~ /postmaster[@](?:biglobe|inacatv|tmtv|ttv)[.]ne[.]jp/
24
+ def inquire(mhead, mbody)
25
+ return nil unless mhead['from'].include?('postmaster@')
26
+ return nil unless %w[biglobe inacatv tmtv ttv].any? { |a| mhead['from'].include?('@' + a + '.ne.jp') }
27
27
  return nil unless mhead['subject'].start_with?('Returned mail:')
28
28
 
29
29
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
30
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
31
- bodyslices = emailsteak[0].split("\n")
30
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
31
+ bodyslices = emailparts[0].split("\n")
32
32
  readcursor = 0 # (Integer) Points the current cursor position
33
33
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
34
34
  v = nil
35
35
 
36
36
  while e = bodyslices.shift do
37
- # Read error messages and delivery status lines from the head of the email
38
- # to the previous line of the beginning of the original message.
37
+ # Read error messages and delivery status lines from the head of the email to the previous
38
+ # line of the beginning of the original message.
39
39
  if readcursor == 0
40
40
  # Beginning of the bounce message or delivery status part
41
41
  readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
@@ -60,7 +60,7 @@ module Sisimai::Lhost
60
60
  #
61
61
  v = dscontents[-1]
62
62
 
63
- if cv = e.match(/\A([^ ]+[@][^ ]+)\z/)
63
+ if e.include?('@') && e.include?(' ') == false
64
64
  # ----- The following addresses had delivery problems -----
65
65
  # ********@***.biglobe.ne.jp
66
66
  if v['recipient']
@@ -69,12 +69,11 @@ module Sisimai::Lhost
69
69
  v = dscontents[-1]
70
70
  end
71
71
 
72
- r = Sisimai::Address.s3s4(cv[1])
73
- next unless Sisimai::RFC5322.is_emailaddress(r)
74
- v['recipient'] = r
72
+ next unless Sisimai::Address.is_emailaddress(e)
73
+ v['recipient'] = e
75
74
  recipients += 1
76
75
  else
77
- next if e =~ /\A[^\w]/
76
+ next if e.include?('--')
78
77
  v['diagnosis'] ||= ''
79
78
  v['diagnosis'] << e + ' '
80
79
  end
@@ -92,7 +91,7 @@ module Sisimai::Lhost
92
91
  end
93
92
  end
94
93
 
95
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
94
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
96
95
  end
97
96
  def description; return 'BIGLOBE: https://www.biglobe.ne.jp'; end
98
97
  end
@@ -1,14 +1,13 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Courier parses a bounce email which created by Courier
3
- # MTA. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Courier parses a bounce email which created by Courier MTA. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Courier
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Courier.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  # https://www.courier-mta.org/courierdsn.html
10
9
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r<^Content-Type:[ ](?:message/rfc822|text/rfc822-headers)>.freeze
10
+ Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
12
11
  StartingOf = {
13
12
  # courier/module.dsn/dsn*.txt
14
13
  message: ['DELAYS IN DELIVERING YOUR MESSAGE', 'UNDELIVERABLE MAIL'],
@@ -29,32 +28,34 @@ module Sisimai::Lhost
29
28
  # @param [String] mbody Message body of a bounce email
30
29
  # @return [Hash] Bounce data list and message/rfc822 part
31
30
  # @return [Nil] it failed to parse or the arguments are missing
32
- def make(mhead, mbody)
31
+ def inquire(mhead, mbody)
33
32
  match = 0
34
33
  match += 1 if mhead['from'].include?('Courier mail server at ')
35
- match += 1 if mhead['subject'] =~ /(?:NOTICE: mail delivery status[.]|WARNING: delayed mail[.])/
34
+ match += 1 if mhead['subject'].include?('NOTICE: mail delivery status.')
35
+ match += 1 if mhead['subject'].include?('WARNING: delayed mail.')
36
36
  if mhead['message-id']
37
37
  # Message-ID: <courier.4D025E3A.00001792@5jo.example.org>
38
- match += 1 if mhead['message-id'] =~ /\A[<]courier[.][0-9A-F]+[.]/
38
+ match += 1 if mhead['message-id'].start_with?('<courier.')
39
39
  end
40
40
  return nil unless match > 0
41
41
 
42
+ require 'sisimai/smtp/command'
42
43
  require 'sisimai/rfc1894'
43
44
  fieldtable = Sisimai::RFC1894.FIELDTABLE
44
45
  permessage = {} # (Hash) Store values of each Per-Message field
45
46
 
46
47
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
47
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
48
- bodyslices = emailsteak[0].split("\n")
48
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
49
+ bodyslices = emailparts[0].split("\n")
49
50
  readslices = ['']
50
51
  readcursor = 0 # (Integer) Points the current cursor position
51
52
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
52
- commandtxt = '' # (String) SMTP Command name begin with the string '>>>'
53
+ thecommand = '' # (String) SMTP Command name begin with the string '>>>'
53
54
  v = nil
54
55
 
55
56
  while e = bodyslices.shift do
56
- # Read error messages and delivery status lines from the head of the email
57
- # to the previous line of the beginning of the original message.
57
+ # Read error messages and delivery status lines from the head of the email to the previous
58
+ # line of the beginning of the original message.
58
59
  readslices << e # Save the current line for the next loop
59
60
 
60
61
  if readcursor == 0
@@ -97,12 +98,12 @@ module Sisimai::Lhost
97
98
  next unless fieldtable[o[0]]
98
99
  v[fieldtable[o[0]]] = o[2]
99
100
 
100
- next unless f == 1
101
+ next unless f
101
102
  permessage[fieldtable[o[0]]] = o[2]
102
103
  end
103
104
  else
104
105
  # The line does not begin with a DSN field defined in RFC3464
105
- if cv = e.match(/\A[>]{3}[ ]+([A-Z]{4})[ ]?/)
106
+ if e.start_with?('>>> ')
106
107
  # Your message to the following recipients cannot be delivered:
107
108
  #
108
109
  # <kijitora@example.co.jp>:
@@ -110,13 +111,12 @@ module Sisimai::Lhost
110
111
  # >>> RCPT TO:<kijitora@example.co.jp>
111
112
  # <<< 550 5.1.1 <kijitora@example.co.jp>... User Unknown
112
113
  #
113
- next unless commandtxt.empty?
114
- commandtxt = cv[1]
114
+ thecommand = Sisimai::SMTP::Command.find(e)
115
115
  else
116
116
  # Continued line of the value of Diagnostic-Code field
117
117
  next unless readslices[-2].start_with?('Diagnostic-Code:')
118
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
119
- v['diagnosis'] << ' ' << cv[1]
118
+ next unless e.start_with?(' ')
119
+ v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
120
120
  readslices[-1] = 'Diagnostic-Code: ' << e
121
121
  end
122
122
  end
@@ -126,7 +126,7 @@ module Sisimai::Lhost
126
126
  dscontents.each do |e|
127
127
  # Set default values if each value is empty.
128
128
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
129
- e['command'] ||= commandtxt || ''
129
+ e['command'] ||= thecommand || ''
130
130
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
131
131
 
132
132
  MessagesOf.each_key do |r|
@@ -137,7 +137,7 @@ module Sisimai::Lhost
137
137
  end
138
138
  end
139
139
 
140
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
140
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
141
141
  end
142
142
  def description; return 'Courier MTA'; end
143
143
  end
@@ -1,19 +1,19 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Domino parses a bounce email which created by IBM
3
- # Domino Server. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Domino parses a bounce email which created by IBM Domino Server. Methods in the
3
+ # module are called from only Sisimai::Message.
4
4
  module Domino
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Domino.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: ['Your message'] }.freeze
12
11
  MessagesOf = {
13
12
  'userunknown' => [
14
13
  'not listed in Domino Directory',
15
14
  'not listed in public Name & Address Book',
16
- "dans l'annuaire Domino", # TODO: "non répertorié dans l'annuaire Domino",
15
+ "non répertorié dans l'annuaire Domino",
16
+ 'no se encuentra en el Directorio de Domino',
17
17
  'Domino ディレクトリには見つかりません',
18
18
  ],
19
19
  'filtered' => ['Cannot route mail to user'],
@@ -25,7 +25,7 @@ module Sisimai::Lhost
25
25
  # @param [String] mbody Message body of a bounce email
26
26
  # @return [Hash] Bounce data list and message/rfc822 part
27
27
  # @return [Nil] it failed to parse or the arguments are missing
28
- def make(mhead, mbody)
28
+ def inquire(mhead, mbody)
29
29
  return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:')
30
30
 
31
31
  require 'sisimai/rfc1894'
@@ -33,16 +33,16 @@ module Sisimai::Lhost
33
33
  permessage = {} # (Hash) Store values of each Per-Message field
34
34
 
35
35
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
36
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
37
- bodyslices = emailsteak[0].split("\n")
36
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
37
+ bodyslices = emailparts[0].split("\n")
38
38
  readcursor = 0 # (Integer) Points the current cursor position
39
39
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
40
40
  subjecttxt = '' # (String) The value of Subject:
41
41
  v = nil
42
42
 
43
43
  while e = bodyslices.shift do
44
- # Read error messages and delivery status lines from the head of the email
45
- # 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.
46
46
  next if e.empty?
47
47
 
48
48
  if readcursor == 0
@@ -76,10 +76,10 @@ module Sisimai::Lhost
76
76
  v['recipient'] ||= e
77
77
  recipients += 1
78
78
 
79
- elsif cv = e.match(/\A[ ][ ]([^ ]+[@][^ ]+)\z/)
79
+ elsif e.start_with?(' ') && e.include?('@') && e.index(' ', 3).nil?
80
80
  # Continued from the line "was not delivered to:"
81
81
  # kijitora@example.net
82
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
82
+ v['recipient'] = Sisimai::Address.s3s4(e[2, e.size])
83
83
 
84
84
  elsif e.start_with?('because:')
85
85
  # because:
@@ -89,9 +89,9 @@ module Sisimai::Lhost
89
89
  # Error message, continued from the line "because:"
90
90
  v['diagnosis'] = e
91
91
 
92
- elsif cv = e.match(/\A[ ][ ]Subject: (.+)\z/)
92
+ elsif e.start_with?(' Subject: ')
93
93
  # Subject: Nyaa
94
- subjecttxt = cv[1]
94
+ subjecttxt = e[11, e.size]
95
95
 
96
96
  elsif f = Sisimai::RFC1894.match(e)
97
97
  # There are some fields defined in RFC3464, try to match
@@ -107,9 +107,14 @@ module Sisimai::Lhost
107
107
  next unless fieldtable[o[0]]
108
108
  v[fieldtable[o[0]]] = o[2]
109
109
 
110
- next unless f == 1
110
+ next unless f
111
111
  permessage[fieldtable[o[0]]] = o[2]
112
112
  end
113
+ else
114
+ if v['diagnosis'] && e.start_with?("\s", "\t")
115
+ # The line is a continued line of "Diagnostic-Code:" field
116
+ v['diagnosis'] += e.sub(/\A[\s\t]+/, '')
117
+ end
113
118
  end
114
119
  end
115
120
  end
@@ -118,7 +123,6 @@ module Sisimai::Lhost
118
123
  dscontents.each do |e|
119
124
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
120
125
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
121
- e['lhost'] ||= permessage['rhost']
122
126
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
123
127
 
124
128
  MessagesOf.each_key do |r|
@@ -130,11 +134,10 @@ module Sisimai::Lhost
130
134
  end
131
135
  end
132
136
 
133
- # Set the value of subjecttxt as a Subject if there is no original
134
- # message in the bounce mail.
135
- emailsteak[1] << ('Subject: ' << subjecttxt << "\n") unless emailsteak[1] =~ /^Subject: /
137
+ # Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
138
+ emailparts[1] << ('Subject: ' << subjecttxt << "\n") unless emailparts[1].include?("\nSubject:")
136
139
 
137
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
140
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
138
141
  end
139
142
  def description; return 'IBM Domino Server'; end
140
143
  end
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::EinsUndEins parses a bounce email which created by
3
- # 1&1. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::EinsUndEins parses a bounce email which created by 1&1. Methods in the module are
3
+ # called from only Sisimai::Message.
4
4
  module EinsUndEins
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/EinsUndEins.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^---[ ]The[ ]header[ ]of[ ]the[ ]original[ ]message[ ]is[ ]following[.][ ]---|.freeze
9
+ Boundaries = ['--- The header of the original message is following. ---'].freeze
11
10
  StartingOf = {
12
11
  message: ['This message was created automatically by mail delivery software'],
13
12
  error: ['For the following reason:'],
@@ -19,20 +18,20 @@ module Sisimai::Lhost
19
18
  # @param [String] mbody Message body of a bounce email
20
19
  # @return [Hash] Bounce data list and message/rfc822 part
21
20
  # @return [Nil] it failed to parse or the arguments are missing
22
- def make(mhead, mbody)
21
+ def inquire(mhead, mbody)
23
22
  return nil unless mhead['from'].start_with?('"Mail Delivery System"')
24
23
  return nil unless mhead['subject'] == 'Mail delivery failed: returning message to sender'
25
24
 
26
25
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
27
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
28
- bodyslices = emailsteak[0].split("\n")
26
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
27
+ bodyslices = emailparts[0].split("\n")
29
28
  readcursor = 0 # (Integer) Points the current cursor position
30
29
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
31
30
  v = nil
32
31
 
33
32
  while e = bodyslices.shift do
34
- # Read error messages and delivery status lines from the head of the email
35
- # to the previous line of the beginning of the original message.
33
+ # Read error messages and delivery status lines from the head of the email to the previous
34
+ # line of the beginning of the original message.
36
35
 
37
36
  if readcursor == 0
38
37
  # Beginning of the bounce message or delivery status part
@@ -52,14 +51,15 @@ module Sisimai::Lhost
52
51
  # http://postmaster.1and1.com/en/error-messages?ip=%1s
53
52
  v = dscontents[-1]
54
53
 
55
- if cv = e.match(/\A([^ ]+[@][^ ]+?)[:]?\z/)
56
- # general@example.eu
54
+ if cv = e.match(/\A\s*([^ ]+[@][^ ]+?)[:]?\z/)
55
+ # general@example.eu OR
56
+ # the line begin with 4 space characters, end with ":" like " neko@example.eu:"
57
57
  if v['recipient']
58
58
  # There are multiple recipient addresses in the message body.
59
59
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
60
60
  v = dscontents[-1]
61
61
  end
62
- v['recipient'] = cv[1]
62
+ v['recipient'] = Sisimai::Address.s3s4(e)
63
63
  recipients += 1
64
64
 
65
65
  elsif e.start_with?(StartingOf[:error][0])
@@ -80,21 +80,26 @@ module Sisimai::Lhost
80
80
  end
81
81
  return nil unless recipients > 0
82
82
 
83
+ require 'sisimai/smtp/command'
83
84
  dscontents.each do |e|
84
85
  e['diagnosis'] ||= ''
85
86
  e['diagnosis'] = e['alterrors'] if e['diagnosis'].empty?
87
+ e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
86
88
 
87
- if cv = e['diagnosis'].match(/host:[ ]+(.+?)[ ]+.+[ ]+reason:.+/)
89
+ if Sisimai::String.aligned(e['diagnosis'], ['host: ', ' reason:'])
88
90
  # SMTP error from remote server for TEXT command,
89
91
  # host: smtp-in.orange.fr (193.252.22.65)
90
92
  # reason: 550 5.2.0 Mail rejete. Mail rejected. ofr_506 [506]
91
- e['rhost'] = cv[1]
92
- e['command'] = 'DATA' if e['diagnosis'] =~ /for TEXT command/
93
- e['spec'] = 'SMTP' if e['diagnosis'] =~ /SMTP error/
93
+ p1 = e['diagnosis'].index('host: ')
94
+ p2 = e['diagnosis'].index(' reason:')
95
+
96
+ e['rhost'] = Sisimai::String.sweep(e['diagnosis'][p1 + 6, p2 - p1 - 6])
97
+ e['command'] = 'DATA' if e['diagnosis'].include?('for TEXT command')
98
+ e['spec'] = 'SMTP' if e['diagnosis'].include?('SMTP error')
94
99
  e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
95
100
  else
96
101
  # For the following reason:
97
- e['diagnosis'].gsub(/\A#{StartingOf[:error][0]}/, '')
102
+ e['diagnosis'][0, StartingOf[:error][0].size] = ''
98
103
  end
99
104
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
100
105
 
@@ -106,7 +111,7 @@ module Sisimai::Lhost
106
111
  end
107
112
  end
108
113
 
109
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
114
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
110
115
  end
111
116
  def description; return '1&1: https://www.1und1.de'; end
112
117
  end