sisimai 5.3.0-java → 5.4.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +12 -0
  3. data/Makefile +3 -2
  4. data/README-JA.md +2 -2
  5. data/README.md +6 -6
  6. data/lib/sisimai/address.rb +45 -56
  7. data/lib/sisimai/arf.rb +11 -16
  8. data/lib/sisimai/datetime.rb +16 -50
  9. data/lib/sisimai/fact/json.rb +5 -5
  10. data/lib/sisimai/fact/yaml.rb +3 -3
  11. data/lib/sisimai/fact.rb +11 -12
  12. data/lib/sisimai/lda.rb +3 -3
  13. data/lib/sisimai/lhost/activehunter.rb +4 -6
  14. data/lib/sisimai/lhost/amazonses.rb +5 -6
  15. data/lib/sisimai/lhost/apachejames.rb +7 -9
  16. data/lib/sisimai/lhost/biglobe.rb +3 -5
  17. data/lib/sisimai/lhost/courier.rb +4 -6
  18. data/lib/sisimai/lhost/domino.rb +4 -5
  19. data/lib/sisimai/lhost/dragonfly.rb +3 -5
  20. data/lib/sisimai/lhost/einsundeins.rb +6 -8
  21. data/lib/sisimai/lhost/exchange2003.rb +10 -12
  22. data/lib/sisimai/lhost/exchange2007.rb +4 -5
  23. data/lib/sisimai/lhost/exim.rb +6 -8
  24. data/lib/sisimai/lhost/ezweb.rb +10 -12
  25. data/lib/sisimai/lhost/fml.rb +2 -3
  26. data/lib/sisimai/lhost/gmail.rb +4 -6
  27. data/lib/sisimai/lhost/gmx.rb +6 -8
  28. data/lib/sisimai/lhost/googlegroups.rb +1 -2
  29. data/lib/sisimai/lhost/googleworkspace.rb +3 -4
  30. data/lib/sisimai/lhost/imailserver.rb +6 -7
  31. data/lib/sisimai/lhost/interscanmss.rb +1 -2
  32. data/lib/sisimai/lhost/kddi.rb +5 -8
  33. data/lib/sisimai/lhost/mailfoundry.rb +4 -7
  34. data/lib/sisimai/lhost/mailmarshalsmtp.rb +4 -6
  35. data/lib/sisimai/lhost/messagingserver.rb +5 -7
  36. data/lib/sisimai/lhost/mfilter.rb +4 -6
  37. data/lib/sisimai/lhost/notes.rb +7 -9
  38. data/lib/sisimai/lhost/opensmtpd.rb +2 -4
  39. data/lib/sisimai/lhost/postfix.rb +8 -11
  40. data/lib/sisimai/lhost/qmail.rb +5 -8
  41. data/lib/sisimai/lhost/sendmail.rb +7 -10
  42. data/lib/sisimai/lhost/v5sendmail.rb +15 -17
  43. data/lib/sisimai/lhost/verizon.rb +9 -14
  44. data/lib/sisimai/lhost/x1.rb +4 -6
  45. data/lib/sisimai/lhost/x2.rb +5 -7
  46. data/lib/sisimai/lhost/x3.rb +3 -4
  47. data/lib/sisimai/lhost/x6.rb +4 -6
  48. data/lib/sisimai/lhost/zoho.rb +6 -8
  49. data/lib/sisimai/lhost.rb +1 -1
  50. data/lib/sisimai/mail/mbox.rb +1 -1
  51. data/lib/sisimai/mail/memory.rb +1 -1
  52. data/lib/sisimai/mail.rb +8 -8
  53. data/lib/sisimai/message.rb +11 -13
  54. data/lib/sisimai/reason/authfailure.rb +10 -10
  55. data/lib/sisimai/reason/badreputation.rb +4 -6
  56. data/lib/sisimai/reason/blocked.rb +6 -8
  57. data/lib/sisimai/reason/contenterror.rb +5 -6
  58. data/lib/sisimai/reason/delivered.rb +2 -2
  59. data/lib/sisimai/reason/exceedlimit.rb +7 -8
  60. data/lib/sisimai/reason/expired.rb +6 -7
  61. data/lib/sisimai/reason/failedstarttls.rb +5 -7
  62. data/lib/sisimai/reason/feedback.rb +2 -2
  63. data/lib/sisimai/reason/filtered.rb +7 -10
  64. data/lib/sisimai/reason/hasmoved.rb +4 -5
  65. data/lib/sisimai/reason/hostunknown.rb +6 -7
  66. data/lib/sisimai/reason/mailboxfull.rb +7 -8
  67. data/lib/sisimai/reason/mailererror.rb +5 -8
  68. data/lib/sisimai/reason/mesgtoobig.rb +5 -6
  69. data/lib/sisimai/reason/networkerror.rb +5 -8
  70. data/lib/sisimai/reason/norelaying.rb +4 -5
  71. data/lib/sisimai/reason/notaccept.rb +5 -8
  72. data/lib/sisimai/reason/notcompliantrfc.rb +5 -6
  73. data/lib/sisimai/reason/onhold.rb +6 -9
  74. data/lib/sisimai/reason/policyviolation.rb +6 -9
  75. data/lib/sisimai/reason/rejected.rb +5 -6
  76. data/lib/sisimai/reason/requireptr.rb +6 -7
  77. data/lib/sisimai/reason/securityerror.rb +6 -9
  78. data/lib/sisimai/reason/spamdetected.rb +8 -9
  79. data/lib/sisimai/reason/speeding.rb +6 -7
  80. data/lib/sisimai/reason/suppressed.rb +3 -7
  81. data/lib/sisimai/reason/suspend.rb +5 -7
  82. data/lib/sisimai/reason/syntaxerror.rb +3 -5
  83. data/lib/sisimai/reason/systemerror.rb +6 -9
  84. data/lib/sisimai/reason/systemfull.rb +5 -8
  85. data/lib/sisimai/reason/toomanyconn.rb +5 -6
  86. data/lib/sisimai/reason/undefined.rb +2 -2
  87. data/lib/sisimai/reason/userunknown.rb +8 -9
  88. data/lib/sisimai/reason/vacation.rb +4 -5
  89. data/lib/sisimai/reason/virusdetected.rb +4 -5
  90. data/lib/sisimai/reason.rb +13 -13
  91. data/lib/sisimai/rfc1123.rb +4 -8
  92. data/lib/sisimai/rfc1894.rb +5 -6
  93. data/lib/sisimai/rfc2045.rb +27 -31
  94. data/lib/sisimai/rfc3464/thirdparty.rb +1 -1
  95. data/lib/sisimai/rfc3464.rb +7 -9
  96. data/lib/sisimai/rfc3834.rb +5 -9
  97. data/lib/sisimai/rfc5322.rb +8 -26
  98. data/lib/sisimai/rfc791.rb +6 -4
  99. data/lib/sisimai/rhost/google.rb +8 -0
  100. data/lib/sisimai/rhost/microsoft.rb +17 -5
  101. data/lib/sisimai/rhost.rb +2 -2
  102. data/lib/sisimai/smtp/command.rb +1 -1
  103. data/lib/sisimai/smtp/failure.rb +5 -12
  104. data/lib/sisimai/smtp/reply.rb +3 -5
  105. data/lib/sisimai/smtp/status.rb +14 -24
  106. data/lib/sisimai/smtp/transcript.rb +1 -10
  107. data/lib/sisimai/string.rb +20 -30
  108. data/lib/sisimai/version.rb +1 -1
  109. data/lib/sisimai.rb +11 -11
  110. data/set-of-emails/maildir/bsd/rhost-microsoft-06.eml +45 -0
  111. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29756003d212276947b7b49d29a10fcf47230ed82d76dce258a446e4e4aaafa9
