sisimai 4.25.8 → 4.25.12

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/ANALYTICAL-PRECISION +1 -1
  4. data/ChangeLog.md +65 -0
  5. data/README-JA.md +3 -3
  6. data/README.md +4 -4
  7. data/lib/sisimai/address.rb +6 -3
  8. data/lib/sisimai/arf.rb +25 -21
  9. data/lib/sisimai/data.rb +7 -1
  10. data/lib/sisimai/datetime.rb +15 -14
  11. data/lib/sisimai/lhost/amazonses.rb +1 -1
  12. data/lib/sisimai/lhost/domino.rb +29 -4
  13. data/lib/sisimai/lhost/einsundeins.rb +1 -1
  14. data/lib/sisimai/lhost/exchange2007.rb +1 -1
  15. data/lib/sisimai/lhost/exim.rb +14 -10
  16. data/lib/sisimai/lhost/ezweb.rb +1 -1
  17. data/lib/sisimai/lhost/gsuite.rb +5 -0
  18. data/lib/sisimai/lhost/imailserver.rb +1 -1
  19. data/lib/sisimai/lhost/mailfoundry.rb +3 -4
  20. data/lib/sisimai/lhost/mailmarshalsmtp.rb +2 -2
  21. data/lib/sisimai/lhost/mxlogic.rb +1 -1
  22. data/lib/sisimai/lhost/notes.rb +1 -1
  23. data/lib/sisimai/lhost/office365.rb +1 -1
  24. data/lib/sisimai/lhost/postfix.rb +3 -10
  25. data/lib/sisimai/lhost/qmail.rb +7 -7
  26. data/lib/sisimai/lhost/sendgrid.rb +2 -2
  27. data/lib/sisimai/lhost/sendmail.rb +1 -1
  28. data/lib/sisimai/lhost/verizon.rb +4 -4
  29. data/lib/sisimai/lhost/x3.rb +4 -0
  30. data/lib/sisimai/lhost/x4.rb +8 -8
  31. data/lib/sisimai/mail.rb +2 -21
  32. data/lib/sisimai/mda.rb +2 -2
  33. data/lib/sisimai/mime.rb +1 -1
  34. data/lib/sisimai/reason/blocked.rb +40 -26
  35. data/lib/sisimai/reason/exceedlimit.rb +4 -1
  36. data/lib/sisimai/reason/expired.rb +2 -0
  37. data/lib/sisimai/reason/filtered.rb +10 -9
  38. data/lib/sisimai/reason/hostunknown.rb +3 -0
  39. data/lib/sisimai/reason/mailererror.rb +1 -1
  40. data/lib/sisimai/reason/norelaying.rb +8 -7
  41. data/lib/sisimai/reason/notaccept.rb +5 -3
  42. data/lib/sisimai/reason/policyviolation.rb +5 -1
  43. data/lib/sisimai/reason/rejected.rb +5 -1
  44. data/lib/sisimai/reason/securityerror.rb +5 -6
  45. data/lib/sisimai/reason/spamdetected.rb +23 -16
  46. data/lib/sisimai/reason/suspend.rb +1 -0
  47. data/lib/sisimai/reason/systemerror.rb +2 -0
  48. data/lib/sisimai/reason/userunknown.rb +25 -21
  49. data/lib/sisimai/reason/virusdetected.rb +9 -3
  50. data/lib/sisimai/rfc1894.rb +24 -22
  51. data/lib/sisimai/rfc3464.rb +1 -1
  52. data/lib/sisimai/rfc3834.rb +1 -1
  53. data/lib/sisimai/rfc5322.rb +8 -3
  54. data/lib/sisimai/rhost/exchangeonline.rb +8 -1
  55. data/lib/sisimai/rhost/franceptt.rb +4 -0
  56. data/lib/sisimai/rhost/googleapps.rb +4 -1
  57. data/lib/sisimai/rhost.rb +1 -0
  58. data/lib/sisimai/smtp/error.rb +8 -6
  59. data/lib/sisimai/smtp/reply.rb +1 -1
  60. data/lib/sisimai/smtp/status.rb +1 -1
  61. data/lib/sisimai/time.rb +1 -2
  62. data/lib/sisimai/version.rb +1 -1
  63. data/lib/sisimai.rb +3 -3
  64. data/set-of-emails/maildir/bsd/arf-25.eml +61 -0
  65. data/set-of-emails/maildir/bsd/lhost-aol-04.eml +23 -23
  66. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +1 -2
  67. data/set-of-emails/maildir/bsd/lhost-exim-61.eml +40 -0
  68. data/set-of-emails/maildir/bsd/lhost-postfix-66.eml +80 -0
  69. data/set-of-emails/maildir/bsd/lhost-postfix-67.eml +80 -0
  70. data/set-of-emails/maildir/bsd/lhost-postfix-68.eml +82 -0
  71. data/set-of-emails/maildir/bsd/lhost-postfix-69.eml +80 -0
  72. data/set-of-emails/maildir/bsd/lhost-postfix-70.eml +87 -0
  73. data/set-of-emails/maildir/bsd/lhost-postfix-71.eml +81 -0
  74. data/set-of-emails/maildir/bsd/lhost-postfix-72.eml +81 -0
  75. data/set-of-emails/maildir/bsd/lhost-postfix-73.eml +79 -0
  76. data/set-of-emails/maildir/bsd/lhost-postfix-74.eml +83 -0
  77. data/set-of-emails/maildir/bsd/lhost-sendmail-08.eml +1 -1
  78. data/set-of-emails/maildir/bsd/lhost-sendmail-11.eml +1 -1
  79. data/set-of-emails/maildir/bsd/lhost-sendmail-57.eml +59 -0
  80. data/set-of-emails/maildir/bsd/lhost-sendmail-58.eml +70 -0
  81. data/set-of-emails/maildir/bsd/lhost-sendmail-59.eml +68 -0
  82. data/set-of-emails/maildir/bsd/lhost-x3-06.eml +53 -0
  83. data/set-of-emails/maildir/bsd/rfc3464-41.eml +19 -0
  84. data/set-of-emails/maildir/bsd/rfc3464-42.eml +34 -0
  85. data/set-of-emails/maildir/bsd/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  86. data/set-of-emails/maildir/bsd/{rhost-exchange-online-02.eml → rhost-exchangeonline-02.eml} +0 -0
  87. data/set-of-emails/maildir/bsd/{rhost-exchange-online-03.eml → rhost-exchangeonline-03.eml} +0 -0
  88. data/set-of-emails/maildir/bsd/rhost-franceptt-12.eml +82 -0
  89. data/set-of-emails/maildir/bsd/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  90. data/set-of-emails/maildir/bsd/{rhost-google-apps-02.eml → rhost-googleapps-02.eml} +0 -0
  91. data/set-of-emails/maildir/dos/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  92. data/set-of-emails/maildir/dos/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  93. data/set-of-emails/maildir/mac/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  94. data/set-of-emails/maildir/mac/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  95. data/sisimai-java.gemspec +4 -4
  96. data/sisimai.gemspec +4 -4
  97. metadata +38 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a97d3034cddf47a54f0970f324fde0b8574f19a11fd29fd85e11ecad9753f5f3
