mail-portertech 2.6.2.edge
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/CHANGELOG.rdoc +753 -0
- data/CONTRIBUTING.md +60 -0
- data/Dependencies.txt +2 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +683 -0
- data/Rakefile +29 -0
- data/TODO.rdoc +9 -0
- data/lib/mail.rb +91 -0
- data/lib/mail/attachments_list.rb +104 -0
- data/lib/mail/body.rb +291 -0
- data/lib/mail/check_delivery_params.rb +20 -0
- data/lib/mail/configuration.rb +75 -0
- data/lib/mail/core_extensions/nil.rb +19 -0
- data/lib/mail/core_extensions/object.rb +13 -0
- data/lib/mail/core_extensions/smtp.rb +24 -0
- data/lib/mail/core_extensions/string.rb +43 -0
- data/lib/mail/core_extensions/string/access.rb +145 -0
- data/lib/mail/core_extensions/string/multibyte.rb +78 -0
- data/lib/mail/elements.rb +14 -0
- data/lib/mail/elements/address.rb +270 -0
- data/lib/mail/elements/address_list.rb +51 -0
- data/lib/mail/elements/content_disposition_element.rb +26 -0
- data/lib/mail/elements/content_location_element.rb +21 -0
- data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
- data/lib/mail/elements/content_type_element.rb +31 -0
- data/lib/mail/elements/date_time_element.rb +22 -0
- data/lib/mail/elements/envelope_from_element.rb +39 -0
- data/lib/mail/elements/message_ids_element.rb +24 -0
- data/lib/mail/elements/mime_version_element.rb +22 -0
- data/lib/mail/elements/phrase_list.rb +16 -0
- data/lib/mail/elements/received_element.rb +26 -0
- data/lib/mail/encodings.rb +304 -0
- data/lib/mail/encodings/7bit.rb +31 -0
- data/lib/mail/encodings/8bit.rb +31 -0
- data/lib/mail/encodings/base64.rb +33 -0
- data/lib/mail/encodings/binary.rb +31 -0
- data/lib/mail/encodings/quoted_printable.rb +39 -0
- data/lib/mail/encodings/transfer_encoding.rb +58 -0
- data/lib/mail/envelope.rb +30 -0
- data/lib/mail/field.rb +247 -0
- data/lib/mail/field_list.rb +33 -0
- data/lib/mail/fields.rb +35 -0
- data/lib/mail/fields/bcc_field.rb +56 -0
- data/lib/mail/fields/cc_field.rb +55 -0
- data/lib/mail/fields/comments_field.rb +41 -0
- data/lib/mail/fields/common/address_container.rb +16 -0
- data/lib/mail/fields/common/common_address.rb +135 -0
- data/lib/mail/fields/common/common_date.rb +35 -0
- data/lib/mail/fields/common/common_field.rb +57 -0
- data/lib/mail/fields/common/common_message_id.rb +48 -0
- data/lib/mail/fields/common/parameter_hash.rb +58 -0
- data/lib/mail/fields/content_description_field.rb +19 -0
- data/lib/mail/fields/content_disposition_field.rb +70 -0
- data/lib/mail/fields/content_id_field.rb +62 -0
- data/lib/mail/fields/content_location_field.rb +42 -0
- data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
- data/lib/mail/fields/content_type_field.rb +201 -0
- data/lib/mail/fields/date_field.rb +57 -0
- data/lib/mail/fields/from_field.rb +55 -0
- data/lib/mail/fields/in_reply_to_field.rb +56 -0
- data/lib/mail/fields/keywords_field.rb +44 -0
- data/lib/mail/fields/message_id_field.rb +82 -0
- data/lib/mail/fields/mime_version_field.rb +53 -0
- data/lib/mail/fields/optional_field.rb +13 -0
- data/lib/mail/fields/received_field.rb +75 -0
- data/lib/mail/fields/references_field.rb +56 -0
- data/lib/mail/fields/reply_to_field.rb +55 -0
- data/lib/mail/fields/resent_bcc_field.rb +55 -0
- data/lib/mail/fields/resent_cc_field.rb +55 -0
- data/lib/mail/fields/resent_date_field.rb +35 -0
- data/lib/mail/fields/resent_from_field.rb +55 -0
- data/lib/mail/fields/resent_message_id_field.rb +34 -0
- data/lib/mail/fields/resent_sender_field.rb +62 -0
- data/lib/mail/fields/resent_to_field.rb +55 -0
- data/lib/mail/fields/return_path_field.rb +65 -0
- data/lib/mail/fields/sender_field.rb +67 -0
- data/lib/mail/fields/structured_field.rb +51 -0
- data/lib/mail/fields/subject_field.rb +16 -0
- data/lib/mail/fields/to_field.rb +55 -0
- data/lib/mail/fields/unstructured_field.rb +204 -0
- data/lib/mail/header.rb +274 -0
- data/lib/mail/indifferent_hash.rb +146 -0
- data/lib/mail/mail.rb +267 -0
- data/lib/mail/matchers/has_sent_mail.rb +157 -0
- data/lib/mail/message.rb +2160 -0
- data/lib/mail/multibyte.rb +42 -0
- data/lib/mail/multibyte/chars.rb +474 -0
- data/lib/mail/multibyte/exceptions.rb +8 -0
- data/lib/mail/multibyte/unicode.rb +400 -0
- data/lib/mail/multibyte/utils.rb +60 -0
- data/lib/mail/network.rb +14 -0
- data/lib/mail/network/delivery_methods/exim.rb +52 -0
- data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
- data/lib/mail/network/delivery_methods/smtp.rb +142 -0
- data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
- data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
- data/lib/mail/network/retriever_methods/base.rb +63 -0
- data/lib/mail/network/retriever_methods/imap.rb +173 -0
- data/lib/mail/network/retriever_methods/pop3.rb +140 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +64 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/ragel/common.rl +184 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby.rb +39 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/received_parser.rb +47 -0
- data/lib/mail/part.rb +120 -0
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/patterns.rb +37 -0
- data/lib/mail/utilities.rb +225 -0
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +4 -0
- data/lib/mail/version_specific/ruby_1_8.rb +119 -0
- data/lib/mail/version_specific/ruby_1_9.rb +159 -0
- metadata +276 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
module CommonMessageId # :nodoc:
|
4
|
+
def element
|
5
|
+
@element ||= Mail::MessageIdsElement.new(value) unless value.blank?
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse(val = value)
|
9
|
+
unless val.blank?
|
10
|
+
@element = Mail::MessageIdsElement.new(val)
|
11
|
+
else
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def message_id
|
17
|
+
element.message_id if element
|
18
|
+
end
|
19
|
+
|
20
|
+
def message_ids
|
21
|
+
element.message_ids if element
|
22
|
+
end
|
23
|
+
|
24
|
+
def default
|
25
|
+
return nil unless message_ids
|
26
|
+
if message_ids.length == 1
|
27
|
+
message_ids[0]
|
28
|
+
else
|
29
|
+
message_ids
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def do_encode(field_name)
|
36
|
+
%Q{#{field_name}: #{formated_message_ids("\r\n ")}\r\n}
|
37
|
+
end
|
38
|
+
|
39
|
+
def do_decode
|
40
|
+
formated_message_ids(' ')
|
41
|
+
end
|
42
|
+
|
43
|
+
def formated_message_ids(join)
|
44
|
+
message_ids.map{ |m| "<#{m}>" }.join(join) if message_ids
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
|
4
|
+
# ParameterHash is an intelligent Hash that allows you to add
|
5
|
+
# parameter values including the MIME extension paramaters that
|
6
|
+
# have the name*0="blah", name*1="bleh" keys, and will just return
|
7
|
+
# a single key called name="blahbleh" and do any required un-encoding
|
8
|
+
# to make that happen
|
9
|
+
# Parameters are defined in RFC2045, split keys are in RFC2231
|
10
|
+
|
11
|
+
class ParameterHash < IndifferentHash
|
12
|
+
|
13
|
+
include Mail::Utilities
|
14
|
+
|
15
|
+
def [](key_name)
|
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
|
28
|
+
if pairs.empty? # Just dealing with a single value pair
|
29
|
+
super(exact || key_name)
|
30
|
+
else # Dealing with a multiple value pair or a single encoded value pair
|
31
|
+
string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('')
|
32
|
+
if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
|
33
|
+
string = mt[3]
|
34
|
+
encoding = mt[1]
|
35
|
+
else
|
36
|
+
encoding = nil
|
37
|
+
end
|
38
|
+
Mail::Encodings.param_decode(string, encoding)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def encoded
|
43
|
+
map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
|
44
|
+
unless value.ascii_only?
|
45
|
+
value = Mail::Encodings.param_encode(value)
|
46
|
+
key_name = "#{key_name}*"
|
47
|
+
end
|
48
|
+
%Q{#{key_name}=#{quote_token(value)}}
|
49
|
+
end.join(";\r\n\s")
|
50
|
+
end
|
51
|
+
|
52
|
+
def decoded
|
53
|
+
map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
|
54
|
+
%Q{#{key_name}=#{quote_token(value)}}
|
55
|
+
end.join("; ")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Mail
|
6
|
+
class ContentDescriptionField < UnstructuredField
|
7
|
+
|
8
|
+
FIELD_NAME = 'content-description'
|
9
|
+
CAPITALIZED_FIELD = 'Content-Description'
|
10
|
+
|
11
|
+
def initialize(value = nil, charset = 'utf-8')
|
12
|
+
self.charset = charset
|
13
|
+
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
14
|
+
self.parse
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'mail/fields/common/parameter_hash'
|
3
|
+
|
4
|
+
module Mail
|
5
|
+
class ContentDispositionField < StructuredField
|
6
|
+
|
7
|
+
FIELD_NAME = 'content-disposition'
|
8
|
+
CAPITALIZED_FIELD = 'Content-Disposition'
|
9
|
+
|
10
|
+
def initialize(value = nil, charset = 'utf-8')
|
11
|
+
self.charset = charset
|
12
|
+
ensure_filename_quoted(value)
|
13
|
+
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
14
|
+
self.parse
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(val = value)
|
19
|
+
unless val.blank?
|
20
|
+
@element = Mail::ContentDispositionElement.new(val)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def element
|
25
|
+
@element ||= Mail::ContentDispositionElement.new(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def disposition_type
|
29
|
+
element.disposition_type
|
30
|
+
end
|
31
|
+
|
32
|
+
def parameters
|
33
|
+
@parameters = ParameterHash.new
|
34
|
+
element.parameters.each { |p| @parameters.merge!(p) }
|
35
|
+
@parameters
|
36
|
+
end
|
37
|
+
|
38
|
+
def filename
|
39
|
+
case
|
40
|
+
when !parameters['filename'].blank?
|
41
|
+
@filename = parameters['filename']
|
42
|
+
when !parameters['name'].blank?
|
43
|
+
@filename = parameters['name']
|
44
|
+
else
|
45
|
+
@filename = nil
|
46
|
+
end
|
47
|
+
@filename
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: Fix this up
|
51
|
+
def encoded
|
52
|
+
if parameters.length > 0
|
53
|
+
p = ";\r\n\s#{parameters.encoded}\r\n"
|
54
|
+
else
|
55
|
+
p = "\r\n"
|
56
|
+
end
|
57
|
+
"#{CAPITALIZED_FIELD}: #{disposition_type}" + p
|
58
|
+
end
|
59
|
+
|
60
|
+
def decoded
|
61
|
+
if parameters.length > 0
|
62
|
+
p = "; #{parameters.decoded}"
|
63
|
+
else
|
64
|
+
p = ""
|
65
|
+
end
|
66
|
+
"#{disposition_type}" + p
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Mail
|
6
|
+
class ContentIdField < StructuredField
|
7
|
+
|
8
|
+
FIELD_NAME = 'content-id'
|
9
|
+
CAPITALIZED_FIELD = "Content-ID"
|
10
|
+
|
11
|
+
def initialize(value = nil, charset = 'utf-8')
|
12
|
+
self.charset = charset
|
13
|
+
@uniq = 1
|
14
|
+
if value.blank?
|
15
|
+
value = generate_content_id
|
16
|
+
else
|
17
|
+
value = strip_field(FIELD_NAME, value)
|
18
|
+
end
|
19
|
+
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
20
|
+
self.parse
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(val = value)
|
25
|
+
unless val.blank?
|
26
|
+
@element = Mail::MessageIdsElement.new(val)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def element
|
31
|
+
@element ||= Mail::MessageIdsElement.new(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
'Content-ID'
|
36
|
+
end
|
37
|
+
|
38
|
+
def content_id
|
39
|
+
element.message_id
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
"<#{content_id}>"
|
44
|
+
end
|
45
|
+
|
46
|
+
# TODO: Fix this up
|
47
|
+
def encoded
|
48
|
+
"#{CAPITALIZED_FIELD}: #{to_s}\r\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def decoded
|
52
|
+
"#{to_s}"
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def generate_content_id
|
58
|
+
"<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Mail
|
6
|
+
class ContentLocationField < StructuredField
|
7
|
+
|
8
|
+
FIELD_NAME = 'content-location'
|
9
|
+
CAPITALIZED_FIELD = 'Content-Location'
|
10
|
+
|
11
|
+
def initialize(value = nil, charset = 'utf-8')
|
12
|
+
self.charset = charset
|
13
|
+
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
14
|
+
self.parse
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(val = value)
|
19
|
+
unless val.blank?
|
20
|
+
@element = Mail::ContentLocationElement.new(val)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def element
|
25
|
+
@element ||= Mail::ContentLocationElement.new(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def location
|
29
|
+
element.location
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: Fix this up
|
33
|
+
def encoded
|
34
|
+
"#{CAPITALIZED_FIELD}: #{location}\r\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
def decoded
|
38
|
+
location
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module Mail
|
6
|
+
class ContentTransferEncodingField < StructuredField
|
7
|
+
|
8
|
+
FIELD_NAME = 'content-transfer-encoding'
|
9
|
+
CAPITALIZED_FIELD = 'Content-Transfer-Encoding'
|
10
|
+
|
11
|
+
def initialize(value = nil, charset = 'utf-8')
|
12
|
+
self.charset = charset
|
13
|
+
value = '7bit' if value.to_s =~ /7-?bits?/i
|
14
|
+
value = '8bit' if value.to_s =~ /8-?bits?/i
|
15
|
+
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
16
|
+
self.parse
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse(val = value)
|
21
|
+
unless val.blank?
|
22
|
+
@element = Mail::ContentTransferEncodingElement.new(val)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def element
|
27
|
+
@element ||= Mail::ContentTransferEncodingElement.new(value)
|
28
|
+
end
|
29
|
+
|
30
|
+
def encoding
|
31
|
+
element.encoding
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO: Fix this up
|
35
|
+
def encoded
|
36
|
+
"#{CAPITALIZED_FIELD}: #{encoding}\r\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
def decoded
|
40
|
+
encoding
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'mail/fields/common/parameter_hash'
|
3
|
+
|
4
|
+
module Mail
|
5
|
+
class ContentTypeField < StructuredField
|
6
|
+
|
7
|
+
FIELD_NAME = 'content-type'
|
8
|
+
CAPITALIZED_FIELD = 'Content-Type'
|
9
|
+
|
10
|
+
def initialize(value = nil, charset = 'utf-8')
|
11
|
+
self.charset = charset
|
12
|
+
if value.class == Array
|
13
|
+
@main_type = value[0]
|
14
|
+
@sub_type = value[1]
|
15
|
+
@parameters = ParameterHash.new.merge!(value.last)
|
16
|
+
else
|
17
|
+
@main_type = nil
|
18
|
+
@sub_type = nil
|
19
|
+
@parameters = nil
|
20
|
+
value = strip_field(FIELD_NAME, value)
|
21
|
+
end
|
22
|
+
ensure_filename_quoted(value)
|
23
|
+
super(CAPITALIZED_FIELD, value, charset)
|
24
|
+
self.parse
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse(val = value)
|
29
|
+
unless val.blank?
|
30
|
+
self.value = val
|
31
|
+
@element = nil
|
32
|
+
element
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def element
|
37
|
+
begin
|
38
|
+
@element ||= Mail::ContentTypeElement.new(value)
|
39
|
+
rescue
|
40
|
+
attempt_to_clean
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def attempt_to_clean
|
45
|
+
# Sanitize the value, handle special cases
|
46
|
+
@element ||= Mail::ContentTypeElement.new(sanatize(value))
|
47
|
+
rescue
|
48
|
+
# All else fails, just get the MIME media type
|
49
|
+
@element ||= Mail::ContentTypeElement.new(get_mime_type(value))
|
50
|
+
end
|
51
|
+
|
52
|
+
def main_type
|
53
|
+
@main_type ||= element.main_type
|
54
|
+
end
|
55
|
+
|
56
|
+
def sub_type
|
57
|
+
@sub_type ||= element.sub_type
|
58
|
+
end
|
59
|
+
|
60
|
+
def string
|
61
|
+
"#{main_type}/#{sub_type}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def default
|
65
|
+
decoded
|
66
|
+
end
|
67
|
+
|
68
|
+
alias :content_type :string
|
69
|
+
|
70
|
+
def parameters
|
71
|
+
unless @parameters
|
72
|
+
@parameters = ParameterHash.new
|
73
|
+
element.parameters.each { |p| @parameters.merge!(p) }
|
74
|
+
end
|
75
|
+
@parameters
|
76
|
+
end
|
77
|
+
|
78
|
+
def ContentTypeField.with_boundary(type)
|
79
|
+
new("#{type}; boundary=#{generate_boundary}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def ContentTypeField.generate_boundary
|
83
|
+
"--==_mimepart_#{Mail.random_tag}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def value
|
87
|
+
if @value.class == Array
|
88
|
+
"#{@main_type}/#{@sub_type}; #{stringify(parameters)}"
|
89
|
+
else
|
90
|
+
@value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def stringify(params)
|
95
|
+
params.map { |k,v| "#{k}=#{Encodings.param_encode(v)}" }.join("; ")
|
96
|
+
end
|
97
|
+
|
98
|
+
def filename
|
99
|
+
case
|
100
|
+
when parameters['filename']
|
101
|
+
@filename = parameters['filename']
|
102
|
+
when parameters['name']
|
103
|
+
@filename = parameters['name']
|
104
|
+
else
|
105
|
+
@filename = nil
|
106
|
+
end
|
107
|
+
@filename
|
108
|
+
end
|
109
|
+
|
110
|
+
# TODO: Fix this up
|
111
|
+
def encoded
|
112
|
+
if parameters.length > 0
|
113
|
+
p = ";\r\n\s#{parameters.encoded}"
|
114
|
+
else
|
115
|
+
p = ""
|
116
|
+
end
|
117
|
+
"#{CAPITALIZED_FIELD}: #{content_type}#{p}\r\n"
|
118
|
+
end
|
119
|
+
|
120
|
+
def decoded
|
121
|
+
if parameters.length > 0
|
122
|
+
p = "; #{parameters.decoded}"
|
123
|
+
else
|
124
|
+
p = ""
|
125
|
+
end
|
126
|
+
"#{content_type}" + p
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def method_missing(name, *args, &block)
|
132
|
+
if name.to_s =~ /(\w+)=/
|
133
|
+
self.parameters[$1] = args.first
|
134
|
+
@value = "#{content_type}; #{stringify(parameters)}"
|
135
|
+
else
|
136
|
+
super
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Various special cases from random emails found that I am not going to change
|
141
|
+
# the parser for
|
142
|
+
def sanatize( val )
|
143
|
+
|
144
|
+
# TODO: check if there are cases where whitespace is not a separator
|
145
|
+
val = val.
|
146
|
+
gsub(/\s*=\s*/,'='). # remove whitespaces around equal sign
|
147
|
+
tr(' ',';').
|
148
|
+
squeeze(';').
|
149
|
+
gsub(';', '; '). #use '; ' as a separator (or EOL)
|
150
|
+
gsub(/;\s*$/,'') #remove trailing to keep examples below
|
151
|
+
|
152
|
+
if val =~ /(boundary=(\S*))/i
|
153
|
+
val = "#{$`.downcase}boundary=#{$2}#{$'.downcase}"
|
154
|
+
else
|
155
|
+
val.downcase!
|
156
|
+
end
|
157
|
+
|
158
|
+
case
|
159
|
+
when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;;+(.*)$/i
|
160
|
+
# Handles 'text/plain;; format="flowed"' (double semi colon)
|
161
|
+
"#{$1}/#{$2}; #{$3}"
|
162
|
+
when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;\s?(ISO[\w\-]+)$/i
|
163
|
+
# Microsoft helper:
|
164
|
+
# Handles 'type/subtype;ISO-8559-1'
|
165
|
+
"#{$1}/#{$2}; charset=#{quote_atom($3)}"
|
166
|
+
when val.chomp =~ /^text;?$/i
|
167
|
+
# Handles 'text;' and 'text'
|
168
|
+
"text/plain;"
|
169
|
+
when val.chomp =~ /^(\w+);\s(.*)$/i
|
170
|
+
# Handles 'text; <parameters>'
|
171
|
+
"text/plain; #{$2}"
|
172
|
+
when val =~ /([\w\-]+\/[\w\-]+);\scharset="charset="(\w+)""/i
|
173
|
+
# Handles text/html; charset="charset="GB2312""
|
174
|
+
"#{$1}; charset=#{quote_atom($2)}"
|
175
|
+
when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i
|
176
|
+
type = $1
|
177
|
+
# Handles misquoted param values
|
178
|
+
# e.g: application/octet-stream; name=archiveshelp1[1].htm
|
179
|
+
# and: audio/x-midi;\r\n\sname=Part .exe
|
180
|
+
params = $2.to_s.split(/\s+/)
|
181
|
+
params = params.map { |i| i.to_s.chomp.strip }
|
182
|
+
params = params.map { |i| i.split(/\s*\=\s*/) }
|
183
|
+
params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s.gsub(/;$/,""))}" }.join('; ')
|
184
|
+
"#{type}; #{params}"
|
185
|
+
when val =~ /^\s*$/
|
186
|
+
'text/plain'
|
187
|
+
else
|
188
|
+
''
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_mime_type( val )
|
193
|
+
case
|
194
|
+
when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i
|
195
|
+
"#{$1}/#{$2}"
|
196
|
+
else
|
197
|
+
'text/plain'
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|