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
data/lib/mail/message.rb CHANGED
@@ -240,7 +240,7 @@ module Mail
240
240
  # This method bypasses checking perform_deliveries and raise_delivery_errors,
241
241
  # so use with caution.
242
242
  #
243
- # It still however fires off the intercepters and calls the observers callbacks if they are defined.
243
+ # It still however fires off the interceptors and calls the observers callbacks if they are defined.
244
244
  #
245
245
  # Returns self
246
246
  def deliver!
@@ -353,17 +353,23 @@ module Mail
353
353
  return false unless other.respond_to?(:encoded)
354
354
 
355
355
  if self.message_id && other.message_id
356
- result = (self.encoded == other.encoded)
356
+ self.encoded == other.encoded
357
357
  else
358
358
  self_message_id, other_message_id = self.message_id, other.message_id
359
- self.message_id, other.message_id = '<temp@test>', '<temp@test>'
360
- result = self.encoded == other.encoded
361
- self.message_id = "<#{self_message_id}>" if self_message_id
362
- other.message_id = "<#{other_message_id}>" if other_message_id
363
- result
359
+ begin
360
+ self.message_id, other.message_id = '<temp@test>', '<temp@test>'
361
+ self.encoded == other.encoded
362
+ ensure
363
+ self.message_id, other.message_id = self_message_id, other_message_id
364
+ end
364
365
  end
365
366
  end
366
367
 
368
+ def initialize_copy(original)
369
+ super
370
+ @header = @header.dup
371
+ end
372
+
367
373
  # Provides access to the raw source of the message as it was when it
368
374
  # was instantiated. This is set at initialization and so is untouched
369
375
  # by the parsers or decoder / encoders
@@ -1388,7 +1394,7 @@ module Mail
1388
1394
  header.has_date?
1389
1395
  end
1390
1396
 
1391
- # Returns true if the message has a Date field, the field may or may
1397
+ # Returns true if the message has a Mime-Version field, the field may or may
1392
1398
  # not have a value, but the field exists or not.
1393
1399
  def has_mime_version?
1394
1400
  header.has_mime_version?
@@ -1594,7 +1600,7 @@ module Mail
1594
1600
  end
1595
1601
 
1596
1602
  # Returns an AttachmentsList object, which holds all of the attachments in
1597
- # the receiver object (either the entier email or a part within) and all
1603
+ # the receiver object (either the entire email or a part within) and all
1598
1604
  # of its descendants.
1599
1605
  #
1600
1606
  # It also allows you to add attachments to the mail object directly, like so:
@@ -1974,8 +1980,9 @@ module Mail
1974
1980
  end
1975
1981
 
1976
1982
  def raw_source=(value)
1977
- value.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
1978
1983
  @raw_source = value.to_crlf
1984
+ @raw_source.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
1985
+ @raw_source
1979
1986
  end
1980
1987
 
1981
1988
  # see comments to body=. We take data and process it lazily
@@ -2128,7 +2135,7 @@ module Mail
2128
2135
  if perform_deliveries
2129
2136
  delivery_method.deliver!(self)
2130
2137
  end
2131
- rescue Exception => e # Net::SMTP errors or sendmail pipe errors
2138
+ rescue => e # Net::SMTP errors or sendmail pipe errors
2132
2139
  raise e if raise_delivery_errors
2133
2140
  end
2134
2141
  end
@@ -341,7 +341,7 @@ module Mail
341
341
  def load
342
342
  begin
343
343
  @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
344
- rescue Exception => e
344
+ rescue => e
345
345
  raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), Mail::Multibyte is unusable")
346
346
  end
347
347
 
@@ -50,7 +50,7 @@ module Mail
50
50
  smtp_from, smtp_to, message = check_delivery_params(mail)
51
51
 
52
52
  from = "-f #{self.class.shellquote(smtp_from)}"
53
- to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ')
53
+ to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
54
54
 
55
55
  arguments = "#{settings[:arguments]} #{from} --"
56
56
  self.class.call(settings[:location], arguments, to, message)
@@ -132,15 +132,11 @@ module Mail
132
132
  openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
133
133
  end
134
134
 
135
- if RUBY_VERSION < '1.9.0'
136
- openssl_verify_mode
137
- else
138
- context = Net::SMTP.default_ssl_context
139
- context.verify_mode = openssl_verify_mode
140
- context.ca_path = settings[:ca_path] if settings[:ca_path]
141
- context.ca_file = settings[:ca_file] if settings[:ca_file]
142
- context
143
- end
135
+ context = Net::SMTP.default_ssl_context
136
+ context.verify_mode = openssl_verify_mode
137
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
138
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
139
+ context
144
140
  end