4
- data.tar.gz: d60fd6b598d277b852f26ee42e483a4ffce7d946f6beefa374fe9aaeef6485a0
3
+ metadata.gz: d4e15f3cb5442e9fdc4cf00980aa77ab197ac7ba6eaf75e06f2b49edb4e5a2a9
4
+ data.tar.gz: 7105ac6159bd67aec8020a54517f451c616bb5c0332c7804035e96323d39dc02
5
5
  SHA512:
6
- metadata.gz: f569792981be8ffcf27846db477b98f814914fed55841d994b16843a668025926e737c7cf8b1ae5287049184714dddee99c0d7e2538f2de5e44ba35ab92f402c
7
- data.tar.gz: cf079e53450f827e7c5e104a64a8abe75d8deba09be822f1cc178e85548abbd7829bc23f74f0a6ae361b331e2ebac07f705c207c9885a115bbcee1b7b125b2c7
6
+ metadata.gz: 4a51b10b7f1cfc9a0565c55fd1b553adde9ea8c2a6edd1f49aeb9b3e3d7b509cfa0bf6740d8d508ab2e74ea9dca84103b1840bdf2fa63a977add33b229ad7232
7
+ data.tar.gz: 321ef7a5c3515e029990df7ac79bb251bf753e57979bf28ca86ef422e2a57a9233b4c3ee44c098ed6ebbaafed7b76c205b1f1e2ffbdf55d5a0c07cece54cda32
data/.travis.yml CHANGED
@@ -2,11 +2,12 @@ language: ruby
2
2
  rvm:
3
3
  # See http://rubies.travis-ci.org for Precompiled Ruby Versions
4
4
  - 2.1.1
5
- - 2.2.4
5
+ - 2.2.10
6
6
  # - 2.3.0
7
- # - 2.4.0
7
+ - 2.4.9
8
8
  # - 2.5.0
9
- - 2.6.0
9
+ - 2.6.6
10
+ - 2.7.0
10
11
  # - jruby-9.0.5.0
11
12
  # - jruby-9.1.9.0
12
13
  before_install:
data/ANALYTICAL-PRECISION CHANGED
@@ -61,4 +61,4 @@ RFC3464 .......... 151/0322 0.4689 Fallback Module for MTAs
61
61
  RFC3834 .......... 0/0014 0.0000 Detector for auto replied message
62
62
  --------------------------------------------------------------------------------
63
63
  bounceHammer 1523/2635 0.5779
64
- Sisimai 4.25.6 2635/2635 1.0000
64
+ Sisimai 4.25.8 2635/2635 1.0000
data/ChangeLog.md CHANGED
@@ -3,6 +3,71 @@ RELEASE NOTES for Ruby version of Sisimai
3
3
  - releases: "https://github.com/sisimai/rb-sisimai/releases"
4
4
  - download: "https://rubygems.org/gems/sisimai"
5
5
 
