Class: Mail::Parsers::AddressListsParser

Inherits:
Object
  • Object
show all
Includes:
Utilities
Defined in:
lib/mail/parsers/address_lists_parser.rb

Constant Summary

Constant Summary

Constants included from Constants

Constants::ASTERISK, Constants::ATOM_UNSAFE, Constants::B_VALUES, Constants::CAPITAL_M, Constants::COLON, Constants::CONTROL_CHAR, Constants::CR, Constants::CRLF, Constants::CR_ENCODED, Constants::EMPTY, Constants::ENCODED_VALUE, Constants::EQUAL_LF, Constants::FIELD_BODY, Constants::FIELD_LINE, Constants::FIELD_NAME, Constants::FIELD_PREFIX, Constants::FIELD_SPLIT, Constants::FWS, Constants::HEADER_LINE, Constants::HEADER_SPLIT, Constants::HYPHEN, Constants::LF, Constants::LF_ENCODED, Constants::NULL_SENDER, Constants::PHRASE_UNSAFE, Constants::QP_SAFE, Constants::QP_UNSAFE, Constants::Q_VALUES, Constants::SPACE, Constants::TEXT, Constants::TOKEN_UNSAFE, Constants::UNDERSCORE, Constants::WSP

Instance Method Summary collapse

Methods included from Utilities

#atom_safe?, #bracket, #capitalize_field, #constantize, #dasherize, #dquote, #escape_paren, #map_lines, #map_with_index, #match_to_s, #paren, #quote_atom, #quote_phrase, #quote_token, #token_safe?, #unbracket, #underscoreize, #unparen, #unquote, #uri_escape, #uri_parser, #uri_unescape

Instance Method Details

#parse(s) ⇒ Object



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
# File 'lib/mail/parsers/address_lists_parser.rb', line 5

def parse(s)
  address_list = AddressListStruct.new([],[])

  if s.blank?
    return address_list
  end

  actions, error = Ragel.parse(:address_lists, s)
  if error
    raise Mail::Field::ParseError.new(Mail::AddressList, s, error)
  end


  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)
  actions.each_slice(2) do |action_id, p|
    action = Mail::Parsers::Ragel::ACTIONS[action_id]
    case action

    # Phrase
    when :phrase_s then phrase_s = p
    when :phrase_e then phrase_e = p-1

    # Quoted String.
    when :qstr_s then qstr_s = p
    when :qstr_e then qstr = s[qstr_s..(p-1)]

    # Comment
    when :comment_s
      comment_s = p unless comment_s
    when :comment_e
      if address
        address.comments << s[comment_s..(p-2)]
      end
      comment_s = nil

    # Group Name
    when :group_name_s then group_name_s = p
    when :group_name_e
      if qstr
        group = qstr
        qstr = nil
      else
        group = s[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
    when :address_s
      address_s = p
    when :address_e
      # Ignore address end events if they don't have
      # a matching address start event.
      next if address_s.nil?
      if address.local.nil? && local_dot_atom_pre_comment_e && local_dot_atom_s && local_dot_atom_e
        if address.domain
          address.local = s[local_dot_atom_s..local_dot_atom_e] if address
        else
          address.local = s[local_dot_atom_s..local_dot_atom_pre_comment_e] if address
        end
      end
      address.raw = s[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

    # 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.
    when :angle_addr_s
      if qstr
        address.display_name = qstr
        qstr = nil
      elsif phrase_e
        address.display_name = s[phrase_s..phrase_e].strip
        phrase_e = phrase_s = nil
      end

    # Domain
    when :domain_s
      domain_s = p
    when :domain_e
      address.domain = s[domain_s..(p-1)].rstrip if address

    # Local
    when :local_dot_atom_s then local_dot_atom_s = p
    when :local_dot_atom_e then local_dot_atom_e = p-1
    when :local_dot_atom_pre_comment_e
      local_dot_atom_pre_comment_e = p-1
    when :local_quoted_string_e
      address.local = '"' + qstr + '"' if address

    # obs_domain_list
    when :obs_domain_list_s then obs_domain_list_s = p
    when :obs_domain_list_e
      address.obs_domain_list = s[obs_domain_list_s..(p-1)]

    else
      raise Mail::Field::ParseError.new(Mail::AddressList, s, "Failed to process unknown action: #{action}")
    end
  end

  if address_list.addresses.empty? && address_list.group_names.empty?
    raise Mail::Field::ParseError.new(Mail::AddressList, s, "Didn't find any addresses or groups")
  end

  address_list
end