145
141
  end
146
142
  end
@@ -73,31 +73,35 @@ module Mail
73
73
  start do |imap|
74
74
  options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
75
75
 
76
- message_ids = imap.uid_search(options[:keys])
77
- message_ids.reverse! if options[:what].to_sym == :last
78
- message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer)
79
- message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
76
+ uids = imap.uid_search(options[:keys])
77
+ uids.reverse! if options[:what].to_sym == :last
78
+ uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
79
+ uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
80
80
  (options[:what].to_sym != :last && options[:order].to_sym == :desc)
81
81
 
82
82
  if block_given?
83
- message_ids.each do |message_id|
84
- fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
83
+ uids.each do |uid|
84
+ uid = options[:uid].to_i unless options[:uid].nil?
85
+ fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
85
86
  new_message = Mail.new(fetchdata.attr['RFC822'])
86
87
  new_message.mark_for_delete = true if options[:delete_after_find]
87
88
  if block.arity == 3
88
- yield new_message, imap, message_id
89
+ yield new_message, imap, uid
89
90
  else
90
91
  yield new_message
91
92
  end
92
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
93
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
94
+ break unless options[:uid].nil?
93
95
  end
94
96
  imap.expunge if options[:delete_after_find]
95
97
  else
96
98
  emails = []
97
- message_ids.each do |message_id|
98
- fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
99
+ uids.each do |uid|
100
+ uid = options[:uid].to_i unless options[:uid].nil?
101
+ fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
99
102
  emails << Mail.new(fetchdata.attr['RFC822'])
100
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
103
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
104
+ break unless options[:uid].nil?
101
105
  end
102
106
  imap.expunge if options[:delete_after_find]
103
107
  emails.size == 1 && options[:count] == 1 ? emails.first : emails
@@ -111,8 +115,8 @@ module Mail
111
115
  mailbox = Net::IMAP.encode_utf7(mailbox)
112
116
 
113
117
  start do |imap|
114
- imap.uid_search(['ALL']).each do |message_id|
115
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
118
+ imap.uid_search(['ALL']).each do |uid|
119
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED])
116
120
  end
117
121
  imap.expunge
118
122
  end
@@ -137,6 +141,7 @@ module Mail
137
141
  options[:order] ||= :asc
138
142
  options[:what] ||= :first
139
143
  options[:keys] ||= 'ALL'
144
+ options[:uid] ||= nil
140
145
  options[:delete_after_find] ||= false
141
146
  options[:mailbox] = Net::IMAP.encode_utf7(options[:mailbox])
142
147
  options[:read_only] ||= false
