dsn 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +21 -0
- data/README.md +64 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dsn.gemspec +31 -0
- data/lib/dsn.rb +31 -0
- data/lib/dsn/data/2.XXX.XXX +5 -0
- data/lib/dsn/data/4.XXX.XXX +7 -0
- data/lib/dsn/data/5.XXX.XXX +6 -0
- data/lib/dsn/data/X.0.0 +5 -0
- data/lib/dsn/data/X.0.XXX +3 -0
- data/lib/dsn/data/X.1.0 +4 -0
- data/lib/dsn/data/X.1.1 +6 -0
- data/lib/dsn/data/X.1.2 +7 -0
- data/lib/dsn/data/X.1.3 +5 -0
- data/lib/dsn/data/X.1.4 +6 -0
- data/lib/dsn/data/X.1.5 +4 -0
- data/lib/dsn/data/X.1.6 +5 -0
- data/lib/dsn/data/X.1.7 +4 -0
- data/lib/dsn/data/X.1.8 +6 -0
- data/lib/dsn/data/X.1.XXX +5 -0
- data/lib/dsn/data/X.2.0 +4 -0
- data/lib/dsn/data/X.2.1 +5 -0
- data/lib/dsn/data/X.2.2 +7 -0
- data/lib/dsn/data/X.2.3 +6 -0
- data/lib/dsn/data/X.2.4 +5 -0
- data/lib/dsn/data/X.2.XXX +5 -0
- data/lib/dsn/data/X.3.0 +5 -0
- data/lib/dsn/data/X.3.1 +6 -0
- data/lib/dsn/data/X.3.2 +6 -0
- data/lib/dsn/data/X.3.3 +6 -0
- data/lib/dsn/data/X.3.4 +5 -0
- data/lib/dsn/data/X.3.5 +4 -0
- data/lib/dsn/data/X.3.XXX +6 -0
- data/lib/dsn/data/X.4.0 +5 -0
- data/lib/dsn/data/X.4.1 +5 -0
- data/lib/dsn/data/X.4.2 +6 -0
- data/lib/dsn/data/X.4.3 +8 -0
- data/lib/dsn/data/X.4.4 +10 -0
- data/lib/dsn/data/X.4.5 +5 -0
- data/lib/dsn/data/X.4.6 +6 -0
- data/lib/dsn/data/X.4.7 +8 -0
- data/lib/dsn/data/X.4.XXX +7 -0
- data/lib/dsn/data/X.5.0 +5 -0
- data/lib/dsn/data/X.5.1 +5 -0
- data/lib/dsn/data/X.5.2 +6 -0
- data/lib/dsn/data/X.5.3 +8 -0
- data/lib/dsn/data/X.5.4 +6 -0
- data/lib/dsn/data/X.5.5 +4 -0
- data/lib/dsn/data/X.5.XXX +6 -0
- data/lib/dsn/data/X.6.0 +5 -0
- data/lib/dsn/data/X.6.1 +5 -0
- data/lib/dsn/data/X.6.2 +6 -0
- data/lib/dsn/data/X.6.3 +7 -0
- data/lib/dsn/data/X.6.4 +7 -0
- data/lib/dsn/data/X.6.5 +4 -0
- data/lib/dsn/data/X.6.XXX +8 -0
- data/lib/dsn/data/X.7.0 +7 -0
- data/lib/dsn/data/X.7.1 +7 -0
- data/lib/dsn/data/X.7.2 +4 -0
- data/lib/dsn/data/X.7.3 +5 -0
- data/lib/dsn/data/X.7.4 +5 -0
- data/lib/dsn/data/X.7.5 +6 -0
- data/lib/dsn/data/X.7.6 +5 -0
- data/lib/dsn/data/X.7.7 +6 -0
- data/lib/dsn/data/X.7.XXX +9 -0
- data/lib/dsn/message.rb +43 -0
- data/lib/dsn/parser/string.rb +45 -0
- data/lib/dsn/status_code.rb +52 -0
- data/lib/dsn/subcode/base.rb +53 -0
- data/lib/dsn/subcode/class_subcode.rb +34 -0
- data/lib/dsn/subcode/detail_subcode.rb +19 -0
- data/lib/dsn/subcode/subject_subcode.rb +19 -0
- data/lib/dsn/version.rb +5 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 534f17912ad61e0312b2237ab2b2f85e1b2297e7188470d0fbc978dcb7f41d5b
|
4
|
+
data.tar.gz: d29e79a5bfcc273805efb859d7f7b2cb8f36fc485c899ac5def0f197d7cf108d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c236e9d93f3222c92994772aea68b7931b3bc005a61d92c3a95d4ef59d4e59da267d4db51ce58c9cf81b04739621ca3ea145371b93245423d4e105b78ab032d0
|
7
|
+
data.tar.gz: 436e8e0289765292e634a9581a9ca815e337b098cf6d23aeb41afe649e5dfc262638698c954df6d232589c21490d15ad901ce3d10cb90d3d3858b91758f031d6
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dsn (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.14.1)
|
10
|
+
rake (12.3.3)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
dsn!
|
17
|
+
minitest (~> 5.0)
|
18
|
+
rake (~> 12.0)
|
19
|
+
|
20
|
+
BUNDLED WITH
|
21
|
+
2.1.2
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# DSN
|
2
|
+
|
3
|
+
Ruby parser for [RFC 3463](https://tools.ietf.org/html/rfc3463) Delivery Status Notification codes.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's `Gemfile`:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'dsn'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install dsn
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
dsn = DSN.new('5.7.5')
|
25
|
+
dsn.valid?
|
26
|
+
# => true
|
27
|
+
dsn.success?
|
28
|
+
# => false
|
29
|
+
dsn.transient_failure?
|
30
|
+
# => false
|
31
|
+
dsn.failed?
|
32
|
+
# => true
|
33
|
+
dsn.to_s
|
34
|
+
# => "5.7.5"
|
35
|
+
dsn.subcode.to_s
|
36
|
+
# => "X.7.5"
|
37
|
+
|
38
|
+
dsn = DSN.new('5.7.999')
|
39
|
+
dsn.valid?
|
40
|
+
# => false
|
41
|
+
dsn.class_subcode.valid?
|
42
|
+
# => true
|
43
|
+
dsn.subject_subcode.valid?
|
44
|
+
# => true
|
45
|
+
dsn.detail_subcode.valid?
|
46
|
+
# => false
|
47
|
+
dsn.to_s
|
48
|
+
# => "5.7.999"
|
49
|
+
dsn.subcode.to_s
|
50
|
+
# => "X.7.XXX"
|
51
|
+
|
52
|
+
msg = DSN::Message.new(dsn.subcode)
|
53
|
+
msg.summary
|
54
|
+
# => "Security or Policy Status"
|
55
|
+
msg.body
|
56
|
+
# => "The security or policy status codes report failures involving policies such as per-recipient or per-host filtering and cryptographic operations. Security and policy status issues are assumed to be under the control of either or both the sender and recipient. Both the sender and recipient must permit the exchange of messages and arrange the exchange of necessary keys and certificates for cryptographic operations."
|
57
|
+
|
58
|
+
DSN.message('5.7.5').summary
|
59
|
+
# => "Cryptographic failure"
|
60
|
+
```
|
61
|
+
|
62
|
+
## Contributing
|
63
|
+
|
64
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/garethrees/dsn.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "dsn"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/dsn.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/dsn/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'dsn'
|
7
|
+
spec.version = DSN::VERSION
|
8
|
+
spec.authors = ['Gareth Rees']
|
9
|
+
spec.email = ['gareth@garethrees.co.uk']
|
10
|
+
spec.license = 'MIT'
|
11
|
+
|
12
|
+
spec.summary = %(Ruby parser for RFC 3463 Delivery Status Notification codes)
|
13
|
+
spec.homepage = 'https://github.com/garethrees/dsn'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
18
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
f.match(%r{^(test|spec|features)/})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
31
|
+
end
|
data/lib/dsn.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dsn/status_code'
|
4
|
+
require 'dsn/message'
|
5
|
+
require 'dsn/version'
|
6
|
+
|
7
|
+
require 'dsn/parser/string'
|
8
|
+
|
9
|
+
require 'dsn/subcode/base'
|
10
|
+
require 'dsn/subcode/class_subcode'
|
11
|
+
require 'dsn/subcode/subject_subcode'
|
12
|
+
require 'dsn/subcode/detail_subcode'
|
13
|
+
|
14
|
+
# Ruby parser for RFC 3463 Delivery Status Notification codes
|
15
|
+
module DSN
|
16
|
+
# Raised when the status code is unparsable.
|
17
|
+
class InvalidStatusCode < StandardError; end
|
18
|
+
|
19
|
+
# Raised when attempting to operate on an invalid subcode.
|
20
|
+
class InvalidSubcode < StandardError; end
|
21
|
+
|
22
|
+
# Parse a StatsCode from a String
|
23
|
+
def self.new(*args)
|
24
|
+
StatusCode.new(Parser::String.new(*args))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the most detailed Message possible from a String code
|
28
|
+
def self.message(*args)
|
29
|
+
Message.new(new(*args).subcode)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Persistent Transient Failure
|
2
|
+
|
3
|
+
A persistent transient failure is one in which the message as
|
4
|
+
sent is valid, but persistence of some temporary condition has
|
5
|
+
caused abandonment or delay of attempts to send the message.
|
6
|
+
If this code accompanies a delivery failure report, sending in
|
7
|
+
the future may be successful.
|
data/lib/dsn/data/X.0.0
ADDED
data/lib/dsn/data/X.1.0
ADDED
data/lib/dsn/data/X.1.1
ADDED
data/lib/dsn/data/X.1.2
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Bad destination system address
|
2
|
+
|
3
|
+
The destination system specified in the address does not exist
|
4
|
+
or is incapable of accepting mail. For Internet mail names,
|
5
|
+
this means the address portion to the right of the "@" is
|
6
|
+
invalid for mail. This code is only useful for permanent
|
7
|
+
failures.
|
data/lib/dsn/data/X.1.3
ADDED
data/lib/dsn/data/X.1.4
ADDED
data/lib/dsn/data/X.1.5
ADDED
data/lib/dsn/data/X.1.6
ADDED
data/lib/dsn/data/X.1.7
ADDED
data/lib/dsn/data/X.1.8
ADDED
data/lib/dsn/data/X.2.0
ADDED
data/lib/dsn/data/X.2.1
ADDED
data/lib/dsn/data/X.2.2
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Mailbox full
|
2
|
+
|
3
|
+
The mailbox is full because the user has exceeded a per-mailbox
|
4
|
+
administrative quota or physical capacity. The general
|
5
|
+
semantics implies that the recipient can delete messages to
|
6
|
+
make more space available. This code should be used as a
|
7
|
+
persistent transient failure.
|
data/lib/dsn/data/X.2.3
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
Message length exceeds administrative limit
|
2
|
+
|
3
|
+
A per-mailbox administrative message length limit has been
|
4
|
+
exceeded. This status code should be used when the per-mailbox
|
5
|
+
message length limit is less than the general system limit.
|
6
|
+
This code should be used as a permanent failure.
|
data/lib/dsn/data/X.2.4
ADDED
data/lib/dsn/data/X.3.0
ADDED
data/lib/dsn/data/X.3.1
ADDED
data/lib/dsn/data/X.3.2
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
System not accepting network messages
|
2
|
+
|
3
|
+
The host on which the mailbox is resident is not accepting
|
4
|
+
messages. Examples of such conditions include an immanent
|
5
|
+
shutdown, excessive load, or system maintenance. This is
|
6
|
+
useful for both permanent and persistent transient errors.
|
data/lib/dsn/data/X.3.3
ADDED
data/lib/dsn/data/X.3.4
ADDED
data/lib/dsn/data/X.3.5
ADDED
data/lib/dsn/data/X.4.0
ADDED
data/lib/dsn/data/X.4.1
ADDED
data/lib/dsn/data/X.4.2
ADDED
data/lib/dsn/data/X.4.3
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Directory server failure
|
2
|
+
|
3
|
+
The network system was unable to forward the message, because a
|
4
|
+
directory server was unavailable. This is useful only as a
|
5
|
+
persistent transient error.
|
6
|
+
|
7
|
+
The inability to connect to an Internet DNS server is one
|
8
|
+
example of the directory server failure error.
|
data/lib/dsn/data/X.4.4
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Unable to route
|
2
|
+
|
3
|
+
The mail system was unable to determine the next hop for the
|
4
|
+
message because the necessary routing information was
|
5
|
+
unavailable from the directory server. This is useful for both
|
6
|
+
permanent and persistent transient errors.
|
7
|
+
|
8
|
+
A DNS lookup returning only an SOA (Start of Administration)
|
9
|
+
record for a domain name is one example of the unable to route
|
10
|
+
error.
|
data/lib/dsn/data/X.4.5
ADDED
data/lib/dsn/data/X.4.6
ADDED
data/lib/dsn/data/X.4.7
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Delivery time expired
|
2
|
+
|
3
|
+
The message was considered too old by the rejecting system,
|
4
|
+
either because it remained on that host too long or because the
|
5
|
+
time-to-live value specified by the sender of the message was
|
6
|
+
exceeded. If possible, the code for the actual problem found
|
7
|
+
when delivery was attempted should be returned rather than this
|
8
|
+
code.
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Network and Routing Status
|
2
|
+
|
3
|
+
The networking or routing codes report status about the
|
4
|
+
delivery system itself. These system components include any
|
5
|
+
necessary infrastructure such as directory and routing
|
6
|
+
services. Network issues are assumed to be under the control
|
7
|
+
of the destination or intermediate system administrator.
|
data/lib/dsn/data/X.5.0
ADDED
data/lib/dsn/data/X.5.1
ADDED
data/lib/dsn/data/X.5.2
ADDED
data/lib/dsn/data/X.5.3
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Too many recipients
|
2
|
+
|
3
|
+
More recipients were specified for the message than could have
|
4
|
+
been delivered by the protocol. This error should normally
|
5
|
+
result in the segmentation of the message into two, the
|
6
|
+
remainder of the recipients to be delivered on a subsequent
|
7
|
+
delivery attempt. It is included in this list in the event
|
8
|
+
that such segmentation is not possible.
|
data/lib/dsn/data/X.5.4
ADDED
data/lib/dsn/data/X.5.5
ADDED
data/lib/dsn/data/X.6.0
ADDED
data/lib/dsn/data/X.6.1
ADDED
data/lib/dsn/data/X.6.2
ADDED
data/lib/dsn/data/X.6.3
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Conversion required but not supported
|
2
|
+
|
3
|
+
The message content must be converted in order to be forwarded
|
4
|
+
but such conversion is not possible or is not practical by a
|
5
|
+
host in the forwarding path. This condition may result when an
|
6
|
+
ESMTP gateway supports 8bit transport but is not able to
|
7
|
+
downgrade the message to 7 bit as required for the next hop.
|
data/lib/dsn/data/X.6.4
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Conversion with loss performed
|
2
|
+
|
3
|
+
This is a warning sent to the sender when message delivery was
|
4
|
+
successfully but when the delivery required a conversion in
|
5
|
+
which some data was lost. This may also be a permanent error
|
6
|
+
if the sender has indicated that conversion with loss is
|
7
|
+
prohibited for the message.
|
data/lib/dsn/data/X.6.5
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Message Content or Media Status
|
2
|
+
|
3
|
+
The message content or media status codes report failures
|
4
|
+
involving the content of the message. These codes report
|
5
|
+
failures due to translation, transcoding, or otherwise
|
6
|
+
unsupported message media. Message content or media issues are
|
7
|
+
under the control of both the sender and the receiver, both of
|
8
|
+
which must support a common set of supported content-types.
|
data/lib/dsn/data/X.7.0
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Other or undefined security status
|
2
|
+
|
3
|
+
Something related to security caused the message to be
|
4
|
+
returned, and the problem cannot be well expressed with any of
|
5
|
+
the other provided detail codes. This status code may also be
|
6
|
+
used when the condition cannot be further described because of
|
7
|
+
security policies in force.
|
data/lib/dsn/data/X.7.1
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Delivery not authorized, message refused
|
2
|
+
|
3
|
+
The sender is not authorized to send to the destination. This
|
4
|
+
can be the result of per-host or per-recipient filtering. This
|
5
|
+
memo does not discuss the merits of any such filtering, but
|
6
|
+
provides a mechanism to report such. This is useful only as a
|
7
|
+
permanent error.
|
data/lib/dsn/data/X.7.2
ADDED
data/lib/dsn/data/X.7.3
ADDED
data/lib/dsn/data/X.7.4
ADDED
data/lib/dsn/data/X.7.5
ADDED
data/lib/dsn/data/X.7.6
ADDED
data/lib/dsn/data/X.7.7
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Security or Policy Status
|
2
|
+
|
3
|
+
The security or policy status codes report failures involving
|
4
|
+
policies such as per-recipient or per-host filtering and
|
5
|
+
cryptographic operations. Security and policy status issues
|
6
|
+
are assumed to be under the control of either or both the
|
7
|
+
sender and recipient. Both the sender and recipient must
|
8
|
+
permit the exchange of messages and arrange the exchange of
|
9
|
+
necessary keys and certificates for cryptographic operations.
|
data/lib/dsn/message.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
# Descriptions of each Subcode as per RFC3463
|
5
|
+
class Message
|
6
|
+
def initialize(subcode)
|
7
|
+
@subcode = subcode
|
8
|
+
end
|
9
|
+
|
10
|
+
def summary
|
11
|
+
data.first
|
12
|
+
end
|
13
|
+
|
14
|
+
def body
|
15
|
+
data.last.gsub("\n", ' ').strip
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
[summary, body].join("\n\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
attr_reader :subcode
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def data
|
29
|
+
@data ||= data!
|
30
|
+
end
|
31
|
+
|
32
|
+
def data!
|
33
|
+
File.read(filepath).split("\n\n")
|
34
|
+
rescue Errno::ENOENT
|
35
|
+
raise InvalidSubcode, %("#{subcode}")
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO: Cleanup
|
39
|
+
def filepath
|
40
|
+
"#{__dir__}/data/#{subcode}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
module Parser
|
5
|
+
# Parse DSN subcode componentds from a String
|
6
|
+
class String
|
7
|
+
def initialize(code)
|
8
|
+
@code = code
|
9
|
+
end
|
10
|
+
|
11
|
+
def class_subcode
|
12
|
+
parts[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def subject_subcode
|
16
|
+
parts[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def detail_subcode
|
20
|
+
parts[2]
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
code
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
attr_reader :code
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parts
|
34
|
+
@parts ||= parts!
|
35
|
+
end
|
36
|
+
|
37
|
+
def parts!
|
38
|
+
split_parts = code.split('.')
|
39
|
+
raise InvalidStatusCode unless split_parts.compact.size == 3
|
40
|
+
|
41
|
+
split_parts
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module DSN
|
6
|
+
# The full status code
|
7
|
+
class StatusCode
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def self.from_string(code)
|
11
|
+
new(Parser::String.new(code))
|
12
|
+
end
|
13
|
+
|
14
|
+
def_delegators :class_subcode, :success?, :transient_failure?, :failed?
|
15
|
+
|
16
|
+
def initialize(code)
|
17
|
+
@code = code
|
18
|
+
@class_subcode = Subcode::ClassSubcode.new(code)
|
19
|
+
@subject_subcode = Subcode::SubjectSubcode.new(code)
|
20
|
+
@detail_subcode = Subcode::DetailSubcode.new(code)
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid?
|
24
|
+
subcodes.all?(&:valid?)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the most detailed subcode that is valid
|
28
|
+
def subcode
|
29
|
+
raise InvalidStatusCode unless class_subcode.valid?
|
30
|
+
|
31
|
+
subcodes.select(&:valid?).last
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
code.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :class_subcode
|
39
|
+
attr_reader :subject_subcode
|
40
|
+
attr_reader :detail_subcode
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
attr_reader :code
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def subcodes
|
49
|
+
[class_subcode, subject_subcode, detail_subcode]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
module Subcode
|
5
|
+
# Shared behaviour for subcodes.
|
6
|
+
class Base
|
7
|
+
def initialize(status_code)
|
8
|
+
@status_code = status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?
|
12
|
+
File.exist?(filepath)
|
13
|
+
rescue InvalidSubcode
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
filename
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_i
|
22
|
+
Integer(significant_parts.last)
|
23
|
+
rescue ArgumentError
|
24
|
+
raise InvalidSubcode
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
attr_reader :status_code
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def filename
|
34
|
+
format_string % significant_parts
|
35
|
+
rescue ArgumentError
|
36
|
+
raise InvalidSubcode
|
37
|
+
end
|
38
|
+
|
39
|
+
def format_string
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
|
43
|
+
def significant_parts
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
|
47
|
+
# TODO: Cleanup
|
48
|
+
def filepath
|
49
|
+
"#{__dir__}/../data/#{self}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
module Subcode
|
5
|
+
# The class sub-code provides a broad classification of the status.
|
6
|
+
class ClassSubcode < Subcode::Base
|
7
|
+
SUCCESS_CODE = 2
|
8
|
+
TRANSIENT_FAILURE_CODE = 4
|
9
|
+
FAILURE_CODE = 5
|
10
|
+
|
11
|
+
def success?
|
12
|
+
to_i == SUCCESS_CODE
|
13
|
+
end
|
14
|
+
|
15
|
+
def transient_failure?
|
16
|
+
to_i == TRANSIENT_FAILURE_CODE
|
17
|
+
end
|
18
|
+
|
19
|
+
def failed?
|
20
|
+
to_i == FAILURE_CODE
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def format_string
|
26
|
+
'%d.XXX.XXX'
|
27
|
+
end
|
28
|
+
|
29
|
+
def significant_parts
|
30
|
+
[status_code.class_subcode]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
module Subcode
|
5
|
+
# The detail value provides more information about the status and is defined
|
6
|
+
# relative to the subject of the status.
|
7
|
+
class DetailSubcode < Subcode::Base
|
8
|
+
private
|
9
|
+
|
10
|
+
def format_string
|
11
|
+
'X.%d.%d'
|
12
|
+
end
|
13
|
+
|
14
|
+
def significant_parts
|
15
|
+
[status_code.subject_subcode, status_code.detail_subcode]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSN
|
4
|
+
module Subcode
|
5
|
+
# The subject sub-code classifies the status. This value applies to each of
|
6
|
+
# the three classifications.
|
7
|
+
class SubjectSubcode < Subcode::Base
|
8
|
+
private
|
9
|
+
|
10
|
+
def format_string
|
11
|
+
'X.%d.XXX'
|
12
|
+
end
|
13
|
+
|
14
|
+
def significant_parts
|
15
|
+
[status_code.subject_subcode]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/dsn/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dsn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gareth Rees
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- gareth@garethrees.co.uk
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".gitignore"
|
35
|
+
- ".travis.yml"
|
36
|
+
- CHANGELOG.md
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- bin/console
|
42
|
+
- bin/setup
|
43
|
+
- dsn.gemspec
|
44
|
+
- lib/dsn.rb
|
45
|
+
- lib/dsn/data/2.XXX.XXX
|
46
|
+
- lib/dsn/data/4.XXX.XXX
|
47
|
+
- lib/dsn/data/5.XXX.XXX
|
48
|
+
- lib/dsn/data/X.0.0
|
49
|
+
- lib/dsn/data/X.0.XXX
|
50
|
+
- lib/dsn/data/X.1.0
|
51
|
+
- lib/dsn/data/X.1.1
|
52
|
+
- lib/dsn/data/X.1.2
|
53
|
+
- lib/dsn/data/X.1.3
|
54
|
+
- lib/dsn/data/X.1.4
|
55
|
+
- lib/dsn/data/X.1.5
|
56
|
+
- lib/dsn/data/X.1.6
|
57
|
+
- lib/dsn/data/X.1.7
|
58
|
+
- lib/dsn/data/X.1.8
|
59
|
+
- lib/dsn/data/X.1.XXX
|
60
|
+
- lib/dsn/data/X.2.0
|
61
|
+
- lib/dsn/data/X.2.1
|
62
|
+
- lib/dsn/data/X.2.2
|
63
|
+
- lib/dsn/data/X.2.3
|
64
|
+
- lib/dsn/data/X.2.4
|
65
|
+
- lib/dsn/data/X.2.XXX
|
66
|
+
- lib/dsn/data/X.3.0
|
67
|
+
- lib/dsn/data/X.3.1
|
68
|
+
- lib/dsn/data/X.3.2
|
69
|
+
- lib/dsn/data/X.3.3
|
70
|
+
- lib/dsn/data/X.3.4
|
71
|
+
- lib/dsn/data/X.3.5
|
72
|
+
- lib/dsn/data/X.3.XXX
|
73
|
+
- lib/dsn/data/X.4.0
|
74
|
+
- lib/dsn/data/X.4.1
|
75
|
+
- lib/dsn/data/X.4.2
|
76
|
+
- lib/dsn/data/X.4.3
|
77
|
+
- lib/dsn/data/X.4.4
|
78
|
+
- lib/dsn/data/X.4.5
|
79
|
+
- lib/dsn/data/X.4.6
|
80
|
+
- lib/dsn/data/X.4.7
|
81
|
+
- lib/dsn/data/X.4.XXX
|
82
|
+
- lib/dsn/data/X.5.0
|
83
|
+
- lib/dsn/data/X.5.1
|
84
|
+
- lib/dsn/data/X.5.2
|
85
|
+
- lib/dsn/data/X.5.3
|
86
|
+
- lib/dsn/data/X.5.4
|
87
|
+
- lib/dsn/data/X.5.5
|
88
|
+
- lib/dsn/data/X.5.XXX
|
89
|
+
- lib/dsn/data/X.6.0
|
90
|
+
- lib/dsn/data/X.6.1
|
91
|
+
- lib/dsn/data/X.6.2
|
92
|
+
- lib/dsn/data/X.6.3
|
93
|
+
- lib/dsn/data/X.6.4
|
94
|
+
- lib/dsn/data/X.6.5
|
95
|
+
- lib/dsn/data/X.6.XXX
|
96
|
+
- lib/dsn/data/X.7.0
|
97
|
+
- lib/dsn/data/X.7.1
|
98
|
+
- lib/dsn/data/X.7.2
|
99
|
+
- lib/dsn/data/X.7.3
|
100
|
+
- lib/dsn/data/X.7.4
|
101
|
+
- lib/dsn/data/X.7.5
|
102
|
+
- lib/dsn/data/X.7.6
|
103
|
+
- lib/dsn/data/X.7.7
|
104
|
+
- lib/dsn/data/X.7.XXX
|
105
|
+
- lib/dsn/message.rb
|
106
|
+
- lib/dsn/parser/string.rb
|
107
|
+
- lib/dsn/status_code.rb
|
108
|
+
- lib/dsn/subcode/base.rb
|
109
|
+
- lib/dsn/subcode/class_subcode.rb
|
110
|
+
- lib/dsn/subcode/detail_subcode.rb
|
111
|
+
- lib/dsn/subcode/subject_subcode.rb
|
112
|
+
- lib/dsn/version.rb
|
113
|
+
homepage: https://github.com/garethrees/dsn
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata:
|
117
|
+
homepage_uri: https://github.com/garethrees/dsn
|
118
|
+
source_code_uri: https://github.com/garethrees/dsn
|
119
|
+
changelog_uri: https://github.com/garethrees/dsn/blob/master/CHANGELOG.md
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 2.3.0
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubygems_version: 3.1.2
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Ruby parser for RFC 3463 Delivery Status Notification codes
|
139
|
+
test_files: []
|