nano-fast-tool 0.0.1
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 +7 -0
- data/mail-2.9.1/MIT-LICENSE +20 -0
- data/mail-2.9.1/README.md +771 -0
- data/mail-2.9.1/lib/mail/attachments_list.rb +109 -0
- data/mail-2.9.1/lib/mail/body.rb +305 -0
- data/mail-2.9.1/lib/mail/configuration.rb +78 -0
- data/mail-2.9.1/lib/mail/constants.rb +79 -0
- data/mail-2.9.1/lib/mail/elements/address.rb +258 -0
- data/mail-2.9.1/lib/mail/elements/address_list.rb +34 -0
- data/mail-2.9.1/lib/mail/elements/content_disposition_element.rb +20 -0
- data/mail-2.9.1/lib/mail/elements/content_location_element.rb +17 -0
- data/mail-2.9.1/lib/mail/elements/content_transfer_encoding_element.rb +13 -0
- data/mail-2.9.1/lib/mail/elements/content_type_element.rb +25 -0
- data/mail-2.9.1/lib/mail/elements/date_time_element.rb +15 -0
- data/mail-2.9.1/lib/mail/elements/envelope_from_element.rb +39 -0
- data/mail-2.9.1/lib/mail/elements/message_ids_element.rb +31 -0
- data/mail-2.9.1/lib/mail/elements/mime_version_element.rb +15 -0
- data/mail-2.9.1/lib/mail/elements/phrase_list.rb +19 -0
- data/mail-2.9.1/lib/mail/elements/received_element.rb +35 -0
- data/mail-2.9.1/lib/mail/elements.rb +15 -0
- data/mail-2.9.1/lib/mail/encodings/7bit.rb +27 -0
- data/mail-2.9.1/lib/mail/encodings/8bit.rb +18 -0
- data/mail-2.9.1/lib/mail/encodings/base64.rb +38 -0
- data/mail-2.9.1/lib/mail/encodings/binary.rb +13 -0
- data/mail-2.9.1/lib/mail/encodings/identity.rb +24 -0
- data/mail-2.9.1/lib/mail/encodings/quoted_printable.rb +45 -0
- data/mail-2.9.1/lib/mail/encodings/transfer_encoding.rb +77 -0
- data/mail-2.9.1/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/mail-2.9.1/lib/mail/encodings.rb +314 -0
- data/mail-2.9.1/lib/mail/envelope.rb +28 -0
- data/mail-2.9.1/lib/mail/field.rb +313 -0
- data/mail-2.9.1/lib/mail/field_list.rb +87 -0
- data/mail-2.9.1/lib/mail/fields/bcc_field.rb +49 -0
- data/mail-2.9.1/lib/mail/fields/cc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/comments_field.rb +31 -0
- data/mail-2.9.1/lib/mail/fields/common_address_field.rb +162 -0
- data/mail-2.9.1/lib/mail/fields/common_date_field.rb +56 -0
- data/mail-2.9.1/lib/mail/fields/common_field.rb +77 -0
- data/mail-2.9.1/lib/mail/fields/common_message_id_field.rb +41 -0
- data/mail-2.9.1/lib/mail/fields/content_description_field.rb +12 -0
- data/mail-2.9.1/lib/mail/fields/content_disposition_field.rb +44 -0
- data/mail-2.9.1/lib/mail/fields/content_id_field.rb +35 -0
- data/mail-2.9.1/lib/mail/fields/content_location_field.rb +28 -0
- data/mail-2.9.1/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
- data/mail-2.9.1/lib/mail/fields/content_type_field.rb +171 -0
- data/mail-2.9.1/lib/mail/fields/date_field.rb +28 -0
- data/mail-2.9.1/lib/mail/fields/from_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/in_reply_to_field.rb +45 -0
- data/mail-2.9.1/lib/mail/fields/keywords_field.rb +30 -0
- data/mail-2.9.1/lib/mail/fields/message_id_field.rb +36 -0
- data/mail-2.9.1/lib/mail/fields/mime_version_field.rb +42 -0
- data/mail-2.9.1/lib/mail/fields/named_structured_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/named_unstructured_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/optional_field.rb +15 -0
- data/mail-2.9.1/lib/mail/fields/parameter_hash.rb +61 -0
- data/mail-2.9.1/lib/mail/fields/received_field.rb +61 -0
- data/mail-2.9.1/lib/mail/fields/references_field.rb +42 -0
- data/mail-2.9.1/lib/mail/fields/reply_to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_bcc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_cc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_date_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/resent_from_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_message_id_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/resent_sender_field.rb +32 -0
- data/mail-2.9.1/lib/mail/fields/resent_to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/return_path_field.rb +60 -0
- data/mail-2.9.1/lib/mail/fields/sender_field.rb +45 -0
- data/mail-2.9.1/lib/mail/fields/structured_field.rb +24 -0
- data/mail-2.9.1/lib/mail/fields/subject_field.rb +14 -0
- data/mail-2.9.1/lib/mail/fields/to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/unstructured_field.rb +189 -0
- data/mail-2.9.1/lib/mail/fields.rb +45 -0
- data/mail-2.9.1/lib/mail/header.rb +237 -0
- data/mail-2.9.1/lib/mail/indifferent_hash.rb +147 -0
- data/mail-2.9.1/lib/mail/mail.rb +267 -0
- data/mail-2.9.1/lib/mail/matchers/attachment_matchers.rb +44 -0
- data/mail-2.9.1/lib/mail/matchers/has_sent_mail.rb +201 -0
- data/mail-2.9.1/lib/mail/message.rb +2159 -0
- data/mail-2.9.1/lib/mail/multibyte/chars.rb +318 -0
- data/mail-2.9.1/lib/mail/multibyte/unicode.rb +405 -0
- data/mail-2.9.1/lib/mail/multibyte/utils.rb +44 -0
- data/mail-2.9.1/lib/mail/multibyte.rb +82 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/exim.rb +50 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/file_delivery.rb +43 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/sendmail.rb +87 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/smtp.rb +200 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/smtp_connection.rb +57 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/base.rb +64 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/imap.rb +190 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/pop3.rb +143 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/test_retriever.rb +45 -0
- data/mail-2.9.1/lib/mail/network.rb +16 -0
- data/mail-2.9.1/lib/mail/parser_tools.rb +15 -0
- data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rb +33245 -0
- data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rl +183 -0
- data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rb +904 -0
- data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rl +93 -0
- data/mail-2.9.1/lib/mail/parsers/content_location_parser.rb +825 -0
- data/mail-2.9.1/lib/mail/parsers/content_location_parser.rl +82 -0
- data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rb +525 -0
- data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
- data/mail-2.9.1/lib/mail/parsers/content_type_parser.rb +1051 -0
- data/mail-2.9.1/lib/mail/parsers/content_type_parser.rl +94 -0
- data/mail-2.9.1/lib/mail/parsers/date_time_parser.rb +894 -0
- data/mail-2.9.1/lib/mail/parsers/date_time_parser.rl +73 -0
- data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rb +3678 -0
- data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rl +93 -0
- data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rb +5164 -0
- data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rl +97 -0
- data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rb +516 -0
- data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rl +72 -0
- data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rb +887 -0
- data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rl +94 -0
- data/mail-2.9.1/lib/mail/parsers/received_parser.rb +8785 -0
- data/mail-2.9.1/lib/mail/parsers/received_parser.rl +95 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/mail-2.9.1/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322.rl +74 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_date_time.rl +37 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/mail-2.9.1/lib/mail/parsers.rb +13 -0
- data/mail-2.9.1/lib/mail/part.rb +119 -0
- data/mail-2.9.1/lib/mail/parts_list.rb +131 -0
- data/mail-2.9.1/lib/mail/smtp_envelope.rb +57 -0
- data/mail-2.9.1/lib/mail/utilities.rb +576 -0
- data/mail-2.9.1/lib/mail/values/unicode_tables.dat +0 -0
- data/mail-2.9.1/lib/mail/version.rb +17 -0
- data/mail-2.9.1/lib/mail/yaml.rb +30 -0
- data/mail-2.9.1/lib/mail.rb +65 -0
- data/nano-fast-tool.gemspec +12 -0
- metadata +177 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Mail
|
|
3
|
+
class AttachmentsList < Array
|
|
4
|
+
|
|
5
|
+
def initialize(parts_list)
|
|
6
|
+
@parts_list = parts_list
|
|
7
|
+
@content_disposition_type = 'attachment'
|
|
8
|
+
parts_list.map { |p|
|
|
9
|
+
if p.mime_type == 'message/rfc822'
|
|
10
|
+
parts = []
|
|
11
|
+
parts << p if p.attachment?
|
|
12
|
+
parts.concat Mail.new(p.body.encoded).attachments
|
|
13
|
+
elsif p.parts.empty?
|
|
14
|
+
p if p.attachment?
|
|
15
|
+
else
|
|
16
|
+
p.attachments
|
|
17
|
+
end
|
|
18
|
+
}.flatten.compact.each { |a| self << a }
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def inline
|
|
23
|
+
@content_disposition_type = 'inline'
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns the attachment by filename or at index.
|
|
28
|
+
#
|
|
29
|
+
# mail.attachments['test.png'] = File.read('test.png')
|
|
30
|
+
# mail.attachments['test.jpg'] = File.read('test.jpg')
|
|
31
|
+
#
|
|
32
|
+
# mail.attachments['test.png'].filename #=> 'test.png'
|
|
33
|
+
# mail.attachments[1].filename #=> 'test.jpg'
|
|
34
|
+
def [](index_value)
|
|
35
|
+
if index_value.is_a?(Integer)
|
|
36
|
+
self.fetch(index_value)
|
|
37
|
+
else
|
|
38
|
+
self.select { |a| a.filename == index_value }.first
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def []=(name, value)
|
|
43
|
+
encoded_name = Mail::Encodings.decode_encode name, :encode
|
|
44
|
+
default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{encoded_name}\"",
|
|
45
|
+
:content_transfer_encoding => "#{guess_encoding}",
|
|
46
|
+
:content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" }
|
|
47
|
+
|
|
48
|
+
if value.is_a?(Hash)
|
|
49
|
+
if path = value.delete(:filename)
|
|
50
|
+
value[:content] ||= File.open(path, 'rb') { |f| f.read }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
default_values[:body] = value.delete(:content) if value[:content]
|
|
54
|
+
|
|
55
|
+
default_values[:body] = value.delete(:data) if value[:data]
|
|
56
|
+
|
|
57
|
+
encoding = value.delete(:transfer_encoding) || value.delete(:encoding)
|
|
58
|
+
if encoding
|
|
59
|
+
if Mail::Encodings.defined? encoding
|
|
60
|
+
default_values[:content_transfer_encoding] = encoding
|
|
61
|
+
else
|
|
62
|
+
raise "Do not know how to handle Content Transfer Encoding #{encoding}, please choose either quoted-printable or base64"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if value[:mime_type]
|
|
67
|
+
default_values[:content_type] = value.delete(:mime_type)
|
|
68
|
+
@mime_type = MiniMime.lookup_by_content_type(default_values[:content_type])
|
|
69
|
+
default_values[:content_transfer_encoding] ||= guess_encoding
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
hash = default_values.merge(value)
|
|
73
|
+
else
|
|
74
|
+
default_values[:body] = value
|
|
75
|
+
hash = default_values
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
|
|
79
|
+
if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].casecmp('binary').zero?
|
|
80
|
+
hash[:body] = hash[:body].dup if hash[:body].frozen?
|
|
81
|
+
hash[:body].force_encoding("BINARY")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
attachment = Part.new(hash)
|
|
86
|
+
attachment.add_content_id(hash[:content_id])
|
|
87
|
+
|
|
88
|
+
@parts_list << attachment
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
|
|
92
|
+
# set it to binary, otherwise as set to plain text
|
|
93
|
+
def guess_encoding
|
|
94
|
+
if @mime_type && !@mime_type.binary?
|
|
95
|
+
"7bit"
|
|
96
|
+
else
|
|
97
|
+
"binary"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def set_mime_type(filename)
|
|
102
|
+
filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
|
|
103
|
+
|
|
104
|
+
@mime_type = MiniMime.lookup_by_filename(filename)
|
|
105
|
+
@mime_type && @mime_type.content_type
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
module Mail
|
|
4
|
+
|
|
5
|
+
# = Body
|
|
6
|
+
#
|
|
7
|
+
# The body is where the text of the email is stored. Mail treats the body
|
|
8
|
+
# as a single object. The body itself has no information about boundaries
|
|
9
|
+
# used in the MIME standard, it just looks at its content as either a single
|
|
10
|
+
# block of text, or (if it is a multipart message) as an array of blocks of text.
|
|
11
|
+
#
|
|
12
|
+
# A body has to be told to split itself up into a multipart message by calling
|
|
13
|
+
# #split with the correct boundary. This is because the body object has no way
|
|
14
|
+
# of knowing what the correct boundary is for itself (there could be many
|
|
15
|
+
# boundaries in a body in the case of a nested MIME text).
|
|
16
|
+
#
|
|
17
|
+
# Once split is called, Mail::Body will slice itself up on this boundary,
|
|
18
|
+
# assigning anything that appears before the first part to the preamble, and
|
|
19
|
+
# anything that appears after the closing boundary to the epilogue, then
|
|
20
|
+
# each part gets initialized into a Mail::Part object.
|
|
21
|
+
#
|
|
22
|
+
# The boundary that is used to split up the Body is also stored in the Body
|
|
23
|
+
# object for use on encoding itself back out to a string. You can
|
|
24
|
+
# overwrite this if it needs to be changed.
|
|
25
|
+
#
|
|
26
|
+
# On encoding, the body will return the preamble, then each part joined by
|
|
27
|
+
# the boundary, followed by a closing boundary string and then the epilogue.
|
|
28
|
+
class Body
|
|
29
|
+
|
|
30
|
+
def initialize(string = '')
|
|
31
|
+
@boundary = nil
|
|
32
|
+
@preamble = nil
|
|
33
|
+
@epilogue = nil
|
|
34
|
+
@charset = nil
|
|
35
|
+
@part_sort_order = [ "text/plain", "text/enriched", "text/html", "multipart/alternative" ]
|
|
36
|
+
@parts = Mail::PartsList.new
|
|
37
|
+
if Utilities.blank?(string)
|
|
38
|
+
@raw_source = ''
|
|
39
|
+
else
|
|
40
|
+
# Do join first incase we have been given an Array in Ruby 1.9
|
|
41
|
+
if string.respond_to?(:join)
|
|
42
|
+
@raw_source = string.join('')
|
|
43
|
+
elsif string.respond_to?(:to_s)
|
|
44
|
+
@raw_source = string.to_s
|
|
45
|
+
else
|
|
46
|
+
raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
@encoding = default_encoding
|
|
50
|
+
set_charset
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def init_with(coder)
|
|
54
|
+
coder.map.each { |k, v| instance_variable_set(:"@#{k}", v) }
|
|
55
|
+
@parts = Mail::PartsList.new(coder['parts'])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Matches this body with another body. Also matches the decoded value of this
|
|
59
|
+
# body with a string.
|
|
60
|
+
#
|
|
61
|
+
# Examples:
|
|
62
|
+
#
|
|
63
|
+
# body = Mail::Body.new('The body')
|
|
64
|
+
# body == body #=> true
|
|
65
|
+
#
|
|
66
|
+
# body = Mail::Body.new('The body')
|
|
67
|
+
# body == 'The body' #=> true
|
|
68
|
+
#
|
|
69
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
|
70
|
+
# body.encoding = 'base64'
|
|
71
|
+
# body == "The body" #=> true
|
|
72
|
+
def ==(other)
|
|
73
|
+
if other.class == String
|
|
74
|
+
self.decoded == other
|
|
75
|
+
else
|
|
76
|
+
super
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Accepts a string and performs a regular expression against the decoded text
|
|
81
|
+
#
|
|
82
|
+
# Examples:
|
|
83
|
+
#
|
|
84
|
+
# body = Mail::Body.new('The body')
|
|
85
|
+
# body =~ /The/ #=> 0
|
|
86
|
+
#
|
|
87
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
|
88
|
+
# body.encoding = 'base64'
|
|
89
|
+
# body =~ /The/ #=> 0
|
|
90
|
+
def =~(regexp)
|
|
91
|
+
self.decoded =~ regexp
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Accepts a string and performs a regular expression against the decoded text
|
|
95
|
+
#
|
|
96
|
+
# Examples:
|
|
97
|
+
#
|
|
98
|
+
# body = Mail::Body.new('The body')
|
|
99
|
+
# body.match(/The/) #=> #<MatchData "The">
|
|
100
|
+
#
|
|
101
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
|
102
|
+
# body.encoding = 'base64'
|
|
103
|
+
# body.match(/The/) #=> #<MatchData "The">
|
|
104
|
+
def match(regexp)
|
|
105
|
+
self.decoded.match(regexp)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Accepts anything that responds to #to_s and checks if it's a substring of the decoded text
|
|
109
|
+
#
|
|
110
|
+
# Examples:
|
|
111
|
+
#
|
|
112
|
+
# body = Mail::Body.new('The body')
|
|
113
|
+
# body.include?('The') #=> true
|
|
114
|
+
#
|
|
115
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
|
116
|
+
# body.encoding = 'base64'
|
|
117
|
+
# body.include?('The') #=> true
|
|
118
|
+
def include?(other)
|
|
119
|
+
self.decoded.include?(other.to_s)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Allows you to set the sort order of the parts, overriding the default sort order.
|
|
123
|
+
# Defaults to 'text/plain', then 'text/enriched', then 'text/html', then 'multipart/alternative'
|
|
124
|
+
# with any other content type coming after.
|
|
125
|
+
def set_sort_order(order)
|
|
126
|
+
@part_sort_order = order
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Allows you to sort the parts according to the default sort order, or the sort order you
|
|
130
|
+
# set with :set_sort_order.
|
|
131
|
+
#
|
|
132
|
+
# sort_parts! is also called from :encode, so there is no need for you to call this explicitly
|
|
133
|
+
def sort_parts!
|
|
134
|
+
@parts.each do |p|
|
|
135
|
+
p.body.set_sort_order(@part_sort_order)
|
|
136
|
+
p.body.sort_parts!
|
|
137
|
+
end
|
|
138
|
+
@parts.sort!(@part_sort_order)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def negotiate_best_encoding(message_encoding, allowed_encodings = nil)
|
|
142
|
+
Mail::Encodings::TransferEncoding.negotiate(message_encoding, encoding, raw_source, allowed_encodings)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns a body encoded using transfer_encoding. Multipart always uses an
|
|
146
|
+
# identiy encoding (i.e. no encoding).
|
|
147
|
+
# Calling this directly is not a good idea, but supported for compatibility
|
|
148
|
+
# TODO: Validate that preamble and epilogue are valid for requested encoding
|
|
149
|
+
def encoded(transfer_encoding = nil)
|
|
150
|
+
if multipart?
|
|
151
|
+
self.sort_parts!
|
|
152
|
+
encoded_parts = parts.map { |p| p.encoded }
|
|
153
|
+
([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
|
|
154
|
+
else
|
|
155
|
+
dec = Mail::Encodings.get_encoding(encoding)
|
|
156
|
+
enc =
|
|
157
|
+
if Utilities.blank?(transfer_encoding)
|
|
158
|
+
dec
|
|
159
|
+
else
|
|
160
|
+
negotiate_best_encoding(transfer_encoding)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if dec.nil?
|
|
164
|
+
# Cannot decode, so skip normalization
|
|
165
|
+
raw_source
|
|
166
|
+
else
|
|
167
|
+
# Decode then encode to normalize and allow transforming
|
|
168
|
+
# from base64 to Q-P and vice versa
|
|
169
|
+
decoded = dec.decode(raw_source)
|
|
170
|
+
if defined?(Encoding) && charset && charset != "US-ASCII"
|
|
171
|
+
decoded = decoded.encode(charset)
|
|
172
|
+
decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
|
|
173
|
+
end
|
|
174
|
+
enc.encode(decoded)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def decoded
|
|
180
|
+
if !Encodings.defined?(encoding)
|
|
181
|
+
raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
|
|
182
|
+
else
|
|
183
|
+
Encodings.get_encoding(encoding).decode(raw_source)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def to_s
|
|
188
|
+
decoded
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def encoding(val = nil)
|
|
192
|
+
if val
|
|
193
|
+
self.encoding = val
|
|
194
|
+
else
|
|
195
|
+
@encoding
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def encoding=( val )
|
|
200
|
+
@encoding =
|
|
201
|
+
if val == "text" || Utilities.blank?(val)
|
|
202
|
+
default_encoding
|
|
203
|
+
else
|
|
204
|
+
val
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Returns the raw source that the body was initialized with, without
|
|
209
|
+
# any tampering
|
|
210
|
+
attr_reader :raw_source
|
|
211
|
+
|
|
212
|
+
# Returns parts of the body
|
|
213
|
+
attr_reader :parts
|
|
214
|
+
|
|
215
|
+
# Returns and sets the original character encoding
|
|
216
|
+
attr_accessor :charset
|
|
217
|
+
|
|
218
|
+
# Returns and sets the preamble as a string (any text that is before the first MIME boundary)
|
|
219
|
+
attr_accessor :preamble
|
|
220
|
+
|
|
221
|
+
# Returns and sets the epilogue as a string (any text that is after the last MIME boundary)
|
|
222
|
+
attr_accessor :epilogue
|
|
223
|
+
|
|
224
|
+
# Returns and sets the boundary used by the body
|
|
225
|
+
# Allows you to change the boundary of this Body object
|
|
226
|
+
attr_accessor :boundary
|
|
227
|
+
|
|
228
|
+
# Returns true if there are parts defined in the body
|
|
229
|
+
def multipart?
|
|
230
|
+
true unless parts.empty?
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def <<( val )
|
|
234
|
+
if @parts
|
|
235
|
+
@parts << val
|
|
236
|
+
else
|
|
237
|
+
@parts = Mail::PartsList.new[val]
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def split!(boundary)
|
|
242
|
+
self.boundary = boundary
|
|
243
|
+
parts = extract_parts
|
|
244
|
+
|
|
245
|
+
# Make the preamble equal to the preamble (if any)
|
|
246
|
+
self.preamble = parts[0].to_s.strip
|
|
247
|
+
# Make the epilogue equal to the epilogue (if any)
|
|
248
|
+
self.epilogue = parts[-1].to_s.strip
|
|
249
|
+
parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
|
|
250
|
+
self
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def ascii_only?
|
|
254
|
+
unless defined? @ascii_only
|
|
255
|
+
@ascii_only = raw_source.ascii_only?
|
|
256
|
+
end
|
|
257
|
+
@ascii_only
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def empty?
|
|
261
|
+
!!raw_source.to_s.empty?
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def default_encoding
|
|
265
|
+
ascii_only? ? '7bit' : '8bit'
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
private
|
|
269
|
+
|
|
270
|
+
# split parts by boundary, ignore first part if empty, append final part when closing boundary was missing
|
|
271
|
+
def extract_parts
|
|
272
|
+
parts_regex = /
|
|
273
|
+
(?: # non-capturing group
|
|
274
|
+
\A | # start of string OR
|
|
275
|
+
\r?\n # line break with optional CR
|
|
276
|
+
)
|
|
277
|
+
(
|
|
278
|
+
--#{Regexp.escape(boundary || "")} # boundary delimiter
|
|
279
|
+
(?:--)? # with non-capturing optional closing
|
|
280
|
+
)
|
|
281
|
+
(?=\s*$) # lookahead matching zero or more spaces followed by line-ending
|
|
282
|
+
/x
|
|
283
|
+
parts = raw_source.split(parts_regex).each_slice(2).to_a
|
|
284
|
+
parts.each_with_index { |(part, _), index| parts.delete_at(index) if index > 0 && Utilities.blank?(part) }
|
|
285
|
+
|
|
286
|
+
if parts.size > 1
|
|
287
|
+
final_separator = parts[-2][1]
|
|
288
|
+
parts << [""] if final_separator != "--#{boundary}--"
|
|
289
|
+
end
|
|
290
|
+
parts.map(&:first)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def crlf_boundary
|
|
294
|
+
"\r\n--#{boundary}\r\n"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def end_boundary
|
|
298
|
+
"\r\n--#{boundary}--\r\n"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def set_charset
|
|
302
|
+
@charset = ascii_only? ? 'US-ASCII' : nil
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
#
|
|
4
|
+
# Thanks to Nicolas Fouché for this wrapper
|
|
5
|
+
#
|
|
6
|
+
require 'singleton'
|
|
7
|
+
|
|
8
|
+
module Mail
|
|
9
|
+
|
|
10
|
+
# The Configuration class is a Singleton used to hold the default
|
|
11
|
+
# configuration for all Mail objects.
|
|
12
|
+
#
|
|
13
|
+
# Each new mail object gets a copy of these values at initialization
|
|
14
|
+
# which can be overwritten on a per mail object basis.
|
|
15
|
+
class Configuration
|
|
16
|
+
include Singleton
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
@delivery_method = nil
|
|
20
|
+
@retriever_method = nil
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delivery_method(method = nil, settings = {})
|
|
25
|
+
return @delivery_method if @delivery_method && method.nil?
|
|
26
|
+
@delivery_method = lookup_delivery_method(method).new(settings)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def lookup_delivery_method(method)
|
|
30
|
+
case method.is_a?(String) ? method.to_sym : method
|
|
31
|
+
when nil
|
|
32
|
+
Mail::SMTP
|
|
33
|
+
when :smtp
|
|
34
|
+
Mail::SMTP
|
|
35
|
+
when :sendmail
|
|
36
|
+
Mail::Sendmail
|
|
37
|
+
when :exim
|
|
38
|
+
Mail::Exim
|
|
39
|
+
when :file
|
|
40
|
+
Mail::FileDelivery
|
|
41
|
+
when :smtp_connection
|
|
42
|
+
Mail::SMTPConnection
|
|
43
|
+
when :test
|
|
44
|
+
Mail::TestMailer
|
|
45
|
+
when :logger
|
|
46
|
+
Mail::LoggerDelivery
|
|
47
|
+
else
|
|
48
|
+
method
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def retriever_method(method = nil, settings = {})
|
|
53
|
+
return @retriever_method if @retriever_method && method.nil?
|
|
54
|
+
@retriever_method = lookup_retriever_method(method).new(settings)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def lookup_retriever_method(method)
|
|
58
|
+
case method
|
|
59
|
+
when nil
|
|
60
|
+
Mail::POP3
|
|
61
|
+
when :pop3
|
|
62
|
+
Mail::POP3
|
|
63
|
+
when :imap
|
|
64
|
+
Mail::IMAP
|
|
65
|
+
when :test
|
|
66
|
+
Mail::TestRetriever
|
|
67
|
+
else
|
|
68
|
+
method
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def param_encode_language(value = nil)
|
|
73
|
+
value ? @encode_language = value : @encode_language ||= 'en'
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# encoding: us-ascii
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
module Mail
|
|
4
|
+
module Constants
|
|
5
|
+
white_space = %Q|\x9\x20|
|
|
6
|
+
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
|
|
7
|
+
field_name = %Q|\x21-\x39\x3b-\x7e|
|
|
8
|
+
qp_safe = %Q|\x20-\x3c\x3e-\x7e|
|
|
9
|
+
|
|
10
|
+
aspecial = %Q|()<>[]:;@\\,."| # RFC5322
|
|
11
|
+
tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
|
|
12
|
+
sp = %Q| |
|
|
13
|
+
control = %Q|\x00-\x1f\x7f-\xff|
|
|
14
|
+
|
|
15
|
+
if control.respond_to?(:force_encoding)
|
|
16
|
+
control = control.dup.force_encoding(Encoding::BINARY)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
LAX_CRLF = /\r?\n/
|
|
20
|
+
WSP = /[#{white_space}]/
|
|
21
|
+
FWS = /#{LAX_CRLF}#{WSP}*/
|
|
22
|
+
UNFOLD_WS = /#{LAX_CRLF}(#{WSP})/m
|
|
23
|
+
TEXT = /[#{text}]/ # + obs-text
|
|
24
|
+
FIELD_NAME = /[#{field_name}]+/
|
|
25
|
+
FIELD_PREFIX = /\A(#{FIELD_NAME})/
|
|
26
|
+
FIELD_BODY = /.+/m
|
|
27
|
+
FIELD_LINE = /^[#{field_name}]+:\s*.+$/
|
|
28
|
+
FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
|
|
29
|
+
HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
|
|
30
|
+
HEADER_SPLIT = /#{LAX_CRLF}(?!#{WSP})/
|
|
31
|
+
|
|
32
|
+
QP_UNSAFE = /[^#{qp_safe}]/
|
|
33
|
+
QP_SAFE = /[#{qp_safe}]/
|
|
34
|
+
CONTROL_CHAR = /[#{control}]/n
|
|
35
|
+
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
|
36
|
+
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
|
37
|
+
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
|
|
38
|
+
|
|
39
|
+
ENCODED_VALUE = %r{
|
|
40
|
+
\=\? # literal =?
|
|
41
|
+
([^?]+) #
|
|
42
|
+
\? # literal ?
|
|
43
|
+
([QB]) # either a "Q" or a "B"
|
|
44
|
+
\? # literal ?
|
|
45
|
+
.*? # lazily match all characters
|
|
46
|
+
\?\= # literal ?=
|
|
47
|
+
}mix # m is multi-line, i is case-insensitive, x is free-spacing
|
|
48
|
+
|
|
49
|
+
FULL_ENCODED_VALUE = %r{ # Identical to ENCODED_VALUE but captures the whole rather than components of
|
|
50
|
+
(
|
|
51
|
+
\=\? # literal =?
|
|
52
|
+
[^?]+ #
|
|
53
|
+
\? # literal ?
|
|
54
|
+
[QB] # either a "Q" or a "B"
|
|
55
|
+
\? # literal ?
|
|
56
|
+
.*? # lazily match all characters
|
|
57
|
+
\?\= # literal ?=
|
|
58
|
+
)
|
|
59
|
+
}mix # m is multi-line, i is case-insensitive, x is free-spacing
|
|
60
|
+
|
|
61
|
+
EMPTY = ''
|
|
62
|
+
SPACE = ' '
|
|
63
|
+
UNDERSCORE = '_'
|
|
64
|
+
HYPHEN = '-'
|
|
65
|
+
COLON = ':'
|
|
66
|
+
ASTERISK = '*'
|
|
67
|
+
CRLF = "\r\n"
|
|
68
|
+
CR = "\r"
|
|
69
|
+
LF = "\n"
|
|
70
|
+
CR_ENCODED = "=0D"
|
|
71
|
+
LF_ENCODED = "=0A"
|
|
72
|
+
CAPITAL_M = 'M'
|
|
73
|
+
EQUAL_LF = "=\n"
|
|
74
|
+
NULL_SENDER = '<>'
|
|
75
|
+
|
|
76
|
+
Q_VALUES = ['Q','q']
|
|
77
|
+
B_VALUES = ['B','b']
|
|
78
|
+
end
|
|
79
|
+
end
|