mail 2.5.2 → 2.6.4

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.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +124 -0
  3. data/CONTRIBUTING.md +21 -6
  4. data/Dependencies.txt +0 -1
  5. data/Gemfile +7 -22
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +86 -31
  8. data/Rakefile +11 -22
  9. data/lib/mail/attachments_list.rb +4 -2
  10. data/lib/mail/body.rb +36 -11
  11. data/lib/mail/check_delivery_params.rb +13 -22
  12. data/lib/mail/configuration.rb +1 -0
  13. data/lib/mail/{patterns.rb → constants.rb} +29 -6
  14. data/lib/mail/core_extensions/smtp.rb +13 -13
  15. data/lib/mail/core_extensions/string/access.rb +1 -0
  16. data/lib/mail/core_extensions/string/multibyte.rb +1 -0
  17. data/lib/mail/core_extensions/string.rb +5 -17
  18. data/lib/mail/elements/address.rb +86 -145
  19. data/lib/mail/elements/address_list.rb +10 -42
  20. data/lib/mail/elements/content_disposition_element.rb +4 -7
  21. data/lib/mail/elements/content_location_element.rb +8 -11
  22. data/lib/mail/elements/content_transfer_encoding_element.rb +4 -10
  23. data/lib/mail/elements/content_type_element.rb +5 -8
  24. data/lib/mail/elements/date_time_element.rb +4 -7
  25. data/lib/mail/elements/envelope_from_element.rb +19 -13
  26. data/lib/mail/elements/message_ids_element.rb +8 -11
  27. data/lib/mail/elements/mime_version_element.rb +4 -7
  28. data/lib/mail/elements/phrase_list.rb +3 -7
  29. data/lib/mail/elements/received_element.rb +4 -7
  30. data/lib/mail/elements.rb +1 -0
  31. data/lib/mail/encodings/7bit.rb +1 -0
  32. data/lib/mail/encodings/8bit.rb +8 -2
  33. data/lib/mail/encodings/base64.rb +7 -1
  34. data/lib/mail/encodings/binary.rb +1 -0
  35. data/lib/mail/encodings/quoted_printable.rb +11 -4
  36. data/lib/mail/encodings/transfer_encoding.rb +27 -17
  37. data/lib/mail/encodings/unix_to_unix.rb +18 -0
  38. data/lib/mail/encodings.rb +54 -39
  39. data/lib/mail/envelope.rb +1 -5
  40. data/lib/mail/field.rb +81 -31
  41. data/lib/mail/field_list.rb +19 -18
  42. data/lib/mail/fields/bcc_field.rb +17 -5
  43. data/lib/mail/fields/cc_field.rb +3 -3
  44. data/lib/mail/fields/comments_field.rb +2 -1
  45. data/lib/mail/fields/common/address_container.rb +1 -0
  46. data/lib/mail/fields/common/common_address.rb +34 -28
  47. data/lib/mail/fields/common/common_date.rb +2 -8
  48. data/lib/mail/fields/common/common_field.rb +9 -5
  49. data/lib/mail/fields/common/common_message_id.rb +3 -2
  50. data/lib/mail/fields/common/parameter_hash.rb +4 -3
  51. data/lib/mail/fields/content_description_field.rb +1 -0
  52. data/lib/mail/fields/content_disposition_field.rb +13 -12
  53. data/lib/mail/fields/content_id_field.rb +4 -4
  54. data/lib/mail/fields/content_location_field.rb +2 -1
  55. data/lib/mail/fields/content_transfer_encoding_field.rb +4 -9
  56. data/lib/mail/fields/content_type_field.rb +4 -3
  57. data/lib/mail/fields/date_field.rb +16 -15
  58. data/lib/mail/fields/from_field.rb +3 -3
  59. data/lib/mail/fields/in_reply_to_field.rb +3 -1
  60. data/lib/mail/fields/keywords_field.rb +2 -2
  61. data/lib/mail/fields/message_id_field.rb +4 -4
  62. data/lib/mail/fields/mime_version_field.rb +3 -2
  63. data/lib/mail/fields/optional_field.rb +1 -0
  64. data/lib/mail/fields/received_field.rb +4 -3
  65. data/lib/mail/fields/references_field.rb +3 -1
  66. data/lib/mail/fields/reply_to_field.rb +3 -3
  67. data/lib/mail/fields/resent_bcc_field.rb +3 -3
  68. data/lib/mail/fields/resent_cc_field.rb +3 -3
  69. data/lib/mail/fields/resent_date_field.rb +2 -1
  70. data/lib/mail/fields/resent_from_field.rb +3 -3
  71. data/lib/mail/fields/resent_message_id_field.rb +1 -0
  72. data/lib/mail/fields/resent_sender_field.rb +4 -4
  73. data/lib/mail/fields/resent_to_field.rb +3 -3
  74. data/lib/mail/fields/return_path_field.rb +1 -1
  75. data/lib/mail/fields/sender_field.rb +9 -9
  76. data/lib/mail/fields/structured_field.rb +1 -0
  77. data/lib/mail/fields/subject_field.rb +1 -0
  78. data/lib/mail/fields/to_field.rb +3 -3
  79. data/lib/mail/fields/unstructured_field.rb +15 -8
  80. data/lib/mail/fields.rb +1 -0
  81. data/lib/mail/header.rb +21 -29
  82. data/lib/mail/indifferent_hash.rb +1 -0
  83. data/lib/mail/mail.rb +16 -1
  84. data/lib/mail/matchers/attachment_matchers.rb +29 -0
  85. data/lib/mail/matchers/has_sent_mail.rb +61 -4
  86. data/lib/mail/message.rb +175 -72
  87. data/lib/mail/multibyte/chars.rb +3 -2
  88. data/lib/mail/multibyte/exceptions.rb +1 -0
  89. data/lib/mail/multibyte/unicode.rb +22 -15
  90. data/lib/mail/multibyte/utils.rb +1 -0
  91. data/lib/mail/multibyte.rb +1 -0
  92. data/lib/mail/network/delivery_methods/exim.rb +3 -7
  93. data/lib/mail/network/delivery_methods/file_delivery.rb +2 -1
  94. data/lib/mail/network/delivery_methods/sendmail.rb +33 -10
  95. data/lib/mail/network/delivery_methods/smtp.rb +32 -34
  96. data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -6
  97. data/lib/mail/network/delivery_methods/test_mailer.rb +3 -2
  98. data/lib/mail/network/retriever_methods/base.rb +1 -0
  99. data/lib/mail/network/retriever_methods/imap.rb +19 -13
  100. data/lib/mail/network/retriever_methods/pop3.rb +1 -0
  101. data/lib/mail/network/retriever_methods/test_retriever.rb +1 -0
  102. data/lib/mail/network.rb +1 -0
  103. data/lib/mail/parsers/address_lists_parser.rb +133 -0
  104. data/lib/mail/parsers/content_disposition_parser.rb +68 -0
  105. data/lib/mail/parsers/content_location_parser.rb +36 -0
  106. data/lib/mail/parsers/content_transfer_encoding_parser.rb +34 -0
  107. data/lib/mail/parsers/content_type_parser.rb +67 -0
  108. data/lib/mail/parsers/date_time_parser.rb +39 -0
  109. data/lib/mail/parsers/envelope_from_parser.rb +46 -0
  110. data/lib/mail/parsers/message_ids_parser.rb +40 -0
  111. data/lib/mail/parsers/mime_version_parser.rb +42 -0
  112. data/lib/mail/parsers/phrase_lists_parser.rb +36 -0
  113. data/lib/mail/parsers/ragel/common.rl +185 -0
  114. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  115. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  116. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  117. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  118. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  119. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  139. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  140. data/lib/mail/parsers/ragel/ruby.rb +40 -0
  141. data/lib/mail/parsers/ragel.rb +18 -0
  142. data/lib/mail/parsers/received_parser.rb +49 -0
  143. data/lib/mail/parsers.rb +27 -0
  144. data/lib/mail/part.rb +11 -4
  145. data/lib/mail/parts_list.rb +30 -10
  146. data/lib/mail/utilities.rb +127 -63
  147. data/lib/mail/values/unicode_tables.dat +0 -0
  148. data/lib/mail/version.rb +8 -15
  149. data/lib/mail/version_specific/ruby_1_8.rb +18 -7
  150. data/lib/mail/version_specific/ruby_1_9.rb +136 -32
  151. data/lib/mail.rb +12 -6
  152. metadata +115 -77
  153. data/lib/VERSION +0 -4
  154. data/lib/load_parsers.rb +0 -41
  155. data/lib/mail/core_extensions/nil.rb +0 -19
  156. data/lib/mail/core_extensions/object.rb +0 -13
  157. data/lib/mail/core_extensions/shell_escape.rb +0 -56
  158. data/lib/mail/parsers/address_lists.rb +0 -64
  159. data/lib/mail/parsers/address_lists.treetop +0 -19
  160. data/lib/mail/parsers/content_disposition.rb +0 -535
  161. data/lib/mail/parsers/content_disposition.treetop +0 -46
  162. data/lib/mail/parsers/content_location.rb +0 -139
  163. data/lib/mail/parsers/content_location.treetop +0 -20
  164. data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
  165. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
  166. data/lib/mail/parsers/content_type.rb +0 -967
  167. data/lib/mail/parsers/content_type.treetop +0 -68
  168. data/lib/mail/parsers/date_time.rb +0 -114
  169. data/lib/mail/parsers/date_time.treetop +0 -11
  170. data/lib/mail/parsers/envelope_from.rb +0 -194
  171. data/lib/mail/parsers/envelope_from.treetop +0 -32
  172. data/lib/mail/parsers/message_ids.rb +0 -45
  173. data/lib/mail/parsers/message_ids.treetop +0 -15
  174. data/lib/mail/parsers/mime_version.rb +0 -144
  175. data/lib/mail/parsers/mime_version.treetop +0 -19
  176. data/lib/mail/parsers/phrase_lists.rb +0 -45
  177. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  178. data/lib/mail/parsers/received.rb +0 -71
  179. data/lib/mail/parsers/received.treetop +0 -11
  180. data/lib/mail/parsers/rfc2045.rb +0 -464
  181. data/lib/mail/parsers/rfc2045.treetop +0 -36
  182. data/lib/mail/parsers/rfc2822.rb +0 -5397
  183. data/lib/mail/parsers/rfc2822.treetop +0 -410
  184. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  185. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  186. data/lib/tasks/corpus.rake +0 -125
  187. data/lib/tasks/treetop.rake +0 -10
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class MessageIdsParser
4
+ def parse(s)
5
+ if Mail::Utilities.blank?(s)
6
+ return MessageIdsStruct.new
7
+ end
8
+
9
+ message_ids = MessageIdsStruct.new([])
10
+
11
+ actions, error = Ragel.parse(:message_ids, s)
12
+ if error
13
+ raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, error)
14
+ end
15
+
16
+ msg_id_s = nil
17
+ actions.each_slice(2) do |action_id, p|
18
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
19
+ case action
20
+
21
+ # Message Ids
22
+ when :msg_id_s then msg_id_s = p
23
+ when :msg_id_e
24
+ message_ids.message_ids << s[msg_id_s..(p-1)].rstrip
25
+
26
+ when :domain_e, :domain_s, :local_dot_atom_e,
27
+ :local_dot_atom_pre_comment_e,
28
+ :local_dot_atom_pre_comment_s,
29
+ :local_dot_atom_s
30
+
31
+ # ignored actions
32
+
33
+ else
34
+ raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, "Failed to process unknown action: #{action}")
35
+ end
36
+ end
37
+ message_ids
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class MimeVersionParser
4
+ include Mail::Utilities
5
+
6
+ def parse(s)
7
+ if Mail::Utilities.blank?(s)
8
+ return MimeVersionStruct.new("", nil)
9
+ end
10
+
11
+ mime_version = MimeVersionStruct.new
12
+
13
+ actions, error = Ragel.parse(:mime_version, s)
14
+ if error
15
+ raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, error)
16
+ end
17
+
18
+ major_digits_s = minor_digits_s = nil
19
+ actions.each_slice(2) do |action_id, p|
20
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
21
+ case action
22
+
23
+ # Major Digits
24
+ when :major_digits_s then major_digits_s = p
25
+ when :major_digits_e
26
+ mime_version.major = s[major_digits_s..(p-1)]
27
+
28
+ # Minor Digits
29
+ when :minor_digits_s then minor_digits_s = p
30
+ when :minor_digits_e
31
+ mime_version.minor = s[minor_digits_s..(p-1)]
32
+
33
+ when :comment_e, :comment_s then nil
34
+
35
+ else
36
+ raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, "Failed to process unknown action: #{action}")
37
+ end
38
+ end
39
+ mime_version
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class PhraseListsParser
4
+
5
+ def parse(s)
6
+ raise Mail::Field::ParseError.new(Mail::PhraseList, s, 'nil is invalid') if s.nil?
7
+
8
+ actions, error = Ragel.parse(:phrase_lists, s)
9
+ if error
10
+ raise Mail::Field::ParseError.new(Mail::PhraseList, s, error)
11
+ end
12
+
13
+ phrase_lists = PhraseListsStruct.new([])
14
+
15
+ phrase_s = nil
16
+ actions.each_slice(2) do |action_id, p|
17
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
18
+ case action
19
+
20
+ # Phrase
21
+ when :phrase_s then phrase_s = p
22
+ when :phrase_e
23
+ phrase_lists.phrases << s[phrase_s..(p-1)] if phrase_s
24
+ phrase_s = nil
25
+
26
+ when :comment_e, :comment_s, :qstr_s, :qstr_e then nil
27
+
28
+ else
29
+ raise Mail::Field::ParseError.new(Mail::PhraseList, s, "Failed to process unknown action: #{action}")
30
+ end
31
+ end
32
+
33
+ phrase_lists
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,185 @@
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
+ null_sender = ('<>' ' '{0,1});
179
+ envelope_from = (addr_spec_no_angle_brackets | null_sender) >address_s %address_e " "
180
+ (ctime_date >ctime_date_s %ctime_date_e);
181
+
182
+ # content_location
183
+ location = quoted_string | ((token | 0x3d)+ >token_string_s %token_string_e);
184
+ content_location = CFWS? location CFWS?;
185
+ }%%
@@ -0,0 +1,30 @@
1
+ %%{
2
+
3
+ machine date_time;
4
+
5
+ # day_of_week
6
+ day_name = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun";
7
+ obs_day_of_week = CFWS? day_name CFWS?;
8
+ day_of_week = (FWS? day_name) | obs_day_of_week;
9
+
10
+ # date
11
+ obs_day = CFWS? (DIGIT | (DIGIT DIGIT)) CFWS?;
12
+ day = (FWS? DIGIT DIGIT? FWS) | obs_day;
13
+ month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec";
14
+ obs_year = CFWS? (DIGIT DIGIT DIGIT*) CFWS?;
15
+ year = FWS DIGIT DIGIT DIGIT DIGIT FWS | obs_year;
16
+ date = day month year;
17
+
18
+ # time
19
+ obs_hour = CFWS? (DIGIT DIGIT) CFWS?;
20
+ hour = DIGIT DIGIT | obs_hour;
21
+ obs_minute = CFWS? (DIGIT DIGIT) CFWS?;
22
+ minute = DIGIT DIGIT | obs_minute;
23
+ obs_second = CFWS? (DIGIT DIGIT) CFWS?;
24
+ second = DIGIT DIGIT | obs_second;
25
+ obs_zone = "UT" | "GMT" | "EST" | "EDT" | "CST" | "CDT" | "MST" | "MDT" | "PST" | "PDT" | 0x41..0x49 | 0x4B..0x5A | 0x61..0x69 | 0x6B..0x7A;
26
+ time_of_day = hour ":" minute (":" second)?;
27
+ zone = FWS ((("+" | "-") DIGIT DIGIT DIGIT DIGIT) | obs_zone);
28
+ time = time_of_day zone;
29
+
30
+ }%%
@@ -0,0 +1,61 @@
1
+ module Mail
2
+ module Parsers
3
+ module Ragel
4
+ ACTIONS = [
5
+ :addr_spec,
6
+ :address_e,
7
+ :address_s,
8
+ :angle_addr_s,
9
+ :comment_e,
10
+ :comment_s,
11
+ :ctime_date_e,
12
+ :ctime_date_s,
13
+ :date_e,
14
+ :date_s,
15
+ :disp_type_e,
16
+ :disp_type_s,
17
+ :domain_e,
18
+ :domain_s,
19
+ :encoding_e,
20
+ :encoding_s,
21
+ :group_name_e,
22
+ :group_name_s,
23
+ :local_dot_atom_e,
24
+ :local_dot_atom_pre_comment_e,
25
+ :local_dot_atom_s,
26
+ :local_quoted_string_e,
27
+ :main_type_e,
28
+ :main_type_s,
29
+ :major_digits_e,
30
+ :major_digits_s,
31
+ :minor_digits_e,
32
+ :minor_digits_s,
33
+ :msg_id_e,
34
+ :msg_id_s,
35
+ :obs_domain_list_e,
36
+ :obs_domain_list_s,
37
+ :param_attr_e,
38
+ :param_attr_s,
39
+ :param_val_e,
40
+ :param_val_s,
41
+ :phrase_e,
42
+ :phrase_s,
43
+ :qstr_e,
44
+ :qstr_s,
45
+ :received_tokens_e,
46
+ :received_tokens_s,
47
+ :sub_type_e,
48
+ :sub_type_s,
49
+ :time_e,
50
+ :time_s,
51
+ :token_string_e,
52
+ :token_string_s
53
+ ]
54
+
55
+ FIELD_PARSERS = %w[ address_lists phrase_lists
56
+ date_time received message_ids envelope_from
57
+ mime_version content_type content_disposition
58
+ content_transfer_encoding content_location ]
59
+ end
60
+ end
61
+ end