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,67 +1,65 @@
1
1
  module Sisimai
2
2
  # Sisimai::RFC3834 - RFC3834 auto reply message detector
3
3
  module RFC3834
4
- # Imported from p5-Sisimail/lib/Sisimai/RFC3834.pm
5
4
  class << self
6
5
  # http://tools.ietf.org/html/rfc3834
7
- MarkingsOf = { :boundary => %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/ }
8
- AutoReply1 = {
9
- # http://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml
10
- 'auto-submitted' => %r/\Aauto-(?:generated|replied|notified)/,
11
- 'x-apple-action' => %r/\Avacation\z/,
12
- 'precedence' => %r/\Aauto_reply\z/,
13
- 'subject' => %r/\A(?>
14
- auto:
15
- |auto[ ]response:
16
- |automatic[ ]reply:
17
- |out[ ]of[ ](?:the[ ])*office:
18
- )
19
- /x,
6
+ MarkingsOf = { :boundary => '__SISIMAI_PSEUDO_BOUNDARY__' }
7
+ LowerLabel = %w[from to subject auto-submitted precedence x-apple-action].freeze
8
+ DoNotParse = {
9
+ 'from' => ['root@', 'postmaster@', 'mailer-daemon@'],
10
+ 'to' => ['root@'],
11
+ 'subject' => [
12
+ 'security information for', # sudo(1)
13
+ 'mail failure -', # Exim
14
+ ],
20
15
  }.freeze
21
- Excludings = {
22
- 'subject' => %r/(?:
23
- security[ ]information[ ]for # sudo
24
- |mail[ ]failure[ ][-] # Exim
25
- )
26
- /x,
27
- 'from' => %r/(?:root|postmaster|mailer-daemon)[@]/,
28
- 'to' => %r/root[@]/,
16
+ AutoReply0 = {
17
+ # http://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml
18
+ 'auto-submitted' => ['auto-generated', 'auto-replied', 'auto-notified'],
19
+ 'precedence' => ['auto_reply'],
20
+ 'subject' => ['auto:', 'auto response:', 'automatic reply:', 'out of office:', 'out of the office:'],
21
+ 'x-apple-action' => ['vacation'],
29
22
  }.freeze
30
23
  SubjectSet = %r{\A(?>
31
- (?:.+?)?Re:
32
- |Auto(?:[ ]Response):
33
- |Automatic[ ]reply:
34
- |Out[ ]of[ ]Office:
24
+ (?:.+?)?re:
25
+ |auto(?:[ ]response):
26
+ |automatic[ ]reply:
27
+ |out[ ]of[ ]office:
35
28
  )
36
29
  [ ]*(.+)\z
37
- }xi.freeze
30
+ }x.freeze
38
31
 
39
32
  # Detect auto reply message as RFC3834
40
33
  # @param [Hash] mhead Message headers of a bounce email
41
34
  # @param [String] mbody Message body of a bounce email
42
35
  # @return [Hash] Bounce data list and message/rfc822 part
43
36
  # @return [Nil] it failed to parse or the arguments are missing
44
- def make(mhead, mbody)
37
+ def inquire(mhead, mbody)
45
38
  leave = 0
46
39
  match = 0
40
+ lower = {}
41
+
42
+ LowerLabel.each do |e|
43
+ # Set lower-cased value of each header related to auto-response
44
+ next unless mhead.has_key?(e)
45
+ lower[e] = mhead[e].downcase
46
+ end
47
47
 
48
48
  # DETECT_EXCLUSION_MESSAGE
49
- Excludings.each_key do |e|
49
+ DoNotParse.each_key do |e|
50
50
  # Exclude message from root@
51
- next unless mhead[e]
52
- next unless mhead[e]
53
- next unless mhead[e].downcase =~ Excludings[e]
51
+ next unless lower[e]
52
+ next unless DoNotParse[e].any? { |a| lower[e].include?(a) }
54
53
  leave = 1
55
54
  break
56
55
  end
57
56
  return nil if leave > 0
58
57
 
59
- # DETECT_AUTO_REPLY_MESSAGE
60
- AutoReply1.each_key do |e|
58
+ # DETECT_AUTO_REPLY_MESSAGE0
59
+ AutoReply0.each_key do |e|
61
60
  # RFC3834 Auto-Submitted and other headers
62
- next unless mhead[e]
63
- next unless mhead[e]
64
- next unless mhead[e].downcase =~ AutoReply1[e]
61
+ next unless lower[e]
62
+ next unless AutoReply0[e].any? { |a| lower[e].include?(a) }
65
63
  match += 1
66
64
  break
67
65
  end
@@ -95,16 +93,15 @@ module Sisimai
95
93
  return nil unless recipients > 0
96
94
 
97
95
  if mhead['content-type']
98
- # Get the boundary string and set regular expression for matching with
99
- # the boundary string.
100
- b0 = Sisimai::MIME.boundary(mhead['content-type'], 0) || ''
101
- MarkingsOf[:boundary] = %r/\A\Q#{b0}\E\z/ unless b0.empty?
96
+ # Get the boundary string and set regular expression for matching with the boundary string.
97
+ q = Sisimai::RFC2045.boundary(mhead['content-type'], 0) || ''
98
+ MarkingsOf[:boundary] = q unless q.empty?
102
99
  end
103
100
 
104
101
  # BODY_PARSER: Get vacation message
105
102
  while e = bodyslices.shift do
106
103
  # Read the first 5 lines except a blank line
107
- countuntil += 1 if e =~ MarkingsOf[:boundary]
104
+ countuntil += 1 if e.include?(MarkingsOf[:boundary])
108
105
 
109
106
  if e.empty?
110
107
  # Check a blank line
@@ -113,8 +110,8 @@ module Sisimai
113
110
  next
114
111
  end
115
112
  next unless e.include?(' ')
116
- next if e.start_with?('Content-Type')
117
- next if e.start_with?('Content-Transfer')
113
+ next if e.start_with?('Content-Type')
114
+ next if e.start_with?('Content-Transfer')
118
115
 
119
116
  v['diagnosis'] ||= ''
120
117
  v['diagnosis'] << e + ' '
@@ -127,7 +124,7 @@ module Sisimai
127
124
  v['date'] = mhead['date']
128
125
  v['status'] = ''
129
126
 
130
- if cv = mhead['subject'].match(SubjectSet)
127
+ if cv = lower['subject'].match(SubjectSet)
131
128
  # Get the Subject header from the original message
132
129
  rfc822part = 'Subject: ' << cv[1] + "\n"
133
130
  end
@@ -1,8 +1,8 @@
1
1
  module Sisimai
2
2
  # Sisimai::RFC5322 provide methods for checking email address.
3
3
  module RFC5322
4
- # Imported from p5-Sisimail/lib/Sisimai/RFC5322.pm
5
4
  class << self
5
+ require 'sisimai/string'
6
6
  HeaderTable = {
7
7
  :messageid => %w[message-id],
8
8
  :subject => %w[subject],
@@ -12,46 +12,26 @@ module Sisimai
12
12
  :recipient => %w[to delivered-to forward-path envelope-to x-envelope-to resent-to apparently-to],
13
13
  }.freeze
14
14
 
15
- build_regular_expressions = lambda do
16
- # See http://www.ietf.org/rfc/rfc5322.txt
17
- # or http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html ...
18
- # addr-spec = local-part "@" domain
19
- # local-part = dot-atom / quoted-string / obs-local-part
20
- # domain = dot-atom / domain-literal / obs-domain
21
- # domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
22
- # dcontent = dtext / quoted-pair
23
- # dtext = NO-WS-CTL / ; Non white space controls
24
- # %d33-90 / ; The rest of the US-ASCII
25
- # %d94-126 ; characters not including "[",
26
- # ; "]", or "\"
27
- re = { rfc5322: nil, ignored: nil, domain: nil }
28
- atom = %r([a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)o
29
- quoted_string = %r/"(?:\\[^\r\n]|[^\\"])*"/o
30
- domain_literal = %r/\[(?:\\[\x01-\x09\x0B-\x0c\x0e-\x7f]|[\x21-\x5a\x5e-\x7e])*\]/o
31
- dot_atom = %r/#{atom}(?:[.]#{atom})*/o
32
- local_part = %r/(?:#{dot_atom}|#{quoted_string})/o
33
- domain = %r/(?:#{dot_atom}|#{domain_literal})/o
34
-
35
- re[:rfc5322] = %r/\A#{local_part}[@]#{domain}\z/o
36
- re[:ignored] = %r/\A#{local_part}[.]*[@]#{domain}\z/o
37
- re[:domain] = %r/\A#{domain}\z/o
38
-
39
- return re
40
- end
41
-
42
15
  build_flatten_rfc822header_list = lambda do
43
- # Convert HEADER: structured hash table to flatten hash table for being
44
- # called from Sisimai::Lhost::*
16
+ # Convert HEADER: structured hash table to flatten hash table for being called from Sisimai::Lhost::*
45
17
  fv = {}
46
18
  HeaderTable.each_value do |e|
47
19
  e.each { |ee| fv[ee] = true }
48
20
  end
49
21
  return fv
50
22
  end
51
-
52
- Re = build_regular_expressions.call
53
23
  HeaderIndex = build_flatten_rfc822header_list.call
54
24
 
25
+ def FIELDINDEX
26
+ return %w[
27
+ Resent-Date From Sender Reply-To To Message-ID Subject Return-Path Received Date X-Mailer
28
+ Content-Type Content-Transfer-Encoding Content-Description Content-Disposition
29
+ ]
30
+ # The following fields are not referred in Sisimai
31
+ # Resent-From Resent-Sender Resent-Cc Cc Bcc Resent-Bcc In-Reply-To References
32
+ # Comments Keywords
33
+ end
34
+
55
35
  # Grouped RFC822 headers
56
36
  # @param [Symbol] group RFC822 Header group name
57
37
  # @return [Array,Hash] RFC822 Header list
@@ -67,66 +47,37 @@ module Sisimai
67
47
  return { 'to' => true, 'from' => true, 'subject' => true, 'message-id' => true }
68
48
  end
69
49
 
70
- # Check that the argument is an email address or not
71
- # @param [String] email Email address string
72
- # @return [True,False] true: is an email address
73
- # false: is not an email address
74
- def is_emailaddress(email)
75
- return false unless email.is_a?(::String)
76
- return false if email =~ %r/(?:[\x00-\x1f]|\x1f)/
77
- return false if email.size > 254
78
- return true if email =~ Re[:ignored]
79
- return false
80
- end
81
-
82
- # Check that the argument is mailer-daemon or not
83
- # @param [String] email Email address
84
- # @return [True,False] true: mailer-daemon
85
- # false: Not mailer-daemon
86
- def is_mailerdaemon(email)
87
- return false unless email.is_a?(::String)
88
- regex = %r/(?:
89
- (?:mailer-daemon|postmaster)[@]
90
- |[<(](?:mailer-daemon|postmaster)[)>]
91
- |\A(?:mailer-daemon|postmaster)\z
92
- |[ ]?mailer-daemon[ ]
93
- )
94
- /x.freeze
95
- return true if email.downcase =~ regex
96
- return false
97
- end
98
-
99
50
  # Convert Received headers to a structured data
100
- # @param [String] argvs Received header
51
+ # @param [String] argv1 Received header
101
52
  # @return [Array] Received header as a structured data
102
- def received(argvs)
103
- return [] unless argvs.is_a?(::String)
53
+ def received(argv1)
54
+ return [] unless argv1.is_a?(::String)
104
55
 
105
56
  hosts = []
106
57
  value = { 'from' => '', 'by' => '' }
107
58
 
108
59
  # Received: (qmail 10000 invoked by uid 999); 24 Apr 2013 00:00:00 +0900
109
- return [] if argvs =~ /qmail[ ]+.+invoked[ ]+/
60
+ return [] if argv1.include?('(qmail ') && argv1.include?(' invoked ')
61
+
62
+ p1 = argv1.index('from ') || -1
63
+ p2 = argv1.index('by ') || -1
64
+ p3 = argv1.index(' ', p2 + 3) || -1
110
65
 
111
- if cr = argvs.match(/\Afrom[ ]+(.+)[ ]+by[ ]+([^ ]+)/)
112
- # Received: from localhost (localhost)
113
- # by nijo.example.jp (V8/cf) id s1QB5ma0018057;
66
+ if p1 == 0 && p2 > 1 && p2 < p3
67
+ # Received: from localhost (localhost) by nijo.example.jp (V8/cf) id s1QB5ma0018057;
114
68
  # Wed, 26 Feb 2014 06:05:48 -0500
115
- value['from'] = cr[1]
116
- value['by'] = cr[2]
117
-
118
- elsif cr = argvs.match(/\bby[ ]+([^ ]+)(.+)/)
119
- # Received: by 10.70.22.98 with SMTP id c2mr1838265pdf.3; Fri, 18 Jul 2014
120
- # 00:31:02 -0700 (PDT)
121
- value['from'] = cr[1] + cr[2]
122
- value['by'] = cr[1]
69
+ value['from'] = Sisimai::String.sweep(argv1[p1 + 5, p2 - p1 - 5])
70
+ value['by'] = Sisimai::String.sweep(argv1[p2 + 3, p3 - p2 - 3])
71
+
72
+ elsif p1 != 0 && p2 > -1
73
+ # Received: by 10.70.22.98 with SMTP id c2mr1838265pdf.3; Fri, 18 Jul 2014 00:31:02 -0700 (PDT)
74
+ value['from'] = Sisimai::String.sweep(argv1[p2 + 3, argv1.size])
75
+ value['by'] = Sisimai::String.sweep(argv1[p2 + 3, p3 - p2 - 3])
123
76
  end
124
77
 
125
78
  if value['from'].include?(' ')
126
- # Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
127
- # (authenticated bits=0)
128
- # by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055;
129
- # Wed, 26 Feb 2014 06:05:47 -0500
79
+ # Received: from [10.22.22.222] (smtp.kyoto.ocn.ne.jp [192.0.2.222]) (authenticated bits=0)
80
+ # by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055; Wed, 26 Feb 2014 06:05:47 -0500
130
81
  received = value['from'].split(' ')
131
82
  namelist = []
132
83
  addrlist = []
@@ -135,13 +86,13 @@ module Sisimai
135
86
 
136
87
  while e = received.shift do
137
88
  # Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
138
- if e =~ /\A[\[(]\d+[.]\d+[.]\d+[.]\d+[)\]]\z/
89
+ cv = Sisimai::String.ipv4(e) || []
90
+ if cv.size > 0
139
91
  # [192.0.2.1] or (192.0.2.1)
140
- e = e.delete('[]()')
141
- addrlist << e
92
+ addrlist.append(*cv)
142
93
  else
143
94
  # hostname
144
- e = e.delete('()')
95
+ e = e.delete('()').strip
145
96
  namelist << e
146
97
  end
147
98
  end
@@ -176,31 +127,55 @@ module Sisimai
176
127
  return hosts
177
128
  end
178
129
 
179
- # Split given entire message body into error message lines and the original
180
- # message part only include email headers
181
- # @param [String] mbody Entire message body
182
- # @param [Regexp] regex Regular expression of the message/rfc822 or the
183
- # beginning of the original message part
130
+ # Split given entire message body into error message lines and the original message part only
131
+ # include email headers
132
+ # @param [String] email Entire message body
133
+ # @param [Array] cutby List of strings which is a boundary of the original message part
134
+ # @param [Bool] keeps Flag for keeping strings after "\n\n"
184
135
  # @return [Array] [Error message lines, The original message]
185
- # @since v4.25.5
186
- def fillet(mbody = '', regex)
187
- return nil if mbody.empty?
188
- return nil unless regex
136
+ # @since v5.0.0
137
+ def part(email = '', cutby = [], keeps = false)
138
+ return nil if email.empty?
139
+ return nil if cutby.empty?
140
+
141
+ boundaryor = '' # A boundary string divides the error message part and the original message part
142
+ positionor = nil # A Position of the boundary string
143
+ formerpart = '' # The error message part
144
+ latterpart = '' # The original message part
145
+
146
+ cutby.each do |e|
147
+ # Find a boundary string(2nd argument) from the 1st argument
148
+ positionor = email.index(e); next unless positionor
149
+ boundaryor = e
150
+ break
151
+ end
189
152
 
190
- v = mbody.split(regex, 2)
191
- v[1] ||= ''
153
+ if positionor
154
+ # There is the boundary string in the message body
155
+ formerpart = email[0, positionor]
156
+ latterpart = email[positionor + boundaryor.size + 1, email.size - positionor]
157
+ else
158
+ # Substitute the entire message to the former part when the boundary string is not included
159
+ # the "email"
160
+ formerpart = email
161
+ latterpart = ''
162
+ end
192
163
 
193
- unless v[1].empty?
164
+ if latterpart.size > 0
194
165
  # Remove blank lines, the message body of the original message, and append "\n" at the end
195
166
  # of the original message headers
196
167
  # 1. Remove leading blank lines
197
168
  # 2. Remove text after the first blank line: \n\n
198
169
  # 3. Append "\n" at the end of test block when the last character is not "\n"
199
- v[1].sub!(/\A[\r\n\s]+/, '')
200
- v[1] = v[1][0, v[1].index("\n\n")] if v[1].include?("\n\n")
201
- v[1] << "\n" unless v[1].end_with?("\n")
170
+ latterpart.sub!(/\A[\r\n\s]+/, '')
171
+ if keeps == false
172
+ # Remove text after the first blank line: \n\n when "keeps" is false
173
+ latterpart = latterpart[0, latterpart.index("\n\n")] if latterpart.include?("\n\n")
174
+ end
175
+ latterpart << "\n" unless latterpart.end_with?("\n")
202
176
  end
203
- return v
177
+
178
+ return [formerpart, latterpart]
204
179
  end
205
180
 
206
181
  end
@@ -0,0 +1,31 @@
1
+ module Sisimai
2
+ # Sisimai::RFC5965 - A class for An Extensible Format for Email Feedback Reports
3
+ module RFC5965
4
+ class << self
5
+ # https://datatracker.ietf.org/doc/html/rfc5965
6
+ def FIELDINDEX
7
+ return [
8
+ # Required Fields
9
+ # The following report header fields MUST appear exactly once:
10
+ 'Feedback-Type', 'User-Agent', 'Version',
11
+
12
+ # Optional Fields Appearing Once
13
+ # The following header fields are optional and MUST NOT appear more than once:
14
+ # - "Reporting-MTA" is defined in Sisimai::RFC1894->FIELDINDEX()
15
+ 'Original-Envelope-Id', 'Original-Mail-From', 'Arrival-Date', 'Source-IP', 'Incidents',
16
+
17
+ # Optional Fields Appearing Multiple Times
18
+ # The following set of header fields are optional and may appear any number of times as
19
+ # appropriate:
20
+ 'Authentication-Results', 'Original-Rcpt-To', 'Reported-Domain', 'Reported-URI',
21
+
22
+ # The historic field "Received-Date" SHOULD also be accepted and interpreted identically
23
+ # to "Arrival-Date". However, if both are present, the report is malformed and SHOULD be
24
+ # treated as described in Section 4.
25
+ 'Received-Date',
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -1,11 +1,10 @@
1
1
  module Sisimai
2
2
  module Rhost
3
- # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
4
- # object as an argument of get() method when the value of "destination" of
5
- # the object is "charter.net". This class is called only Sisimai::Data class.
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
+ # of get() method when the value of "destination" of the object is "charter.net". This class is
5
+ # called only Sisimai::Fact class.
6
6
  module Cox
7
7
  class << self
8
- # Imported from p5-Sisimail/lib/Sisimai/Rhost/Cox.pm
9
8
  ErrorCodes = {
10
9
  # https://www.cox.com/residential/support/email-error-codes.html
11
10
  'CXBL' => 'blocked', # The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
@@ -79,11 +78,11 @@ module Sisimai
79
78
  }.freeze
80
79
 
81
80
  # Detect bounce reason from https://cox.com/
82
- # @param [Sisimai::Data] argvs Parsed email object
81
+ # @param [Sisimai::Fact] argvs Parsed email object
83
82
  # @return [String, Nil] The bounce reason at Cox
84
83
  # @since v4.25.8
85
84
  def get(argvs)
86
- statusmesg = argvs.diagnosticcode
85
+ statusmesg = argvs['diagnosticcode']
87
86
  codenumber = 0
88
87
 
89
88
  if cv = statusmesg.match(/AUP#([0-9A-Z]+)/)
@@ -1,12 +1,10 @@
1
1
  module Sisimai
2
2
  module Rhost
3
- # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
4
- # object as an argument of get() method when the value of "rhost" of the object
5
- # is "*.laposte.net" or "*.orange.fr".
6
- # This class is called only Sisimai::Data class.
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
+ # of get() method when the value of "rhost" of the object is "*.laposte.net" or "*.orange.fr".
5
+ # This class is called only Sisimai::Fact class.
7
6
  module FrancePTT
8
7
  class << self
9
- # Imported from p5-Sisimail/lib/Sisimai/Rhost/FrancePTT.pm
10
8
  ErrorCodes = {
11
9
  # 550 5.7.1 Service unavailable; client [X.X.X.X] blocked using Spamhaus
12
10
  # Les emails envoyes vers la messagerie Laposte.net ont ete bloques par nos services.
@@ -133,12 +131,12 @@ module Sisimai
133
131
  }.freeze
134
132
 
135
133
  # Detect bounce reason from Oranage or La Poste
136
- # @param [Sisimai::Data] argvs Parsed email object
134
+ # @param [Sisimai::Fact] argvs Parsed email object
137
135
  # @return [String] The bounce reason for Orange or La Poste
138
136
  def get(argvs)
139
- return argvs.reason unless argvs.reason.empty?
137
+ return argvs['reason'] unless argvs['reason'].empty?
140
138
 
141
- statusmesg = argvs.diagnosticcode
139
+ statusmesg = argvs['diagnosticcode']
142
140
  reasontext = ''
143
141
 
144
142
  if cv = statusmesg.match(/\b(LPN|LPNAAA|OFR|OUK)(_[0-9]{3}|[0-9]{3}[-_][0-9]{3})\b/i)
@@ -1,14 +1,13 @@
1
1
  module Sisimai
2
2
  module Rhost
3
- # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
4
- # object as an argument of get() method when the value of "rhost" of the object
5
- # is "*.secureserver.net". This class is called only Sisimai::Data class.
3
+ # Sisimai::Rhost detects the bounce reason from the content of Sisimai::Fact object as an argument
4
+ # of get() method when the value of "rhost" of the object is "*.secureserver.net". This class is
5
+ # called only Sisimai::Fact class.
6
6
  module GoDaddy
7
7
  class << self
8
- # Imported from p5-Sisimail/lib/Sisimai/Rhost/GoDaddy.pm
9
8
  # https://www.godaddy.com/help/what-does-my-email-bounceback-mean-3568
10
9
  ErrorCodes = {
11
- 'IB103' => 'blocked', # 554 Connection refused. This IP has a poor reputation on Cloudmark Sender Intelligence (CSI). IB103
10
+ 'IB103' => 'badreputation', # 554 Connection refused. This IP has a poor reputation on Cloudmark Sender Intelligence (CSI). IB103
12
11
  'IB104' => 'blocked', # 554 Connection refused. This IP is listed on the Spamhaus Block List (SBL). IB104
13
12
  'IB105' => 'blocked', # 554 Connection refused. This IP is listed on the Exploits Block List (XBL). IB105
14
13
  'IB106' => 'blocked', # 554 Connection refused. This IP is listed on the Policy Block List (PBL). IB106
@@ -39,19 +38,19 @@ module Sisimai
39
38
  }.freeze
40
39
 
41
40
  # Detect bounce reason from GoDaddy
42
- # @param [Sisimai::Data] argvs Parsed email object
41
+ # @param [Sisimai::Fact] argvs Parsed email object
43
42
  # @return [String] The bounce reason for GoDaddy
44
43
  # @see https://www.godaddy.com/help/what-does-my-email-bounceback-mean-3568
45
44
  def get(argvs)
46
- return argvs.reason unless argvs.reason.empty?
45
+ return argvs['reason'] unless argvs['reason'].empty?
47
46
 
48
- statusmesg = argvs.diagnosticcode
47
+ statusmesg = argvs['diagnosticcode']
48
+ positionib = statusmesg.index(' IB') || -1
49
49
  reasontext = ''
50
50
 
51
- if cv = statusmesg.match(/\s(IB\d{3})\b/)
52
- # 192.0.2.22 has sent to too many recipients this hour. IB607 ...
53
- reasontext = ErrorCodes[cv[1]]
54
- else
51
+ # 192.0.2.22 has sent to too many recipients this hour. IB607 ...
52
+ reasontext = ErrorCodes[statusmesg[positionib + 1, 5]] || '' if positionib > 1
53
+ if reasontext.empty?
55
54
  # 553 http://www.spamhaus.org/query/bl?ip=192.0.0.222
56
55
  MessagesOf.each_key do |e|
57
56
  MessagesOf[e].each do |f|
@@ -62,6 +61,7 @@ module Sisimai
62
61
  break unless reasontext.empty?
63
62
  end
64
63
  end
64
+
65
65
  return reasontext
66
66
  end
67
67