@@ -0,0 +1,132 @@
1
+ module Mail::Parsers
2
+ class AddressListsParser
3
+ include Mail::Utilities
4
+
5
+ def parse(s)
6
+ address_list = AddressListStruct.new([],[])
7
+
8
+ if s.blank?
9
+ return address_list
10
+ end
11
+
12
+ actions, error = Ragel.parse(:address_lists, s)
13
+ if error
14
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, error)
15
+ end
16
+
17
+
18
+ phrase_s = phrase_e = qstr_s = qstr = comment_s = nil
19
+ group_name_s = domain_s = group_name = nil
20
+ local_dot_atom_s = local_dot_atom_e = nil
21
+ local_dot_atom_pre_comment_e = nil
22
+ obs_domain_list_s = nil
23
+
24
+ address_s = 0
25
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
26
+ actions.each_slice(2) do |action_id, p|
27
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
28
+ case action
29
+
30
+ # Phrase
31
+ when :phrase_s then phrase_s = p
32
+ when :phrase_e then phrase_e = p-1
33
+
34
+ # Quoted String.
35
+ when :qstr_s then qstr_s = p
36
+ when :qstr_e then qstr = s[qstr_s..(p-1)]
37
+
38
+ # Comment
39
+ when :comment_s
40
+ comment_s = p unless comment_s
41
+ when :comment_e
42
+ if address
43
+ address.comments << s[comment_s..(p-2)]
44
+ end
45
+ comment_s = nil
46
+
47
+ # Group Name
48
+ when :group_name_s then group_name_s = p
49
+ when :group_name_e
50
+ if qstr
51
+ group = qstr
52
+ qstr = nil
53
+ else
54
+ group = s[group_name_s..(p-1)]
55
+ group_name_s = nil
56
+ end
57
+ address_list.group_names << group
58
+ group_name = group
59
+
60
+ # Start next address
61
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
62
+ address_s = p
63
+ address.group = group_name
64
+
65
+ # Address
66
+ when :address_s
67
+ address_s = p
68
+ when :address_e
69
+ # Ignore address end events if they don't have
70
+ # a matching address start event.
71
+ next if address_s.nil?
72
+ if address.local.nil? && local_dot_atom_pre_comment_e && local_dot_atom_s && local_dot_atom_e
73
+ if address.domain
74
+ address.local = s[local_dot_atom_s..local_dot_atom_e] if address
75
+ else
76
+ address.local = s[local_dot_atom_s..local_dot_atom_pre_comment_e] if address
77
+ end
78
+ end
79
+ address.raw = s[address_s..(p-1)]
80
+ address_list.addresses << address if address
81
+
82
+ # Start next address
83
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
84
+ address.group = group_name
85
+ address_s = nil
86
+
87
+ # Don't set the display name until the
88
+ # address has actually started. This allows
89
+ # us to choose quoted_s version if it
90
+ # exists and always use the 'full' phrase
91
+ # version.
92
+ when :angle_addr_s
93
+ if qstr
94
+ address.display_name = qstr
95
+ qstr = nil
96
+ elsif phrase_e
97
+ address.display_name = s[phrase_s..phrase_e].strip
98
+ phrase_e = phrase_s = nil
99
+ end
100
+
101
+ # Domain
102
+ when :domain_s
103
+ domain_s = p
104
+ when :domain_e
105
+ address.domain = s[domain_s..(p-1)].rstrip if address
106
+
107
+ # Local
108
+ when :local_dot_atom_s then local_dot_atom_s = p
109
+ when :local_dot_atom_e then local_dot_atom_e = p-1
110
+ when :local_dot_atom_pre_comment_e
111
+ local_dot_atom_pre_comment_e = p-1
112
+ when :local_quoted_string_e
113
+ address.local = '"' + qstr + '"' if address
114
+
115
+ # obs_domain_list
116
+ when :obs_domain_list_s then obs_domain_list_s = p
117
+ when :obs_domain_list_e
118
+ address.obs_domain_list = s[obs_domain_list_s..(p-1)]
119
+
120
+ else
121
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, "Failed to process unknown action: #{action}")
122
+ end
123
+ end
124
+
125
+ if address_list.addresses.empty? && address_list.group_names.empty?
126
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, "Didn't find any addresses or groups")
127
+ end
128
+
129
+ address_list
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,67 @@
1
+ module Mail::Parsers
2
+ class ContentDispositionParser
3
+ include Mail::Utilities
4
+
5
+ def parse(s)
6
+ content_disposition = ContentDispositionStruct.new("", nil)
7
+ if s.blank?
8
+ return content_disposition
9
+ end
10
+
11
+ actions, error = Ragel.parse(:content_disposition, s)
12
+ if error
13
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, error)
14
+ end
15
+
16
+ content_disposition.parameters = []
17
+
18
+ disp_type_s = param_attr_s = param_attr = qstr_s = qstr = param_val_s = nil
19
+ actions.each_slice(2) do |action_id, p|
20
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
21
+ case action
22
+
23
+ # Disposition Type
24
+ when :disp_type_s then disp_type_s = p
25
+ when :disp_type_e
26
+ content_disposition.disposition_type = s[disp_type_s..(p-1)].downcase
27
+
28
+ # Parameter Attribute
29
+ when :param_attr_s then param_attr_s = p
30
+ when :param_attr_e then param_attr = s[param_attr_s..(p-1)]
31
+
32
+ # Quoted String.
33
+ when :qstr_s then qstr_s = p
34
+ when :qstr_e then qstr = s[qstr_s..(p-1)]
35
+
36
+ # Parameter Value
37
+ when :param_val_s then param_val_s = p
38
+ when :param_val_e
39
+ if param_attr.nil?
40
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, "no attribute for value")
41
+ end
42
+
43
+ # Use quoted string value if one exists, otherwise use parameter value
44
+ if qstr
45
+ value = qstr
46
+ else
47
+ value = s[param_val_s..(p-1)]
48
+ end
49
+
50
+ content_disposition.parameters << { param_attr => value }
51
+ param_attr = nil
52
+ qstr = nil
53
+
54
+ else
55
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, "Failed to process unknown action: #{action}")
56
+ end
57
+ end
58
+
59
+ content_disposition
60
+ end
61
+
62
+ private
63
+ def cleaned(string)
64
+ string =~ /(.+);\s*$/ ? $1 : string
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,35 @@
1
+ module Mail::Parsers
2
+ class ContentLocationParser
3
+ def parse(s)
4
+ content_location = ContentLocationStruct.new(nil)
5
+ if s.blank?
6
+ return content_location
7
+ end
8
+
9
+ actions, error = Ragel.parse(:content_location, s)
10
+ if error
11
+ raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, error)
12
+ end
13
+
14
+ qstr_s = token_string_s = nil
15
+ actions.each_slice(2) do |action_id, p|
16
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
17
+ case action
18
+
19
+ # Quoted String.
20
+ when :qstr_s then qstr_s = p
21
+ when :qstr_e then content_location.location = s[qstr_s..(p-1)]
22
+
23
+ # Token String
24
+ when :token_string_s then token_string_s = p
25
+ when :token_string_e
26
+ content_location.location = s[token_string_s..(p-1)]
27
+
28
+ else
29
+ raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, "Failed to process unknown action: #{action}")
30
+ end
31
+ end
32
+ content_location
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ module Mail::Parsers
2
+ class ContentTransferEncodingParser
3
+
4
+ def parse(s)
5
+ content_transfer_encoding = ContentTransferEncodingStruct.new("")
6
+ if s.blank?
7
+ return content_transfer_encoding
8
+ end
9
+
10
+ actions, error = Ragel.parse(:content_transfer_encoding, s)
11
+ if error
12
+ raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, error)
13
+ end
14
+
15
+ encoding_s = nil
16
+ actions.each_slice(2) do |action_id, p|
17
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
18
+ case action
19
+
20
+ # Encoding
21
+ when :encoding_s then encoding_s = p
22
+ when :encoding_e
23
+ content_transfer_encoding.encoding = s[encoding_s..(p-1)].downcase
24
+
25
+ else
26
+ raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, "Failed to process unknown action: #{action}")
27
+ end
28
+ end
29
+
30
+ content_transfer_encoding
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ module Mail::Parsers
2
+ class ContentTypeParser
3
+ include Mail::Utilities
4
+
5
+ def parse(s)
6
+ actions, error = Ragel.parse(:content_type, s)
7
+ if error
8
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, error)
9
+ end
10
+
11
+ content_type = ContentTypeStruct.new(nil,nil,[])
12
+
13
+ content_type.parameters = []
14
+
15
+ main_type_s = sub_type_s = param_attr_s = param_attr = nil
16
+ qstr_s = qstr = param_val_s = nil
17
+ actions.each_slice(2) do |action_id, p|
18
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
19
+ case action
20
+
21
+ # Main Type
22
+ when :main_type_s then main_type_s = p
23
+ when :main_type_e then
24
+ content_type.main_type = s[main_type_s..(p-1)].downcase
25
+
26
+ # Sub Type
27
+ when :sub_type_s then sub_type_s = p
28
+ when :sub_type_e
29
+ content_type.sub_type = s[sub_type_s..(p-1)].downcase
30
+
31
+ # Parameter Attribute
32
+ when :param_attr_s then param_attr_s = p
33
+ when :param_attr_e then param_attr = s[param_attr_s..(p-1)]
34
+
35
+ # Quoted String.
36
+ when :qstr_s then qstr_s = p
37
+ when :qstr_e then qstr = s[qstr_s..(p-1)]
38
+
39
+ # Parameter Value
40
+ when :param_val_s then param_val_s = p
41
+ when :param_val_e
42
+ if param_attr.nil?
43
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "no attribute for value")
44
+ end
45
+
46
+ # Use quoted s value if one exists, otherwise use parameter value
47
+ if qstr
48
+ value = qstr
49
+ else
50
+ value = s[param_val_s..(p-1)]
51
+ end
52
+
53
+ content_type.parameters << { param_attr => value }
54
+ param_attr = nil
55
+ qstr = nil
56
+
57
+ else
58
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "Failed to process unknown action: #{action}")
59
+ end
60
+ end
61
+ content_type
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,36 @@
1
+ module Mail::Parsers
2
+ class DateTimeParser
3
+ include Mail::Utilities
4
+
5
+ def parse(s)
6
+ date_time = DateTimeStruct.new([])
7
+
8
+ actions, error = Ragel.parse(:date_time, s)
9
+ if error
10
+ raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, error)
11
+ end
12
+
13
+ date_s = time_s = nil
14
+ actions.each_slice(2) do |action_id, p|
15
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
16
+ case action
17
+
18
+ # Date
19
+ when :date_s then date_s = p
20
+ when :date_e
21
+ date_time.date_string = s[date_s..(p-1)]
22
+
23
+ # Time
24
+ when :time_s then time_s = p
25
+ when :time_e
26
+ date_time.time_string = s[time_s..(p-1)]
27
+
28
+ else
29
+ raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, "Failed to process unknown action: #{action}")
30
+ end
31
+ end
32
+
33
+ date_time
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ module Mail::Parsers
2
+ class EnvelopeFromParser
3
+ def parse(s)
4
+ envelope_from = EnvelopeFromStruct.new
5
+ if s.blank?
6
+ return envelope_from
7
+ end
8
+
9
+ actions, error = Ragel.parse(:envelope_from, s)
10
+ if error
11
+ raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, error)
12
+ end
13
+
14
+ address_s = ctime_date_s = nil
15
+ envelope_from = EnvelopeFromStruct.new
16
+ actions.each_slice(2) do |action_id, p|
17
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
18
+ case action
19
+
20
+ # Address
21
+ when :address_s then address_s = p
22
+ when :address_e
23
+ envelope_from.address = s[address_s..(p-1)].rstrip
24
+
25
+ # ctime_date
26
+ when :ctime_date_s then ctime_date_s = p
27
+ when :ctime_date_e
28
+ envelope_from.ctime_date = s[ctime_date_s..(p-1)]
29
+
30
+ # ignored actions
31
+ when :angle_addr_s, :comment_e, :comment_s,
32
+ :domain_e, :domain_s, :local_dot_atom_e,
33
+ :local_dot_atom_pre_comment_e,
34
+ :local_dot_atom_pre_comment_s,
35
+ :local_dot_atom_s, :qstr_e, :qstr_s
36
+ nil
37
+
38
+ else
39
+ raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, "Failed to process unknown action: #{action}")
40
+ end
41
+ end
42
+ envelope_from
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ module Mail::Parsers
2
+ class MessageIdsParser
3
+ def parse(s)
4
+ if s.blank?
5
+ return MessageIdsStruct.new
6
+ end
7
+
8
+ message_ids = MessageIdsStruct.new([])
9
+
10
+ actions, error = Ragel.parse(:message_ids, s)
11
+ if error
12
+ raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, error)
13
+ end
14
+
15
+ msg_id_s = nil
16
+ actions.each_slice(2) do |action_id, p|
17
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
18
+ case action
19
+
20
+ # Message Ids
21
+ when :msg_id_s then msg_id_s = p
22
+ when :msg_id_e
23
+ message_ids.message_ids << s[msg_id_s..(p-1)].rstrip
24
+
25
+ when :domain_e, :domain_s, :local_dot_atom_e,
26
+ :local_dot_atom_pre_comment_e,
27
+ :local_dot_atom_pre_comment_s,
28
+ :local_dot_atom_s
29
+
30
+ # ignored actions
31
+
32
+ else
33
+ raise Mail::Field::ParseError.new(Mail::MessageIdsElement, s, "Failed to process unknown action: #{action}")
34
+ end
35
+ end
36
+ message_ids
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ module Mail::Parsers
2
+ class MimeVersionParser
3
+ include Mail::Utilities
4
+
5
+ def parse(s)
6
+ if s.blank?
7
+ return MimeVersionStruct.new("", nil)
8
+ end
9
+
10
+ mime_version = MimeVersionStruct.new
11
+
12
+ actions, error = Ragel.parse(:mime_version, s)
13
+ if error
14
+ raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, error)
15
+ end
16
+
17
+ major_digits_s = minor_digits_s = nil
18
+ actions.each_slice(2) do |action_id, p|
19
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
20
+ case action
21
+
22
+ # Major Digits
23
+ when :major_digits_s then major_digits_s = p
24
+ when :major_digits_e
25
+ mime_version.major = s[major_digits_s..(p-1)]
26
+
27
+ # Minor Digits
28
+ when :minor_digits_s then minor_digits_s = p
29
+ when :minor_digits_e
30
+ mime_version.minor = s[minor_digits_s..(p-1)]
31
+
32
+ when :comment_e, :comment_s then nil
33
+
34
+ else
35
+ raise Mail::Field::ParseError.new(Mail::MimeVersionElement, s, "Failed to process unknown action: #{action}")
36
+ end
37
+ end
38
+ mime_version
39
+ end
40
+ end
41
+ end