mail 2.5.4 → 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.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +7 -2
  3. data/CONTRIBUTING.md +13 -0
  4. data/Dependencies.txt +0 -1
  5. data/Gemfile +9 -7
  6. data/README.md +41 -21
  7. data/Rakefile +10 -2
  8. data/VERSION +4 -0
  9. data/lib/mail/body.rb +2 -2
  10. data/lib/mail/core_extensions/string.rb +12 -2
  11. data/lib/mail/elements/address.rb +38 -82
  12. data/lib/mail/elements/address_list.rb +19 -42
  13. data/lib/mail/elements/content_disposition_element.rb +3 -7
  14. data/lib/mail/elements/content_location_element.rb +2 -6
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
  16. data/lib/mail/elements/content_type_element.rb +4 -8
  17. data/lib/mail/elements/date_time_element.rb +3 -7
  18. data/lib/mail/elements/envelope_from_element.rb +3 -11
  19. data/lib/mail/elements/message_ids_element.rb +1 -6
  20. data/lib/mail/elements/mime_version_element.rb +3 -7
  21. data/lib/mail/elements/phrase_list.rb +2 -7
  22. data/lib/mail/elements/received_element.rb +3 -7
  23. data/lib/mail/encodings.rb +0 -1
  24. data/lib/mail/envelope.rb +0 -5
  25. data/lib/mail/field.rb +53 -17
  26. data/lib/mail/field_list.rb +18 -18
  27. data/lib/mail/fields/common/common_address.rb +15 -20
  28. data/lib/mail/fields/common/common_date.rb +0 -7
  29. data/lib/mail/fields/common/common_field.rb +1 -1
  30. data/lib/mail/fields/content_transfer_encoding_field.rb +0 -6
  31. data/lib/mail/fields/resent_sender_field.rb +1 -1
  32. data/lib/mail/fields/sender_field.rb +1 -1
  33. data/lib/mail/fields/unstructured_field.rb +7 -1
  34. data/lib/mail/header.rb +8 -22
  35. data/lib/mail/mail.rb +12 -0
  36. data/lib/mail/matchers/has_sent_mail.rb +34 -1
  37. data/lib/mail/message.rb +18 -11
  38. data/lib/mail/multibyte/unicode.rb +1 -1
  39. data/lib/mail/network/delivery_methods/sendmail.rb +1 -1
  40. data/lib/mail/network/delivery_methods/smtp.rb +5 -9
  41. data/lib/mail/network/retriever_methods/imap.rb +18 -13
  42. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  43. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  44. data/lib/mail/parsers/content_location_parser.rb +35 -0
  45. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  46. data/lib/mail/parsers/content_type_parser.rb +64 -0
  47. data/lib/mail/parsers/date_time_parser.rb +36 -0
  48. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  49. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  50. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  51. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  52. data/lib/mail/parsers/ragel/common.rl +184 -0
  53. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  54. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  55. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  56. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  57. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  58. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  59. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  60. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  61. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  62. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  63. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  64. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  65. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  66. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  67. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  68. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  69. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  70. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  71. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  72. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  73. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  74. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  75. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  76. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  77. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  78. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  79. data/lib/mail/parsers/ragel/ruby.rb +29 -0
  80. data/lib/mail/parsers/ragel.rb +17 -0
  81. data/lib/mail/parsers/received_parser.rb +47 -0
  82. data/lib/mail/parsers.rb +26 -0
  83. data/lib/mail/parts_list.rb +5 -3
  84. data/lib/mail/patterns.rb +3 -1
  85. data/lib/mail/utilities.rb +3 -1
  86. data/lib/mail/version.rb +1 -1
  87. data/lib/mail/version_specific/ruby_1_8.rb +1 -1
  88. data/lib/mail/version_specific/ruby_1_9.rb +16 -1
  89. data/lib/mail.rb +1 -1
  90. metadata +77 -87
  91. data/lib/VERSION +0 -4
  92. data/lib/load_parsers.rb +0 -35
  93. data/lib/mail/parsers/address_lists.rb +0 -64
  94. data/lib/mail/parsers/address_lists.treetop +0 -19
  95. data/lib/mail/parsers/content_disposition.rb +0 -535
  96. data/lib/mail/parsers/content_disposition.treetop +0 -46
  97. data/lib/mail/parsers/content_location.rb +0 -139
  98. data/lib/mail/parsers/content_location.treetop +0 -20
  99. data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
  100. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
  101. data/lib/mail/parsers/content_type.rb +0 -971
  102. data/lib/mail/parsers/content_type.treetop +0 -68
  103. data/lib/mail/parsers/date_time.rb +0 -114
  104. data/lib/mail/parsers/date_time.treetop +0 -11
  105. data/lib/mail/parsers/envelope_from.rb +0 -194
  106. data/lib/mail/parsers/envelope_from.treetop +0 -32
  107. data/lib/mail/parsers/message_ids.rb +0 -45
  108. data/lib/mail/parsers/message_ids.treetop +0 -15
  109. data/lib/mail/parsers/mime_version.rb +0 -144
  110. data/lib/mail/parsers/mime_version.treetop +0 -19
  111. data/lib/mail/parsers/phrase_lists.rb +0 -45
  112. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  113. data/lib/mail/parsers/received.rb +0 -71
  114. data/lib/mail/parsers/received.treetop +0 -11
  115. data/lib/mail/parsers/rfc2045.rb +0 -421
  116. data/lib/mail/parsers/rfc2045.treetop +0 -35
  117. data/lib/mail/parsers/rfc2822.rb +0 -5397
  118. data/lib/mail/parsers/rfc2822.treetop +0 -408
  119. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  120. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  121. data/lib/tasks/corpus.rake +0 -125
  122. data/lib/tasks/treetop.rake +0 -10
@@ -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,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
+ }%%
@@ -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