4
- data.tar.gz: d4dd4f6f77820a1e78f4862518e4f25c4017727ef619dd3c36b938cde77207b4
3
+ metadata.gz: 6e7c01c8568c5c1922dc71d9948d86eb8684bf18a981243b3e476a2de4d187f6
4
+ data.tar.gz: 0ca7b2415f6afc00b98f9e8e25b939f9962d0aba7c08f0c1689647a26f6329ec
5
5
  SHA512:
6
- metadata.gz: 88875b98d81bbb2367254e516ce4b6ee48a78d706d857bcc913235cf2f1d45c5c2cc528ecb34d162656ccf5757abf1c54beb69bf790170bc7dc246025caddd4b
7
- data.tar.gz: e6441418d25648f4bed4eb90cb9688fb321f76c1e929997e29450dae168e2e983825d2b404c3d74f865f761fbba21aac0172dd379fa54a488c61f4e7293edb5b
6
+ metadata.gz: 201468479dbd8c7cf75d6ac3d7560e2ec9bf9badb6d9a847c5979264138477699450a15a9553e1e919f69dd8f369c9792af6fac56e2a07eea5940daa4a943273
7
+ data.tar.gz: 933f217ffb3bc6092e2f338a4df40291e11ad3c59b6bdb22e56ba53d9b88368ff21ab37687d2dc87873f3ce4327aede14913616312eff1ee716768a7c960b816
data/ChangeLog.md CHANGED
@@ -3,6 +3,18 @@ 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
+ v5.4.0
7
+ ---------------------------------------------------------------------------------------------------
8
+ - release: "Tue, 1 Jul 2025 20:22:22 +0900 (JST)"
9
+ - version: "5.4.0"
10
+ - changes:
11
+ - #341 #342 #345 Implement the new status code `5.7.515` as `authfailure` and other undocumented
12
+ status codes begin with `4.4.` as `systemerror` of Microsoft in `Sisimai::Rhost::Microsoft`.
13
+ - #343 #346 Some internal methods do not return `nil`, standardize return values to align with
14
+ zero-value principle.
15
+ - #347 Support a frozen string literal
16
+ - #349 #350 Implement new status codes of Google: `4.7.40` and `5.7.32` as `authfailure`.
17
+
6
18
  v5.3.0
7
19
  ---------------------------------------------------------------------------------------------------
8
20
  - release: "Sat, 29 Mar 2025 06:04:41 +0900 (JST)"
data/Makefile CHANGED
@@ -16,6 +16,7 @@ CP := cp
16
16
  RM := rm -f
17
17
 
18
18
  DEPENDENCIES = bundle rake minitest
19
+ RUBYARGUMENT = --enable-frozen-string-literal
19
20
  .DEFAULT_GOAL = git-status