6
+ v4.25.12
7
+ --------------------------------------------------------------------------------
8
+ - release: "Mon, 22 Nov 2021 12:22:22 +0900 (JST)"
9
+ - version: "4.25.12"
10
+ - changes:
11
+ - Fix 2 encoding related errors:
12
+ - Fix an error with message `incompatible character encodings:ASCII-8BIT and
13
+ UTF-8` reported at issue #223. Thanks to @chahn
14
+ - Fix an error with message `invalid byte sequence in UTF-8 (ArgumentError)`
15
+ reported at issue #224. Thanks to @chahn
16
+ - Add `rfc3464-41.eml` and `rfc3464-42.eml` provided by @chahn
17
+ - Add a new error code of La Poste at `Sisimai::Rhost::FrancePTT` module and
18
+ a new sample email `rhost-franceptt-12.eml` into `set-of-emails` directory
19
+ imported from sisimai/p5-sisimai#441.
20
+ - Remove all the HTML elements from the value of `diagnosticcode`.
21
+ - Fix serious bugs:
22
+ - Both of the values of `deliverystatus` and `replycode` detected from the
23
+ message body did not use at `Sisimai::Lhost::Exim`.
24
+ - `true` method strictly checks the value of `smtpcommand` at some classes
25
+ in `Sisimai/Reason`. For example, when a detected reason is `spamdetected`
26
+ and `virusdetected` the value of `smtpcommand` should be `DATA` or an SMTP
27
+ command to be sent after `DATA`.
28
+
29
+ v4.25.11
30
+ --------------------------------------------------------------------------------
31
+ - release: "Mon, 22 Feb 2021 21:15:22 +0900 (JST)"
32
+ - version: "4.25.11"
33
+ - changes:
34
+ - Fix typo in `Sisimai::RFC3464`
35
+ - Import some commits from Sisimai version 5 preview #
36
+ - Improved code for getting an email address in `Sisimai::Address`
37
+ - Improved code for checking the day of month value, for converting a full
38
+ month name and a full day of the week at `Sisimai::DateTime`
39
+ - Improvement code for picking text blocks of message/rfc822 part in RFC5322
40
+ - Add 60+ error message patterns
41
+ - Improved code for encodings in `Sisimai::Lhost::Domino`, `Sisimai::String`
42
+
43
+ v4.25.10
44
+ --------------------------------------------------------------------------------
45
+ - release: "Tue, 22 Dec 2020 13:22:22 +0900 (JST)"
46
+ - version: "4.25.10"
47
+ - changes:
48
+ - #187 Remove the following old methods (marked as obsolete from v4.25.6)
49
+ - `Sisimai::Mail.close` (automatically closes at the EOF)
50
+ - `Sisimai::Mail.type` (use `Sisimai::Mail.kind` instead)
51
+ - `Sisimai::Mail.mail.*` (use `Sisimai::Mail.data.*` instead)
52
+ - `Sisimai::Lhost::Exim` and `Sisimai::Lhost::X3` improvement
53
+ - #205 Code improvement for `Source-IP` field on `Sisimai::ARF`
54
+ - #207 Updates for DMARC and SPF related errors
55
+ - The value of `reason` rejected due to DMARC policy is `policyviolation`
56
+ - The value of `reason` rejected due to no SPF record is `rejected`
57
+ - Add some sample emails related to above into set-of-emails/
58
+
59
+ v4.25.9
60
+ --------------------------------------------------------------------------------
61
+ - release: "Sat, 3 Oct 2020 22:00:00 +0900 (JST)"
62
+ - version: ""
63
+ - changes:
64
+ - Suppress warning messages on Ruby 2.7. Thanks to @koic
65
+ - Suppress keyword argument warnings in Ruby 2.7 #200
66
+ - Suppress a Ruby warning for `Object#=~` and bug fix to match patterns #201
67
+ - #203 Replace `.+` with `[^ ]` on some large regular expressions for serious
68
+ performance reason.
69
+ - #204 Suport Null MX (RFC7505) on Sendmail sisimai/set-of-emails#4
70
+
6
71
  v4.25.8
7
72
  --------------------------------------------------------------------------------
8
73
  - release: "Fri, 17 Jul 2020 11:59:49 +0900 (JST)"
data/README-JA.md CHANGED
@@ -53,7 +53,7 @@ Key features
53
53
  * git clone & make
54
54
  * __高い解析精度__
55
55
  * 解析精度はbounceHammerの2倍
56
- * 66種類のMTA/MDA/ESPに対応
56
+ * 68種類のMTA/MDA/ESPに対応
57
57
  * Feedback Loopにも対応
58
58
  * 29種類のエラー理由を検出
59
59
 
@@ -220,8 +220,8 @@ Differences between Ruby version and Perl version
220
220
  | メール解析速度(1000通のメール) | 2.22秒[2] | 1.35秒 |
221
221
  | インストール方法 | gem install | cpanm, cpm |
222
222
  | 依存モジュール数(コアモジュールを除く) | 1モジュール | 2モジュール |
223
- | LOC:ソースコードの行数 | 10200行 | 10400行 |
224
- | テスト件数(spec/,t/,xt/ディレクトリ) | 236000件 | 266000件 |
223
+ | LOC:ソースコードの行数 | 10400行 | 10500行 |
224
+ | テスト件数(spec/,t/,xt/ディレクトリ) | 241000件 | 270000件 |
225
225
  | ライセンス | 二条項BSD | 二条項BSD |
226
226
  | 開発会社によるサポート契約 | 提供中 | 提供中 |
227
227
 
data/README.md CHANGED
@@ -52,7 +52,7 @@ Key Features
52
52
  * git clone & make
53
53
  * __High Precision of Analysis__
54
54
  * 2 times higher than bounceHammer
55
- * Support 66 MTAs/MDAs/ESPs
55
+ * Support 68 MTAs/MDAs/ESPs
56
56
  * Support Feedback Loop Message(ARF)
