mail 2.2.5 → 2.2.19
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.
- data/CHANGELOG.rdoc +163 -7
- data/README.rdoc +56 -65
- data/Rakefile +31 -6
- data/lib/VERSION +2 -2
- data/lib/mail/attachments_list.rb +4 -4
- data/lib/mail/body.rb +6 -2
- data/lib/mail/configuration.rb +7 -1
- data/lib/mail/core_extensions/shellwords.rb +55 -0
- data/lib/mail/core_extensions/smtp.rb +24 -0
- data/lib/mail/elements/address.rb +6 -6
- data/lib/mail/elements/content_disposition_element.rb +1 -1
- data/lib/mail/elements/content_type_element.rb +2 -2
- data/lib/mail/encodings.rb +55 -57
- data/lib/mail/field.rb +2 -1
- data/lib/mail/field_list.rb +1 -1
- data/lib/mail/fields/common/common_field.rb +10 -9
- data/lib/mail/fields/common/common_message_id.rb +6 -5
- data/lib/mail/fields/common/parameter_hash.rb +14 -4
- data/lib/mail/fields/content_disposition_field.rb +1 -1
- data/lib/mail/fields/content_type_field.rb +41 -28
- data/lib/mail/fields/date_field.rb +3 -1
- data/lib/mail/fields/received_field.rb +11 -3
- data/lib/mail/fields/resent_date_field.rb +1 -1
- data/lib/mail/fields/return_path_field.rb +1 -0
- data/lib/mail/fields/unstructured_field.rb +4 -1
- data/lib/mail/header.rb +8 -5
- data/lib/mail/mail.rb +71 -57
- data/lib/mail/message.rb +518 -391
- data/lib/mail/network/delivery_methods/sendmail.rb +15 -15
- data/lib/mail/network/delivery_methods/smtp.rb +33 -6
- data/lib/mail/network/delivery_methods/smtp_connection.rb +74 -0
- data/lib/mail/network/retriever_methods/base.rb +63 -0
- data/lib/mail/network/retriever_methods/imap.rb +147 -7
- data/lib/mail/network/retriever_methods/pop3.rb +25 -44
- data/lib/mail/network/retriever_methods/test_retriever.rb +40 -0
- data/lib/mail/network.rb +4 -0
- data/lib/mail/parsers/address_lists.rb +2 -2
- data/lib/mail/parsers/address_lists.treetop +2 -2
- data/lib/mail/parsers/content_disposition.rb +166 -18
- data/lib/mail/parsers/content_disposition.treetop +1 -1
- data/lib/mail/parsers/content_type.rb +477 -49
- data/lib/mail/parsers/content_type.treetop +12 -2
- data/lib/mail/parsers/rfc2822.rb +58 -35
- data/lib/mail/parsers/rfc2822.treetop +2 -2
- data/lib/mail/part.rb +2 -2
- data/lib/mail/parts_list.rb +16 -8
- data/lib/mail/patterns.rb +7 -2
- data/lib/mail/utilities.rb +31 -1
- data/lib/mail/version.rb +10 -8
- data/lib/mail/version_specific/ruby_1_8.rb +2 -2
- data/lib/mail/version_specific/ruby_1_9.rb +29 -8
- data/lib/mail.rb +8 -4
- metadata +44 -110
- data/lib/mail/attachments_list.rbc +0 -1983
- data/lib/mail/body.rbc +0 -3809
- data/lib/mail/configuration.rbc +0 -1112
- data/lib/mail/core_extensions/nil.rbc +0 -244
- data/lib/mail/core_extensions/string.rbc +0 -0
- data/lib/mail/elements/address.rbc +0 -4112
- data/lib/mail/elements/address_list.rbc +0 -1309
- data/lib/mail/elements/content_disposition_element.rbc +0 -701
- data/lib/mail/elements/content_location_element.rbc +0 -573
- data/lib/mail/elements/content_transfer_encoding_element.rbc +0 -535
- data/lib/mail/elements/content_type_element.rbc +0 -786
- data/lib/mail/elements/date_time_element.rbc +0 -583
- data/lib/mail/elements/envelope_from_element.rbc +0 -771
- data/lib/mail/elements/message_ids_element.rbc +0 -740
- data/lib/mail/elements/mime_version_element.rbc +0 -583
- data/lib/mail/elements/phrase_list.rbc +0 -562
- data/lib/mail/elements/received_element.rbc +0 -725
- data/lib/mail/elements.rbc +0 -362
- data/lib/mail/encodings/7bit.rbc +0 -538
- data/lib/mail/encodings/8bit.rbc +0 -541
- data/lib/mail/encodings/base64.rbc +0 -629
- data/lib/mail/encodings/binary.rbc +0 -529
- data/lib/mail/encodings/quoted_printable.rbc +0 -766
- data/lib/mail/encodings/transfer_encoding.rbc +0 -1134
- data/lib/mail/encodings.rbc +0 -0
- data/lib/mail/envelope.rbc +0 -719
- data/lib/mail/field.rbc +0 -4708
- data/lib/mail/field_list.rbc +0 -518
- data/lib/mail/fields/bcc_field.rbc +0 -564
- data/lib/mail/fields/cc_field.rbc +0 -579
- data/lib/mail/fields/comments_field.rbc +0 -383
- data/lib/mail/fields/common/address_container.rbc +0 -363
- data/lib/mail/fields/common/common_address.rbc +0 -3550
- data/lib/mail/fields/common/common_date.rbc +0 -908
- data/lib/mail/fields/common/common_field.rbc +0 -973
- data/lib/mail/fields/common/common_message_id.rbc +0 -1051
- data/lib/mail/fields/common/parameter_hash.rbc +0 -1335
- data/lib/mail/fields/content_description_field.rbc +0 -396
- data/lib/mail/fields/content_disposition_field.rbc +0 -1440
- data/lib/mail/fields/content_id_field.rbc +0 -1236
- data/lib/mail/fields/content_location_field.rbc +0 -892
- data/lib/mail/fields/content_transfer_encoding_field.rbc +0 -1184
- data/lib/mail/fields/content_type_field.rbc +0 -3958
- data/lib/mail/fields/date_field.rbc +0 -712
- data/lib/mail/fields/from_field.rbc +0 -579
- data/lib/mail/fields/in_reply_to_field.rbc +0 -579
- data/lib/mail/fields/keywords_field.rbc +0 -979
- data/lib/mail/fields/message_id_field.rbc +0 -1008
- data/lib/mail/fields/mime_version_field.rbc +0 -1107
- data/lib/mail/fields/optional_field.rbc +0 -153
- data/lib/mail/fields/received_field.rbc +0 -1137
- data/lib/mail/fields/references_field.rbc +0 -574
- data/lib/mail/fields/reply_to_field.rbc +0 -579
- data/lib/mail/fields/resent_bcc_field.rbc +0 -579
- data/lib/mail/fields/resent_cc_field.rbc +0 -579
- data/lib/mail/fields/resent_date_field.rbc +0 -656
- data/lib/mail/fields/resent_from_field.rbc +0 -579
- data/lib/mail/fields/resent_message_id_field.rbc +0 -639
- data/lib/mail/fields/resent_sender_field.rbc +0 -731
- data/lib/mail/fields/resent_to_field.rbc +0 -579
- data/lib/mail/fields/return_path_field.rbc +0 -737
- data/lib/mail/fields/sender_field.rbc +0 -799
- data/lib/mail/fields/structured_field.rbc +0 -671
- data/lib/mail/fields/subject_field.rbc +0 -378
- data/lib/mail/fields/to_field.rbc +0 -579
- data/lib/mail/fields/unstructured_field.rbc +0 -2292
- data/lib/mail/fields.rbc +0 -782
- data/lib/mail/header.rbc +0 -3720
- data/lib/mail/mail.rbc +0 -2168
- data/lib/mail/message.rbc +0 -19034
- data/lib/mail/network/delivery_methods/file_delivery.rbc +0 -722
- data/lib/mail/network/delivery_methods/sendmail.rbc +0 -800
- data/lib/mail/network/delivery_methods/smtp.rbc +0 -1081
- data/lib/mail/network/delivery_methods/test_mailer.rbc +0 -552
- data/lib/mail/network/retriever_methods/pop3.rbc +0 -2447
- data/lib/mail/network.rbc +0 -236
- data/lib/mail/parsers/address_lists.rbc +0 -1307
- data/lib/mail/parsers/content_disposition.rbc +0 -5968
- data/lib/mail/parsers/content_location.rbc +0 -2166
- data/lib/mail/parsers/content_transfer_encoding.rbc +0 -2591
- data/lib/mail/parsers/content_type.rbc +0 -7949
- data/lib/mail/parsers/date_time.rbc +0 -1836
- data/lib/mail/parsers/envelope_from.rbc +0 -3106
- data/lib/mail/parsers/message_ids.rbc +0 -989
- data/lib/mail/parsers/mime_version.rbc +0 -2254
- data/lib/mail/parsers/phrase_lists.rbc +0 -989
- data/lib/mail/parsers/received.rbc +0 -1267
- data/lib/mail/parsers/rfc2045.rbc +0 -5614
- data/lib/mail/parsers/rfc2822.rbc +0 -74848
- data/lib/mail/parsers/rfc2822_obsolete.rbc +0 -55220
- data/lib/mail/part.rbc +0 -2314
- data/lib/mail/parts_list.rbc +0 -832
- data/lib/mail/patterns.rbc +0 -0
- data/lib/mail/utilities.rbc +0 -2377
- data/lib/mail/version.rbc +0 -450
- data/lib/mail/version_specific/ruby_1_8.rbc +0 -2496
- data/lib/mail.rbc +0 -1151
- data/lib/tasks/corpus.rake.compiled.rbc +0 -2195
- data/lib/tasks/treetop.rake.compiled.rbc +0 -297
data/lib/mail/configuration.rb
CHANGED
|
@@ -35,6 +35,8 @@ module Mail
|
|
|
35
35
|
Mail::Sendmail
|
|
36
36
|
when :file
|
|
37
37
|
Mail::FileDelivery
|
|
38
|
+
when :smtp_connection
|
|
39
|
+
Mail::SMTPConnection
|
|
38
40
|
when :test
|
|
39
41
|
Mail::TestMailer
|
|
40
42
|
else
|
|
@@ -53,6 +55,10 @@ module Mail
|
|
|
53
55
|
Mail::POP3
|
|
54
56
|
when :pop3
|
|
55
57
|
Mail::POP3
|
|
58
|
+
when :imap
|
|
59
|
+
Mail::IMAP
|
|
60
|
+
when :test
|
|
61
|
+
Mail::TestRetriever
|
|
56
62
|
else
|
|
57
63
|
method
|
|
58
64
|
end
|
|
@@ -64,4 +70,4 @@ module Mail
|
|
|
64
70
|
|
|
65
71
|
end
|
|
66
72
|
|
|
67
|
-
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# The following is imported from ruby 1.9.2 shellwords.rb
|
|
2
|
+
#
|
|
3
|
+
module Shellwords
|
|
4
|
+
# Escapes a string so that it can be safely used in a Bourne shell
|
|
5
|
+
# command line.
|
|
6
|
+
#
|
|
7
|
+
# Note that a resulted string should be used unquoted and is not
|
|
8
|
+
# intended for use in double quotes nor in single quotes.
|
|
9
|
+
#
|
|
10
|
+
# open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
|
|
11
|
+
# # ...
|
|
12
|
+
# }
|
|
13
|
+
#
|
|
14
|
+
# +String#shellescape+ is a shorthand for this function.
|
|
15
|
+
#
|
|
16
|
+
# open("| grep #{pattern.shellescape} file") { |pipe|
|
|
17
|
+
# # ...
|
|
18
|
+
# }
|
|
19
|
+
#
|
|
20
|
+
def shellescape(str)
|
|
21
|
+
# An empty argument will be skipped, so return empty quotes.
|
|
22
|
+
return "''" if str.empty?
|
|
23
|
+
|
|
24
|
+
str = str.dup
|
|
25
|
+
|
|
26
|
+
# Process as a single byte sequence because not all shell
|
|
27
|
+
# implementations are multibyte aware.
|
|
28
|
+
str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
|
|
29
|
+
|
|
30
|
+
# A LF cannot be escaped with a backslash because a backslash + LF
|
|
31
|
+
# combo is regarded as line continuation and simply ignored.
|
|
32
|
+
str.gsub!(/\n/, "'\n'")
|
|
33
|
+
|
|
34
|
+
return str
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module_function :shellescape
|
|
38
|
+
|
|
39
|
+
class << self
|
|
40
|
+
alias escape shellescape
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class String
|
|
46
|
+
# call-seq:
|
|
47
|
+
# str.shellescape => string
|
|
48
|
+
#
|
|
49
|
+
# Escapes +str+ so that it can be safely used in a Bourne shell
|
|
50
|
+
# command line. See +Shellwords::shellescape+ for details.
|
|
51
|
+
#
|
|
52
|
+
def shellescape
|
|
53
|
+
Shellwords.escape(self)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Net
|
|
2
|
+
class SMTP
|
|
3
|
+
# This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
|
|
4
|
+
# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
|
|
5
|
+
#
|
|
6
|
+
# Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
|
|
7
|
+
remove_method :tlsconnect if defined?(Net::SMTP.new.tlsconnect)
|
|
8
|
+
|
|
9
|
+
def tlsconnect(s)
|
|
10
|
+
verified = false
|
|
11
|
+
s = OpenSSL::SSL::SSLSocket.new s, @ssl_context
|
|
12
|
+
logging "TLS connection started"
|
|
13
|
+
s.sync_close = true
|
|
14
|
+
s.connect
|
|
15
|
+
if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
|
16
|
+
s.post_connection_check(@address)
|
|
17
|
+
end
|
|
18
|
+
verified = true
|
|
19
|
+
s
|
|
20
|
+
ensure
|
|
21
|
+
s.close unless verified
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -104,7 +104,7 @@ module Mail
|
|
|
104
104
|
# a.local #=> 'mikel'
|
|
105
105
|
def local
|
|
106
106
|
parse unless @parsed
|
|
107
|
-
"#{obs_domain_list}#{get_local.strip}"
|
|
107
|
+
"#{obs_domain_list}#{get_local.strip}" if get_local
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
|
@@ -184,11 +184,11 @@ module Mail
|
|
|
184
184
|
|
|
185
185
|
|
|
186
186
|
def get_domain
|
|
187
|
-
if tree.respond_to?(:angle_addr)
|
|
187
|
+
if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
|
|
188
188
|
@domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
|
|
189
189
|
elsif tree.respond_to?(:domain)
|
|
190
190
|
@domain_text ||= tree.domain.text_value.strip
|
|
191
|
-
elsif tree.respond_to?(:addr_spec)
|
|
191
|
+
elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
|
|
192
192
|
tree.addr_spec.domain.text_value.strip
|
|
193
193
|
else
|
|
194
194
|
nil
|
|
@@ -292,12 +292,12 @@ module Mail
|
|
|
292
292
|
case
|
|
293
293
|
when tree.respond_to?(:local_dot_atom_text)
|
|
294
294
|
tree.local_dot_atom_text.text_value
|
|
295
|
-
when tree.respond_to?(:angle_addr)
|
|
295
|
+
when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_part)
|
|
296
296
|
tree.angle_addr.addr_spec.local_part.text_value
|
|
297
|
-
when tree.respond_to?(:addr_spec)
|
|
297
|
+
when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part)
|
|
298
298
|
tree.addr_spec.local_part.text_value
|
|
299
299
|
else
|
|
300
|
-
tree.local_part.text_value
|
|
300
|
+
tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil
|
|
301
301
|
end
|
|
302
302
|
end
|
|
303
303
|
|
|
@@ -7,7 +7,7 @@ module Mail
|
|
|
7
7
|
def initialize( string )
|
|
8
8
|
parser = Mail::ContentDispositionParser.new
|
|
9
9
|
if tree = parser.parse(cleaned(string))
|
|
10
|
-
@disposition_type = tree.disposition_type.text_value
|
|
10
|
+
@disposition_type = tree.disposition_type.text_value.downcase
|
|
11
11
|
@parameters = tree.parameters
|
|
12
12
|
else
|
|
13
13
|
raise Mail::Field::ParseError, "ContentDispositionElement can not parse |#{string}|\nReason was: #{parser.failure_reason}\n"
|
|
@@ -7,8 +7,8 @@ module Mail
|
|
|
7
7
|
def initialize( string )
|
|
8
8
|
parser = Mail::ContentTypeParser.new
|
|
9
9
|
if tree = parser.parse(cleaned(string))
|
|
10
|
-
@main_type = tree.main_type.text_value
|
|
11
|
-
@sub_type = tree.sub_type.text_value
|
|
10
|
+
@main_type = tree.main_type.text_value.downcase
|
|
11
|
+
@sub_type = tree.sub_type.text_value.downcase
|
|
12
12
|
@parameters = tree.parameters
|
|
13
13
|
else
|
|
14
14
|
raise Mail::Field::ParseError, "ContentTypeElement can not parse |#{string}|\nReason was: #{parser.failure_reason}\n"
|
data/lib/mail/encodings.rb
CHANGED
|
@@ -6,12 +6,12 @@ module Mail
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module Encodings
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
include Mail::Patterns
|
|
11
11
|
extend Mail::Utilities
|
|
12
12
|
|
|
13
13
|
@transfer_encodings = {}
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# Register transfer encoding
|
|
16
16
|
#
|
|
17
17
|
# Example
|
|
@@ -20,23 +20,23 @@ module Mail
|
|
|
20
20
|
def Encodings.register(name, cls)
|
|
21
21
|
@transfer_encodings[get_name(name)] = cls
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
# Is the encoding we want defined?
|
|
25
|
-
#
|
|
25
|
+
#
|
|
26
26
|
# Example:
|
|
27
|
-
#
|
|
27
|
+
#
|
|
28
28
|
# Encodings.defined?(:base64) #=> true
|
|
29
29
|
def Encodings.defined?( str )
|
|
30
30
|
@transfer_encodings.include? get_name(str)
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
# Gets a defined encoding type, QuotedPrintable or Base64 for now.
|
|
34
|
-
#
|
|
35
|
-
# Each encoding needs to be defined as a Mail::Encodings::ClassName for
|
|
34
|
+
#
|
|
35
|
+
# Each encoding needs to be defined as a Mail::Encodings::ClassName for
|
|
36
36
|
# this to work, allows us to add other encodings in the future.
|
|
37
|
-
#
|
|
37
|
+
#
|
|
38
38
|
# Example:
|
|
39
|
-
#
|
|
39
|
+
#
|
|
40
40
|
# Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64
|
|
41
41
|
def Encodings.get_encoding( str )
|
|
42
42
|
@transfer_encodings[get_name(str)]
|
|
@@ -52,16 +52,16 @@ module Mail
|
|
|
52
52
|
|
|
53
53
|
# Encodes a parameter value using URI Escaping, note the language field 'en' can
|
|
54
54
|
# be set using Mail::Configuration, like so:
|
|
55
|
-
#
|
|
55
|
+
#
|
|
56
56
|
# Mail.defaults.do
|
|
57
57
|
# param_encode_language 'jp'
|
|
58
58
|
# end
|
|
59
59
|
#
|
|
60
|
-
# The character set used for encoding will either be the value of $KCODE for
|
|
60
|
+
# The character set used for encoding will either be the value of $KCODE for
|
|
61
61
|
# Ruby < 1.9 or the encoding on the string passed in.
|
|
62
|
-
#
|
|
62
|
+
#
|
|
63
63
|
# Example:
|
|
64
|
-
#
|
|
64
|
+
#
|
|
65
65
|
# Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"
|
|
66
66
|
def Encodings.param_encode(str)
|
|
67
67
|
case
|
|
@@ -75,9 +75,9 @@ module Mail
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# Decodes a parameter value using URI Escaping.
|
|
78
|
-
#
|
|
78
|
+
#
|
|
79
79
|
# Example:
|
|
80
|
-
#
|
|
80
|
+
#
|
|
81
81
|
# Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun"
|
|
82
82
|
#
|
|
83
83
|
# str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1')
|
|
@@ -86,14 +86,14 @@ module Mail
|
|
|
86
86
|
def Encodings.param_decode(str, encoding)
|
|
87
87
|
RubyVer.param_decode(str, encoding)
|
|
88
88
|
end
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# Decodes or encodes a string as needed for either Base64 or QP encoding types in
|
|
91
91
|
# the =?<encoding>?[QB]?<string>?=" format.
|
|
92
|
-
#
|
|
92
|
+
#
|
|
93
93
|
# The output type needs to be :decode to decode the input string or :encode to
|
|
94
94
|
# encode the input string. The character set used for encoding will either be
|
|
95
95
|
# the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.
|
|
96
|
-
#
|
|
96
|
+
#
|
|
97
97
|
# On encoding, will only send out Base64 encoded strings.
|
|
98
98
|
def Encodings.decode_encode(str, output_type)
|
|
99
99
|
case
|
|
@@ -110,39 +110,33 @@ module Mail
|
|
|
110
110
|
|
|
111
111
|
# Decodes a given string as Base64 or Quoted Printable, depending on what
|
|
112
112
|
# type it is.
|
|
113
|
-
#
|
|
113
|
+
#
|
|
114
114
|
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
115
115
|
def Encodings.value_decode(str)
|
|
116
116
|
# Optimization: If there's no encoded-words in the string, just return it
|
|
117
117
|
return str unless str.index("=?")
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
str = str.gsub(/\?=(\s*)=\?/, '?==?') # Remove whitespaces between 'encoded-word's
|
|
120
120
|
|
|
121
121
|
# Split on white-space boundaries with capture, so we capture the white-space as well
|
|
122
122
|
str.split(/([ \t])/).map do |text|
|
|
123
|
-
if text.index('=?')
|
|
123
|
+
if text.index('=?') .nil?
|
|
124
124
|
text
|
|
125
125
|
else
|
|
126
126
|
# Join QP encoded-words that are adjacent to avoid decoding partial chars
|
|
127
127
|
text.gsub!(/\?\=\=\?.+?\?[Qq]\?/m, '') if text =~ /\?==\?/
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
# Separate encoded-words with a space, so we can treat them one by one
|
|
130
130
|
text.gsub!(/\?\=\=\?/, '?= =?')
|
|
131
|
-
|
|
132
131
|
text.split(/ /).map do |word|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
when text.to_str =~ /=\?.+\?[Qq]\?/m
|
|
137
|
-
q_value_decode(word)
|
|
138
|
-
else
|
|
139
|
-
word.to_str
|
|
132
|
+
word.to_str.
|
|
133
|
+
gsub( /=\?.+\?[Bb]\?.+\?=/m ) { |substr| b_value_decode(substr) }.
|
|
134
|
+
gsub( /=\?.+\?[Qq]\?.+\?=/m ) { |substr| q_value_decode(substr) }
|
|
140
135
|
end
|
|
141
|
-
end
|
|
142
136
|
end
|
|
143
137
|
end.join("")
|
|
144
138
|
end
|
|
145
|
-
|
|
139
|
+
|
|
146
140
|
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
|
|
147
141
|
def Encodings.unquote_and_convert_to(str, to_encoding)
|
|
148
142
|
original_encoding, string = split_encoding_from_string( str )
|
|
@@ -153,8 +147,12 @@ module Mail
|
|
|
153
147
|
output
|
|
154
148
|
elsif original_encoding && to_encoding
|
|
155
149
|
begin
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
if RUBY_VERSION >= '1.9'
|
|
151
|
+
output.encode(to_encoding)
|
|
152
|
+
else
|
|
153
|
+
require 'iconv'
|
|
154
|
+
Iconv.iconv(to_encoding, original_encoding, output).first
|
|
155
|
+
end
|
|
158
156
|
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
|
159
157
|
# the 'from' parameter specifies a charset other than what the text
|
|
160
158
|
# actually is...not much we can do in this case but just return the
|
|
@@ -168,7 +166,7 @@ module Mail
|
|
|
168
166
|
output
|
|
169
167
|
end
|
|
170
168
|
end
|
|
171
|
-
|
|
169
|
+
|
|
172
170
|
def Encodings.address_encode(address, charset = 'utf-8')
|
|
173
171
|
if address.is_a?(Array)
|
|
174
172
|
# loop back through for each element
|
|
@@ -180,13 +178,13 @@ module Mail
|
|
|
180
178
|
end
|
|
181
179
|
|
|
182
180
|
def Encodings.encode_non_usascii(address, charset)
|
|
183
|
-
return address if address.ascii_only?
|
|
181
|
+
return address if address.ascii_only? or charset.nil?
|
|
184
182
|
us_ascii = %Q{\x00-\x7f}
|
|
185
183
|
# Encode any non usascii strings embedded inside of quotes
|
|
186
184
|
address.gsub!(/(".*?[^#{us_ascii}].+?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
|
187
185
|
# Then loop through all remaining items and encode as needed
|
|
188
186
|
tokens = address.split(/\s/)
|
|
189
|
-
tokens
|
|
187
|
+
map_with_index(tokens) do |word, i|
|
|
190
188
|
if word.ascii_only?
|
|
191
189
|
word
|
|
192
190
|
else
|
|
@@ -198,60 +196,60 @@ module Mail
|
|
|
198
196
|
end
|
|
199
197
|
end.join(' ')
|
|
200
198
|
end
|
|
201
|
-
|
|
199
|
+
|
|
202
200
|
# Encode a string with Base64 Encoding and returns it ready to be inserted
|
|
203
201
|
# as a value for a field, that is, in the =?<charset>?B?<string>?= format
|
|
204
202
|
#
|
|
205
203
|
# Example:
|
|
206
|
-
#
|
|
207
|
-
# Encodings.b_value_encode('This is あ string', 'UTF-8')
|
|
204
|
+
#
|
|
205
|
+
# Encodings.b_value_encode('This is あ string', 'UTF-8')
|
|
208
206
|
# #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="
|
|
209
207
|
def Encodings.b_value_encode(str, encoding = nil)
|
|
210
208
|
return str if str.to_s.ascii_only?
|
|
211
209
|
string, encoding = RubyVer.b_value_encode(str, encoding)
|
|
212
|
-
string
|
|
210
|
+
map_lines(string) do |str|
|
|
213
211
|
"=?#{encoding}?B?#{str.chomp}?="
|
|
214
212
|
end.join(" ")
|
|
215
213
|
end
|
|
216
|
-
|
|
214
|
+
|
|
217
215
|
# Encode a string with Quoted-Printable Encoding and returns it ready to be inserted
|
|
218
216
|
# as a value for a field, that is, in the =?<charset>?Q?<string>?= format
|
|
219
217
|
#
|
|
220
218
|
# Example:
|
|
221
|
-
#
|
|
222
|
-
# Encodings.q_value_encode('This is あ string', 'UTF-8')
|
|
219
|
+
#
|
|
220
|
+
# Encodings.q_value_encode('This is あ string', 'UTF-8')
|
|
223
221
|
# #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
|
|
224
222
|
def Encodings.q_value_encode(str, encoding = nil)
|
|
225
223
|
return str if str.to_s.ascii_only?
|
|
226
224
|
string, encoding = RubyVer.q_value_encode(str, encoding)
|
|
227
225
|
string.gsub!("=\r\n", '') # We already have limited the string to the length we want
|
|
228
|
-
string
|
|
226
|
+
map_lines(string) do |str|
|
|
229
227
|
"=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
|
|
230
228
|
end.join(" ")
|
|
231
229
|
end
|
|
232
|
-
|
|
230
|
+
|
|
233
231
|
private
|
|
234
|
-
|
|
232
|
+
|
|
235
233
|
# Decodes a Base64 string from the "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" format
|
|
236
|
-
#
|
|
234
|
+
#
|
|
237
235
|
# Example:
|
|
238
|
-
#
|
|
239
|
-
# Encodings.
|
|
236
|
+
#
|
|
237
|
+
# Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
|
|
240
238
|
# #=> 'This is あ string'
|
|
241
239
|
def Encodings.b_value_decode(str)
|
|
242
240
|
RubyVer.b_value_decode(str)
|
|
243
241
|
end
|
|
244
|
-
|
|
242
|
+
|
|
245
243
|
# Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
|
|
246
|
-
#
|
|
244
|
+
#
|
|
247
245
|
# Example:
|
|
248
|
-
#
|
|
249
|
-
# Encodings.
|
|
246
|
+
#
|
|
247
|
+
# Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
|
|
250
248
|
# #=> 'This is あ string'
|
|
251
249
|
def Encodings.q_value_decode(str)
|
|
252
250
|
RubyVer.q_value_decode(str).gsub(/_/, ' ')
|
|
253
251
|
end
|
|
254
|
-
|
|
252
|
+
|
|
255
253
|
def Encodings.split_encoding_from_string( str )
|
|
256
254
|
match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
|
|
257
255
|
if match
|
|
@@ -260,7 +258,7 @@ module Mail
|
|
|
260
258
|
nil
|
|
261
259
|
end
|
|
262
260
|
end
|
|
263
|
-
|
|
261
|
+
|
|
264
262
|
def Encodings.find_encoding(str)
|
|
265
263
|
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
|
|
266
264
|
end
|
data/lib/mail/field.rb
CHANGED
|
@@ -69,7 +69,8 @@ module Mail
|
|
|
69
69
|
# Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
|
|
70
70
|
def initialize(name, value = nil, charset = 'utf-8')
|
|
71
71
|
case
|
|
72
|
-
when name =~ /:/
|
|
72
|
+
when name =~ /:/ # Field.new("field-name: field data")
|
|
73
|
+
charset = value unless value.blank?
|
|
73
74
|
name, value = split(name)
|
|
74
75
|
create_field(name, value, charset)
|
|
75
76
|
when name !~ /:/ && value.blank? # Field.new("field-name")
|
data/lib/mail/field_list.rb
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Mail
|
|
3
3
|
module CommonField # :nodoc:
|
|
4
|
+
|
|
4
5
|
def name=(value)
|
|
5
6
|
@name = value
|
|
6
7
|
end
|
|
7
|
-
|
|
8
|
+
|
|
8
9
|
def name
|
|
9
|
-
@name
|
|
10
|
+
@name ||= nil
|
|
10
11
|
end
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
def value=(value)
|
|
13
14
|
@length = nil
|
|
14
15
|
@tree = nil
|
|
15
16
|
@element = nil
|
|
16
17
|
@value = value
|
|
17
18
|
end
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
def value
|
|
20
21
|
@value
|
|
21
22
|
end
|
|
22
|
-
|
|
23
|
+
|
|
23
24
|
def to_s
|
|
24
25
|
decoded
|
|
25
26
|
end
|
|
26
|
-
|
|
27
|
+
|
|
27
28
|
def default
|
|
28
29
|
decoded
|
|
29
30
|
end
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
def field_length
|
|
32
33
|
@length ||= "#{name}: #{encode(decoded)}".length
|
|
33
34
|
end
|
|
34
|
-
|
|
35
|
+
|
|
35
36
|
def responsible_for?( val )
|
|
36
37
|
name.to_s.downcase == val.to_s.downcase
|
|
37
38
|
end
|
|
38
|
-
|
|
39
|
+
|
|
39
40
|
private
|
|
40
41
|
|
|
41
42
|
def strip_field(field_name, value)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
module Mail
|
|
3
3
|
module CommonMessageId # :nodoc:
|
|
4
4
|
def element
|
|
5
|
-
@element ||= Mail::MessageIdsElement.new(value)
|
|
5
|
+
@element ||= Mail::MessageIdsElement.new(value) unless value.blank?
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def parse(val = value)
|
|
@@ -14,14 +14,15 @@ module Mail
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def message_id
|
|
17
|
-
element.message_id
|
|
17
|
+
element.message_id if element
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def message_ids
|
|
21
|
-
element.message_ids
|
|
21
|
+
element.message_ids if element
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def default
|
|
25
|
+
return nil unless message_ids
|
|
25
26
|
if message_ids.length == 1
|
|
26
27
|
message_ids[0]
|
|
27
28
|
else
|
|
@@ -32,11 +33,11 @@ module Mail
|
|
|
32
33
|
private
|
|
33
34
|
|
|
34
35
|
def do_encode(field_name)
|
|
35
|
-
%Q{#{field_name}: #{
|
|
36
|
+
%Q{#{field_name}: #{do_decode}\r\n}
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def do_decode
|
|
39
|
-
"#{message_ids.map { |m| "<#{m}>" }.join('
|
|
40
|
+
"#{message_ids.map { |m| "<#{m}>" }.join(' ')}" if message_ids
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
end
|
|
@@ -13,13 +13,23 @@ module Mail
|
|
|
13
13
|
include Mail::Utilities
|
|
14
14
|
|
|
15
15
|
def [](key_name)
|
|
16
|
-
|
|
17
|
-
pairs =
|
|
16
|
+
key_pattern = Regexp.escape(key_name.to_s)
|
|
17
|
+
pairs = []
|
|
18
|
+
exact = nil
|
|
19
|
+
each do |k,v|
|
|
20
|
+
if k =~ /^#{key_pattern}(\*|$)/i
|
|
21
|
+
if $1 == '*'
|
|
22
|
+
pairs << [k, v]
|
|
23
|
+
else
|
|
24
|
+
exact = k
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
18
28
|
if pairs.empty? # Just dealing with a single value pair
|
|
19
|
-
super(key_name)
|
|
29
|
+
super(exact || key_name)
|
|
20
30
|
else # Dealing with a multiple value pair or a single encoded value pair
|
|
21
31
|
string = pairs.sort { |a,b| a.first <=> b.first }.map { |v| v.last }.join('')
|
|
22
|
-
if mt = string.match(/([\w
|
|
32
|
+
if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
|
|
23
33
|
string = mt[3]
|
|
24
34
|
encoding = mt[1]
|
|
25
35
|
else
|