sisimai 5.2.1-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.
- checksums.yaml +4 -4
- data/.github/workflows/rake-test.yml +1 -1
- data/ChangeLog.md +24 -0
- data/Makefile +3 -2
- data/README-JA.md +4 -4
- data/README.md +8 -8
- data/lib/sisimai/address.rb +45 -56
- data/lib/sisimai/arf.rb +11 -16
- data/lib/sisimai/datetime.rb +16 -50
- data/lib/sisimai/fact/json.rb +5 -5
- data/lib/sisimai/fact/yaml.rb +3 -3
- data/lib/sisimai/fact.rb +21 -12
- data/lib/sisimai/lda.rb +3 -3
- data/lib/sisimai/lhost/activehunter.rb +4 -6
- data/lib/sisimai/lhost/amazonses.rb +5 -6
- data/lib/sisimai/lhost/apachejames.rb +7 -9
- data/lib/sisimai/lhost/biglobe.rb +3 -5
- data/lib/sisimai/lhost/courier.rb +4 -6
- data/lib/sisimai/lhost/domino.rb +4 -5
- data/lib/sisimai/lhost/dragonfly.rb +3 -5
- data/lib/sisimai/lhost/einsundeins.rb +6 -8
- data/lib/sisimai/lhost/exchange2003.rb +10 -12
- data/lib/sisimai/lhost/exchange2007.rb +4 -5
- data/lib/sisimai/lhost/exim.rb +6 -8
- data/lib/sisimai/lhost/ezweb.rb +10 -12
- data/lib/sisimai/lhost/fml.rb +2 -3
- data/lib/sisimai/lhost/gmail.rb +4 -6
- data/lib/sisimai/lhost/gmx.rb +6 -8
- data/lib/sisimai/lhost/googlegroups.rb +1 -2
- data/lib/sisimai/lhost/googleworkspace.rb +3 -4
- data/lib/sisimai/lhost/imailserver.rb +6 -7
- data/lib/sisimai/lhost/interscanmss.rb +1 -2
- data/lib/sisimai/lhost/kddi.rb +5 -8
- data/lib/sisimai/lhost/mailfoundry.rb +4 -7
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +4 -6
- data/lib/sisimai/lhost/messagingserver.rb +5 -7
- data/lib/sisimai/lhost/mfilter.rb +4 -6
- data/lib/sisimai/lhost/notes.rb +7 -9
- data/lib/sisimai/lhost/opensmtpd.rb +2 -4
- data/lib/sisimai/lhost/postfix.rb +8 -11
- data/lib/sisimai/lhost/qmail.rb +5 -8
- data/lib/sisimai/lhost/sendmail.rb +7 -10
- data/lib/sisimai/lhost/v5sendmail.rb +15 -17
- data/lib/sisimai/lhost/verizon.rb +9 -14
- data/lib/sisimai/lhost/x1.rb +4 -6
- data/lib/sisimai/lhost/x2.rb +5 -7
- data/lib/sisimai/lhost/x3.rb +3 -4
- data/lib/sisimai/lhost/x6.rb +4 -6
- data/lib/sisimai/lhost/zoho.rb +6 -8
- data/lib/sisimai/lhost.rb +1 -1
- data/lib/sisimai/mail/mbox.rb +1 -1
- data/lib/sisimai/mail/memory.rb +1 -1
- data/lib/sisimai/mail.rb +8 -8
- data/lib/sisimai/message.rb +11 -13
- data/lib/sisimai/order.rb +12 -11
- data/lib/sisimai/reason/authfailure.rb +10 -10
- data/lib/sisimai/reason/badreputation.rb +4 -6
- data/lib/sisimai/reason/blocked.rb +6 -8
- data/lib/sisimai/reason/contenterror.rb +5 -6
- data/lib/sisimai/reason/delivered.rb +2 -2
- data/lib/sisimai/reason/exceedlimit.rb +7 -8
- data/lib/sisimai/reason/expired.rb +6 -7
- data/lib/sisimai/reason/failedstarttls.rb +5 -7
- data/lib/sisimai/reason/feedback.rb +2 -2
- data/lib/sisimai/reason/filtered.rb +7 -10
- data/lib/sisimai/reason/hasmoved.rb +4 -5
- data/lib/sisimai/reason/hostunknown.rb +6 -7
- data/lib/sisimai/reason/mailboxfull.rb +7 -8
- data/lib/sisimai/reason/mailererror.rb +5 -8
- data/lib/sisimai/reason/mesgtoobig.rb +5 -6
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +4 -5
- data/lib/sisimai/reason/notaccept.rb +5 -8
- data/lib/sisimai/reason/notcompliantrfc.rb +5 -6
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +6 -9
- data/lib/sisimai/reason/rejected.rb +5 -6
- data/lib/sisimai/reason/requireptr.rb +6 -7
- data/lib/sisimai/reason/securityerror.rb +6 -9
- data/lib/sisimai/reason/spamdetected.rb +8 -9
- data/lib/sisimai/reason/speeding.rb +6 -7
- data/lib/sisimai/reason/suppressed.rb +3 -7
- data/lib/sisimai/reason/suspend.rb +5 -7
- data/lib/sisimai/reason/syntaxerror.rb +3 -5
- data/lib/sisimai/reason/systemerror.rb +6 -9
- data/lib/sisimai/reason/systemfull.rb +5 -8
- data/lib/sisimai/reason/toomanyconn.rb +5 -6
- data/lib/sisimai/reason/undefined.rb +2 -2
- data/lib/sisimai/reason/userunknown.rb +8 -9
- data/lib/sisimai/reason/vacation.rb +4 -5
- data/lib/sisimai/reason/virusdetected.rb +4 -5
- data/lib/sisimai/reason.rb +13 -13
- data/lib/sisimai/rfc1123.rb +4 -8
- data/lib/sisimai/rfc1894.rb +5 -6
- data/lib/sisimai/rfc2045.rb +27 -31
- data/lib/sisimai/rfc3464/thirdparty.rb +1 -1
- data/lib/sisimai/rfc3464.rb +7 -9
- data/lib/sisimai/rfc3834.rb +5 -9
- data/lib/sisimai/rfc5322.rb +8 -26
- data/lib/sisimai/rfc791.rb +6 -4
- data/lib/sisimai/rhost/google.rb +8 -0
- data/lib/sisimai/rhost/microsoft.rb +17 -5
- data/lib/sisimai/rhost.rb +2 -2
- data/lib/sisimai/smtp/command.rb +1 -1
- data/lib/sisimai/smtp/failure.rb +5 -12
- data/lib/sisimai/smtp/reply.rb +33 -12
- data/lib/sisimai/smtp/status.rb +21 -22
- data/lib/sisimai/smtp/transcript.rb +1 -10
- data/lib/sisimai/string.rb +20 -30
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +11 -11
- data/set-of-emails/maildir/bsd/rhost-microsoft-06.eml +45 -0
- metadata +8 -10
data/lib/sisimai/datetime.rb
CHANGED
@@ -4,34 +4,7 @@ module Sisimai
|
|
4
4
|
require 'date'
|
5
5
|
|
6
6
|
class << self
|
7
|
-
|
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
|
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)
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
365
|
+
return "" if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
|
400
366
|
|
401
|
-
digit = {
|
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
|
data/lib/sisimai/fact/json.rb
CHANGED
@@ -6,10 +6,10 @@ module Sisimai
|
|
6
6
|
class << self
|
7
7
|
# Serializer (JSON)
|
8
8
|
# @param [Sisimai::Fact] argvs Object
|
9
|
-
# @return [String
|
9
|
+
# @return [String] Dumped data or an empty string if the argument is missing
|
10
10
|
def dump(argvs)
|
11
|
-
return
|
12
|
-
return
|
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: '
|
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: '
|
28
|
+
warn '***warning: Failed to Oj.dump: ' + ce.to_s
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
data/lib/sisimai/fact/yaml.rb
CHANGED
@@ -10,8 +10,8 @@ module Sisimai
|
|
10
10
|
# @param [Sisimai::Fact] argvs Object
|
11
11
|
# @return [String, nil] Dumped data or nil if the argument is missing
|
12
12
|
def dump(argvs)
|
13
|
-
return
|
14
|
-
return
|
13
|
+
return "" unless argvs
|
14
|
+
return "" unless argvs.is_a? Sisimai::Fact
|
15
15
|
|
16
16
|
damneddata = argvs.damn
|
17
17
|
yamlstring = nil
|
@@ -19,7 +19,7 @@ module Sisimai
|
|
19
19
|
begin
|
20
20
|
yamlstring = ::YAML.dump(damneddata)
|
21
21
|
rescue StandardError => ce
|
22
|
-
warn '***warning: Failed to YAML.dump: '
|
22
|
+
warn '***warning: Failed to YAML.dump: ' + ce.to_s
|
23
23
|
end
|
24
24
|
|
25
25
|
return yamlstring
|
data/lib/sisimai/fact.rb
CHANGED
@@ -48,7 +48,7 @@ module Sisimai
|
|
48
48
|
|
49
49
|
RetryIndex = Sisimai::Reason.retry
|
50
50
|
RFC822Head = Sisimai::RFC5322.HEADERTABLE
|
51
|
-
ActionList = {
|
51
|
+
ActionList = {delayed: 1, delivered: 1, expanded: 1, failed: 1, relayed: 1};
|
52
52
|
|
53
53
|
if RUBY_PLATFORM.start_with?('java')
|
54
54
|
# [WORKAROUND] #159 #267 JRuby seems to fail and throws exception at strptime(), but this
|
@@ -108,7 +108,7 @@ module Sisimai
|
|
108
108
|
return nil unless argvs.is_a? Hash
|
109
109
|
|
110
110
|
email = argvs[:data]; return nil unless email
|
111
|
-
args1 = {
|
111
|
+
args1 = {data: email, hook: argvs[:hook]}
|
112
112
|
mesg1 = Sisimai::Message.rise(**args1)
|
113
113
|
return nil unless mesg1
|
114
114
|
return nil unless mesg1['ds']
|
@@ -179,7 +179,7 @@ module Sisimai
|
|
179
179
|
datevalues << mesg1['header']['date'] if datevalues.size < 2
|
180
180
|
while v = datevalues.shift do
|
181
181
|
# Parse each date value in the array
|
182
|
-
datestring = Sisimai::DateTime.parse(v)
|
182
|
+
datestring = Sisimai::DateTime.parse(v); next if datestring.empty?
|
183
183
|
|
184
184
|
if cv = datestring.match(/\A(.+)[ ]+([-+]\d{4})\z/)
|
185
185
|
# Get the value of timezone offset from datestring: Wed, 26 Feb 2014 06:05:48 -0500
|
@@ -195,7 +195,7 @@ module Sisimai
|
|
195
195
|
t = TimeModule.strptime(datestring, '%a, %d %b %Y %T')
|
196
196
|
piece['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
|
197
197
|
rescue
|
198
|
-
warn
|
198
|
+
warn " ***warning: Failed to strptime #{datestring.to_s}"
|
199
199
|
end
|
200
200
|
next unless piece['timestamp']
|
201
201
|
|
@@ -402,8 +402,7 @@ module Sisimai
|
|
402
402
|
next unless er.include?(' for ')
|
403
403
|
|
404
404
|
af = Sisimai::RFC5322.received(er)
|
405
|
-
next if af.empty?
|
406
|
-
next if af[5].empty?
|
405
|
+
next if af.empty? || af[5].empty?
|
407
406
|
next unless Sisimai::Address.is_emailaddress(af[5])
|
408
407
|
next if thing['recipient'].address == af[5]
|
409
408
|
|
@@ -434,14 +433,14 @@ module Sisimai
|
|
434
433
|
thing['replycode'] = '' unless thing['reason'] == 'delivered'
|
435
434
|
else
|
436
435
|
# The reason is not "delivered", or "feedback", or "vacation"
|
437
|
-
smtperrors = piece['deliverystatus']
|
436
|
+
smtperrors = "#{piece['deliverystatus']} #{piece['diagnosticcode']}"
|
438
437
|
smtperrors = '' if smtperrors.size < 4
|
439
438
|
thing['hardbounce'] = Sisimai::SMTP::Failure.is_hardbounce(thing['reason'], smtperrors)
|
440
439
|
end
|
441
440
|
|
442
441
|
# DELIVERYSTATUS: Set a pseudo status code if the value of "deliverystatus" is empty
|
443
442
|
if thing['deliverystatus'].empty?
|
444
|
-
smtperrors = piece['replycode']
|
443
|
+
smtperrors = "#{piece['replycode']} #{piece['diagnosticcode']}"
|
445
444
|
smtperrors = '' if smtperrors.size < 4
|
446
445
|
permanent0 = Sisimai::SMTP::Failure.is_permanent(smtperrors)
|
447
446
|
temporary0 = Sisimai::SMTP::Failure.is_temporary(smtperrors)
|
@@ -459,7 +458,7 @@ module Sisimai
|
|
459
458
|
|
460
459
|
unless ActionList.has_key?(thing['action'])
|
461
460
|
# There is an action value which is not described at RFC1894
|
462
|
-
if ox = Sisimai::RFC1894.field(
|
461
|
+
if ox = Sisimai::RFC1894.field("Action: #{thing['action']}")
|
463
462
|
# Rewrite the value of "Action:" field to the valid value
|
464
463
|
#
|
465
464
|
# The syntax for the action-field is:
|
@@ -473,6 +472,16 @@ module Sisimai
|
|
473
472
|
thing["action"] = "delayed" if thing["action"].empty? && thing["reason"] == "expired"
|
474
473
|
thing["action"] = "failed" if thing["action"].empty? && cx[0] == "4" || cx[0] == "5"
|
475
474
|
|
475
|
+
if thing["replycode"].size > 0
|
476
|
+
# Fill empty values: ["SMTP Command", "DSN", "Reason"]
|
477
|
+
cv = Sisimai::SMTP::Reply.associatedwith(thing["replycode"])
|
478
|
+
if cv.size > 0
|
479
|
+
thing["command"] = cv[0] if cv[0] != "" && thing["command"].empty?
|
480
|
+
thing["deliverystatus"] = cv[1] if cv[1] != "" && Sisimai::SMTP::Status.is_explicit(thing["deliverystatus"]) == false
|
481
|
+
thing["reason"] = cv[2] if cv[2] != "" && Sisimai::Reason.is_explicit(thing["reason"]) == false
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
476
485
|
# Feedback-ID: 1.us-west-2.QHuyeCQrGtIIMGKQfVdUhP9hCQR2LglVOrRamBc+Prk=:AmazonSES
|
477
486
|
thing["feedbackid"] = rfc822data["feedback-id"] || ""
|
478
487
|
|
@@ -499,7 +508,7 @@ module Sisimai
|
|
499
508
|
v['recipient'] = self.recipient.address
|
500
509
|
v['timestamp'] = self.timestamp.to_time.to_i
|
501
510
|
|
502
|
-
# Backward compatibility until v5.
|
511
|
+
# Backward compatibility until v5.5.0
|
503
512
|
v["smtpagent"] = self.decodedby
|
504
513
|
v["smtpcommand"] = self.command
|
505
514
|
data = v
|
@@ -516,12 +525,12 @@ module Sisimai
|
|
516
525
|
# [Nil] The value of the first argument is neither "json" nor "yaml"
|
517
526
|
def dump(type = 'json')
|
518
527
|
return nil unless %w[json yaml].include?(type)
|
519
|
-
referclass =
|
528
|
+
referclass = "Sisimai::Fact::#{type.upcase}"
|
520
529
|
|
521
530
|
begin
|
522
531
|
require referclass.downcase.gsub('::', '/')
|
523
532
|
rescue
|
524
|
-
warn
|
533
|
+
warn "***warning: Failed to load #{referclass}"
|
525
534
|
end
|
526
535
|
|
527
536
|
dumpeddata = Module.const_get(referclass).dump(self)
|
data/lib/sisimai/lda.rb
CHANGED
@@ -68,9 +68,9 @@ module Sisimai
|
|
68
68
|
# @param [Sisimai::Fact] argvs Decoded email object
|
69
69
|
# @return [String] Bounce reason
|
70
70
|
def find(argvs)
|
71
|
-
return
|
72
|
-
return ""
|
73
|
-
return ""
|
71
|
+
return "" if argvs.nil?
|
72
|
+
return "" if argvs["diagnosticcode"].empty?
|
73
|
+
return "" if argvs["command"] != "" && argvs["command"] != "DATA"
|
74
74
|
|
75
75
|
deliversby = "" # [String] Local Delivery Agent name
|
76
76
|
reasontext = "" # [String] Error reason
|
@@ -8,7 +8,7 @@ module Sisimai::Lhost
|
|
8
8
|
|
9
9
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
10
|
Boundaries = ['Content-Type: message/rfc822'].freeze
|
11
|
-
StartingOf = {
|
11
|
+
StartingOf = {message: [' ----- The following addresses had permanent fatal errors -----']}.freeze
|
12
12
|
|
13
13
|
# @abstract decodes the bounce message from QUALITIA Active!hunter
|
14
14
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -20,12 +20,11 @@ module Sisimai::Lhost
|
|
20
20
|
# :subject => %r/FAILURE NOTICE :/,
|
21
21
|
return nil unless mhead['x-ahmailid']
|
22
22
|
|
23
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
23
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
24
24
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
25
25
|
bodyslices = emailparts[0].split("\n")
|
26
26
|
readcursor = 0 # (Integer) Points the current cursor position
|
27
27
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
28
|
-
v = nil
|
29
28
|
|
30
29
|
while e = bodyslices.shift do
|
31
30
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -35,8 +34,7 @@ module Sisimai::Lhost
|
|
35
34
|
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
36
35
|
next
|
37
36
|
end
|
38
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
39
|
-
next if e.empty?
|
37
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
40
38
|
|
41
39
|
# ----- The following addresses had permanent fatal errors -----
|
42
40
|
#
|
@@ -68,7 +66,7 @@ module Sisimai::Lhost
|
|
68
66
|
return nil unless recipients > 0
|
69
67
|
|
70
68
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
71
|
-
return {
|
69
|
+
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
72
70
|
end
|
73
71
|
def description; return 'TransWARE Active!hunter'; end
|
74
72
|
end
|
@@ -111,7 +111,7 @@ module Sisimai::Lhost
|
|
111
111
|
end
|
112
112
|
rescue StandardError => ce
|
113
113
|
# Something wrong in decoding JSON
|
114
|
-
warn
|
114
|
+
warn " ***warning: Failed to decode JSON: #{ce.to_s}"
|
115
115
|
return nil
|
116
116
|
end
|
117
117
|
return nil if jsonobject.has_key?("notificationType") == false
|
@@ -121,10 +121,9 @@ module Sisimai::Lhost
|
|
121
121
|
require "sisimai/smtp/reply"
|
122
122
|
require "sisimai/smtp/status"
|
123
123
|
require "sisimai/smtp/command"
|
124
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
124
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = dscontents[-1]
|
125
125
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
126
126
|
whatnotify = jsonobject["notificationType"][0, 1] || ""
|
127
|
-
v = dscontents[-1]
|
128
127
|
|
129
128
|
if whatnotify == "B"
|
130
129
|
# "notificationType":"Bounce"
|
@@ -207,13 +206,13 @@ module Sisimai::Lhost
|
|
207
206
|
|
208
207
|
cv = ""
|
209
208
|
jsonobject["mail"]["headers"].each do |e|
|
210
|
-
cv
|
209
|
+
cv += sprintf("%s: %s\n", e["name"], e["value"])
|
211
210
|
end
|
212
211
|
%w[date subject].each do |e|
|
213
212
|
next if jsonobject["mail"]["commonHeaders"].has_key?(e) == false
|
214
|
-
cv
|
213
|
+
cv += sprintf("%s: %s\n", e.capitalize, jsonobject["mail"]["commonHeaders"][e])
|
215
214
|
end
|
216
|
-
return {
|
215
|
+
return {"ds" => dscontents, "rfc822" => cv}
|
217
216
|
end
|
218
217
|
def description; return 'Amazon SES(Sending): https://aws.amazon.com/ses/'; end
|
219
218
|
end
|
@@ -26,13 +26,12 @@ module Sisimai::Lhost
|
|
26
26
|
match += 1 if mhead["received"].any? { |a| a.include?("JAMES SMTP Server") }
|
27
27
|
return nil unless match > 0
|
28
28
|
|
29
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = dscontents[-1]
|
30
30
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
31
31
|
bodyslices = emailparts[0].split("\n")
|
32
32
|
readcursor = 0 # Points the current cursor position
|
33
33
|
recipients = 0 # The number of 'Final-Recipient' header
|
34
34
|
alternates = ["", "", "", ""] # [Envelope-From, Header-From, Date, Subject]
|
35
|
-
v = dscontents[-1]
|
36
35
|
|
37
36
|
while e = bodyslices.shift do
|
38
37
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -45,11 +44,10 @@ module Sisimai::Lhost
|
|
45
44
|
readcursor |= Indicators[:deliverystatus]
|
46
45
|
next
|
47
46
|
end
|
48
|
-
v["diagnosis"]
|
47
|
+
v["diagnosis"] += "#{e }" if e != ""
|
49
48
|
next
|
50
49
|
end
|
51
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
52
|
-
next if e.empty?
|
50
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
53
51
|
|
54
52
|
# Message details:
|
55
53
|
# Subject: Nyaaan
|
@@ -93,16 +91,16 @@ module Sisimai::Lhost
|
|
93
91
|
|
94
92
|
if emailparts[1].empty?
|
95
93
|
# The original message is empty
|
96
|
-
emailparts[1]
|
97
|
-
emailparts[1]
|
94
|
+
emailparts[1] += sprintf("From: %s\n", alternates[1]) if alternates[1] != ""
|
95
|
+
emailparts[1] += sprintf("Date: %s\n", alternates[2]) if alternates[2] != ""
|
98
96
|
end
|
99
97
|
if emailparts[1].include?("Return-Path: ") == false
|
100
98
|
# Set the envelope from address as a Return-Path: header
|
101
|
-
emailparts[1]
|
99
|
+
emailparts[1] += sprintf("Return-Path: <%s>\n", alternates[0]) if alternates[0] != ""
|
102
100
|
end
|
103
101
|
if emailparts[1].include?("\nSubject: ") == false
|
104
102
|
# Set the envelope from address as a Return-Path: header
|
105
|
-
emailparts[1]
|
103
|
+
emailparts[1] += sprintf("Subject: %s\n", alternates[3]) if alternates[3] != ""
|
106
104
|
end
|
107
105
|
|
108
106
|
dscontents.each { |e| e["diagnosis"] = Sisimai::String.sweep(e["diagnosis"]) }
|
@@ -26,12 +26,11 @@ module Sisimai::Lhost
|
|
26
26
|
return nil unless %w[biglobe inacatv tmtv ttv].any? { |a| mhead['from'].include?('@' + a + '.ne.jp') }
|
27
27
|
return nil unless mhead['subject'].start_with?('Returned mail:')
|
28
28
|
|
29
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
29
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
30
30
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
31
31
|
bodyslices = emailparts[0].split("\n")
|
32
32
|
readcursor = 0 # (Integer) Points the current cursor position
|
33
33
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
34
|
-
v = nil
|
35
34
|
|
36
35
|
while e = bodyslices.shift do
|
37
36
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -41,8 +40,7 @@ module Sisimai::Lhost
|
|
41
40
|
readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
|
42
41
|
next
|
43
42
|
end
|
44
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
45
|
-
next if e.empty?
|
43
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
46
44
|
|
47
45
|
# This is a MIME-encapsulated message.
|
48
46
|
#
|
@@ -74,7 +72,7 @@ module Sisimai::Lhost
|
|
74
72
|
recipients += 1
|
75
73
|
else
|
76
74
|
next if e.include?('--')
|
77
|
-
v['diagnosis']
|
75
|
+
v['diagnosis'] += "#{e }"
|
78
76
|
end
|
79
77
|
end
|
80
78
|
return nil unless recipients > 0
|
@@ -44,14 +44,13 @@ module Sisimai::Lhost
|
|
44
44
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
45
45
|
permessage = {} # (Hash) Store values of each Per-Message field
|
46
46
|
|
47
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
47
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
48
48
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
49
49
|
bodyslices = emailparts[0].split("\n")
|
50
50
|
readslices = ['']
|
51
51
|
readcursor = 0 # (Integer) Points the current cursor position
|
52
52
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
53
53
|
thecommand = '' # (String) SMTP Command name begin with the string '>>>'
|
54
|
-
v = nil
|
55
54
|
|
56
55
|
while e = bodyslices.shift do
|
57
56
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -65,8 +64,7 @@ module Sisimai::Lhost
|
|
65
64
|
next
|
66
65
|
end
|
67
66
|
end
|
68
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
69
|
-
next if e.empty?
|
67
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
70
68
|
|
71
69
|
f = Sisimai::RFC1894.match(e)
|
72
70
|
if f > 0
|
@@ -118,8 +116,8 @@ module Sisimai::Lhost
|
|
118
116
|
# Continued line of the value of Diagnostic-Code field
|
119
117
|
next unless readslices[-2].start_with?('Diagnostic-Code:')
|
120
118
|
next unless e.start_with?(' ')
|
121
|
-
v['diagnosis']
|
122
|
-
readslices[-1]
|
119
|
+
v['diagnosis'] += " #{Sisimai::String.sweep(e)}"
|
120
|
+
readslices[-1] = "Diagnostic-Code: #{e}"
|
123
121
|
end
|
124
122
|
end
|
125
123
|
end
|
data/lib/sisimai/lhost/domino.rb
CHANGED
@@ -7,7 +7,7 @@ module Sisimai::Lhost
|
|
7
7
|
|
8
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
9
9
|
Boundaries = ['Content-Type: message/rfc822'].freeze
|
10
|
-
StartingOf = {
|
10
|
+
StartingOf = {message: ['Your message']}.freeze
|
11
11
|
MessagesOf = {
|
12
12
|
"filtered" => ["Cannot route mail to user"],
|
13
13
|
"systemerror" => ["Several matches found in Domino Directory"],
|
@@ -33,13 +33,12 @@ module Sisimai::Lhost
|
|
33
33
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
34
34
|
permessage = {} # (Hash) Store values of each Per-Message field
|
35
35
|
|
36
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
36
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
37
37
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
38
38
|
bodyslices = emailparts[0].split("\n")
|
39
39
|
readcursor = 0 # (Integer) Points the current cursor position
|
40
40
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
41
41
|
subjecttxt = '' # (String) The value of Subject:
|
42
|
-
v = nil
|
43
42
|
|
44
43
|
while e = bodyslices.shift do
|
45
44
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -135,9 +134,9 @@ module Sisimai::Lhost
|
|
135
134
|
end
|
136
135
|
|
137
136
|
# Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
|
138
|
-
emailparts[1]
|
137
|
+
emailparts[1] += "Subject: #{subjecttxt}\n" unless emailparts[1].include?("\nSubject:")
|
139
138
|
|
140
|
-
return {
|
139
|
+
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
141
140
|
end
|
142
141
|
def description; return 'IBM Domino Server'; end
|
143
142
|
end
|
@@ -41,12 +41,11 @@ module Sisimai::Lhost
|
|
41
41
|
return nil unless mhead['subject'].start_with?('Mail delivery failed')
|
42
42
|
return nil unless mhead['received'].any? { |a| a.include?(' (DragonFly Mail Agent') }
|
43
43
|
|
44
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
44
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
45
45
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
46
46
|
bodyslices = emailparts[0].split("\n")
|
47
47
|
readcursor = 0 # (Integer) Points the current cursor position
|
48
48
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
49
|
-
v = nil
|
50
49
|
|
51
50
|
while e = bodyslices.shift do
|
52
51
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -56,8 +55,7 @@ module Sisimai::Lhost
|
|
56
55
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
57
56
|
next
|
58
57
|
end
|
59
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
60
|
-
next if e.empty?
|
58
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
61
59
|
|
62
60
|
# This is the DragonFly Mail Agent v0.13 at df.example.jp.
|
63
61
|
#
|
@@ -81,7 +79,7 @@ module Sisimai::Lhost
|
|
81
79
|
recipients += 1
|
82
80
|
else
|
83
81
|
# Pick the error message
|
84
|
-
v['diagnosis']
|
82
|
+
v['diagnosis'] += " #{e}"
|
85
83
|
|
86
84
|
# Pick the remote hostname, and the SMTP command
|
87
85
|
# net.c:500| snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s",
|
@@ -11,7 +11,7 @@ module Sisimai::Lhost
|
|
11
11
|
message: ['This message was created automatically by mail delivery software'],
|
12
12
|
error: ['For the following reason:'],
|
13
13
|
}.freeze
|
14
|
-
MessagesOf = {
|
14
|
+
MessagesOf = {'mesgtoobig' => ['Mail size limit exceeded']}.freeze
|
15
15
|
|
16
16
|
# @abstract Decode the bounce message from 1&1
|
17
17
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -22,12 +22,11 @@ module Sisimai::Lhost
|
|
22
22
|
return nil unless mhead['from'].start_with?('"Mail Delivery System"')
|
23
23
|
return nil unless mhead['subject'] == 'Mail delivery failed: returning message to sender'
|
24
24
|
|
25
|
-
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
25
|
+
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
26
26
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
27
27
|
bodyslices = emailparts[0].split("\n")
|
28
28
|
readcursor = 0 # (Integer) Points the current cursor position
|
29
29
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
30
|
-
v = nil
|
31
30
|
|
32
31
|
while e = bodyslices.shift do
|
33
32
|
# Read error messages and delivery status lines from the head of the email to the previous
|
@@ -38,8 +37,7 @@ module Sisimai::Lhost
|
|
38
37
|
readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
|
39
38
|
next
|
40
39
|
end
|
41
|
-
next if (readcursor & Indicators[:deliverystatus]) == 0
|
42
|
-
next if e.empty?
|
40
|
+
next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
|
43
41
|
|
44
42
|
# The following address failed:
|
45
43
|
#
|
@@ -68,13 +66,13 @@ module Sisimai::Lhost
|
|
68
66
|
else
|
69
67
|
if v['diagnosis']
|
70
68
|
# Get error message and append error message strings
|
71
|
-
v['diagnosis']
|
69
|
+
v['diagnosis'] += " #{e}"
|
72
70
|
else
|
73
71
|
# OR the following format:
|
74
72
|
# neko@example.fr:
|
75
73
|
# SMTP error from remote server for TEXT command, host: ...
|
76
74
|
v['alterrors'] ||= ''
|
77
|
-
v['alterrors']
|
75
|
+
v['alterrors'] += " #{e}"
|
78
76
|
end
|
79
77
|
end
|
80
78
|
end
|
@@ -110,7 +108,7 @@ module Sisimai::Lhost
|
|
110
108
|
end
|
111
109
|
end
|
112
110
|
|
113
|
-
return {
|
111
|
+
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
114
112
|
end
|
115
113
|
def description; return '1&1: https://www.1und1.de'; end
|
116
114
|
end
|