57
57
  * Can detect 29 error reasons
58
58
 
@@ -225,8 +225,8 @@ and bounceHammer are available at
225
225
  | The speed of parsing email(1000 emails) | 2.22s[2] | 1.35s |
226
226
  | How to install | gem install | cpanm, cpm |
227
227
  | Dependencies (Except core modules) | 1 module | 2 modules |
228
- | LOC:Source lines of code | 10200 lines | 10400 lines |
229
- | The number of tests(spec/,t/,xt/) directory | 236000 tests | 266000 tests |
228
+ | LOC:Source lines of code | 10400 lines | 10500 lines |
229
+ | The number of tests(spec/,t/,xt/) directory | 241000 tests | 270000 tests |
230
230
  | License | BSD 2-Clause | BSD 2-Clause |
231
231
  | Support Contract provided by Developer | Available | Available |
232
232
 
@@ -283,7 +283,7 @@ Author
283
283
 
284
284
  Copyright
285
285
  ===============================================================================
286
- Copyright (C) 2015-2020 azumakuniyuki, All Rights Reserved.
286
+ Copyright (C) 2015-2021 azumakuniyuki, All Rights Reserved.
287
287
 
288
288
  License
289
289
  ===============================================================================
@@ -240,7 +240,7 @@ module Sisimai
240
240
 
241
241
  # Remove angle brackets, other brackets, and quotations: []<>{}'`
242
242
  # except a domain part is an IP address like neko@[192.0.2.222]
