mail 2.5.5 → 2.6.0
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 +4 -4
- data/CHANGELOG.rdoc +8 -9
- data/CONTRIBUTING.md +13 -0
- data/Dependencies.txt +0 -1
- data/Gemfile +7 -24
- data/README.md +36 -15
- data/Rakefile +10 -2
- data/VERSION +4 -0
- data/lib/mail.rb +1 -1
- data/lib/mail/body.rb +2 -2
- data/lib/mail/check_delivery_params.rb +10 -47
- data/lib/mail/core_extensions/string.rb +12 -2
- data/lib/mail/elements/address.rb +38 -82
- data/lib/mail/elements/address_list.rb +19 -42
- data/lib/mail/elements/content_disposition_element.rb +3 -7
- data/lib/mail/elements/content_location_element.rb +2 -6
- data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
- data/lib/mail/elements/content_type_element.rb +4 -8
- data/lib/mail/elements/date_time_element.rb +3 -7
- data/lib/mail/elements/envelope_from_element.rb +3 -11
- data/lib/mail/elements/message_ids_element.rb +1 -6
- data/lib/mail/elements/mime_version_element.rb +3 -7
- data/lib/mail/elements/phrase_list.rb +2 -7
- data/lib/mail/elements/received_element.rb +3 -7
- data/lib/mail/encodings.rb +0 -1
- data/lib/mail/envelope.rb +0 -5
- data/lib/mail/field.rb +53 -17
- data/lib/mail/field_list.rb +18 -18
- data/lib/mail/fields/common/common_address.rb +15 -20
- data/lib/mail/fields/common/common_date.rb +0 -7
- data/lib/mail/fields/common/common_field.rb +1 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +0 -6
- data/lib/mail/fields/resent_sender_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +1 -1
- data/lib/mail/fields/unstructured_field.rb +7 -1
- data/lib/mail/header.rb +8 -22
- data/lib/mail/mail.rb +12 -0
- data/lib/mail/matchers/has_sent_mail.rb +34 -1
- data/lib/mail/message.rb +18 -11
- data/lib/mail/multibyte/unicode.rb +1 -1
- data/lib/mail/network/delivery_methods/exim.rb +10 -6
- data/lib/mail/network/delivery_methods/file_delivery.rb +8 -4
- data/lib/mail/network/delivery_methods/sendmail.rb +7 -9
- data/lib/mail/network/delivery_methods/smtp.rb +5 -2
- data/lib/mail/network/delivery_methods/smtp_connection.rb +6 -2
- data/lib/mail/network/delivery_methods/test_mailer.rb +8 -5
- data/lib/mail/network/retriever_methods/imap.rb +18 -13
- 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 +29 -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/parts_list.rb +4 -2
- data/lib/mail/patterns.rb +3 -1
- data/lib/mail/utilities.rb +3 -1
- data/lib/mail/version.rb +1 -1
- data/lib/mail/version_specific/ruby_1_8.rb +1 -1
- data/lib/mail/version_specific/ruby_1_9.rb +13 -1
- metadata +55 -51
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -35
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
- data/lib/mail/parsers/content_type.rb +0 -971
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -421
- data/lib/mail/parsers/rfc2045.treetop +0 -35
- data/lib/mail/parsers/rfc2822.rb +0 -5397
- data/lib/mail/parsers/rfc2822.treetop +0 -408
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
@@ -0,0 +1,35 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class ContentLocationParser
|
3
|
+
def parse(s)
|
4
|
+
content_location = ContentLocationStruct.new(nil)
|
5
|
+
if s.blank?
|
6
|
+
return content_location
|
7
|
+
end
|
8
|
+
|
9
|
+
actions, error = Ragel.parse(:content_location, s)
|
10
|
+
if error
|
11
|
+
raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, error)
|
12
|
+
end
|
13
|
+
|
14
|
+
qstr_s = token_string_s = nil
|
15
|
+
actions.each_slice(2) do |action_id, p|
|
16
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
17
|
+
case action
|
18
|
+
|
19
|
+
# Quoted String.
|
20
|
+
when :qstr_s then qstr_s = p
|
21
|
+
when :qstr_e then content_location.location = s[qstr_s..(p-1)]
|
22
|
+
|
23
|
+
# Token String
|
24
|
+
when :token_string_s then token_string_s = p
|
25
|
+
when :token_string_e
|
26
|
+
content_location.location = s[token_string_s..(p-1)]
|
27
|
+
|
28
|
+
else
|
29
|
+
raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, "Failed to process unknown action: #{action}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
content_location
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class ContentTransferEncodingParser
|
3
|
+
|
4
|
+
def parse(s)
|
5
|
+
content_transfer_encoding = ContentTransferEncodingStruct.new("")
|
6
|
+
if s.blank?
|
7
|
+
return content_transfer_encoding
|
8
|
+
end
|
9
|
+
|
10
|
+
actions, error = Ragel.parse(:content_transfer_encoding, s)
|
11
|
+
if error
|
12
|
+
raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, error)
|
13
|
+
end
|
14
|
+
|
15
|
+
encoding_s = nil
|
16
|
+
actions.each_slice(2) do |action_id, p|
|
17
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
18
|
+
case action
|
19
|
+
|
20
|
+
# Encoding
|
21
|
+
when :encoding_s then encoding_s = p
|
22
|
+
when :encoding_e
|
23
|
+
content_transfer_encoding.encoding = s[encoding_s..(p-1)].downcase
|
24
|
+
|
25
|
+
else
|
26
|
+
raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, "Failed to process unknown action: #{action}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
content_transfer_encoding
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class ContentTypeParser
|
3
|
+
include Mail::Utilities
|
4
|
+
|
5
|
+
def parse(s)
|
6
|
+
actions, error = Ragel.parse(:content_type, s)
|
7
|
+
if error
|
8
|
+
raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, error)
|
9
|
+
end
|
10
|
+
|
11
|
+
content_type = ContentTypeStruct.new(nil,nil,[])
|
12
|
+
|
13
|
+
content_type.parameters = []
|
14
|
+
|
15
|
+
main_type_s = sub_type_s = param_attr_s = param_attr = nil
|
16
|
+
qstr_s = qstr = param_val_s = nil
|
17
|
+
actions.each_slice(2) do |action_id, p|
|
18
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
19
|
+
case action
|
20
|
+
|
21
|
+
# Main Type
|
22
|
+
when :main_type_s then main_type_s = p
|
23
|
+
when :main_type_e then
|
24
|
+
content_type.main_type = s[main_type_s..(p-1)].downcase
|
25
|
+
|
26
|
+
# Sub Type
|
27
|
+
when :sub_type_s then sub_type_s = p
|
28
|
+
when :sub_type_e
|
29
|
+
content_type.sub_type = s[sub_type_s..(p-1)].downcase
|
30
|
+
|
31
|
+
# Parameter Attribute
|
32
|
+
when :param_attr_s then param_attr_s = p
|
33
|
+
when :param_attr_e then param_attr = s[param_attr_s..(p-1)]
|
34
|
+
|
35
|
+
# Quoted String.
|
36
|
+
when :qstr_s then qstr_s = p
|
37
|
+
when :qstr_e then qstr = s[qstr_s..(p-1)]
|
38
|
+
|
39
|
+
# Parameter Value
|
40
|
+
when :param_val_s then param_val_s = p
|
41
|
+
when :param_val_e
|
42
|
+
if param_attr.nil?
|
43
|
+
raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "no attribute for value")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Use quoted s value if one exists, otherwise use parameter value
|
47
|
+
if qstr
|
48
|
+
value = qstr
|
49
|
+
else
|
50
|
+
value = s[param_val_s..(p-1)]
|
51
|
+
end
|
52
|
+
|
53
|
+
content_type.parameters << { param_attr => value }
|
54
|
+
param_attr = nil
|
55
|
+
qstr = nil
|
56
|
+
|
57
|
+
else
|
58
|
+
raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "Failed to process unknown action: #{action}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
content_type
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class DateTimeParser
|
3
|
+
include Mail::Utilities
|
4
|
+
|
5
|
+
def parse(s)
|
6
|
+
date_time = DateTimeStruct.new([])
|
7
|
+
|
8
|
+
actions, error = Ragel.parse(:date_time, s)
|
9
|
+
if error
|
10
|
+
raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, error)
|
11
|
+
end
|
12
|
+
|
13
|
+
date_s = time_s = nil
|
14
|
+
actions.each_slice(2) do |action_id, p|
|
15
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
16
|
+
case action
|
17
|
+
|
18
|
+
# Date
|
19
|
+
when :date_s then date_s = p
|
20
|
+
when :date_e
|
21
|
+
date_time.date_string = s[date_s..(p-1)]
|
22
|
+
|
23
|
+
# Time
|
24
|
+
when :time_s then time_s = p
|
25
|
+
when :time_e
|
26
|
+
date_time.time_string = s[time_s..(p-1)]
|
27
|
+
|
28
|
+
else
|
29
|
+
raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, "Failed to process unknown action: #{action}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
date_time
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class EnvelopeFromParser
|
3
|
+
def parse(s)
|
4
|
+
envelope_from = EnvelopeFromStruct.new
|
5
|
+
if s.blank?
|
6
|
+
return envelope_from
|
7
|
+
end
|
8
|
+
|
9
|
+
actions, error = Ragel.parse(:envelope_from, s)
|
10
|
+
if error
|
11
|
+
raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, error)
|
12
|
+
end
|
13
|
+
|
14
|
+
address_s = ctime_date_s = nil
|
15
|
+
envelope_from = EnvelopeFromStruct.new
|
16
|
+
actions.each_slice(2) do |action_id, p|
|
17
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
18
|
+
case action
|
19
|
+
|
20
|
+
# Address
|
21
|
+
when :address_s then address_s = p
|
22
|
+
when :address_e
|
23
|
+
envelope_from.address = s[address_s..(p-1)].rstrip
|
24
|
+
|
25
|
+
# ctime_date
|
26
|
+
when :ctime_date_s then ctime_date_s = p
|
27
|
+
when :ctime_date_e
|
28
|
+
envelope_from.ctime_date = s[ctime_date_s..(p-1)]
|
29
|
+
|
30
|
+
# ignored actions
|
31
|
+
when :angle_addr_s, :comment_e, :comment_s,
|
32
|
+
:domain_e, :domain_s, :local_dot_atom_e,
|
33
|
+
:local_dot_atom_pre_comment_e,
|
34
|
+
:local_dot_atom_pre_comment_s,
|
35
|
+
:local_dot_atom_s, :qstr_e, :qstr_s
|
36
|
+
nil
|
37
|
+
|
38
|
+
else
|
39
|
+
raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, "Failed to process unknown action: #{action}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
envelope_from
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class MessageIdsParser
|
3
|
+
def parse(s)
|
4
|
+
if s.blank?
|
5
|
+
return MessageIdsStruct.new
|
6
|
+
end
|
7
|
+
|
8
|
+
message_ids = MessageIdsStruct.new([])
|
9
|
+
|
10
|
+
actions, error = Ragel.parse(:message_ids, s)
|
11
|
+
if error
|
12
|
+
raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, error)
|
13
|
+
end
|
14
|
+
|
15
|
+
msg_id_s = nil
|
16
|
+
actions.each_slice(2) do |action_id, p|
|
17
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
18
|
+
case action
|
19
|
+
|
20
|
+
# Message Ids
|
21
|
+
when :msg_id_s then msg_id_s = p
|
22
|
+
when :msg_id_e
|
23
|
+
message_ids.message_ids << s[msg_id_s..(p-1)].rstrip
|
24
|
+
|
25
|
+
when :domain_e, :domain_s, :local_dot_atom_e,
|
26
|
+
:local_dot_atom_pre_comment_e,
|
27
|
+
:local_dot_atom_pre_comment_s,
|
28
|
+
:local_dot_atom_s
|
29
|
+
|
30
|
+
# ignored actions
|
31
|
+
|
32
|
+
else
|
33
|
+
raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, "Failed to process unknown action: #{action}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
message_ids
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class MimeVersionParser
|
3
|
+
include Mail::Utilities
|
4
|
+
|
5
|
+
def parse(s)
|
6
|
+
if s.blank?
|
7
|
+
return MimeVersionStruct.new("", nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
mime_version = MimeVersionStruct.new
|
11
|
+
|
12
|
+
actions, error = Ragel.parse(:mime_version, s)
|
13
|
+
if error
|
14
|
+
raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, error)
|
15
|
+
end
|
16
|
+
|
17
|
+
major_digits_s = minor_digits_s = nil
|
18
|
+
actions.each_slice(2) do |action_id, p|
|
19
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
20
|
+
case action
|
21
|
+
|
22
|
+
# Major Digits
|
23
|
+
when :major_digits_s then major_digits_s = p
|
24
|
+
when :major_digits_e
|
25
|
+
mime_version.major = s[major_digits_s..(p-1)]
|
26
|
+
|
27
|
+
# Minor Digits
|
28
|
+
when :minor_digits_s then minor_digits_s = p
|
29
|
+
when :minor_digits_e
|
30
|
+
mime_version.minor = s[minor_digits_s..(p-1)]
|
31
|
+
|
32
|
+
when :comment_e, :comment_s then nil
|
33
|
+
|
34
|
+
else
|
35
|
+
raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, "Failed to process unknown action: #{action}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
mime_version
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mail::Parsers
|
2
|
+
class PhraseListsParser
|
3
|
+
|
4
|
+
def parse(s)
|
5
|
+
actions, error = Ragel.parse(:phrase_lists, s)
|
6
|
+
if error
|
7
|
+
raise Mail::Field::ParseError.new(Mail::PhraseList, s, error)
|
8
|
+
end
|
9
|
+
|
10
|
+
phrase_lists = PhraseListsStruct.new([])
|
11
|
+
|
12
|
+
phrase_s = nil
|
13
|
+
actions.each_slice(2) do |action_id, p|
|
14
|
+
action = Mail::Parsers::Ragel::ACTIONS[action_id]
|
15
|
+
case action
|
16
|
+
|
17
|
+
# Phrase
|
18
|
+
when :phrase_s then phrase_s = p
|
19
|
+
when :phrase_e
|
20
|
+
phrase_lists.phrases << s[phrase_s..(p-1)] if phrase_s
|
21
|
+
phrase_s = nil
|
22
|
+
|
23
|
+
when :comment_e, :comment_s, :qstr_s, :qstr_e then nil
|
24
|
+
|
25
|
+
else
|
26
|
+
raise Mail::Field::ParseError.new(Mail::PhraseList, s, "Failed to process unknown action: #{action}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
phrase_lists
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mail
|
2
|
+
module Parsers
|
3
|
+
module Ragel
|
4
|
+
require 'mail/parsers/ragel/parser_info'
|
5
|
+
require "mail/parsers/ragel/ruby"
|
6
|
+
|
7
|
+
def self.parse(machine, string)
|
8
|
+
@machine_module ||= Ruby
|
9
|
+
@machine_module.parse(machine, string)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.machine_module=(m)
|
13
|
+
@machine_module = m
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
%%{
|
2
|
+
|
3
|
+
machine common;
|
4
|
+
|
5
|
+
action comment_begin { fcall comment_tail; }
|
6
|
+
action comment_exit { fret; }
|
7
|
+
|
8
|
+
# RFC5322: address_lists, date_time, message_ids, phrase_lists, received
|
9
|
+
|
10
|
+
obs_NO_WS_CTL = 0x01..0x08 | 0x0b | 0x0c | 0x0e..0x1f | 0x7f;
|
11
|
+
LF = "\n";
|
12
|
+
CR = "\r";
|
13
|
+
CRLF = "\r\n";
|
14
|
+
WSP = 0x09 | 0x20;
|
15
|
+
obs_ctext = obs_NO_WS_CTL;
|
16
|
+
VCHAR = 0x21..0x7e;
|
17
|
+
obs_qp = "\\" (0x00 | obs_NO_WS_CTL | LF | CR);
|
18
|
+
obs_FWS = (CRLF? WSP)+;
|
19
|
+
ctext = 0x21..0x27 | 0x2a..0x5b | 0x5d..0x7e | obs_ctext;
|
20
|
+
quoted_pair = ("\\" (VCHAR | WSP)) | obs_qp;
|
21
|
+
FWS = (WSP* CRLF WSP+) | (CRLF WSP+) | obs_FWS;
|
22
|
+
ALPHA = [a-zA-Z];
|
23
|
+
DIGIT = [0-9];
|
24
|
+
DQUOTE = '"';
|
25
|
+
obs_qtext = obs_NO_WS_CTL;
|
26
|
+
atext = ALPHA | DIGIT | "!" | "#" | "$" | "%" | "&" |
|
27
|
+
"'" | "*" | "+" | "-" | "/" | "=" | "?" | "^" |
|
28
|
+
"_" | "`" | "{" | "|" | "}" | "~";
|
29
|
+
qtext = 0x21 | 0x23..0x5b | 0x5d..0x7e | obs_qtext;
|
30
|
+
obs_dtext = obs_NO_WS_CTL | quoted_pair;
|
31
|
+
qcontent = qtext | quoted_pair;
|
32
|
+
|
33
|
+
# Handle recursive comments
|
34
|
+
ccontent = ctext | quoted_pair | "(" @comment_begin;
|
35
|
+
comment_tail := ((FWS? ccontent)* >comment_s) FWS? ")" @comment_exit;
|
36
|
+
comment = "(" @comment_begin %comment_e;
|
37
|
+
CFWS = ((FWS? comment)+ FWS?) | FWS;
|
38
|
+
|
39
|
+
quoted_string = CFWS?
|
40
|
+
(DQUOTE
|
41
|
+
(((FWS? qcontent)* FWS?) >qstr_s %qstr_e)
|
42
|
+
DQUOTE)
|
43
|
+
CFWS?;
|
44
|
+
|
45
|
+
atom = CFWS? atext+ CFWS?;
|
46
|
+
word = atom | quoted_string;
|
47
|
+
|
48
|
+
# phrase_lists
|
49
|
+
obs_phrase = (word | "." | "@")+;
|
50
|
+
phrase = (obs_phrase | word+) >phrase_s %phrase_e;
|
51
|
+
phrase_lists = phrase ("," FWS* phrase)*;
|
52
|
+
|
53
|
+
# address_lists
|
54
|
+
|
55
|
+
# local_part:
|
56
|
+
domain_text = (DQUOTE (FWS? qcontent)+ FWS? DQUOTE) | atext+;
|
57
|
+
local_dot_atom_text = ("."* domain_text "."*)+;
|
58
|
+
local_dot_atom = CFWS?
|
59
|
+
(local_dot_atom_text >local_dot_atom_s %local_dot_atom_pre_comment_e)
|
60
|
+
CFWS?;
|
61
|
+
obs_local_part = word ("." word)*;
|
62
|
+
local_part = (local_dot_atom >local_dot_atom_s %local_dot_atom_e |
|
63
|
+
(quoted_string %local_quoted_string_e) |
|
64
|
+
obs_local_part);
|
65
|
+
|
66
|
+
# Treetop parser behavior was to ignore addresses missing '@' inside of angle
|
67
|
+
# brackets. This construction preserves that behavior.
|
68
|
+
local_part_no_capture = (local_dot_atom | quoted_string | obs_local_part);
|
69
|
+
|
70
|
+
# domain:
|
71
|
+
dot_atom_text = "."* domain_text ("."* domain_text)*;
|
72
|
+
dtext = 0x21..0x5a | 0x5e..0x7e | obs_dtext;
|
73
|
+
dot_atom = CFWS? dot_atom_text (CFWS? >(comment_after_address,1));
|
74
|
+
domain_literal = CFWS? "[" (FWS? dtext)* FWS? "]" CFWS?;
|
75
|
+
obs_domain = atom ("." atom)*;
|
76
|
+
domain = (dot_atom | domain_literal | obs_domain) >domain_s %domain_e;
|
77
|
+
|
78
|
+
# addr_spec:
|
79
|
+
|
80
|
+
# The %(end_addr,N) priority resolves uncertainty when whitespace
|
81
|
+
# after an addr_spec could cause it to be interpreted as a
|
82
|
+
# display name: "bar@example.com ,..."
|
83
|
+
|
84
|
+
addr_spec_in_angle_brackets =
|
85
|
+
(local_part "@" domain) %(end_addr,1) |
|
86
|
+
local_part_no_capture %(end_addr,0);
|
87
|
+
|
88
|
+
addr_spec_no_angle_brackets =
|
89
|
+
(local_part "@" domain) %(end_addr,1) |
|
90
|
+
local_part %(end_addr,0);
|
91
|
+
|
92
|
+
# angle_addr:
|
93
|
+
obs_domain_list = (CFWS | ",")* "@" domain ("," CFWS? ("@" domain)?)*;
|
94
|
+
obs_route = (obs_domain_list ":") >obs_domain_list_s %obs_domain_list_e;
|
95
|
+
obs_angle_addr = CFWS? "<" obs_route? addr_spec_in_angle_brackets ">" CFWS?;
|
96
|
+
|
97
|
+
angle_addr = CFWS? ("<" >angle_addr_s) addr_spec_in_angle_brackets ">" CFWS? |
|
98
|
+
obs_angle_addr;
|
99
|
+
|
100
|
+
# Address
|
101
|
+
display_name = phrase;
|
102
|
+
name_addr = display_name? %(end_addr,2) angle_addr;
|
103
|
+
mailbox = (name_addr | addr_spec_no_angle_brackets) >address_s %address_e;
|
104
|
+
obs_mbox_list = (CFWS? ",")* mailbox ("," (mailbox | CFWS)?)*;
|
105
|
+
mailbox_list = (mailbox (("," | ";") mailbox)*) | obs_mbox_list;
|
106
|
+
obs_group_list = (CFWS? ",")+ CFWS?;
|
107
|
+
group_list = mailbox_list | CFWS | obs_group_list;
|
108
|
+
group = (display_name >group_name_s %group_name_e) ":"
|
109
|
+
(group_list?) ";" CFWS?;
|
110
|
+
address = group | mailbox;
|
111
|
+
#obs_addr_list = (CFWS? ",")* address ("," (address | CFWS)?)*;
|
112
|
+
address_lists = address? %(comment_after_address,0)
|
113
|
+
(FWS* ("," | ";") FWS* address?)*;
|
114
|
+
|
115
|
+
# message_ids
|
116
|
+
obs_id_left = local_part;
|
117
|
+
id_left = dot_atom_text | obs_id_left;
|
118
|
+
# id_right modifications to support multiple '@' in msg_id.
|
119
|
+
msg_id_atext = ALPHA | DIGIT | "!" | "#" | "$" | "%" | "&" | "'" | "*" |
|
120
|
+
"+" | "-" | "/" | "=" | "?" | "^" | "_" | "`" | "{" | "|" |
|
121
|
+
"}" | "~" | "@";
|
122
|
+
msg_id_dot_atom_text = (msg_id_atext+ "."?)+;
|
123
|
+
obs_id_right = domain;
|
124
|
+
no_fold_literal = "[" (dtext)* "]";
|
125
|
+
id_right = msg_id_dot_atom_text | no_fold_literal | obs_id_right;
|
126
|
+
msg_id = (CFWS)?
|
127
|
+
(("<" id_left "@" id_right ">") >msg_id_s %msg_id_e)
|
128
|
+
(CFWS)?;
|
129
|
+
message_ids = msg_id (CFWS? msg_id)*;
|
130
|
+
|
131
|
+
include date_time "date_time.rl";
|
132
|
+
date_time = (day_of_week ",")?
|
133
|
+
(date >date_s %date_e) <: (time >time_s %time_e) CFWS?;
|
134
|
+
|
135
|
+
# Added CFWS? to increase robustness
|
136
|
+
# (qmail likes to include a comment style string...?)
|
137
|
+
received_token = word | angle_addr | addr_spec_no_angle_brackets | domain;
|
138
|
+
received = ((CFWS? received_token*) >received_tokens_s %received_tokens_e)
|
139
|
+
";" date_time;
|
140
|
+
|
141
|
+
# RFC2045: mime_version, content_type, content_transfer_encoding
|
142
|
+
mime_version = CFWS?
|
143
|
+
(DIGIT+ >major_digits_s %major_digits_e)
|
144
|
+
comment? "." comment?
|
145
|
+
(DIGIT+ >minor_digits_s %minor_digits_e)
|
146
|
+
CFWS?;
|
147
|
+
|
148
|
+
token = 0x21..0x27 | 0x2a..0x2b | 0x2c..0x2e |
|
149
|
+
0x30..0x39 | 0x41..0x5a | 0x5e..0x7e;
|
150
|
+
value = (quoted_string | (token -- '"' | 0x3d)+) >param_val_s %param_val_e;
|
151
|
+
attribute = (token+) >param_attr_s %param_attr_e;
|
152
|
+
parameter = CFWS? attribute "=" value CFWS?;
|
153
|
+
|
154
|
+
ietf_token = token+;
|
155
|
+
custom_x_token = 'x'i "-" token+;
|
156
|
+
extension_token = ietf_token | custom_x_token;
|
157
|
+
discrete_type = 'text'i | 'image'i | 'audio'i | 'video'i |
|
158
|
+
'application'i | extension_token;
|
159
|
+
composite_type = 'message'i | 'multipart'i | extension_token;
|
160
|
+
iana_token = token+;
|
161
|
+
main_type = (discrete_type | composite_type) >main_type_s %main_type_e;
|
162
|
+
sub_type = (extension_token | iana_token) >sub_type_s %sub_type_e;
|
163
|
+
content_type = main_type "/" sub_type (((CFWS? ";"+) | CFWS) parameter CFWS?)*;
|
164
|
+
|
165
|
+
encoding = ('7bits' | '8bits' | '7bit' | '8bit' | 'binary' |
|
166
|
+
'quoted-printable' | 'base64' | ietf_token |
|
167
|
+
custom_x_token) >encoding_s %encoding_e;
|
168
|
+
content_transfer_encoding = CFWS? encoding CFWS? ";"? CFWS?;
|
169
|
+
|
170
|
+
# RFC2183: content_disposition
|
171
|
+
# TODO: recognize filename, size, creation date, etc.
|
172
|
+
disposition_type = 'inline'i | 'attachment'i | extension_token | '';
|
173
|
+
content_disposition = (disposition_type >disp_type_s %disp_type_e)
|
174
|
+
(CFWS? ";" parameter CFWS?)*;
|
175
|
+
|
176
|
+
# Envelope From
|
177
|
+
ctime_date = day_name " "+ month " "+ day " " time_of_day " " year;
|
178
|
+
envelope_from = (addr_spec_no_angle_brackets) >address_s %address_e " "
|
179
|
+
(ctime_date >ctime_date_s %ctime_date_e);
|
180
|
+
|
181
|
+
# content_location
|
182
|
+
location = quoted_string | ((token | 0x3d)+ >token_string_s %token_string_e);
|
183
|
+
content_location = CFWS? location CFWS?;
|
184
|
+
}%%
|