20
21
  REPOS_TARGETS = git-status git-push git-commit-amend git-tag-list git-diff git-reset-soft \
21
22
  git-rm-cached git-branch
@@ -58,11 +59,11 @@ release:
58
59
  test: user-test author-test
59
60
  user-test:
60
61
  # Suppress warning messages until v5.5.0
61
- rake publictest 2> /dev/null
62
+ RUBYOPT="$(RUBYARGUMENT)" rake publictest 2> /dev/null
62
63
 
63
64
  author-test:
64
65
  # Suppress warning messages until v5.5.0
65
- rake privatetest 2> /dev/null
66
+ RUBYOPT="$(RUBYARGUMENT)" rake privatetest 2> /dev/null
66
67
 
67
68
  check:
68
69
  find lib -type f -exec grep --color -E ' $$' {} /dev/null \;
data/README-JA.md CHANGED
@@ -23,7 +23,7 @@
23
23
  > SisimaiはPerlモジュールまたはRuby Gemですが、PHPやPython、GoやRustなどJSONを読める言語であれば
24
24
  > どのような環境においても解析結果を得ることでバウンスの発生状況を捉えるのにとても有用です。
25
25
 
26
- - [**README(English)**](README.md)
26
+ - [**README(🇬🇧)**](README.md)
27
27
  - [シシマイ? | What is Sisimai](#what-is-sisimai)
28
28
  - [主な特徴的機能 | The key features](#the-key-features-of-sisimai)
29
29
  - [コマンドラインでのデモ | Command line demo](#command-line-demo)
@@ -447,7 +447,7 @@ Related sites
447
447
 
448
448
  See also
449
449
  ---------------------------------------------------------------------------------------------------
450
- * [README.md - README.md in English](https://github.com/sisimai/rb-sisimai/blob/master/README.md)
450
+ * [README.md - README.md in English(🇬🇧)](https://github.com/sisimai/rb-sisimai/blob/master/README.md)
451
451
  * [RFC3463 - Enhanced Mail System Status Codes](https://tools.ietf.org/html/rfc3463)
452
452
  * [RFC3464 - An Extensible Message Format for Delivery Status Notifications](https://tools.ietf.org/html/rfc3464)
453
453
  * [RFC3834 - Recommendations for Automatic Responses to Electronic Mail](https://tools.ietf.org/html/rfc3834)
data/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
  > such as PHP, Python, Go, and Rust. By obtaining the analysis results, it is very useful for understanding
26
26
  > the bounce occurrence status.
27
27
 
28
- - [**README-JA(日本�**](README-JA.md)
28
+ - [**README-JA(🇯🇵)**](README-JA.md)
29
29
  - [What is Sisimai](#what-is-sisimai)
30
30
  - [The key features of sisimai](#the-key-features-of-sisimai)
31
31
  - [Command line demo](#command-line-demo)
@@ -57,10 +57,10 @@
57
57
 
58
58
  What is Sisimai
59
59
  ===================================================================================================
60
- Sisimai is a library that decodes complex and diverse bounce emails and outputs the results of the
61
- delivery failure, such as the reason for the bounce and the recipient email address, in structured
62
- data. It is also possible to output in JSON format. The Ruby version of Sisimai is ported from the
63
- Perl version of Sisimai at [github.com/sisimai/p5-sisimai](https://github.com/sisimai/p5-sisimai/).
60
+ Sisimai (pronounced /ɕi.ɕi.ma.i/) is a library that decodes complex and diverse bounce emails and
61
+ outputs the results of the delivery failure, such as the reason for the bounce and the recipient
62
+ email address, in structured data. It is also possible to output in JSON format. The Ruby version
63
+ of Sisimai is ported from [the Perl version of Sisimai](https://github.com/sisimai/p5-sisimai/).
64
64
 
65
65
  ![](https://libsisimai.org/static/images/figure/sisimai-overview-2.png)
66
66
 
@@ -450,7 +450,7 @@ Related Sites
450
450
 
451
451
  See also
452
452
  ---------------------------------------------------------------------------------------------------
453
- * [README-JA.md - README.md in Japanese(日本�](https://github.com/sisimai/rb-sisimai/blob/master/README-JA.md)
453
+ * [README-JA.md - README.md in Japanese(🇯🇵)](https://github.com/sisimai/rb-sisimai/blob/master/README-JA.md)
454
454
  * [RFC3463 - Enhanced Mail System Status Codes](https://tools.ietf.org/html/rfc3463)
455
455
  * [RFC3464 - An Extensible Message Format for Delivery Status Notifications](https://tools.ietf.org/html/rfc3464)
456
456
  * [RFC3834 - Recommendations for Automatic Responses to Electronic Mail](https://tools.ietf.org/html/rfc3834)
@@ -12,7 +12,7 @@ module Sisimai
12
12
  # dtext = NO-WS-CTL / ; Non white space controls
13
13
  # %d33-90 / ; The rest of the US-ASCII
14
14
  # %d94-126 ; characters not including "[", "]", or "\"
15
- re = { rfc5322: nil, ignored: nil, domain: nil }
15
+ re = {rfc5322: nil, ignored: nil, domain: nil}
16
16
  atom = %r([a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)o
17
17
  quoted_string = %r/"(?:\\[^\r\n]|[^\\"])*"/o
18
18
  domain_literal = %r/\[(?:\\[\x01-\x09\x0B-\x0c\x0e-\x7f]|[\x21-\x5a\x5e-\x7e])*\]/o
@@ -33,7 +33,7 @@ module Sisimai
33
33
  :'quoted-string' => (1 << 1), # "Neko, Nyaan"
34
34
  :'comment-block' => (1 << 2), # (neko)
35
35
  }.freeze
36
- Delimiters = { '<' => 1, '>' => 1, '(' => 1, ')' => 1, '"' => 1, ',' => 1 }.freeze
36
+ Delimiters = {'<' => 1, '>' => 1, '(' => 1, ')' => 1, '"' => 1, ',' => 1}.freeze
37
37
 
38
38
  # Return pseudo recipient or sender address
39
39
  # @param [Symbol] argv0 Address type: true = recipient, false = sender
@@ -45,12 +45,10 @@ module Sisimai
45
45
 
46
46
  # Check that the argument is an email address or not
47
47
  # @param [String] email Email address string
48
- # @return [True,False] true: is an email address
49
- # false: is not an email address
48
+ # @return [Boolean] true: is an email address, false: is not an email address
50
49
  def self.is_emailaddress(email)
51
- return false unless email.is_a?(::String)
52
- return false if email =~ %r/(?:[\x00-\x1f]|\x1f)/
53
- return false if email.size > 254
50
+ return false if email.is_a?(::String) == false
51
+ return false if email =~ %r/(?:[\x00-\x1f]|\x1f)/ || email.size > 254
54
52
  return true if email =~ Re[:ignored]
55
53
  return false
56
54
  end
@@ -60,9 +58,7 @@ module Sisimai
60
58
  # @return [True,False] true: mailer-daemon
61
59
  # false: Not mailer-daemon
62
60
  def self.is_mailerdaemon(argv0 = nil)
63
- return false unless argv0
64
- return false unless argv0.size > 0
65
- return false unless argv0.is_a?(::String)
61
+ return false if argv0.to_s == "" || argv0.is_a?(::String) == false
66
62
 
67
63
  email = argv0.downcase
68
64
  postmaster = [
@@ -71,8 +67,7 @@ module Sisimai
71
67
  ].freeze
72
68
 
73
69
  return true if postmaster.any? { |a| email.include?(a) }
74
- return true if email == 'mailer-daemon'
75
- return true if email == 'postmaster'
70
+ return true if email == 'mailer-daemon' || email == 'postmaster'
76
71
  return false
77
72
  end
78
73
 
@@ -87,7 +82,7 @@ module Sisimai
87
82
  # #=> [{ address: 'neko@example.org', name: 'Neko', comment: '(nyaan)'}]
88
83
  return nil unless argv1
89
84
 
90
- emailtable = { address: '', name: '', comment: '' }
85
+ emailtable = {address: '', name: '', comment: ''}
91
86
  addrtables = []
92
87
  readbuffer = []
93
88
  readcursor = 0
@@ -109,20 +104,20 @@ module Sisimai
109
104
  # An email address has already been picked
110
105
  if readcursor & Indicators[:'comment-block'] > 0
111
106
  # The cursor is in the comment block (Neko, Nyaan)
112
- v[:comment] << e
107
+ v[:comment] += e
113
108
  elsif readcursor & Indicators[:'quoted-string'] > 0
114
109
  # "Neko, Nyaan"
115
- v[:name] << e
110
+ v[:name] += e
116
111
  else
117
112
  # The cursor is not in neither the quoted-string nor the comment block
118
113
  readcursor = 0 # reset cursor position
119
114
  readbuffer << v
120
- v = { address: '', name: '', comment: '' }
115
+ v = {address: '', name: '', comment: ''}
121
116
  p = ''
122
117
  end
123
118
  else
124
119
  # "Neko, Nyaan" <neko@nyaan.example.org> OR <"neko,nyaan"@example.org>
125
- p.empty? ? (v[:name] << e) : (v[p] << e)
120
+ p.empty? ? (v[:name] += e) : (v[p] += e)
126
121
  end
127
122
  next
128
123
  end # End of if(',')
@@ -130,11 +125,11 @@ module Sisimai
130
125
  if e == '<'
131
126
  # <: The beginning of an email address or not
132
127
  if v[:address].size > 0
133
- p.empty? ? (v[:name] << e) : (v[p] << e)
128
+ p.empty? ? (v[:name] += e) : (v[p] += e)
134
129
  else
135
130
  # <neko@nyaan.example.org>
136
131
  readcursor |= Indicators[:'email-address']
137
- v[:address] << e
132
+ v[:address] += e
138
133
  p = :address
139
134
  end
140
135
  next
@@ -146,11 +141,11 @@ module Sisimai
146
141
  if readcursor & Indicators[:'email-address'] > 0
147
142
  # <neko@example.org>
148
143
  readcursor &= ~Indicators[:'email-address']
149
- v[:address] << e
144
+ v[:address] += e
150
145
  p = ''
151
146
  else
152
147
  # a comment block or a display name
153
- p.empty? ? (v[:name] << e) : (v[:comment] << e)
148
+ p.empty? ? (v[:name] == e) : (v[:comment] -= e)
154
149
  end
155
150
  next
156
151
  end # End of if('>')
@@ -161,27 +156,27 @@ module Sisimai
161
156
  # <"neko(nyaan)"@example.org> or <neko(nyaan)@example.org>
162
157
  if v[:address].include?('"')
163
158
  # Quoted local part: <"neko(nyaan)"@example.org>
164
- v[:address] << e
159
+ v[:address] += e
165
160
  else
166
161
  # Comment: <neko(nyaan)@example.org>
167
162
  readcursor |= Indicators[:'comment-block']
168
- v[:comment] << ' ' if v[:comment].end_with?(')')
169
- v[:comment] << e
163
+ v[:comment] += ' ' if v[:comment].end_with?(')')
164
+ v[:comment] += e
170
165
  p = :comment
171
166
  end
172
167
  elsif readcursor & Indicators[:'comment-block'] > 0
173
168
  # Comment at the outside of an email address (...(...)
174
- v[:comment] << ' ' if v[:comment].end_with?(')')
175
- v[:comment] << e
169
+ v[:comment] += ' ' if v[:comment].end_with?(')')
170
+ v[:comment] += e
176
171
 
177
172
  elsif readcursor & Indicators[:'quoted-string'] > 0
178
173
  # "Neko, Nyaan(cat)", Deal as a display name
179
- v[:name] << e
174
+ v[:name] += e
180
175
  else
181
176
  # The beginning of a comment block
182
177
  readcursor |= Indicators[:'comment-block']
183
- v[:comment] << ' ' if v[:comment].end_with?(')')
184
- v[:comment] << e
178
+ v[:comment] += ' ' if v[:comment].end_with?(')')
179
+ v[:comment] += e
185
180
  p = :comment
186
181
  end
187
182
  next
@@ -193,22 +188,22 @@ module Sisimai
193
188
  # <"neko(nyaan)"@example.org> OR <neko(nyaan)@example.org>
194
189
  if v[:address].include?('"')
195
190
  # Quoted string in the local part: <"neko(nyaan)"@example.org>
196
- v[:address] << e
191
+ v[:address] += e
197
192
  else
198
193
  # Comment: <neko(nyaan)@example.org>
199
194
  readcursor &= ~Indicators[:'comment-block']
200
- v[:comment] << e
195
+ v[:comment] += e
201
196
  p = :address
202
197
  end
203
198
  elsif readcursor & Indicators[:'comment-block'] > 0
204
199
  # Comment at the outside of an email address (...(...)
205
200
  readcursor &= ~Indicators[:'comment-block']
206
- v[:comment] << e
201
+ v[:comment] += e
207
202
  p = ''
208
203
  else
209
204
  # Deal as a display name
210
205
  readcursor &= ~Indicators[:'comment-block']
211
- v[:name] << e
206
+ v[:name] += e
212
207
  p = ''
213
208
  end
214
209
  next
@@ -218,10 +213,10 @@ module Sisimai
218
213
  # The beginning or the end of a quoted-string
219
214
  if p.size > 0
220
215
  # email-address or comment-block
221
- v[p] << e
216
+ v[p] += e
222
217
  else
223
218
  # Display name like "Neko, Nyaan"
224
- v[:name] << e
219
+ v[:name] += e
225
220
  next unless readcursor & Indicators[:'quoted-string'] > 0
226
221
  next if v[:name].end_with?(%Q|\x5c"|) # "Neko, Nyaan \"...
227
222
  readcursor &= ~Indicators[:'quoted-string']
@@ -231,7 +226,7 @@ module Sisimai
231
226
  end # End of if('"')
232
227
  else
233
228
  # The character is not a delimiter
234
- p.empty? ? (v[:name] << e) : (v[p] << e)
229
+ p.empty? ? (v[:name] += e) : (v[p] += e)
235
230
  next
236
231
  end
237
232
  end
@@ -283,7 +278,7 @@ module Sisimai
283
278
  e.delete(:comment)
284
279
  else
285
280
  # Remove double-quotations, trailing spaces.
286
- [:name, :comment].each { |f| e[f].strip! }
281
+ [:name, :comment].each { |f| e[f] = e[f].strip }
287
282
  e[:comment] = '' unless e[:comment] =~ /\A[(].+[)]/
288
283
  e[:name].squeeze!(' ') unless e[:name] =~ /\A["].+["]\z/
289
284
  e[:name].sub!(/\A["]/, '') unless e[:name] =~ /\A["].+["][@]/
@@ -301,8 +296,8 @@ module Sisimai
301
296
  # @return [String] Email address without comment, brackets
302
297
  # @example s3s4('<neko@example.cat>') #=> 'neko@example.cat'
303
298
  def self.s3s4(input)
304
- return nil unless input
305
- return input unless input.is_a? Object::String
299
+ return "" if input.to_s == ""
300
+ return "" if input.is_a?(Object::String) == false
306
301
 
307
302
  addrs = Sisimai::Address.find(input, true) || []
308
303
  return input if addrs.empty?
@@ -315,8 +310,8 @@ module Sisimai
315
310
  # @example Expand VERP address
316
311
  # expand_verp('bounce+neko=example.org@example.org') #=> 'neko@example.org'
317
312
  def self.expand_verp(email)
318
- return nil unless email.is_a? Object::String
319
- return nil unless cv = email.split('@', 2).first.match(/\A[-\w]+?[+](\w[-.\w]+\w)[=](\w[-.\w]+\w)\z/)
313
+ return "" unless email.is_a? Object::String
314
+ return "" unless cv = email.split('@', 2).first.match(/\A[-\w]+?[+](\w[-.\w]+\w)[=](\w[-.\w]+\w)\z/)
320
315
  verp0 = cv[1] + '@' + cv[2]
321
316
  return verp0 if Sisimai::Address.is_emailaddress(verp0)
322
317
  end
@@ -327,10 +322,10 @@ module Sisimai
327
322
  # @example Expand alias
328
323
  # expand_alias('neko+straycat@example.org') #=> 'neko@example.org'
329
324
  def self.expand_alias(email)
330
- return nil unless Sisimai::Address.is_emailaddress(email)
325
+ return "" unless Sisimai::Address.is_emailaddress(email)
331
326
 
332
327
  local = email.split('@')
333
- return nil unless cv = local[0].match(/\A([-\w]+?)[+].+\z/)
328
+ return "" unless cv = local[0].match(/\A([-\w]+?)[+].+\z/)
334
329
  return cv[1] + '@' + local[1]
335
330
  end
336
331
 
@@ -347,11 +342,9 @@ module Sisimai
347
342
  # Constructor of Sisimai::Address
348
343
  # @param [Hash] argvs Email address, name, and other elements
349
344
  # @return [Sisimai::Address] Object or nil when the email address was not valid.
350
- # @example new({address: 'neko@example.org', name: 'Neko', comment: '(nyaan)')} # => Sisimai::Address object
345
+ # @example new(address: 'neko@example.org', name: 'Neko', comment: '(nyaan)') # => Sisimai::Address object
351
346
  def initialize(argvs)
352
- return nil unless argvs.is_a? Hash
353
- return nil unless argvs[:address]
354
- return nil if argvs[:address].empty?
347
+ return nil if argvs.is_a?(Hash) == false || argvs[:address].nil? || argvs[:address].empty?
355
348
 
356
349
  heads = ['<']
357
350
  tails = ['>', ',', '.', ';']
@@ -364,10 +357,10 @@ module Sisimai
364
357
  email = Sisimai::Address.expand_verp(argvs[:address])
365
358
  aname = nil
366
359
 
367
- unless email
360
+ if email.empty?
368
361
  # Is not VERP address, try to expand the address as an alias
369
- email = Sisimai::Address.expand_alias(argvs[:address]) || ''
370
- aname = true unless email.empty?
362
+ email = Sisimai::Address.expand_alias(argvs[:address])
363
+ aname = true if email.empty? == false
371
364
  end
372
365
 
373
366
  if email.include?('@')
@@ -422,15 +415,11 @@ module Sisimai
422
415
 
423
416
  # Returns the value of address as String
424
417
  # @return [String] Email address
425
- def to_json(*)
426
- return self.address.to_s
427
- end
418
+ def to_json(*); return self.address.to_s; end
428
419
 
429
420
  # Returns the value of address as String
430
421
  # @return [String] Email address
431
- def to_s
432
- return self.address.to_s
433
- end
422
+ def to_s; return self.address.to_s; end
434
423
 
435
424
  end
436
425
  end
data/lib/sisimai/arf.rb CHANGED
@@ -53,12 +53,9 @@ module Sisimai
53
53
  end
54
54
  end
55
55
 
56
- while true
57
- # X-Apple-Unsubscribe: true
58
- break unless heads.has_key?("x-apple-unsubscribe")
59
- return true if heads["x-apple-unsubscribe"] == "true"
60
- break
61
- end
56
+ # X-Apple-Unsubscribe: true
57
+ return false unless heads.has_key?("x-apple-unsubscribe")
58
+ return true if heads["x-apple-unsubscribe"] == "true"
62
59
  return false
63
60
  end
64
61
 
@@ -70,7 +67,7 @@ module Sisimai
70
67
  def inquire(mhead, mbody)
71
68
  return nil unless self.is_arf(mhead)
72
69
 
73
- dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
70
+ dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = dscontents[-1]
74
71
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
75
72
  bodyslices = emailparts[0].split("\n")
76
73
  reportpart = false
@@ -80,7 +77,6 @@ module Sisimai
80
77
  remotehost = "" # The value of "Source-IP" field
81
78
  reportedby = "" # The value of "Reporting-MTA" field
82
79
  anotherone = "" # Other fields(append to Diagnosis)
83
- v = dscontents[-1]
84
80
 
85
81
  # 3.1. Required Fields
86
82
  #
@@ -115,13 +111,12 @@ module Sisimai
115
111
  # this is an autogenerated email abuse complaint regarding your network.
116
112
  next unless Sisimai::String.aligned(r, f)
117
113
  readcursor |= Indicators[:deliverystatus]
118
- v["diagnosis"] << " " + e
114
+ v["diagnosis"] += " #{e}"
119
115
  break
120
116
  end
121
117
  next
122
118
  end
123
- next unless readcursor & Indicators[:deliverystatus] > 0
124
- next if e.empty?
119
+ next if (readcursor & Indicators[:deliverystatus]) > 0 || e.empty?
125
120
  if e == ReportFrom then reportpart = true; next; end
126
121
 
127
122
  if reportpart
@@ -158,12 +153,12 @@ module Sisimai
158
153
  #
159
154
  # Authentication-Results: mail.example.com;
160
155
  # spf=fail smtp.mail=somespammer@example.com
161
- anotherone << e + ", "
156
+ anotherone += "#{e}, "
162
157
 
163
158
  elsif e.start_with?("User-Agent: ")
164
159
  # The header field MUST appear exactly once.
165
160
  # User-Agent: SomeGenerator/1.0
166
- anotherone << e + ", "
161
+ anotherone += "#{e}, "
167
162
 
168
163
  elsif e.start_with?("Received-Date: ") || e.start_with?("Arrival-Date: ")
169
164
  # Arrival-Date header is optional and MUST NOT appear more than once.
@@ -185,11 +180,11 @@ module Sisimai
185
180
  elsif e.start_with?("Original-Mail-From: ")
186
181
  # the header is optional and MUST NOT appear more than once.
187
182
  # Original-Mail-From: <somespammer@example.net>
188
- anotherone << e + ", "
183
+ anotherone += "#{e}, "
189
184
  end
190
185
  else
191
186
  # Messages before "Content-Type: message/feedback-report" part
192
- v["diagnosis"] << " " + e
187
+ v["diagnosis"] += " #{e}"
193
188
  end
194
189
 
195
190
  while recipients == 0
@@ -220,7 +215,7 @@ module Sisimai
220
215
  end
221
216
  return nil if recipients == 0
222
217
 
223
- anotherone = ": " + Sisimai::String.sweep(anotherone) if anotherone != ""
218
+ anotherone = ": #{Sisimai::String.sweep(anotherone)}" if anotherone != ""
224
219
  anotherone = anotherone.chop if anotherone[-1, 1] == ","
225
220
 
226
221
  j = -1
@@ -4,34 +4,7 @@ module Sisimai
4
4
  require 'date'
5
5
 
6
6
  class << self
7
- BASE_D = 86400 # 1 day = 86400 sec
8
- BASE_Y = 365.2425 # 1 year = 365.2425 days
9
- BASE_L = 29.53059 # 1 lunar month = 29.53059 days
10
-
11
- CONST_P = 4 * Math.atan2(1, 1) # PI, 3.1415926535
12
- CONST_E = Math.exp(1) # e, Napier's constant
13
- TZ_OFFSET = 54000 # Max time zone offset, 54000 seconds
14
-
15
- TimeUnit = {
16
- 'o' => (BASE_D * BASE_Y * 4), # Olympiad, 4 years
17
- 'y' => (BASE_D * BASE_Y), # Year, Gregorian Calendar
18
- 'q' => (BASE_D * BASE_Y / 4), # Quarter, year/4
19
- 'l' => (BASE_D * BASE_L), # Lunar month
20
- 'f' => (BASE_D * 14), # Fortnight, 2 weeks
21
- 'w' => (BASE_D * 7), # Week, 604800 seconds
22
- 'd' => BASE_D, # Day
23
- 'h' => 3600, # Hour
24
- 'b' => 86.4, # Beat, Swatch internet time: 1000b = 1d
25
- 'm' => 60, # Minute,
26
- 's' => 1, # Second
27
- }.freeze
28
-
29
- MathematicalConstant = {
30
- 'e' => CONST_E,
31
- 'p' => CONST_P,
32
- 'g' => CONST_E**CONST_P,
33
- }.freeze
34
-
7
+ TZ_OFFSET = 54000 # Max time zone offset, 54000 seconds
35
8
  MonthName = {
36
9
  full: %w[January February March April May June July August September October November December],
37
10
  abbr: %w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec],
@@ -191,12 +164,9 @@ module Sisimai
191
164
  # parse("2015-11-03T23:34:45 Tue") #=> Tue, 3 Nov 2015 23:34:45 +0900
192
165
  # parse("Tue, Nov 3 2015 2:2:2") #=> Tue, 3 Nov 2015 02:02:02 +0900
193
166
  def parse(argv1)
194
- return nil unless argv1.is_a?(::String)
195
- return nil if argv1.empty?
167
+ return "" if argv1.is_a?(::String) == false || argv1.empty?
196
168
 
197
- datestring = argv1
198
- datestring.sub!(/[,](\d+)/, ', \1') # Thu,13 -> Thu, 13
199
- datestring.sub!(/(\d{1,2}),/, '\1') # Apr,29 -> Apr 29
169
+ datestring = argv1.sub(/[,](\d+)/, ', \1').sub(/(\d{1,2}),/, '\1')
200
170
  timetokens = datestring.split(' ')
201
171
  afternoon1 = 0 # (Integer) After noon flag
202
172
  altervalue = {} # (Hash) To store alternative values
@@ -267,7 +237,7 @@ module Sisimai
267
237
 
268
238
  elsif p =~ /\A[(]?[A-Z]{2,5}[)]?\z/
269
239
  # Timezone abbreviation; JST, GMT, UTC, ...
270
- v[:z] ||= abbr2tz(p) || '+0000'
240
+ v[:z] ||= abbr2tz(p); v[:z] = "+0000" if v[:z].empty?
271
241
  else
272
242
  # Other date format
273
243
  if cr = p.match(%r|\A(\d{4})[-/](\d{1,2})[-/](\d{1,2})\z|)
@@ -333,13 +303,9 @@ module Sisimai
333
303
  if v.value?(nil)
334
304
  # Strange date format
335
305
  warn sprintf(' ***warning: Strange date format [%s]', datestring)
336
- return nil
337
- end
338
-
339
- if v[:Y].to_i < 1902 || v[:Y].to_i > 2037
340
- # -(2^31) ~ (2^31)
341
- return nil
306
+ return ""
342
307
  end
308
+ return "" if v[:Y].to_i < 1902 || v[:Y].to_i > 2037 # -(2^31) ~ (2^31)
343
309
 
344
310
  # Build date string
345
311
  # Thu, 29 Apr 2004 10:01:11 +0900
@@ -348,23 +314,23 @@ module Sisimai
348
314
 
349
315
  # Abbreviation -> Tiemzone
350
316
  # @param [String] argv1 Abbr. e.g.) JST, GMT, PDT
351
- # @return [String, Nil] +0900, +0000, -0600 or nil if the argument is invalid format or
352
- # not supported abbreviation
317
+ # @return [String] +0900, +0000, -0600 or an empty string if the argument is invalid
318
+ # format or not supported abbreviation
353
319
  # @example Get the timezone string of "JST"
354
320
  # abbr2tz('JST') #=> '+0900'
355
321
  def abbr2tz(argv1)
356
- return nil unless argv1.is_a?(::String)
357
- return TimeZones[argv1]
322
+ return "" if argv1.is_a?(::String) == false
323
+ return TimeZones[argv1] || ""
358
324
  end
359
325
 
360
326
  # Convert to second
361
327
  # @param [String] argv1 Timezone string e.g) +0900
362
- # @return [Integer, Nil] n: seconds or nil it the argument is invalid format string
328
+ # @return [Integer] n: seconds or 0 when the argument is invalid format
363
329
  # @see second2tz
364
330
  # @example Convert '+0900' to seconds
365
331
  # tz2second('+0900') #=> 32400
366
332
  def tz2second(argv1)
367
- return nil unless argv1.is_a?(::String)
333
+ return 0 if argv1.is_a?(::String) == false
368
334
  ztime = 0
369
335
 
370
336
  if cr = argv1.match(/\A([-+])(\d)(\d)(\d{2})\z/)
@@ -378,13 +344,13 @@ module Sisimai
378
344
  ztime += (digit[:'minutes'] * 60)
379
345
  ztime *= -1 if digit[:'operator'] == '-'
380
346
 
381
- return nil if ztime.abs > TZ_OFFSET
347
+ return 0 if ztime.abs > TZ_OFFSET
382
348
  return ztime
383
349
 
384
350
  elsif argv1 =~ /\A[A-Za-z]+\z/
385
351
  return tz2second(TimeZones[argv1])
386
352
  else
387
- return nil
353
+ return 0
388
354
  end
389
355
  end
390
356
 
@@ -396,9 +362,9 @@ module Sisimai
396
362
  # second2tz(12345) #=> '+0325'
397
363
  def second2tz(argv1)
398
364
  return '+0000' unless argv1.is_a?(::Integer)
399
- return nil if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
365
+ return "" if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
400
366
 
401
- digit = { :operator => '+' }
367
+ digit = {:operator => '+'}
402
368
  digit[:operator] = '-' if argv1 < 0
403
369
  digit[:hours] = (argv1.abs / 3600).to_i
404
370
  digit[:minutes] = ((argv1.abs % 3600) / 60).to_i
@@ -6,10 +6,10 @@ module Sisimai
6
6
  class << self
7
7
  # Serializer (JSON)
8
8
  # @param [Sisimai::Fact] argvs Object
9
- # @return [String, nil] Dumped data or nil if the argument is missing
9
+ # @return [String] Dumped data or an empty string if the argument is missing
10
10
  def dump(argvs)
11
- return nil unless argvs
12
- return nil unless argvs.is_a? Sisimai::Fact
11
+ return "" unless argvs
12
+ return "" unless argvs.is_a? Sisimai::Fact
13
13
 
14
14
  if RUBY_PLATFORM.start_with?('java')
15
15
  # java-based ruby environment like JRuby.
@@ -17,7 +17,7 @@ module Sisimai
17
17
  require 'jrjackson'
18
18
  jsonstring = JrJackson::Json.dump(argvs.damn)
19
19
  rescue StandardError => ce
20
- warn '***warning: Failed to JrJackson::Json.dump: ' << ce.to_s
20
+ warn '***warning: Failed to JrJackson::Json.dump: ' + ce.to_s
21
21
  end
22
22
  else
23
23
  # MRI
@@ -25,7 +25,7 @@ module Sisimai
25
25
  require 'oj'
26
26
  jsonstring = Oj.dump(argvs.damn, :mode => :compat)
27
27
  rescue StandardError => ce
28
- warn '***warning: Failed to Oj.dump: ' << ce.to_s
28
+ warn '***warning: Failed to Oj.dump: ' + ce.to_s
29
29
  end
30
30
  end
31
31