1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
# frozen_string_literal: true
require 'mail/utilities'
require 'mail/parser_tools'
begin
original_verbose, $VERBOSE = $VERBOSE, nil
%%{
machine address_lists;
alphtype int;
# Phrase
action phrase_s { phrase_s = p }
action phrase_e { phrase_e = p-1 }
# Quoted String.
action qstr_s { qstr_s = p }
action qstr_e { qstr = chars(data, qstr_s, p-1) }
# Comment
action comment_s { comment_s = p unless comment_s }
action comment_e {
if address
address.comments << chars(data, comment_s, p-2)
end
comment_s = nil
}
# Group Name
action group_name_s { group_name_s = p }
action group_name_e {
if qstr
group = qstr
qstr = nil
else
group = chars(data, group_name_s, p-1)
group_name_s = nil
end
address_list.group_names << group
group_name = group
# Start next address
address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
address_s = p
address.group = group_name
}
# Address
action address_s { address_s = p }
# Ignore address end events without a start event.
action address_e {
if address_s
if address.local.nil? && local_dot_atom_pre_comment_e && local_dot_atom_s && local_dot_atom_e
if address.domain
address.local = chars(data, local_dot_atom_s, local_dot_atom_e)
else
address.local = chars(data, local_dot_atom_s, local_dot_atom_pre_comment_e)
end
end
address.raw = chars(data, address_s, p-1)
address_list.addresses << address if address
# Start next address
address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
address.group = group_name
address_s = nil
end
}
# Don't set the display name until the address has actually started. This
# allows us to choose quoted_s version if it exists and always use the
# 'full' phrase version.
action angle_addr_s {
if qstr
address.display_name = Mail::Utilities.unescape(qstr)
qstr = nil
elsif phrase_e
address.display_name = chars(data, phrase_s, phrase_e).strip
phrase_e = phrase_s = nil
end
}
# Domain
action domain_s { domain_s = p }
action domain_e {
address.domain = chars(data, domain_s, p-1).rstrip if address
}
# Local
action local_dot_atom_s { local_dot_atom_s = p }
action local_dot_atom_e { local_dot_atom_e = p-1 }
action local_dot_atom_pre_comment_e { local_dot_atom_pre_comment_e = p-1 }
action local_quoted_string_e { address.local = '"' + qstr + '"' if address }
# obs_domain_list
action obs_domain_list_s { obs_domain_list_s = p }
action obs_domain_list_e { address.obs_domain_list = chars(data, obs_domain_list_s, p-1) }
# Junk actions
action addr_spec { }
action ctime_date_e { }
action ctime_date_s { }
action date_e { }
action date_s { }
action disp_type_e { }
action disp_type_s { }
action encoding_e { }
action encoding_s { }
action main_type_e { }
action main_type_s { }
action major_digits_e { }
action major_digits_s { }
action minor_digits_e { }
action minor_digits_s { }
action msg_id_e { }
action msg_id_s { }
action param_attr_e { }
action param_attr_s { }
action param_val_e { }
action param_val_s { }
action received_tokens_e { }
action received_tokens_s { }
action sub_type_e { }
action sub_type_s { }
action time_e { }
action time_s { }
action token_string_e { }
action token_string_s { }
include rfc5322 "rfc5322.rl";
main := address_lists;
}%%
module Mail::Parsers
module AddressListsParser
extend Mail::ParserTools
AddressListStruct = Struct.new(:addresses, :group_names, :error)
AddressStruct = Struct.new(:raw, :domain, :comments, :local,
:obs_domain_list, :display_name, :group, :error)
%%write data noprefix;
def self.parse(data)
data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding)
address_list = AddressListStruct.new([], [])
return address_list if Mail::Utilities.blank?(data)
phrase_s = phrase_e = qstr_s = qstr = comment_s = nil
group_name_s = domain_s = group_name = nil
local_dot_atom_s = local_dot_atom_e = nil
local_dot_atom_pre_comment_e = nil
obs_domain_list_s = nil
address_s = 0
address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
# 5.1 Variables Used by Ragel
p = 0
eof = pe = data.length
stack = []
%%write init;
%%write exec;
if p != eof || cs < %%{ write first_final; }%%
raise Mail::Field::IncompleteParseError.new(Mail::AddressList, data, p)
end
address_list
end
end
end
ensure
$VERBOSE = original_verbose
end
|