sisimai 5.1.0-java → 5.2.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 (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake-test.yml +1 -1
  3. data/ChangeLog.md +102 -0
  4. data/Makefile +4 -2
  5. data/README-JA.md +23 -16
  6. data/README.md +22 -15
  7. data/lib/sisimai/arf.rb +121 -210
  8. data/lib/sisimai/fact.rb +208 -158
  9. data/lib/sisimai/lda.rb +98 -0
  10. data/lib/sisimai/lhost/activehunter.rb +1 -1
  11. data/lib/sisimai/lhost/amazonses.rb +185 -301
  12. data/lib/sisimai/lhost/apachejames.rb +48 -51
  13. data/lib/sisimai/lhost/biglobe.rb +1 -2
  14. data/lib/sisimai/lhost/courier.rb +10 -8
  15. data/lib/sisimai/lhost/domino.rb +25 -25
  16. data/lib/sisimai/lhost/dragonfly.rb +3 -4
  17. data/lib/sisimai/lhost/einsundeins.rb +3 -4
  18. data/lib/sisimai/lhost/exchange2003.rb +6 -8
  19. data/lib/sisimai/lhost/exchange2007.rb +111 -101
  20. data/lib/sisimai/lhost/exim.rb +232 -242
  21. data/lib/sisimai/lhost/ezweb.rb +43 -51
  22. data/lib/sisimai/lhost/fml.rb +2 -3
  23. data/lib/sisimai/lhost/gmail.rb +32 -28
  24. data/lib/sisimai/lhost/gmx.rb +4 -16
  25. data/lib/sisimai/lhost/googlegroups.rb +9 -8
  26. data/lib/sisimai/lhost/googleworkspace.rb +94 -0
  27. data/lib/sisimai/lhost/imailserver.rb +7 -16
  28. data/lib/sisimai/lhost/interscanmss.rb +1 -1
  29. data/lib/sisimai/lhost/kddi.rb +3 -4
  30. data/lib/sisimai/lhost/mailfoundry.rb +2 -5
  31. data/lib/sisimai/lhost/mailmarshalsmtp.rb +1 -2
  32. data/lib/sisimai/lhost/messagingserver.rb +14 -13
  33. data/lib/sisimai/lhost/mfilter.rb +4 -3
  34. data/lib/sisimai/lhost/notes.rb +2 -4
  35. data/lib/sisimai/lhost/opensmtpd.rb +2 -2
  36. data/lib/sisimai/lhost/postfix.rb +25 -27
  37. data/lib/sisimai/lhost/qmail.rb +130 -106
  38. data/lib/sisimai/lhost/sendmail.rb +19 -18
  39. data/lib/sisimai/lhost/v5sendmail.rb +88 -60
  40. data/lib/sisimai/lhost/verizon.rb +2 -2
  41. data/lib/sisimai/lhost/x1.rb +1 -1
  42. data/lib/sisimai/lhost/x2.rb +1 -2
  43. data/lib/sisimai/lhost/x3.rb +2 -2
  44. data/lib/sisimai/lhost/x6.rb +1 -1
  45. data/lib/sisimai/lhost/zoho.rb +2 -2
  46. data/lib/sisimai/lhost.rb +18 -21
  47. data/lib/sisimai/message.rb +93 -146
  48. data/lib/sisimai/order.rb +21 -77
  49. data/lib/sisimai/reason/authfailure.rb +1 -4
  50. data/lib/sisimai/reason/badreputation.rb +2 -2
  51. data/lib/sisimai/reason/blocked.rb +7 -10
  52. data/lib/sisimai/reason/contenterror.rb +7 -1
  53. data/lib/sisimai/reason/exceedlimit.rb +1 -4
  54. data/lib/sisimai/reason/failedstarttls.rb +42 -0
  55. data/lib/sisimai/reason/filtered.rb +5 -4
  56. data/lib/sisimai/reason/hasmoved.rb +1 -2
  57. data/lib/sisimai/reason/hostunknown.rb +3 -3
  58. data/lib/sisimai/reason/mailboxfull.rb +2 -4
  59. data/lib/sisimai/reason/mailererror.rb +1 -2
  60. data/lib/sisimai/reason/mesgtoobig.rb +2 -4
  61. data/lib/sisimai/reason/norelaying.rb +2 -3
  62. data/lib/sisimai/reason/notaccept.rb +2 -3
  63. data/lib/sisimai/reason/notcompliantrfc.rb +10 -4
  64. data/lib/sisimai/reason/rejected.rb +1 -1
  65. data/lib/sisimai/reason/requireptr.rb +2 -2
  66. data/lib/sisimai/reason/securityerror.rb +1 -3
  67. data/lib/sisimai/reason/spamdetected.rb +6 -8
  68. data/lib/sisimai/reason/speeding.rb +1 -2
  69. data/lib/sisimai/reason/suppressed.rb +36 -0
  70. data/lib/sisimai/reason/suspend.rb +1 -3
  71. data/lib/sisimai/reason/systemerror.rb +5 -0
  72. data/lib/sisimai/reason/toomanyconn.rb +1 -2
  73. data/lib/sisimai/reason/userunknown.rb +1 -1
  74. data/lib/sisimai/reason/virusdetected.rb +5 -6
  75. data/lib/sisimai/reason.rb +77 -73
  76. data/lib/sisimai/rfc1123.rb +152 -0
  77. data/lib/sisimai/rfc1894.rb +102 -62
  78. data/lib/sisimai/rfc2045.rb +2 -1
  79. data/lib/sisimai/rfc3464/thirdparty.rb +102 -0
  80. data/lib/sisimai/rfc3464.rb +222 -343
  81. data/lib/sisimai/rfc3834.rb +1 -1
  82. data/lib/sisimai/rfc5322.rb +7 -17
  83. data/lib/sisimai/rfc791.rb +69 -0
  84. data/lib/sisimai/rhost/aol.rb +36 -0
  85. data/lib/sisimai/rhost/apple.rb +5 -2
  86. data/lib/sisimai/rhost/cox.rb +3 -2
  87. data/lib/sisimai/rhost/facebook.rb +100 -0
  88. data/lib/sisimai/rhost/franceptt.rb +3 -2
  89. data/lib/sisimai/rhost/godaddy.rb +3 -2
  90. data/lib/sisimai/rhost/google.rb +19 -17
  91. data/lib/sisimai/rhost/gsuite.rb +42 -0
  92. data/lib/sisimai/rhost/iua.rb +3 -3
  93. data/lib/sisimai/rhost/kddi.rb +3 -2
  94. data/lib/sisimai/rhost/messagelabs.rb +37 -0
  95. data/lib/sisimai/rhost/microsoft.rb +56 -49
  96. data/lib/sisimai/rhost/mimecast.rb +29 -27
  97. data/lib/sisimai/rhost/nttdocomo.rb +4 -3
  98. data/lib/sisimai/rhost/outlook.rb +36 -0
  99. data/lib/sisimai/rhost/spectrum.rb +3 -2
  100. data/lib/sisimai/rhost/tencent.rb +3 -2
  101. data/lib/sisimai/rhost/yahooinc.rb +4 -3
  102. data/lib/sisimai/rhost.rb +69 -39
  103. data/lib/sisimai/smtp/command.rb +31 -21
  104. data/lib/sisimai/smtp/failure.rb +103 -0
  105. data/lib/sisimai/smtp/reply.rb +29 -25
  106. data/lib/sisimai/smtp/status.rb +36 -19
  107. data/lib/sisimai/smtp/transcript.rb +15 -15
  108. data/lib/sisimai/string.rb +0 -46
  109. data/lib/sisimai/version.rb +1 -1
  110. data/set-of-emails/maildir/bsd/lhost-postfix-30.eml +81 -81
  111. data/set-of-emails/maildir/bsd/{lhost-aol-03.eml → rhost-aol-03.eml} +1264 -1264
  112. data/set-of-emails/maildir/bsd/{lhost-aol-04.eml → rhost-aol-04.eml} +1260 -1260
  113. data/set-of-emails/maildir/bsd/{lhost-aol-05.eml → rhost-aol-05.eml} +105 -105
  114. data/set-of-emails/maildir/bsd/{lhost-aol-06.eml → rhost-aol-06.eml} +105 -105
  115. data/set-of-emails/maildir/bsd/rhost-gsuite-01.eml +189 -0
  116. data/set-of-emails/maildir/bsd/rhost-gsuite-02.eml +180 -0
  117. data/set-of-emails/maildir/bsd/rhost-gsuite-03.eml +251 -0
  118. data/set-of-emails/maildir/bsd/rhost-gsuite-04.eml +211 -0
  119. data/set-of-emails/maildir/bsd/rhost-gsuite-05.eml +226 -0
  120. data/set-of-emails/maildir/bsd/rhost-gsuite-06.eml +257 -0
  121. data/set-of-emails/maildir/bsd/rhost-gsuite-07.eml +289 -0
  122. data/set-of-emails/maildir/bsd/rhost-gsuite-08.eml +231 -0
  123. data/set-of-emails/maildir/bsd/rhost-gsuite-09.eml +231 -0
  124. data/set-of-emails/maildir/bsd/rhost-gsuite-10.eml +254 -0
  125. data/set-of-emails/maildir/bsd/rhost-gsuite-11.eml +228 -0
  126. data/set-of-emails/maildir/bsd/rhost-gsuite-12.eml +271 -0
  127. data/set-of-emails/maildir/bsd/rhost-gsuite-13.eml +261 -0
  128. data/set-of-emails/maildir/bsd/rhost-gsuite-14.eml +273 -0
  129. data/set-of-emails/maildir/bsd/rhost-gsuite-15.eml +229 -0
  130. data/set-of-emails/maildir/bsd/{lhost-messagelabs-01.eml → rhost-messagelabs-01.eml} +93 -93
  131. data/set-of-emails/maildir/bsd/rhost-outlook-01.eml +72 -0
  132. data/set-of-emails/maildir/bsd/rhost-outlook-02.eml +72 -0
  133. data/set-of-emails/maildir/bsd/rhost-outlook-03.eml +72 -0
  134. data/set-of-emails/maildir/bsd/rhost-outlook-04.eml +79 -0
  135. data/set-of-emails/maildir/bsd/rhost-outlook-06.eml +75 -0
  136. data/set-of-emails/maildir/bsd/rhost-outlook-07.eml +70 -0
  137. data/set-of-emails/maildir/bsd/rhost-outlook-08.eml +70 -0
  138. data/set-of-emails/maildir/bsd/rhost-outlook-09.eml +56 -0
  139. data/set-of-emails/maildir/tmp/arf-22.eml +49 -0
  140. data/set-of-emails/maildir/tmp/arf-23.eml +49 -0
  141. data/set-of-emails/maildir/tmp/arf-24.eml +50 -0
  142. data/set-of-emails/maildir/tmp/lhost-exim-07.eml +28 -0
  143. metadata +73 -56
  144. data/lib/sisimai/lhost/amavis.rb +0 -163
  145. data/lib/sisimai/lhost/amazonworkmail.rb +0 -127
  146. data/lib/sisimai/lhost/aol.rb +0 -125
  147. data/lib/sisimai/lhost/barracuda.rb +0 -92
  148. data/lib/sisimai/lhost/bigfoot.rb +0 -125
  149. data/lib/sisimai/lhost/facebook.rb +0 -188
  150. data/lib/sisimai/lhost/gsuite.rb +0 -194
  151. data/lib/sisimai/lhost/mailru.rb +0 -214
  152. data/lib/sisimai/lhost/mcafee.rb +0 -109
  153. data/lib/sisimai/lhost/messagelabs.rb +0 -120
  154. data/lib/sisimai/lhost/mxlogic.rb +0 -198
  155. data/lib/sisimai/lhost/office365.rb +0 -252
  156. data/lib/sisimai/lhost/outlook.rb +0 -129
  157. data/lib/sisimai/lhost/powermta.rb +0 -118
  158. data/lib/sisimai/lhost/receivingses.rb +0 -126
  159. data/lib/sisimai/lhost/sendgrid.rb +0 -150
  160. data/lib/sisimai/lhost/surfcontrol.rb +0 -105
  161. data/lib/sisimai/lhost/x4.rb +0 -269
  162. data/lib/sisimai/lhost/x5.rb +0 -112
  163. data/lib/sisimai/lhost/yahoo.rb +0 -102
  164. data/lib/sisimai/lhost/yandex.rb +0 -118
  165. data/lib/sisimai/mda.rb +0 -121
  166. data/lib/sisimai/smtp/error.rb +0 -119
  167. /data/set-of-emails/maildir/bsd/{lhost-googlegroups-15.eml → lhost-googleworkspace-01.eml} +0 -0
  168. /data/set-of-emails/maildir/bsd/{lhost-x4-08.eml → lhost-x2-06.eml} +0 -0
  169. /data/set-of-emails/maildir/bsd/{lhost-gsuite-01.eml → rfc3464-51.eml} +0 -0
  170. /data/set-of-emails/maildir/bsd/{lhost-gsuite-03.eml → rfc3464-52.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{lhost-gsuite-04.eml → rfc3464-53.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{lhost-gsuite-05.eml → rfc3464-54.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{lhost-gsuite-06.eml → rfc3464-55.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{lhost-gsuite-07.eml → rfc3464-56.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{lhost-gsuite-08.eml → rfc3464-57.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{lhost-gsuite-09.eml → rfc3464-58.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{lhost-gsuite-10.eml → rfc3464-59.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{lhost-gsuite-11.eml → rfc3464-60.eml} +0 -0
  179. /data/set-of-emails/maildir/bsd/{lhost-gsuite-12.eml → rfc3464-61.eml} +0 -0
  180. /data/set-of-emails/maildir/bsd/{lhost-gsuite-13.eml → rfc3464-62.eml} +0 -0
  181. /data/set-of-emails/maildir/bsd/{lhost-gsuite-14.eml → rfc3464-63.eml} +0 -0
  182. /data/set-of-emails/maildir/bsd/{lhost-gsuite-15.eml → rfc3464-64.eml} +0 -0
  183. /data/set-of-emails/maildir/bsd/{lhost-gsuite-02.eml → rfc3464-65.eml} +0 -0
  184. /data/set-of-emails/maildir/bsd/{lhost-aol-01.eml → rhost-aol-01.eml} +0 -0
  185. /data/set-of-emails/maildir/bsd/{lhost-aol-02.eml → rhost-aol-02.eml} +0 -0
  186. /data/set-of-emails/maildir/bsd/{lhost-facebook-03.eml → rhost-facebook-03.eml} +0 -0
  187. /data/set-of-emails/maildir/bsd/{lhost-facebook-04.eml → rhost-facebook-04.eml} +0 -0
  188. /data/set-of-emails/maildir/bsd/{lhost-messagelabs-02.eml → rhost-messagelabs-02.eml} +0 -0
  189. /data/set-of-emails/maildir/bsd/{lhost-messagelabs-03.eml → rhost-messagelabs-03.eml} +0 -0
  190. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-37.eml +0 -0
  191. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-38.eml +0 -0
  192. /data/set-of-emails/maildir/{bsd → tmp}/rfc3464-39.eml +0 -0
@@ -0,0 +1,103 @@
1
+ module Sisimai
2
+ module SMTP
3
+ # Sisimai::SMTP::Failure is utilities for checking SMTP Errors from error message text.
4
+ module Failure
5
+ class << self
6
+ require 'sisimai/smtp/reply'
7
+ require 'sisimai/smtp/status'
8
+
9
+ # Returns true if the given string indicates a permanent error
10
+ # @param [String] argv1 String including SMTP Status code
11
+ # @return [Boolean] true: Permanet error
12
+ # false: Is not a permanent error
13
+ # @since v4.17.3
14
+ def is_permanent(argv1 = '')
15
+ return false unless argv1
16
+ return false unless argv1.size > 0
17
+
18
+ statuscode = Sisimai::SMTP::Status.find(argv1)
19
+ statuscode = Sisimai::SMTP::Reply.find(argv1) if statuscode.empty?
20
+ return true if statuscode[0, 1] == "5"
21
+ return true if argv1.downcase.include?(' permanent ')
22
+ return false
23
+ end
24
+
25
+ # Returns true if the given string indicates a temporary error
26
+ # @param [String] argv1 String including SMTP Status code
27
+ # @return [Boolean] true: Temporary error
28
+ # false: is not a temporary error
29
+ # @since v5.2.0
30
+ def is_temporary(argv1 = '')
31
+ return false unless argv1
32
+ return false unless argv1.size > 0
33
+
34
+ statuscode = Sisimai::SMTP::Status.find(argv1);
35
+ statuscode = Sisimai::SMTP::Reply.find(argv1) if statuscode.empty?
36
+ issuedcode = argv1.downcase
37
+
38
+ return true if statuscode[0, 1] == "4"
39
+ return true if issuedcode.include?(' temporar')
40
+ return true if issuedcode.include?(' persistent')
41
+ return false
42
+ end
43
+
44
+ # Checks the reason sisimai detected is a hard bounce or not
45
+ # @param [String] argv1 Detected bounce reason
46
+ # @param [String] argv2 String including SMTP Status code
47
+ # @return [Boolean] true: is a hard bounce
48
+ def is_hardbounce(argv1 = '', argv2 = '')
49
+ return false unless argv1
50
+ return false unless argv1.size > 0
51
+
52
+ return false if argv1 == "undefined" || argv1 == "onhold"
53
+ return false if argv1 == "delivered" || argv1 == "feedback" || argv1 == "vacation"
54
+ return true if argv1 == "hasmoved" || argv1 == "userunknown" || argv1 == "hostunknown"
55
+ return false if argv1 != "notaccept"
56
+
57
+ # NotAccept: 5xx => hard bounce, 4xx => soft bounce
58
+ hardbounce = false
59
+ if argv2.size > 0
60
+ # Check the 2nd argument(a status code or a reply code)
61
+ cv = Sisimai::SMTP::Status.find(argv2, "")
62
+ cv = Sisimai::SMTP::Reply.find(argv2, "") if cv.empty?
63
+
64
+ # The SMTP status code or the SMTP reply code starts with "5"
65
+ # Deal as a hard bounce when the error message does not indicate a temporary error
66
+ hardbounce = true if cv[0, 1] == "5" || Sisimai::SMTP::Failure.is_temporary(argv2) == false
67
+ else
68
+ # Deal "NotAccept" as a hard bounce when the 2nd argument is empty
69
+ hardbounce = true
70
+ end
71
+ return hardbounce
72
+ end
73
+
74
+ # Checks the reason sisimai detected is a soft bounce or not
75
+ # @param [String] argv1 Detected bounce reason
76
+ # @param [String] argv2 String including SMTP Status code
77
+ # @return [Boolean] true: is a soft bounce
78
+ def is_softbounce(argv1 = '', argv2 = '')
79
+ return false unless argv1
80
+ return false unless argv1.size > 0
81
+
82
+ return false if argv1 == "delivered" || argv1 == "feedback" || argv1 == "vacation"
83
+ return false if argv1 == "hasmoved" || argv1 == "userunknown" || argv1 == "hostunknown"
84
+ return true if argv1 == "undefined" || argv1 == "onhold"
85
+ return true if argv1 != "notaccept"
86
+
87
+ # NotAccept: 5xx => hard bounce, 4xx => soft bounce
88
+ softbounce = false
89
+ if argv2.size > 0
90
+ # Check the 2nd argument(a status code or a reply code)
91
+ cv = Sisimai::SMTP::Status.find(argv2, "")
92
+ cv = Sisimai::SMTP::Reply.find(argv2, "") if cv.empty?
93
+
94
+ # The SMTP status code or the SMTP reply code starts with "4"
95
+ softbounce = true if cv[0, 1] == "4"
96
+ end
97
+ return softbounce
98
+ end
99
+
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,4 +1,5 @@
1
1
  # http://www.ietf.org/rfc/rfc5321.txt
2
+ # -------------------------------------------------------------------------------------------------
2
3
  # 4.2.1. Reply Code Severities and Theory
3
4
  #
4
5
  # There are four values for the first digit of the reply code:
@@ -103,32 +104,32 @@ module Sisimai
103
104
  # 554 Transaction failed (Or, in the case of a connection-opening response, "No SMTP service here")
104
105
  # 555 MAIL FROM/RCPT TO parameters not recognized or not implemented
105
106
  # 556 Domain does not accept mail (See RFC7504)
107
+ # 557 draft-moore-email-addrquery-01
106
108
  '550', '552', '553', '551', '521', '525', '502', '520', '523', '524', '530', '533', '534',
107
- '535', '538', '551', '555', '556', '554', '500', '501', '502', '503', '504',
109
+ '535', '538', '551', '555', '556', '554', '557', '500', '501', '502', '503', '504',
108
110
  ].freeze
109
111
  CodeOfSMTP = { '2' => ReplyCode2, '4' => ReplyCode4, '5' => ReplyCode5 }.freeze
110
112
 
111
113
  # Check whether a reply code is a valid code or not
112
114
  # @param [String] argv1 Reply Code(DSN)
113
- # @return [Boolean] 0 = Invalid reply code, 1 = Valid reply code
115
+ # @return [Boolean] false = Invalid reply code, true = Valid reply code
114
116
  # @see code
115
117
  # @since v5.0.0
116
118
  def test(argv1 = '')
117
- return nil if argv1.empty?
119
+ return false if argv1.empty?
118
120
 
119
121
  reply = argv1.to_i
120
122
  first = (reply / 100).to_i
121
123
 
122
- return false if reply < 200
123
- return false if reply > 599
124
+ return false if reply < 211
125
+ return false if reply > 557
124
126
  return false if reply % 100 > 59
125
127
 
126
128
  if first == 2
127
129
  # 2yz
128
- return true if reply == 235
129
- return false if reply < 211
130
- return false if reply > 252
131
- return false if reply > 221 && reply < 250
130
+ return true if reply == 235 # 235 is a valid code for AUTH (RFC4954)
131
+ return false if reply > 253 # The maximum code of 2xy is 253 (RFC5248)
132
+ return false if reply > 221 && reply < 250 # There is no reply code between 221 and 250
132
133
  return true
133
134
  end
134
135
 
@@ -147,34 +148,37 @@ module Sisimai
147
148
  # @return [String] SMTP Reply Code
148
149
  # [Nil] The first argument did not include SMTP Reply Code value
149
150
  def find(argv1 = '', argv2 = '0')
150
- return nil if argv1.to_s.size < 3
151
- return nil if argv1.upcase.include?('X-UNIX')
151
+ return "" if argv1.to_s.size < 3
152
+ return "" if argv1.upcase.include?('X-UNIX')
152
153
 
154
+ esmtperror = ' ' + argv1 + ' '
155
+ esmtpreply = ''
153
156
  statuscode = argv2[0, 1]
154
157
  replycodes = if statuscode == '5' || statuscode == '4' || statuscode == '2'
155
158
  CodeOfSMTP[statuscode]
156
159
  else
157
160
  [*CodeOfSMTP['5'], *CodeOfSMTP['4'], *CodeOfSMTP['2']]
158
161
  end
159
- esmtperror = ' ' + argv1 + ' '
160
- esmtpreply = '' # SMTP Reply Code
161
- replyindex = 0 # A position of SMTP reply code found by the index()
162
- formerchar = 0 # a character that is one character before the SMTP reply code
163
- latterchar = 0 # a character that is one character after the SMTP reply code
164
162
 
165
163
  replycodes.each do |e|
166
164
  # Try to find an SMTP Reply Code from the given string
167
- replyindex = esmtperror.index(e); next unless replyindex
168
- formerchar = esmtperror[replyindex - 1, 1].ord || 0
169
- latterchar = esmtperror[replyindex + 3, 1].ord || 0
165
+ appearance = esmtperror.index(e); next if appearance.nil?
166
+ startingat = 1
167
+ mesglength = esmtperror.size
170
168
 
171
- next if formerchar > 45 && formerchar < 58
172
- next if latterchar > 45 && latterchar < 58
173
- esmtpreply = e
174
- break
175
- end
169
+ while startingat + 3 < mesglength
170
+ # Find all the reply code in the error message
171
+ replyindex = esmtperror.index(e, startingat); break if replyindex.nil?
172
+ formerchar = esmtperror[replyindex - 1, 1].ord || 0
173
+ latterchar = esmtperror[replyindex + 3, 1].ord || 0
176
174
 
177
- return nil if esmtpreply.empty?
175
+ if formerchar > 45 && formerchar < 58 then startingat += 3; next; end
176
+ if latterchar > 45 && latterchar < 58 then startingat += 3; next; end
177
+ esmtpreply = e
178
+ break
179
+ end
180
+ break if esmtpreply != ""
181
+ end
178
182
  return esmtpreply
179
183
  end
180
184
 
@@ -479,6 +479,8 @@ module Sisimai
479
479
  # reason from D.S.N. value, and getting D.S.N. from the text including D.S.N.
480
480
  module Status
481
481
  class << self
482
+ require "sisimai/rfc791"
483
+
482
484
  CodePatterns = [
483
485
  %r/[ ]?[(][#]([45][.]\d[.]\d+)[)]?[ ]?/, # #5.5.1
484
486
  %r/\b\d{3}[- ][#]?([45][.]\d[.]\d+)\b/, # 550-5.1.1 OR 550 5.5.1
@@ -492,7 +494,7 @@ module Sisimai
492
494
  '4.1.7' => 'rejected', # Bad sender's mailbox address syntax
493
495
  '4.1.8' => 'rejected', # Bad sender's system address
494
496
  '4.1.9' => 'systemerror', # Message relayed to non-compliant mailer
495
- '4.2.1' => 'suspend', # Mailbox disabled, not accepting messages
497
+ '4.2.1' => 'blocked', # Mailbox disabled, not accepting messages
496
498
  '4.2.2' => 'mailboxfull', # Mailbox full
497
499
  '4.2.3' => 'exceedlimit', # Message length exceeds administrative limit
498
500
  '4.2.4' => 'filtered', # Mailing list expansion problem
@@ -595,47 +597,53 @@ module Sisimai
595
597
  '5.7.27' => 'notaccept', # MX resource record of a destination host is Null MX: RFC7505
596
598
  '5.7.28' => 'spamdetected', # The message appears to be part of a mail flood of similar abusive messages.
597
599
  '5.7.29' => 'authfailure', # This status code may be returned when a message fails ARC validation.
598
- '5.7.30' => 'securityerror', # REQUIRETLS support required
600
+ '5.7.30' => 'failedstarttls', # REQUIRETLS support required
599
601
  }.freeze
600
602
 
601
603
  InternalCode = {
602
604
  :temporary => {
603
- 'authfailure' => '4.0.972',
605
+ 'authfailure' => '4.0.926',
604
606
  'badreputation' => '4.0.975',
605
607
  'blocked' => '4.0.971',
606
608
  'contenterror' => '4.0.960',
607
- # 'exceedlimit' => '4.0.923',
609
+ 'exceedlimit' => '4.0.923',
608
610
  'expired' => '4.0.947',
611
+ 'failedstarttls' => '4.0.976',
609
612
  'filtered' => '4.0.924',
610
613
  # 'hasmoved' => '4.0.916',
611
614
  # 'hostunknown' => '4.0.912',
612
615
  'mailboxfull' => '4.0.922',
613
- # 'mailererror' => '4.0.939',
614
- # 'mesgtoobig' => '4.0.934',
616
+ 'mailererror' => '4.0.939',
617
+ 'mesgtoobig' => '4.0.934',
615
618
  'networkerror' => '4.0.944',
616
- # 'norelaying' => '4.0.909',
619
+ 'norelaying' => '4.0.909',
617
620
  'notaccept' => '4.0.932',
618
621
  'notcompliantrfc' => '4.0.974',
619
622
  'onhold' => '4.0.901',
623
+ 'policyviolaton' => '4.0.972',
620
624
  'rejected' => '4.0.918',
621
625
  'requireptr' => '4.0.973',
622
626
  'securityerror' => '4.0.970',
623
627
  'spamdetected' => '4.0.980',
624
628
  'speeding' => '4.0.946',
625
- # 'suspend' => '4.0.921',
629
+ 'suppressed' => '4.0.903',
630
+ 'suspend' => '4.0.921',
626
631
  'systemerror' => '4.0.930',
627
632
  'systemfull' => '4.0.931',
633
+ 'syntaxerror' => '4.0.902',
628
634
  'toomanyconn' => '4.0.945',
629
635
  # 'userunknown' => '4.0.911',
630
636
  'undefined' => '4.0.900',
637
+ 'virusdetected' => '4.0.981',
631
638
  },
632
639
  :permanent => {
633
- 'authfailure' => '5.0.972',
640
+ 'authfailure' => '5.0.926',
634
641
  'badreputation' => '5.0.975',
635
642
  'blocked' => '5.0.971',
636
643
  'contenterror' => '5.0.960',
637
644
  'exceedlimit' => '5.0.923',
638
645
  'expired' => '5.0.947',
646
+ 'failedstarttls' => '5.0.976',
639
647
  'filtered' => '5.0.910',
640
648
  'hasmoved' => '5.0.916',
641
649
  'hostunknown' => '5.0.912',
@@ -653,6 +661,7 @@ module Sisimai
653
661
  'securityerror' => '5.0.970',
654
662
  'spamdetected' => '5.0.980',
655
663
  'speeding' => '5.0.946',
664
+ 'suppressed' => '5.0.903',
656
665
  'suspend' => '5.0.921',
657
666
  'systemerror' => '5.0.930',
658
667
  'systemfull' => '5.0.931',
@@ -660,7 +669,7 @@ module Sisimai
660
669
  'toomanyconn' => '5.0.945',
661
670
  'userunknown' => '5.0.911',
662
671
  'undefined' => '5.0.900',
663
- 'virusdetected' => '5.0.971',
672
+ 'virusdetected' => '5.0.981',
664
673
  },
665
674
  }.freeze
666
675
 
@@ -696,7 +705,7 @@ module Sisimai
696
705
  # @see code
697
706
  # @since v5.0.0
698
707
  def test(argv1 = '')
699
- return nil if argv1.to_s.empty?
708
+ return false if argv1.to_s.empty?
700
709
  return false if argv1.size < 5
701
710
  return false if argv1.size > 7
702
711
 
@@ -717,8 +726,8 @@ module Sisimai
717
726
  # @param [String] argv2 An SMTP Reply Code or 2 or 4 or 5
718
727
  # @return [String, Nil] An SMTP Status Code
719
728
  def find(argv1 = nil, argv2 = '0')
720
- return nil if argv1.to_s.empty?
721
- return nil if argv1.size < 7
729
+ return "" if argv1.to_s.empty?
730
+ return "" if argv1.size < 7
722
731
 
723
732
  givenclass = argv2[0, 1]
724
733
  eestatuses = if givenclass == '2' || givenclass == '4' || givenclass == '5'
@@ -729,7 +738,7 @@ module Sisimai
729
738
  esmtperror = ' ' + argv1 + ' '
730
739
  lookingfor = []
731
740
 
732
- Sisimai::String.ipv4(esmtperror).each do |e|
741
+ Sisimai::RFC791.find(esmtperror).each do |e|
733
742
  # Rewrite an IPv4 address in the given string(argv1) with '***.***.***.***'
734
743
  p0 = esmtperror.index(e) || next
735
744
  esmtperror[p0, e.size] = '***.***.***.***'
@@ -745,7 +754,7 @@ module Sisimai
745
754
  p1 = p0 + 5
746
755
  end
747
756
  end
748
- return nil if lookingfor.size == 0
757
+ return "" if lookingfor.size == 0
749
758
 
750
759
  statuscode = [] # List of SMTP Status Code, Keep the order of appearances
751
760
  anotherone = '' # Alternative code
@@ -811,10 +820,13 @@ module Sisimai
811
820
  next if characters[6] > 47 && characters[6] < 58
812
821
  statuscode << readbuffer
813
822
  end
814
-
815
823
  statuscode << anotherone if anotherone.size > 0
816
- return nil if statuscode.size == 0
817
- return statuscode.shift
824
+ return "" if statuscode.size == 0
825
+
826
+ # Select one from picked status codes
827
+ cv = statuscode.shift; statuscode.each { |e| cv = Sisimai::SMTP::Status.prefer(cv, e, "") }
828
+
829
+ return cv
818
830
  end
819
831
 
820
832
  # Return the preferred value selected from the arguments
@@ -860,11 +872,16 @@ module Sisimai
860
872
 
861
873
  return statuscode if zeroindex2['error'] > 0 # An SMTP status code is "X.0.0"
862
874
  return codeinmesg if statuscode == '4.4.7' # "4.4.7" is an ambiguous code
875
+ return codeinmesg if statuscode == '4.7.0' # "4.7.0" indicates "too many errors"
863
876
  return codeinmesg if statuscode.start_with?('5.3.') # "5.3.Z" is an error of a system
877
+ return codeinmesg if statuscode.end_with?('.5.1') # "X.5.1" indicates an invalid command
878
+ return codeinmesg if statuscode.end_with?('.5.2') # "X.5.2" indicates a syntax error
879
+ return codeinmesg if statuscode.end_with?('.5.4') # "X.5.4" indicates an invalid command arguments
880
+ return codeinmesg if statuscode.end_with?('.5.5') # "X.5.5" indicates a wrong protocol version
864
881
 
865
882
  if statuscode == '5.1.1'
866
883
  # "5.1.1" is a code of "userunknown"
867
- return statuscode if zeroindex1['error'] > 0
884
+ return statuscode if codeinmesg.start_with?('5.5.') || zeroindex1['error'] > 0
868
885
  return codeinmesg
869
886
 
870
887
  elsif statuscode == '5.1.3'
@@ -34,18 +34,17 @@ module Sisimai
34
34
  }
35
35
  }
36
36
  end
37
- parameters = '' # Command parameters of MAIL, RCPT
38
- cursession = nil # Current session for $esmtp
39
37
 
40
38
  cv = ''
41
- p0 = argv0.index('<<<') || -1 # Server response
39
+ cx = nil # Current session for esmtp
42
40
  p1 = argv0.index('>>>') || -1 # Sent command
43
- if p0 < p1
41
+ p2 = argv0.index('<<<') || -1 # Server response
42
+ if p2 < p1
44
43
  # An SMTP server response starting with '<<<' is the first
45
44
  esmtp << table.call
46
- cursession = esmtp[-1]
47
- cursession['command'] = 'CONN'
48
- argv0 = argv0[p0, argv0.size] if p0 > -1
45
+ cx = esmtp[-1]
46
+ cx['command'] = 'CONN'
47
+ argv0 = argv0[p2, argv0.size] if p2 > -1
49
48
  else
50
49
  # An SMTP command starting with '>>>' is the first
51
50
  argv0 = argv0[p1, argv0.size] if p1 > -1
@@ -63,17 +62,18 @@ module Sisimai
63
62
  # >>> SMTP Command
64
63
  thecommand = cv[1]
65
64
  commandarg = cv[2]
65
+ parameters = ''
66
66
 
67
67
  esmtp << table.call
68
- cursession = esmtp[-1]
69
- cursession['command'] = thecommand.upcase
68
+ cx = esmtp[-1]
69
+ cx['command'] = thecommand.upcase
70
70
 
71
71
  if thecommand =~ /\A(?:MAIL|RCPT|XFORWARD)/
72
72
  # MAIL or RCPT
73
73
  if cv = commandarg.match(/\A(?:FROM|TO):[ ]*<(.+[@].+)>[ ]*(.*)\z/)
74
74
  # >>> MAIL FROM: <neko@example.com> SIZE=65535
75
75
  # >>> RCPT TO: <kijitora@example.org>
76
- cursession['argument'] = cv[1]
76
+ cx['argument'] = cv[1]
77
77
  parameters = cv[2]
78
78
 
79
79
  else
@@ -87,11 +87,11 @@ module Sisimai
87
87
 
88
88
  parameters.split(" ").each do |p|
89
89
  # SIZE=22022, PROTO=SMTP, and so on
90
- if cv = p.match(/\A([^ =]+)=([^ =]+)\z/) then cursession['parameter'][cv[1].downcase] = cv[2] end
90
+ if cv = p.match(/\A([^ =]+)=([^ =]+)\z/) then cx['parameter'][cv[1].downcase] = cv[2] end
91
91
  end
92
92
  else
93
93
  # HELO, EHLO, AUTH, DATA, QUIT or Other SMTP command
94
- cursession['argument'] = commandarg
94
+ cx['argument'] = commandarg
95
95
  end
96
96
  end
97
97
  else
@@ -101,9 +101,9 @@ module Sisimai
101
101
  e = e[4, e.size]
102
102
 
103
103
  e.sub!(/\A<<<[ ]/, '')
104
- if cv = e.match(/\A([2-5]\d\d)[ ]/) then cursession['response']['reply'] = cv[1] end
105
- if cv = e.match(/\A[245]\d\d[ ]([245][.]\d{1,3}[.]\d{1,3})[ ]/) then cursession['response']['status'] = cv[1] end
106
- cursession['response']['text'] << e
104
+ if cv = e.match(/\A([2-5]\d\d)[ ]/) then cx['response']['reply'] = cv[1] end
105
+ if cv = e.match(/\A[245]\d\d[ ]([245][.]\d{1,3}[.]\d{1,3})[ ]/) then cx['response']['status'] = cv[1] end
106
+ cx['response']['text'] << e
107
107
  end
108
108
  end
109
109
 
@@ -75,52 +75,6 @@ module Sisimai
75
75
  return false
76
76
  end
77
77
 
78
- # Find an IPv4 address from the given string
79
- # @param [String] argv1 String including an IPv4 address
80
- # @return [Array] List of IPv4 addresses
81
- # @since v5.0.0
82
- def ipv4(argv0)
83
- return nil if argv0.to_s.empty?
84
- return [] if argv0.size < 7
85
-
86
- ipv4a = []
87
- %w|( ) [ ]|.each do |e|
88
- # Rewrite: "mx.example.jp[192.0.2.1]" => "mx.example.jp 192.0.2.1"
89
- p0 = argv0.index(e); next unless p0
90
- argv0[p0, 1] = ' '
91
- end
92
-
93
- argv0.split(' ').each do |e|
94
- # Find string including an IPv4 address
95
- next unless e.index('.') # IPv4 address must include "." character
96
-
97
- lx = e.size; next if lx < 7 || lx > 17 # 0.0.0.0 = 7, [255.255.255.255] = 17
98
- cu = 0 # Cursor for seeking each octet of an IPv4 address
99
- as = '' # ASCII Code of each character
100
- eo = '' # Buffer of each octet of IPv4 Address
101
-
102
- while cu < lx
103
- # Check whether each character is a number or "." or not
104
- as = e[cu, 1].ord
105
- cu += 1
106
-
107
- if as < 48 || as > 57
108
- # The character is not a number(0-9)
109
- break if as != 46 # The character is not "."
110
- next if eo == '' # The current buffer is empty
111
- break if eo.to_i > 255 # The current buffer is greater than 255
112
- eo = ''
113
- next
114
- end
115
- eo << as.chr
116
- break if eo.to_i > 255
117
- end
118
- ipv4a << e if eo.size > 0 && eo.to_i < 256
119
- end
120
-
121
- return ipv4a
122
- end
123
-
124
78
  # Convert given HTML text to plain text
125
79
  # @param [String] argv1 HTML text
126
80
  # @param [Boolean] loose Loose check flag
@@ -1,4 +1,4 @@
1
1
  # Define the version number of Sisimai
2
2
  module Sisimai
3
- VERSION = '5.1.0'.freeze
3
+ VERSION = '5.2.0'.freeze
4
4
  end