243
- e[:address] = e[:address].sub(/\A[\[<{('`]/, '').sub(/['`>})]\z/, '')
243
+ e[:address] = e[:address].sub(/\A[\[<{('`]/, '').sub(/[.'`>});]\z/, '')
244
244
  e[:address].chomp!(']') unless e[:address] =~ /[@]\[[0-9A-Za-z:\.]+\]\z/
245
245
  e[:address] = e[:address].sub(/\A["]/, '').chomp('"') unless e[:address] =~ /\A["].+["][@]/
246
246
 
@@ -321,13 +321,16 @@ module Sisimai
321
321
  addrs = Sisimai::Address.find(argv1)
322
322
  return nil unless addrs
323
323
  return nil if addrs.empty?
324
+
324
325
  thing = addrs.shift
326
+ heads = ['<']
327
+ tails = ['>', ',', '.', ';']
325
328
 
326
329
  if cv = thing[:address].match(/\A([^\s]+)[@]([^@]+)\z/) ||
327
330
  thing[:address].match(/\A(["].+?["])[@]([^@]+)\z/)
328
331
  # Get the local part and the domain part from the email address
329
- lpart = cv[1]
330
- dpart = cv[2]
332
+ lpart = cv[1]; heads.each { |e| lpart.gsub!(/\A#{e}/, '') if lpart.start_with?(e) }
333
+ dpart = cv[2]; tails.each { |e| dpart.gsub!(/#{e}\z/, '') if dpart.end_with?(e) }
331
334
  email = Sisimai::Address.expand_verp(thing[:address])
332
335
  aname = nil
333
336
 
data/lib/sisimai/arf.rb CHANGED
@@ -14,15 +14,20 @@ module Sisimai
14
14
  # OpenDMARC 1.3.0 uses: This is an authentication failure report for an email message received from IP
15
15
  # Abusix ARF uses this is an autogenerated email abuse complaint regarding your network.
16
16
  Indicators = Sisimai::Lhost.INDICATORS
17
- StartingOf = { rfc822: ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'] }.freeze
17
+ StartingOf = {
18
+ rfc822: ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'],
19
+ report: ['Content-Type: message/feedback-report'],
20
+ }.freeze
18
21
  MarkingsOf = {
19
22
  message: %r{\A(?>
20
- [Tt]his[ ]is[ ].+[ ]email[ ]abuse[ ]report
21
- |[Tt]his[ ]is[ ](?:
22
- an[ ]autogenerated[ ]email[ ]abuse[ ]complaint
23
- |an?[ ].+[ ]report[ ]for
24
- |a[ ].+[ ]authentication[ -]failure[ ]report[ ]for
25
- )
23
+ [Tt]his[ ]is[ ]a[ ][^ ]+[ ](?:email[ ])?[Aa]buse[ ][Rr]eport
24
+ |[Tt]his[ ]is[ ]an[ ]email[ ]abuse[ ]report
25
+ |[Tt]his[ ]is[ ](?:
26
+ a[ ][^ ]+[ ]authentication[ -]failure[ ]report
27
+ |an[ ]authentication[ -]failure[ ]report
28
+ |an[ ]autogenerated[ ]email[ ]abuse[ ]complaint
29
+ |an?[ ][^ ]+[ ]report[ ]for
30
+ )
26
31
  )
27
32
  }x,
28
33
  }.freeze
@@ -33,8 +38,7 @@ module Sisimai
33
38
  def description; return 'Abuse Feedback Reporting Format'; end
34
39
 
35
40
  # Email is a Feedback-Loop message or not
36
- # @param [Hash] heads Email header including "Content-Type", "From",
37
- # and "Subject" field
41
+ # @param [Hash] heads Email header including "Content-Type", "From", and "Subject" field
38
42
  # @return [True,False] true: Feedback Loop
39
43
  # false: is not Feedback loop
40
44
  def is_arf(heads)
@@ -109,12 +113,17 @@ module Sisimai
109
113
  # this specification is set to "1".
110
114
  #
111
115
  while e = bodyslices.shift do
116
+ # This is an email abuse report for an email message with the
117
+ # message-id of 0000-000000000000000000000000000000000@mx
118
+ # received from IP address 192.0.2.1 on
119
+ # Thu, 29 Apr 2010 00:00:00 +0900 (JST)
120
+ if e =~ MarkingsOf[:message]
121
+ commondata['diagnosis'] = e if commondata['diagnosis'].empty?
122
+ end
123
+
112
124
  if readcursor == 0
113
125
  # Beginning of the bounce message or message/delivery-status part
114
- if e =~ MarkingsOf[:message]
115
- readcursor |= Indicators[:deliverystatus]
116
- next
117
- end
126
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:report][0])
118
127
  end
119
128
 
120
129
  if (readcursor & Indicators[:'message-rfc822']) == 0
@@ -169,7 +178,7 @@ module Sisimai
169
178
  rcptintext = rhs if lhs == 'to'
170
179
  end
171
180
  else
172
- # message/delivery-status part
181
+ # message/feedback-report part
173
182
  next unless readcursor & Indicators[:deliverystatus] > 0
174
183
  next if e.empty?
175
184
 
@@ -226,7 +235,7 @@ module Sisimai
226
235
  # Reporting-MTA: dns; mx.example.jp
227
236
  commondata['rhost'] = cv[1]
228
237
 
229
- elsif cv = e.match(/\ASource-IP:[ ]*(.+)\z/)
238
+ elsif cv = e.match(/\ASource-I[Pp]:[ ]*(.+)\z/)
230
239
  # The header is optional and MUST NOT appear more than once.
231
240
  # Source-IP: 192.0.2.45
232
241
  arfheaders['rhost'] = cv[1]
@@ -236,12 +245,6 @@ module Sisimai
236
245
  # Original-Mail-From: <somespammer@example.net>
237
246
  commondata['from'] = Sisimai::Address.s3s4(cv[1]) if commondata['from'].empty?
238
247
 
239
- elsif e =~ MarkingsOf[:message]
240
- # This is an email abuse report for an email message with the
241
- # message-id of 0000-000000000000000000000000000000000@mx
242
- # received from IP address 192.0.2.1 on
243
- # Thu, 29 Apr 2010 00:00:00 +0900 (JST)
244
- commondata['diagnosis'] = e
245
248
  end
246
249
  end
247
250
  end
@@ -287,6 +290,7 @@ module Sisimai
287
290
 
288
291
  e['softbounce'] = -1
289
292
  e['diagnosis'] = commondata['diagnosis'] unless e['diagnosis']
293
+ e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
290
294
  e['date'] = mhead['date'] if e['date'].empty?
291
295
  e['reason'] = 'feedback'
292
296
  e['agent'] = 'Feedback-Loop'
data/lib/sisimai/data.rb CHANGED
@@ -262,10 +262,16 @@ module Sisimai
262
262
  # 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,
263
263
  # 550-5.7.1 this message has been blocked. Please visit
264
264
  # 550 5.7.1 https://support.google.com/mail/answer/188131 for more information.
265
- p['diagnosticcode'] = Sisimai::String.sweep(p['diagnosticcode'].gsub(re, ' '))
265
+ p['diagnosticcode'] = p['diagnosticcode'].gsub(re, ' ')
266
+ p['diagnosticcode'] = Sisimai::String.sweep(p['diagnosticcode'].sub(%r|<html>.+</html>|i, ''))
266
267
  end
267
268
  end
268
269
 
270
+ if Sisimai::String.is_8bit(p['diagnosticcode'])
271
+ # To avoid incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError
272
+ p['diagnosticcode'] = p['diagnosticcode'].force_encoding('UTF-8').scrub('?')
273
+ end
274
+
269
275
  p['diagnostictype'] ||= 'X-UNIX' if p['reason'] == 'mailererror'
270
276
  p['diagnostictype'] ||= 'SMTP' unless %w[feedback vacation].include?(p['reason'])
271
277
 
@@ -207,24 +207,24 @@ module Sisimai
207
207
  end
208
208
 
209
209
  # Month name list
210
- # @param [Integer] argv1 Require full name or not
210
+ # @param [Boolean] argv1 Require full name or not
211
211
  # @return [Array, String] Month name list or month name
212
212
  # @example Get the names of each month
213
- # monthname() #=> [ 'Jan', 'Feb', ... ]
214
- # monthname(1) #=> [ 'January', 'February', 'March', ... ]
215
- def monthname(argv1 = 0)
216
- value = argv1 > 0 ? :full : :abbr
213
+ # monthname() #=> [ 'Jan', 'Feb', ... ]
214
+ # monthname(true) #=> [ 'January', 'February', 'March', ... ]
215
+ def monthname(argv1 = false)
216
+ value = argv1 ? :full : :abbr
217
217
  return MonthName[value]
218
218
  end
219
219
 
220
220
  # List of day of week
221
- # @param [Integer] argv1 Require full name
221
+ # @param [Boolean] argv1 Require full name
222
222
  # @return [Array, String] List of day of week or day of week
223
223
  # @example Get the names of each day of week
224
- # dayofweek() #=> [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
225
- # dayofweek(1) #=> [ 'Sunday', 'Monday', 'Tuesday', ... ]
226
- def dayofweek(argv1 = 0)
227
- value = argv1 > 0 ? :full : :abbr
224
+ # dayofweek() #=> [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
225
+ # dayofweek(true) #=> [ 'Sunday', 'Monday', 'Tuesday', ... ]
226
+ def dayofweek(argv1 = false)
227
+ value = argv1 ? :full : :abbr
228
228
  return DayOfWeek[value]
229
229
  end
230
230
 
@@ -257,9 +257,10 @@ module Sisimai
257
257
 
258
258
  while p = timetokens.shift do
259
259
  # Parse each piece of time
260
- if p =~ /\A[A-Z][a-z]{2}[,]?\z/
260
+ if p =~ /\A[A-Z][a-z]{2,}[,]?\z/
261
261
  # Day of week or Day of week; Thu, Apr, ...
262
- p.chop if p.size == 4 # Thu, -> Thu
262
+ p.gsub!(/,\z/, '') if p.end_with?(',') # "Thu," => "Thu"
263
+ p = p[0,3] if p.size > 3
263
264
 
264
265
  if DayOfWeek[:abbr].include?(p)
265
266
  # Day of week; Mon, Thu, Sun,...
@@ -273,7 +274,7 @@ module Sisimai
273
274
  # Year or Day; 2005, 31, 04, 1, ...
274
275
  if p.to_i > 31
275
276
  # The piece is the value of an year
276
- v[:Y] = p
277
+ v[:Y] = p.to_i
277
278
  else
278
279
  # The piece is the value of a day
279
280
  if v[:d]
@@ -441,7 +442,7 @@ module Sisimai
441
442
  # @example Get timezone offset string of specified seconds
442
443
  # second2tz(12345) #=> '+0325'
443
444
  def second2tz(argv1)
444
- return '+0000' unless argv1.is_a?(Number)
445
+ return '+0000' unless argv1.is_a?(::Integer)
445
446
  return nil if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
446
447
 
447
448
  digit = { :operator => '+' }
@@ -182,7 +182,7 @@ module Sisimai::Lhost
182
182
  v['status'] = Sisimai::SMTP::Status.find(v['diagnosis']) || ''
183
183
  v['replycode'] = Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
184
184
  v['reason'] = 'delivered'
185
- v['action'] = 'deliverable'
185
+ v['action'] = 'delivered'
186
186
 
187
187
  v['date'] = o['timestamp'] || p['mail']['timestamp']
188
188
  v['date'].sub!(/[.]\d+Z\z/, '')
@@ -7,12 +7,13 @@ module Sisimai::Lhost
7
7
  require 'sisimai/lhost'
8
8
 
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/delivery-status|.freeze
10
+ ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
11
11
  StartingOf = { message: ['Your message'] }.freeze
12
12
  MessagesOf = {
13
13
  'userunknown' => [
14
14
  'not listed in Domino Directory',
15
15
  'not listed in public Name & Address Book',
16
+ "dans l'annuaire Domino", # TODO: "non répertorié dans l'annuaire Domino",
16
17
  'Domino ディレクトリには見つかりません',
17
18
  ],
18
19
  'filtered' => ['Cannot route mail to user'],
@@ -25,7 +26,11 @@ module Sisimai::Lhost
25
26
  # @return [Hash] Bounce data list and message/rfc822 part
26
27
  # @return [Nil] it failed to parse or the arguments are missing
27
28
  def make(mhead, mbody)
28
- return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:')
29
+ return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:')
30
+
31
+ require 'sisimai/rfc1894'
32
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
33
+ permessage = {} # (Hash) Store values of each Per-Message field
29
34
 
30
35
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
31
36
  emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
@@ -87,6 +92,24 @@ module Sisimai::Lhost
87
92
  elsif cv = e.match(/\A[ ][ ]Subject: (.+)\z/)
88
93
  # Subject: Nyaa
89
94
  subjecttxt = cv[1]
95
+
96
+ elsif f = Sisimai::RFC1894.match(e)
97
+ # There are some fields defined in RFC3464, try to match
98
+ o = Sisimai::RFC1894.field(e) || next
99
+ next if o[-1] == 'addr'
100
+
101
+ if o[-1] == 'code'
102
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
103
+ v['spec'] = o[1] if v['spec'].to_s.empty?
104
+ v['diagnosis'] = o[2] if v['diagnosis'].to_s.empty?
105
+ else
106
+ # Other DSN fields defined in RFC3464
107
+ next unless fieldtable[o[0]]
108
+ v[fieldtable[o[0]]] = o[2]
109
+
110
+ next unless f == 1
111
+ permessage[fieldtable[o[0]]] = o[2]
112
+ end
90
113
  end
91
114
  end
92
115
  end
@@ -95,12 +118,14 @@ module Sisimai::Lhost
95
118
  dscontents.each do |e|
96
119
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
97
120
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
121
+ e['lhost'] ||= permessage['rhost']
122
+ permessage.each_key { |a| e[a] ||= permessage[a] || '' }
98
123
 
99
124
  MessagesOf.each_key do |r|
100
125
  # Check each regular expression of Domino error messages
101
126
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
102
- e['reason'] = r
103
- e['status'] = Sisimai::SMTP::Status.code(r.to_s, false) || ''
127
+ e['reason'] = r
128
+ e['status'] ||= Sisimai::SMTP::Status.code(r.to_s, false) || ''
104
129
  break
105
130
  end
106
131
  end
@@ -52,7 +52,7 @@ module Sisimai::Lhost
52
52
  # http://postmaster.1and1.com/en/error-messages?ip=%1s
53
53
  v = dscontents[-1]
54
54
 
55
- if cv = e.match(/\A([^ ]+[@][^ ]+)\z/)
55
+ if cv = e.match(/\A([^ ]+[@][^ ]+?)[:]?\z/)
56
56
  # general@example.eu
57
57
  if v['recipient']
58
58
  # There are multiple recipient addresses in the message body.
@@ -24,7 +24,7 @@ module Sisimai::Lhost
24
24
  error: %r/ ((?:RESOLVER|QUEUE)[.][A-Za-z]+(?:[.]\w+)?);/,
25
25
  rhost: %r{\A(?:
26
26
  Generating[ ]server # en-US
27
- |Serveur[ ]de[ ]g.+ration[ ] # fr-FR/Serveur de génération
27
+ |Serveur[ ]de[ ]g[^ ]+ration[ ] # fr-FR/Serveur de génération
28
28
  |Server[ ]di[ ]generazione # it-CH
29
29
  ):[ ]?(.*)
30
30
  }x,
@@ -12,7 +12,7 @@ module Sisimai::Lhost
12
12
  # deliver.c:6425| else fprintf(f,
13
13
  # deliver.c:6426|"------ This is a copy of the message's headers. ------\n");
14
14
  ReBackbone = %r{^(?:
15
- [-]+[ ]This[ ]is[ ]a[ ]copy[ ]of[ ](?:the|your)[ ]message.+?headers[.][ ][-]+
15
+ [-]+[ ]This[ ]is[ ]a[ ]copy[ ]of[ ](?:the|your)[ ]message,[ ]including[ ]all[ ]the[ ]headers[.][ ][-]+
16
16
  |Content-Type:[ ]*message/rfc822\n(?:[\s\t]+.*?\n\n)?
17
17
  )
18
18
  }x.freeze
@@ -36,13 +36,14 @@ module Sisimai::Lhost
36
36
  # deliver.c:6305|"address(es) failed:\n", sender_address);
37
37
  # deliver.c:6306| }
38
38
  alias: %r/\A([ ]+an undisclosed address)\z/,
39
- frozen: %r/\AMessage .+ (?:has been frozen|was frozen on arrival)/,
39
+ frozen: %r/\AMessage [^ ]+ (?:has been frozen|was frozen on arrival)/,
40
40
  message: %r{\A(?>
41
41
  This[ ]message[ ]was[ ]created[ ]automatically[ ]by[ ]mail[ ]delivery[ ]software[.]
42
42
  |A[ ]message[ ]that[ ]you[ ]sent[ ]was[ ]rejected[ ]by[ ]the[ ]local[ ]scanning[ ]code
43
43
  |A[ ]message[ ]that[ ]you[ ]sent[ ]contained[ ]one[ ]or[ ]more[ ]recipient[ ]addresses[ ]
44
- |Message[ ].+[ ](?:has[ ]been[ ]frozen|was[ ]frozen[ ]on[ ]arrival)
45
- |The[ ].+[ ]router[ ]encountered[ ]the[ ]following[ ]error[(]s[)]:
44
+ |A[ ]message[ ]that[ ]you[ ]sent[ ]could[ ]not[ ]be[ ]delivered[ ]to[ ]all[ ]of[ ]its[ ]recipients
45
+ |Message[ ][^ ]+[ ](?:has[ ]been[ ]frozen|was[ ]frozen[ ]on[ ]arrival)
46
+ |The[ ][^ ]+[ ]router[ ]encountered[ ]the[ ]following[ ]error[(]s[)]:
46
47
  )
47
48
  }x,
48
49
  }.freeze
@@ -134,7 +135,7 @@ module Sisimai::Lhost
134
135
  match += 1 if mhead['message-id'].to_s =~ %r/\A[<]\w{7}[-]\w{6}[-]\w{2}[@]/
135
136
  match += 1 if mhead['subject'] =~ %r{(?:
136
137
  Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
137
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
138
+ |Warning:[ ]message[ ][^ ]+[ ]delayed[ ]+
138
139
  |Delivery[ ]Status[ ]Notification
139
140
  |Mail[ ]failure
140
141
  |Message[ ]frozen
@@ -264,7 +265,10 @@ module Sisimai::Lhost
264
265
  # Content-type: message/delivery-status
265
266
  nextcursor = 1 if e.start_with?(StartingOf[:deliverystatus][0])
266
267
  v['alterrors'] ||= ''
267
- v['alterrors'] << e + ' ' if e.start_with?(' ')
268
+ if e.start_with?("\s", "\t")
269
+ e.sub!(/\A[\s\t]+/, '')
270
+ v['alterrors'] << e + ' ' unless v['alterrors'].include?(e)
271
+ end
268
272
  end
269
273
  else
270
274
  if dscontents.size == recipients
@@ -275,7 +279,7 @@ module Sisimai::Lhost
275
279
  else
276
280
  # Error message when email address above does not include '@'
277
281
  # and domain part.
278
- if e =~ %r<\A[ ]+pipe[ ]to[ ][|]/.+>
282
+ if e =~ %r<\A[ ]+pipe[ ]to[ ][|]/[^ ]+>
279
283
  # pipe to |/path/to/prog ...
280
284
  # generated by kijitora@example.com
281
285
  v['diagnosis'] = e
@@ -374,7 +378,7 @@ module Sisimai::Lhost
374
378
  rxdiagnosis = %r/e['diagnosis']/i
375
379
  # Override the value of diagnostic code message because
376
380
  # the value of alterrors includes the value of diagnosis.
377
- e['diagnosis'] = e['alterrors'] if e['alterrors'] =~ rxdiagnosis
381
+ e['diagnosis'] = e['alterrors'] if e['alterrors'].downcase.include?(e['diagnosis'].downcase)
378
382
  end
379
383
  end
380
384
  e.delete('alterrors')
@@ -436,8 +440,8 @@ module Sisimai::Lhost
436
440
  # Diagnostic-Code: smtp; 450 TEMPERROR: retry timeout exceeded
437
441
  # The value of "Status:" indicates permanent error but the value
438
442
  # of SMTP reply code in Diagnostic-Code: field is "TEMPERROR"!!!!
439
- sv = Sisimai::SMTP::Status.find(e['diagnosis'])
440
- rv = Sisimai::SMTP::Reply.find(e['diagnosis'])
443
+ sv = e['status'] || Sisimai::SMTP::Status.find(e['diagnosis'])
444
+ rv = e['replycode'] || Sisimai::SMTP::Reply.find(e['diagnosis'])
441
445
  s1 = 0 # First character of Status as integer
442
446
  r1 = 0 # First character of SMTP reply code as integer
443
447
 
@@ -125,7 +125,7 @@ module Sisimai::Lhost
125
125
  v['command'] = cv[1]
126
126
  else
127
127
  # Check error message
128
- if rxmessages.any? { |a| e =~ a }
128
+ if rxmessages.any? { |messages| messages.any? { |message| e =~ message } }
129
129
  # Check with regular expressions of each error
130
130
  v['diagnosis'] ||= ''
131
131
  v['diagnosis'] << ' ' << e
@@ -82,6 +82,11 @@ module Sisimai::Lhost
82
82
  next unless fieldtable[o[0]]
83
83
  v[fieldtable[o[0]]] = o[2]
84
84
 
85
+ if fieldtable[o[0]] == 'lhost'
86
+ # Do not set an email address as a hostname in "lhost" value
87
+ v['lhost'] = '' if v['lhost'].include?('@')
88
+ end
89
+
85
90
  next unless f == 1
86
91
  permessage[fieldtable[o[0]]] = o[2]
87
92
  end
@@ -71,7 +71,7 @@ module Sisimai::Lhost
71
71
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
72
72
  v = dscontents[-1]
73
73
  end
74
- v['recipient'] = cv[1]
74
+ v['recipient'] = Sisimai::Address.s3s4(cv[1])
75
75
  recipients += 1
76
76
  else
77
77
  # Other error message text
@@ -9,7 +9,7 @@ module Sisimai::Lhost
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
10
  ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
11
11
  StartingOf = {
12
- message: ['This is a MIME encoded message'],
12
+ message: ['Unable to deliver message to:'],
13
13
  error: ['Delivery failed for the following reason:'],
14
14
  }.freeze
15
15
 
@@ -34,8 +34,7 @@ module Sisimai::Lhost
34
34
  # to the previous line of the beginning of the original message.
35
35
  if readcursor == 0
36
36
  # Beginning of the bounce message or delivery status part
37
- readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
38
- next
37
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
39
38
  end
40
39
  next if (readcursor & Indicators[:deliverystatus]) == 0
41
40
  next if e.empty?
@@ -44,7 +43,7 @@ module Sisimai::Lhost
44
43
  # Delivery failed for the following reason:
45
44
  # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
46
45
  #
47
- # This has been a permanent failure. No further delivery attempts will be made.
46
+ # This has been a permanent failure. No further delivery attempts will be made.
48
47
  v = dscontents[-1]
49
48
 
50
49
  if cv = e.match(/\AUnable to deliver message to: [<]([^ ]+[@][^ ]+)[>]\z/)
@@ -32,10 +32,10 @@ module Sisimai::Lhost
32
32
  regularexp = nil
33
33
  v = nil
34
34
 
35
- boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
35
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
36
36
  regularexp = if boundary00.size > 0
37
37
  # Convert to regular expression
38
- Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z')
38
+ Regexp.new('\A' << Regexp.escape(boundary00) << '\z')
39
39
  else
40
40
  regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
41
41
  end
@@ -85,7 +85,7 @@ module Sisimai::Lhost
85
85
  match += 1 if mhead['from'].start_with?('Mail Delivery System')
86
86
  match += 1 if mhead['subject'] =~ %r{(?:
87
87
  Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
88
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
88
+ |Warning:[ ]message[ ][^ ]+[ ]delayed[ ]+
89
89
  |Delivery[ ]Status[ ]Notification
90
90
  )
91
91
  }x
@@ -14,7 +14,7 @@ module Sisimai::Lhost
14
14
  'User not listed in public Name & Address Book',
15
15
  'ディレクトリのリストにありません',
16
16
  ],
17
- networkerror: ['Message has exceeded maximum hop count'],
17
+ 'networkerror' => ['Message has exceeded maximum hop count'],
18
18
  }.freeze
19
19
 
20
20
  # Parse bounce messages from Lotus Notes