mail 2.4.4 → 2.5.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mail might be problematic. Click here for more details.
- data/CHANGELOG.rdoc +60 -0
- data/Gemfile +1 -1
- data/README.md +11 -10
- data/lib/VERSION +2 -2
- data/lib/load_parsers.rb +41 -0
- data/lib/mail.rb +18 -17
- data/lib/mail/body.rb +2 -2
- data/lib/mail/check_delivery_params.rb +30 -0
- data/lib/mail/configuration.rb +1 -1
- data/lib/mail/core_extensions/nil.rb +4 -2
- data/lib/mail/core_extensions/shell_escape.rb +1 -1
- data/lib/mail/elements.rb +12 -12
- data/lib/mail/encodings.rb +8 -10
- data/lib/mail/encodings/quoted_printable.rb +1 -1
- data/lib/mail/field.rb +73 -95
- data/lib/mail/fields.rb +32 -32
- data/lib/mail/fields/common/common_address.rb +6 -1
- data/lib/mail/fields/common/common_field.rb +7 -1
- data/lib/mail/fields/common/common_message_id.rb +9 -5
- data/lib/mail/fields/content_disposition_field.rb +1 -0
- data/lib/mail/fields/content_type_field.rb +4 -1
- data/lib/mail/fields/keywords_field.rb +1 -1
- data/lib/mail/fields/unstructured_field.rb +33 -26
- data/lib/mail/header.rb +32 -13
- data/lib/mail/message.rb +8 -9
- data/lib/mail/multibyte/chars.rb +2 -2
- data/lib/mail/multibyte/unicode.rb +6 -0
- data/lib/mail/network.rb +9 -9
- data/lib/mail/network/delivery_methods/exim.rb +5 -1
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +5 -0
- data/lib/mail/network/delivery_methods/smtp.rb +11 -19
- data/lib/mail/network/delivery_methods/smtp_connection.rb +5 -18
- data/lib/mail/network/delivery_methods/test_mailer.rb +5 -1
- data/lib/mail/network/retriever_methods/imap.rb +14 -6
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
- data/lib/mail/parsers/rfc2822.rb +77 -21
- data/lib/mail/parsers/rfc2822.treetop +3 -3
- data/lib/mail/patterns.rb +0 -1
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version_specific/ruby_1_8.rb +18 -1
- data/lib/mail/version_specific/ruby_1_9.rb +7 -1
- metadata +27 -10
- data/Gemfile.lock +0 -36
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,65 @@
|
|
1
1
|
== HEAD
|
2
2
|
|
3
|
+
== Version 2.5.2 - Sun Nov 18 15:01:00 +1100 2012 Mikel Lindsaar <mikel@reinteractive.net>
|
4
|
+
|
5
|
+
* Removing double loading of treetop parsers to remove warnings
|
6
|
+
* Making parsers auto compile on spec suite and load in production code to avoid error that caused yank of 2.5.0
|
7
|
+
* Reapply pull request 443 - CC fields with semicolon are now parsed right (paulwittmann)
|
8
|
+
|
9
|
+
== Version 2.5.1 - Sun Nov 18 14:01:00 +1100 2012 Mikel Lindsaar <mikel@reinteractive.net>
|
10
|
+
|
11
|
+
* Yanked 2.5.0
|
12
|
+
* Reverted pull request 443 - CC fields with semicolon are now parsed right (paulwittmann)
|
13
|
+
|
14
|
+
== Version 2.5.0 - Sun Nov 18 12:20:00 +1100 2012 Mikel Lindsaar <mikel@reinteractive.net>
|
15
|
+
|
16
|
+
Features:
|
17
|
+
* Close pull request 406 - Add Mail#eager_autoload! to load all autoloaded files on demand (bpot)
|
18
|
+
* Close pull request 461 - Allow string as delivery_method (skyeagle, radar)
|
19
|
+
* Close pull request 407 - Do not require Net::IMAP or Net::POP if they're already loaded (bpot)
|
20
|
+
* Close pull request 400 - Raise exception if delivery values or from values are missing completely from an email that is getting delivered (dmathieu)
|
21
|
+
* Close pull request 397 - Support dots in local part of the addresses (eac)
|
22
|
+
* Close pull request 477 - Fixed handling content_type with superfluous spaces (ledermann)
|
23
|
+
* Close pull request 451 - Ignore nil in addresses so things do not blow up when e.g. a user had no email (grosser)
|
24
|
+
* Close pull request 362 - Enable TLS in Ruby 1.8 (kingargyle)
|
25
|
+
* Close pull request 358 - Fix Mail::CommonAddress#value=, Mail::CommonAddress#<< and Mail::Encodings.encode_non_usascii (mrkn)
|
26
|
+
* Close pull request 350 - Makes mail Header object ennumerable (ged)
|
27
|
+
|
28
|
+
Performance:
|
29
|
+
* Close pull request 369 - Mail::Header#charset is called pretty often during header parser work (bogdan)
|
30
|
+
* Close pull request 368 - Improve existing code by moving some objects to contstant instead of constructing them over and over again. (bogdan)
|
31
|
+
* Close pull request 366 - Headers parsing performance optimization (bogdan)
|
32
|
+
* Close pull request 365 - Add maximum_amount of parsed headers configuration parameter (bogdan)
|
33
|
+
|
34
|
+
Bugs:
|
35
|
+
* Close pull request 444 - Fix typo in spec (cczona)
|
36
|
+
* Close pull request 439 - Fix Ruby 1.9 behaviour to match 1.8.7 behaviour on ignoring invalid or undefined characters (ochko)
|
37
|
+
* Close pull request 430 - Unstructured field converts to string before calling encoding on it (brupm mikel)
|
38
|
+
* Close pull request 424 - Use String#to_crlf instead of String#gsub (okkez)
|
39
|
+
* Close pull request 429 - Fix an obvious bug in exim delivery_method (dskim)
|
40
|
+
* Close pull request 425 - Remove Gemfile.lock from generated gem (kbackowski)
|
41
|
+
* Close pull request 414 - Fix typo on "ignoring" (derwiki)
|
42
|
+
* Close pull request 405 - Fix stack overflow (RegexpError) triggered by large emails with an envelope (bpot)
|
43
|
+
* Close pull request 402 - Prevent InReplyTo, Keyword, References or ResentMessageId fields from generating lines longer than 998 chars (pplr)
|
44
|
+
* Close pull request 391 - Fixed failed attachment parsing when file name in headers contains spaces and is not wrapped in quotes (danieltreacy)
|
45
|
+
* Close pull request 385 - Fix Multibyte::Chars#upcase/downcase (technoweenie)
|
46
|
+
* Close pull request 384 - copy dat unicode over from active support (technoweenie)
|
47
|
+
* Close pull request 380 - Split strictly on MIME boundary lines (ConradIrwin)
|
48
|
+
* Close pull request 277 - Fix specific email decoding failure example (yalab)
|
49
|
+
* Close pull request 361 - Support 8bit encoding for ruby 1.9 (bogdan)
|
50
|
+
* Close pull request 346 - Fix two bugs of TestRetriever (ermaker)
|
51
|
+
* Close pull request 337 - Make the behavior of value_decode the same between Ruby 1.8 and Ruby 1.9. (kennyj)
|
52
|
+
* Close pull request 336 - Fix more warning: possibly useless use of == in void context (kennyj)
|
53
|
+
* Close pull request 293 - make charset and mime type more resliant to bad header values (kmeehl)
|
54
|
+
* Fix failing spec Issue 453 on Ruby 1.9.3
|
55
|
+
* Fix mail reading: don't raise invalid byte sequence in UTF-8 when reading non-UTF-8 emails (mreinsch)
|
56
|
+
* Close pull request 353 - define NilClass#blank? only if not defined yet (amatsuda)
|
57
|
+
* Close pull request 357 - Fixes #349 an inverted condition on imap open read_only (felixroeser)
|
58
|
+
* Remove duplicated line feed from regexp
|
59
|
+
* Remove unused variable
|
60
|
+
* Updated IMAP documentation
|
61
|
+
* Tweak publisher
|
62
|
+
|
3
63
|
== Version 2.4.4 - Wed Mar 14 22:44:00 +1100 2012 Mikel Lindsaar <mikel@reinteractive.net>
|
4
64
|
|
5
65
|
* Fix security vulnerability allowing command line exploit when using file delivery method
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Donations
|
|
29
29
|
-------------
|
30
30
|
|
31
31
|
Mail has been downloaded millions of times, by people around the world, in fact,
|
32
|
-
it represents more than 1% of *all* gems downloaded.
|
32
|
+
it represents more than 1% of *all* gems downloaded.
|
33
33
|
|
34
34
|
It is (like all open source software) a labour of love and something I am doing
|
35
35
|
with my own free time. If you would like to say thanks, please feel free to
|
@@ -42,14 +42,15 @@ me a nice email :)
|
|
42
42
|
Compatibility
|
43
43
|
-------------
|
44
44
|
|
45
|
-
Mail is tested by Travis (![Travis Build Status](https://
|
45
|
+
Mail is tested by Travis ([![Travis Build Status](https://travis-ci.org/mikel/mail.png "Build Status")](https://travis-ci.org/mikel/mail)) and works on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
|
46
46
|
|
47
|
-
*
|
48
|
-
* rbx-head-d18 [ x86_64 ]
|
49
|
-
* ree-1.8.7-2011.03 [ i686 ]
|
50
|
-
* ruby-1.8.7-p357 [ i686 ]
|
47
|
+
* ruby-1.8.7-p370 [ i686 ]
|
51
48
|
* ruby-1.9.2-p290 [ x86_64 ]
|
52
|
-
* ruby-1.9.3-
|
49
|
+
* ruby-1.9.3-p327 [ x86_64 ]
|
50
|
+
* jruby-1.6.8 [ x86_64 ]
|
51
|
+
* jruby-1.7.0 [ x86_64 ]
|
52
|
+
* rbx-d18 [ x86_64 ]
|
53
|
+
* rbx-d19 [ x86_64 ]
|
53
54
|
|
54
55
|
Discussion
|
55
56
|
----------
|
@@ -104,7 +105,7 @@ It also means you can be sure Mail will behave correctly.
|
|
104
105
|
API Policy
|
105
106
|
----------
|
106
107
|
|
107
|
-
No API removals within a single point release. All removals to be
|
108
|
+
No API removals within a single point release. All removals to be deprecated with
|
108
109
|
warnings for at least one MINOR point release before removal.
|
109
110
|
|
110
111
|
Also, all private or protected methods to be declared as such - though this is still I/P.
|
@@ -294,7 +295,7 @@ The most recent email:
|
|
294
295
|
```ruby
|
295
296
|
Mail.all #=> Returns an array of all emails
|
296
297
|
Mail.first #=> Returns the first unread email
|
297
|
-
Mail.last #=> Returns the
|
298
|
+
Mail.last #=> Returns the last unread email
|
298
299
|
```
|
299
300
|
|
300
301
|
The first 10 emails sorted by date in ascending order:
|
@@ -641,7 +642,7 @@ License
|
|
641
642
|
|
642
643
|
(The MIT License)
|
643
644
|
|
644
|
-
Copyright (c) 2009, 2010, 2011, 2012
|
645
|
+
Copyright (c) 2009, 2010, 2011, 2012 Mikel Lindsaar
|
645
646
|
|
646
647
|
Permission is hereby granted, free of charge, to any person obtaining
|
647
648
|
a copy of this software and associated documentation files (the
|
data/lib/VERSION
CHANGED
data/lib/load_parsers.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file loads up the parsers for mail to use. It also will attempt to compile parsers
|
3
|
+
# if they don't exist.
|
4
|
+
#
|
5
|
+
# It also only uses the compiler if we are running the SPEC suite
|
6
|
+
module Mail # :doc:
|
7
|
+
require 'treetop/runtime'
|
8
|
+
|
9
|
+
def self.compile_parser(parser)
|
10
|
+
require 'treetop/compiler'
|
11
|
+
STDOUT.puts "Compiling parser #{parser} from treetop source"
|
12
|
+
Treetop.load(File.join(File.dirname(__FILE__)) + "/mail/parsers/#{parser}")
|
13
|
+
end
|
14
|
+
|
15
|
+
parsers = %w[ rfc2822_obsolete rfc2822 address_lists phrase_lists
|
16
|
+
date_time received message_ids envelope_from rfc2045
|
17
|
+
mime_version content_type content_disposition
|
18
|
+
content_transfer_encoding content_location ]
|
19
|
+
|
20
|
+
if defined?(MAIL_SPEC_SUITE_RUNNING)
|
21
|
+
STDOUT.puts "Compiling all parsers from treetop source"
|
22
|
+
|
23
|
+
parsers.each do |parser|
|
24
|
+
compile_parser(parser)
|
25
|
+
end
|
26
|
+
|
27
|
+
else
|
28
|
+
STDOUT.puts "Loading precompiled parsers from ruby source"
|
29
|
+
|
30
|
+
parsers.each do |parser|
|
31
|
+
begin
|
32
|
+
require "mail/parsers/#{parser}"
|
33
|
+
rescue LoadError
|
34
|
+
STDOUT.puts "Couldn't load parser #{parser} from ruby source"
|
35
|
+
compile_parser(parser)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/lib/mail.rb
CHANGED
@@ -46,6 +46,23 @@ module Mail # :doc:
|
|
46
46
|
require 'mail/utilities'
|
47
47
|
require 'mail/configuration'
|
48
48
|
|
49
|
+
@@autoloads = {}
|
50
|
+
def self.register_autoload(name, path)
|
51
|
+
@@autoloads[name] = path
|
52
|
+
autoload(name, path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# This runs through the autoload list and explictly requires them for you.
|
56
|
+
# Useful when running mail in a threaded process.
|
57
|
+
#
|
58
|
+
# Usage:
|
59
|
+
#
|
60
|
+
# require 'mail'
|
61
|
+
# Mail.eager_autoload!
|
62
|
+
def self.eager_autoload!
|
63
|
+
@@autoloads.each { |_,path| require(path) }
|
64
|
+
end
|
65
|
+
|
49
66
|
# Autoload mail send and receive classes.
|
50
67
|
require 'mail/network'
|
51
68
|
|
@@ -60,23 +77,7 @@ module Mail # :doc:
|
|
60
77
|
|
61
78
|
require 'mail/envelope'
|
62
79
|
|
63
|
-
|
64
|
-
date_time received message_ids envelope_from rfc2045
|
65
|
-
mime_version content_type content_disposition
|
66
|
-
content_transfer_encoding content_location ]
|
67
|
-
|
68
|
-
parsers.each do |parser|
|
69
|
-
begin
|
70
|
-
# Try requiring the pre-compiled ruby version first
|
71
|
-
require 'treetop/runtime'
|
72
|
-
require "mail/parsers/#{parser}"
|
73
|
-
rescue LoadError
|
74
|
-
# Otherwise, get treetop to compile and load it
|
75
|
-
require 'treetop/runtime'
|
76
|
-
require 'treetop/compiler'
|
77
|
-
Treetop.load(File.join(File.dirname(__FILE__)) + "/mail/parsers/#{parser}")
|
78
|
-
end
|
79
|
-
end
|
80
|
+
require 'load_parsers'
|
80
81
|
|
81
82
|
# Autoload header field elements and transfer encodings.
|
82
83
|
require 'mail/elements'
|
data/lib/mail/body.rb
CHANGED
@@ -6,7 +6,7 @@ module Mail
|
|
6
6
|
# The body is where the text of the email is stored. Mail treats the body
|
7
7
|
# as a single object. The body itself has no information about boundaries
|
8
8
|
# used in the MIME standard, it just looks at it's content as either a single
|
9
|
-
# block of text, or (if it is a multipart message) as an array of blocks
|
9
|
+
# block of text, or (if it is a multipart message) as an array of blocks of text.
|
10
10
|
#
|
11
11
|
# A body has to be told to split itself up into a multipart message by calling
|
12
12
|
# #split with the correct boundary. This is because the body object has no way
|
@@ -257,7 +257,7 @@ module Mail
|
|
257
257
|
|
258
258
|
def split!(boundary)
|
259
259
|
self.boundary = boundary
|
260
|
-
parts = raw_source.split(
|
260
|
+
parts = raw_source.split(/--#{Regexp.escape(boundary)}(?=(?:--)?\s*$)/)
|
261
261
|
# Make the preamble equal to the preamble (if any)
|
262
262
|
self.preamble = parts[0].to_s.strip
|
263
263
|
# Make the epilogue equal to the epilogue (if any)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Mail
|
2
|
+
|
3
|
+
module CheckDeliveryParams
|
4
|
+
|
5
|
+
def self.included(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
|
8
|
+
def check_params(mail)
|
9
|
+
envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
|
10
|
+
if envelope_from.blank?
|
11
|
+
raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
|
12
|
+
end
|
13
|
+
|
14
|
+
destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
|
15
|
+
if destinations.blank?
|
16
|
+
raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
|
17
|
+
end
|
18
|
+
|
19
|
+
message ||= mail.encoded if mail.respond_to?(:encoded)
|
20
|
+
if message.blank?
|
21
|
+
raise ArgumentError.new('A encoded content is required to send a message')
|
22
|
+
end
|
23
|
+
|
24
|
+
[envelope_from, destinations, message]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/mail/configuration.rb
CHANGED
@@ -30,7 +30,7 @@ module Mail
|
|
30
30
|
|
31
31
|
# Process as a single byte sequence because not all shell
|
32
32
|
# implementations are multibyte aware.
|
33
|
-
str.gsub!(/([^A-Za-z0-9_\s
|
33
|
+
str.gsub!(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1")
|
34
34
|
|
35
35
|
# A LF cannot be escaped with a backslash because a backslash + LF
|
36
36
|
# combo is regarded as line continuation and simply ignored.
|
data/lib/mail/elements.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Mail
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
2
|
+
register_autoload :Address, 'mail/elements/address'
|
3
|
+
register_autoload :AddressList, 'mail/elements/address_list'
|
4
|
+
register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element'
|
5
|
+
register_autoload :ContentLocationElement, 'mail/elements/content_location_element'
|
6
|
+
register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element'
|
7
|
+
register_autoload :ContentTypeElement, 'mail/elements/content_type_element'
|
8
|
+
register_autoload :DateTimeElement, 'mail/elements/date_time_element'
|
9
|
+
register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element'
|
10
|
+
register_autoload :MessageIdsElement, 'mail/elements/message_ids_element'
|
11
|
+
register_autoload :MimeVersionElement, 'mail/elements/mime_version_element'
|
12
|
+
register_autoload :PhraseList, 'mail/elements/phrase_list'
|
13
|
+
register_autoload :ReceivedElement, 'mail/elements/received_element'
|
14
14
|
end
|
data/lib/mail/encodings.rb
CHANGED
@@ -147,19 +147,17 @@ module Mail
|
|
147
147
|
|
148
148
|
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
|
149
149
|
def Encodings.unquote_and_convert_to(str, to_encoding)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
if original_encoding.to_s.downcase.gsub("-", "") == to_encoding.to_s.downcase.gsub("-", "")
|
150
|
+
output = value_decode( str ).to_s # output is already converted to UTF-8
|
151
|
+
|
152
|
+
if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
|
155
153
|
output
|
156
|
-
elsif
|
154
|
+
elsif to_encoding
|
157
155
|
begin
|
158
156
|
if RUBY_VERSION >= '1.9'
|
159
157
|
output.encode(to_encoding)
|
160
158
|
else
|
161
159
|
require 'iconv'
|
162
|
-
Iconv.iconv(to_encoding,
|
160
|
+
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
163
161
|
end
|
164
162
|
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
165
163
|
# the 'from' parameter specifies a charset other than what the text
|
@@ -178,10 +176,10 @@ module Mail
|
|
178
176
|
def Encodings.address_encode(address, charset = 'utf-8')
|
179
177
|
if address.is_a?(Array)
|
180
178
|
# loop back through for each element
|
181
|
-
address.map { |a| Encodings.address_encode(a, charset) }.join(", ")
|
179
|
+
address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
|
182
180
|
else
|
183
181
|
# find any word boundary that is not ascii and encode it
|
184
|
-
encode_non_usascii(address, charset)
|
182
|
+
encode_non_usascii(address, charset) if address
|
185
183
|
end
|
186
184
|
end
|
187
185
|
|
@@ -189,7 +187,7 @@ module Mail
|
|
189
187
|
return address if address.ascii_only? or charset.nil?
|
190
188
|
us_ascii = %Q{\x00-\x7f}
|
191
189
|
# Encode any non usascii strings embedded inside of quotes
|
192
|
-
address.gsub
|
190
|
+
address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
193
191
|
# Then loop through all remaining items and encode as needed
|
194
192
|
tokens = address.split(/\s/)
|
195
193
|
map_with_index(tokens) do |word, i|
|
data/lib/mail/field.rb
CHANGED
@@ -5,11 +5,11 @@ module Mail
|
|
5
5
|
# Provides a single class to call to create a new structured or unstructured
|
6
6
|
# field. Works out per RFC what field of field it is being given and returns
|
7
7
|
# the correct field of class back on new.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# ===Per RFC 2822
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# 2.2. Header Fields
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# Header fields are lines composed of a field name, followed by a colon
|
14
14
|
# (":"), followed by a field body, and terminated by CRLF. A field
|
15
15
|
# name MUST be composed of printable US-ASCII characters (i.e.,
|
@@ -19,12 +19,12 @@ module Mail
|
|
19
19
|
# used in header "folding" and "unfolding" as described in section
|
20
20
|
# 2.2.3. All field bodies MUST conform to the syntax described in
|
21
21
|
# sections 3 and 4 of this standard.
|
22
|
-
#
|
22
|
+
#
|
23
23
|
class Field
|
24
|
-
|
24
|
+
|
25
25
|
include Patterns
|
26
26
|
include Comparable
|
27
|
-
|
27
|
+
|
28
28
|
STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition
|
29
29
|
content-id content-location content-transfer-encoding
|
30
30
|
content-type date from in-reply-to keywords message-id
|
@@ -34,7 +34,39 @@ module Mail
|
|
34
34
|
return-path sender to ]
|
35
35
|
|
36
36
|
KNOWN_FIELDS = STRUCTURED_FIELDS + ['comments', 'subject']
|
37
|
-
|
37
|
+
|
38
|
+
FIELDS_MAP = {
|
39
|
+
"to" => ToField,
|
40
|
+
"cc" => CcField,
|
41
|
+
"bcc" => BccField,
|
42
|
+
"message-id" => MessageIdField,
|
43
|
+
"in-reply-to" => InReplyToField,
|
44
|
+
"references" => ReferencesField,
|
45
|
+
"subject" => SubjectField,
|
46
|
+
"comments" => CommentsField,
|
47
|
+
"keywords" => KeywordsField,
|
48
|
+
"date" => DateField,
|
49
|
+
"from" => FromField,
|
50
|
+
"sender" => SenderField,
|
51
|
+
"reply-to" => ReplyToField,
|
52
|
+
"resent-date" => ResentDateField,
|
53
|
+
"resent-from" => ResentFromField,
|
54
|
+
"resent-sender" => ResentSenderField,
|
55
|
+
"resent-to" => ResentToField,
|
56
|
+
"resent-cc" => ResentCcField,
|
57
|
+
"resent-bcc" => ResentBccField,
|
58
|
+
"resent-message-id" => ResentMessageIdField,
|
59
|
+
"return-path" => ReturnPathField,
|
60
|
+
"received" => ReceivedField,
|
61
|
+
"mime-version" => MimeVersionField,
|
62
|
+
"content-transfer-encoding" => ContentTransferEncodingField,
|
63
|
+
"content-description" => ContentDescriptionField,
|
64
|
+
"content-disposition" => ContentDispositionField,
|
65
|
+
"content-type" => ContentTypeField,
|
66
|
+
"content-id" => ContentIdField,
|
67
|
+
"content-location" => ContentLocationField,
|
68
|
+
}
|
69
|
+
|
38
70
|
# Generic Field Exception
|
39
71
|
class FieldError < StandardError
|
40
72
|
end
|
@@ -55,25 +87,25 @@ module Mail
|
|
55
87
|
# Raised when attempting to set a structured field's contents to an invalid syntax
|
56
88
|
class SyntaxError < FieldError #:nodoc:
|
57
89
|
end
|
58
|
-
|
90
|
+
|
59
91
|
# Accepts a string:
|
60
|
-
#
|
92
|
+
#
|
61
93
|
# Field.new("field-name: field data")
|
62
|
-
#
|
94
|
+
#
|
63
95
|
# Or name, value pair:
|
64
|
-
#
|
96
|
+
#
|
65
97
|
# Field.new("field-name", "value")
|
66
|
-
#
|
98
|
+
#
|
67
99
|
# Or a name by itself:
|
68
|
-
#
|
100
|
+
#
|
69
101
|
# Field.new("field-name")
|
70
|
-
#
|
102
|
+
#
|
71
103
|
# Note, does not want a terminating carriage return. Returns
|
72
104
|
# self appropriately parsed. If value is not a string, then
|
73
105
|
# it will be passed through as is, for example, content-type
|
74
|
-
# field can accept an array with the type and a hash of
|
106
|
+
# field can accept an array with the type and a hash of
|
75
107
|
# parameters:
|
76
|
-
#
|
108
|
+
#
|
77
109
|
# Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
|
78
110
|
def initialize(name, value = nil, charset = 'utf-8')
|
79
111
|
case
|
@@ -92,47 +124,47 @@ module Mail
|
|
92
124
|
def field=(value)
|
93
125
|
@field = value
|
94
126
|
end
|
95
|
-
|
127
|
+
|
96
128
|
def field
|
97
129
|
@field
|
98
130
|
end
|
99
|
-
|
131
|
+
|
100
132
|
def name
|
101
133
|
field.name
|
102
134
|
end
|
103
|
-
|
135
|
+
|
104
136
|
def value
|
105
137
|
field.value
|
106
138
|
end
|
107
|
-
|
139
|
+
|
108
140
|
def value=(val)
|
109
141
|
create_field(name, val, charset)
|
110
142
|
end
|
111
|
-
|
143
|
+
|
112
144
|
def to_s
|
113
145
|
field.to_s
|
114
146
|
end
|
115
|
-
|
147
|
+
|
116
148
|
def update(name, value)
|
117
149
|
create_field(name, value, charset)
|
118
150
|
end
|
119
|
-
|
151
|
+
|
120
152
|
def same( other )
|
121
153
|
match_to_s(other.name, field.name)
|
122
154
|
end
|
123
|
-
|
155
|
+
|
124
156
|
alias_method :==, :same
|
125
|
-
|
157
|
+
|
126
158
|
def <=>( other )
|
127
159
|
self_order = FIELD_ORDER.rindex(self.name.to_s.downcase) || 100
|
128
160
|
other_order = FIELD_ORDER.rindex(other.name.to_s.downcase) || 100
|
129
161
|
self_order <=> other_order
|
130
162
|
end
|
131
|
-
|
163
|
+
|
132
164
|
def method_missing(name, *args, &block)
|
133
165
|
field.send(name, *args, &block)
|
134
166
|
end
|
135
|
-
|
167
|
+
|
136
168
|
FIELD_ORDER = %w[ return-path received
|
137
169
|
resent-date resent-from resent-sender resent-to
|
138
170
|
resent-cc resent-bcc resent-message-id
|
@@ -141,16 +173,16 @@ module Mail
|
|
141
173
|
subject comments keywords
|
142
174
|
mime-version content-type content-transfer-encoding
|
143
175
|
content-location content-disposition content-description ]
|
144
|
-
|
176
|
+
|
145
177
|
private
|
146
|
-
|
178
|
+
|
147
179
|
def split(raw_field)
|
148
180
|
match_data = raw_field.mb_chars.match(/^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/)
|
149
181
|
[match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip]
|
150
182
|
rescue
|
151
|
-
STDERR.puts "WARNING: Could not parse (and so
|
183
|
+
STDERR.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'"
|
152
184
|
end
|
153
|
-
|
185
|
+
|
154
186
|
def create_field(name, value, charset)
|
155
187
|
begin
|
156
188
|
self.field = new_field(name, value, charset)
|
@@ -162,73 +194,19 @@ module Mail
|
|
162
194
|
end
|
163
195
|
|
164
196
|
def new_field(name, value, charset)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
BccField.new(value, charset)
|
174
|
-
when /^message-id$/i
|
175
|
-
MessageIdField.new(value, charset)
|
176
|
-
when /^in-reply-to$/i
|
177
|
-
InReplyToField.new(value, charset)
|
178
|
-
when /^references$/i
|
179
|
-
ReferencesField.new(value, charset)
|
180
|
-
when /^subject$/i
|
181
|
-
SubjectField.new(value, charset)
|
182
|
-
when /^comments$/i
|
183
|
-
CommentsField.new(value, charset)
|
184
|
-
when /^keywords$/i
|
185
|
-
KeywordsField.new(value, charset)
|
186
|
-
when /^date$/i
|
187
|
-
DateField.new(value, charset)
|
188
|
-
when /^from$/i
|
189
|
-
FromField.new(value, charset)
|
190
|
-
when /^sender$/i
|
191
|
-
SenderField.new(value, charset)
|
192
|
-
when /^reply-to$/i
|
193
|
-
ReplyToField.new(value, charset)
|
194
|
-
when /^resent-date$/i
|
195
|
-
ResentDateField.new(value, charset)
|
196
|
-
when /^resent-from$/i
|
197
|
-
ResentFromField.new(value, charset)
|
198
|
-
when /^resent-sender$/i
|
199
|
-
ResentSenderField.new(value, charset)
|
200
|
-
when /^resent-to$/i
|
201
|
-
ResentToField.new(value, charset)
|
202
|
-
when /^resent-cc$/i
|
203
|
-
ResentCcField.new(value, charset)
|
204
|
-
when /^resent-bcc$/i
|
205
|
-
ResentBccField.new(value, charset)
|
206
|
-
when /^resent-message-id$/i
|
207
|
-
ResentMessageIdField.new(value, charset)
|
208
|
-
when /^return-path$/i
|
209
|
-
ReturnPathField.new(value, charset)
|
210
|
-
when /^received$/i
|
211
|
-
ReceivedField.new(value, charset)
|
212
|
-
when /^mime-version$/i
|
213
|
-
MimeVersionField.new(value, charset)
|
214
|
-
when /^content-transfer-encoding$/i
|
215
|
-
ContentTransferEncodingField.new(value, charset)
|
216
|
-
when /^content-description$/i
|
217
|
-
ContentDescriptionField.new(value, charset)
|
218
|
-
when /^content-disposition$/i
|
219
|
-
ContentDispositionField.new(value, charset)
|
220
|
-
when /^content-type$/i
|
221
|
-
ContentTypeField.new(value, charset)
|
222
|
-
when /^content-id$/i
|
223
|
-
ContentIdField.new(value, charset)
|
224
|
-
when /^content-location$/i
|
225
|
-
ContentLocationField.new(value, charset)
|
226
|
-
else
|
197
|
+
lower_case_name = name.to_s.downcase
|
198
|
+
header_name = nil
|
199
|
+
FIELDS_MAP.each do |field_name, _|
|
200
|
+
header_name = field_name if lower_case_name == field_name
|
201
|
+
end
|
202
|
+
if header_name
|
203
|
+
FIELDS_MAP[header_name].new(value, charset)
|
204
|
+
else
|
227
205
|
OptionalField.new(name, value, charset)
|
228
206
|
end
|
229
|
-
|
207
|
+
|
230
208
|
end
|
231
209
|
|
232
210
|
end
|
233
|
-
|
211
|
+
|
234
212
|
end
|