# Originally from https://github.com/mikel/mail lib/mail/parsers/rfc2822.treetop module Pre grammar RFC2822 include RFC2822Obsolete rule ALPHA [a-zA-Z] end rule DIGIT [0-9] end rule DQUOTE '"' end rule LF "\n" end rule CR "\r" end rule CRLF "\r\n" end rule WSP [\x09\x20] end rule FWS # Folding white space (WSP* CRLF WSP+) / (CRLF WSP+) / obs_FWS end rule CFWS (FWS* comment)* FWS? end rule NO_WS_CTL [\x01-\x08] / # US-ASCII control characters [\x0B-\x0C] / # that do not include the [\x0E-\x1F] / # carriage return, line feed, [\x7f] # and white space characters end rule specials "(" / ")" / # Special characters used in "<" / ">" / # other parts of the syntax "[" / "]" / ":" / ";" / "@" / '\\' / "," / "." / DQUOTE end rule ctext NO_WS_CTL / # Non white space controls [\x21-\x27] / # The rest of the US-ASCII [\x2a-\x5b] / # characters not including "(", [\x5d-\x7e] # ")", or "\" end rule ccontent ctext / quoted_pair / comment end rule comment "(" ( FWS? ccontent )* FWS? ")" end rule atext ALPHA / DIGIT / # Any character except controls, "!" / "#" / # SP, and specials. "$" / "%" / # Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" end rule mtext (atext / ".")+ end rule atom CFWS? atext+ CFWS? end rule dot_atom CFWS? dot_atom_text CFWS? end rule local_dot_atom CFWS? local_dot_atom_text CFWS? end rule message_id_text mtext+ end rule dot_atom_text (domain_text "."?)+ end rule local_dot_atom_text ("."? domain_text)+ end rule domain_text (DQUOTE (FWS? quoted_domain)+ FWS? DQUOTE) / atext+ end rule quoted_domain qdcontent / "\\" text end rule qdcontent NO_WS_CTL / # Non white space controls [\x21] / # The rest of the US-ASCII [\x23-\x45] / # characters not including "\" [\x47-\x5b] / # or the "." or the [\x5d-\x7e] # double quote character end rule phrase obs_phrase / word+ end rule word atom / quoted_string end rule phrase_list first_phrase:phrase other_phrases:("," FWS* phrase_value:phrase)* end rule domain_literal CFWS? "[" (FWS? dcontent)* FWS? "]" CFWS? end rule dcontent dtext / quoted_pair end rule dtext NO_WS_CTL / # Non white space controls [\x21-\x5a] / # The rest of the US-ASCII characters [\x5e-\x7e] # not including "[", "]", or "\" end rule angle_addr CFWS? "<" addr_spec ">" CFWS? / obs_angle_addr end rule addr_spec (local_part "@" domain) / local_part end rule local_part local_dot_atom / quoted_string / obs_local_part end rule domain dot_atom / domain_literal / obs_domain end rule group group_name:display_name ":" group_list:(mailbox_list_group / CFWS)? ";" CFWS? end rule mailbox_list_group mailbox_list { def addresses [first_addr] + other_addr.elements.map { |o| o.addr_value } end } end rule quoted_string CFWS? DQUOTE quoted_content:(FWS? qcontent)+ FWS? DQUOTE CFWS? end rule qcontent qtext / quoted_pair end rule quoted_pair ("\\" text) / obs_qp end rule qtext NO_WS_CTL / # Non white space controls [\x21] / # The rest of the US-ASCII [\x23-\x5b] / # characters not including "\" [\x5d-\x7e] # or the quote character end rule text [\x01-\x09] / # Characters excluding CR and LF [\x0b-\x0c] / [\x0e-\x7e] / obs_text end rule display_name phrase end rule name_addr display_name angle_addr / angle_addr end rule mailbox_list (first_addr:mailbox other_addr:("," addr_value:mailbox)*) / obs_mbox_list end rule mailbox name_addr / addr_spec end rule address group { def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end } / mailbox { def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end } end rule address_list first_addr:address? other_addr:(FWS* "," FWS* addr_value:address?)* end rule date_time ( day_of_week ",")? date FWS time CFWS? end rule day_of_week (FWS? day_name) / obs_day_of_week end rule day_name "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" end rule date day month year end rule year DIGIT DIGIT DIGIT DIGIT / obs_year end rule month (FWS month_name FWS) / obs_month end rule month_name "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" end rule day (FWS? DIGIT DIGIT?) / obs_day end rule time time_of_day FWS zone end rule time_of_day hour ":" minute ( ":" second )? end rule hour DIGIT DIGIT / obs_hour end rule minute DIGIT DIGIT / obs_minute end rule second DIGIT DIGIT / obs_second end rule zone (( "+" / "-" ) DIGIT DIGIT DIGIT DIGIT) / obs_zone end rule return path CRLF end rule path ((CFWS)? "<" ((CFWS)? / addr_spec) ">" (CFWS)?) / obs_path end rule received name_val_list ";" date_time CRLF end rule name_val_list (CFWS)? (name_val_pair (CFWS name_val_pair)*) end rule name_val_pair item_name CFWS item_value end rule item_name ALPHA (("-")? (ALPHA / DIGIT))* end rule item_value (angle_addr)+ / addr_spec / atom / domain / msg_id end rule message_ids first_msg_id:msg_id other_msg_ids:( CFWS msg_id_value:msg_id )* end rule msg_id (CFWS)? "<" msg_id_value ">" (CFWS)? end rule msg_id_value id_left "@" id_right end rule id_left message_id_text / no_fold_quote / obs_id_left end rule id_right msg_id_dot_atom_text / no_fold_literal / obs_id_right end rule msg_id_dot_atom_text (msg_id_domain_text "."?)+ end rule msg_id_domain_text (DQUOTE (FWS? quoted_domain)+ FWS? DQUOTE) / msg_id_atext+ end rule msg_id_atext ALPHA / DIGIT / # Any character except controls, "!" / "#" / # SP, and specials. "$" / "%" / # Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" / "@" end rule no_fold_quote DQUOTE (qtext / quoted_pair)+ DQUOTE end rule no_fold_literal "[" (dtext / quoted_pair)+ "]" end end end