mail 2.5.5 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +8 -9
  3. data/CONTRIBUTING.md +13 -0
  4. data/Dependencies.txt +0 -1
  5. data/Gemfile +7 -24
  6. data/README.md +36 -15
  7. data/Rakefile +10 -2
  8. data/VERSION +4 -0
  9. data/lib/mail.rb +1 -1
  10. data/lib/mail/body.rb +2 -2
  11. data/lib/mail/check_delivery_params.rb +10 -47
  12. data/lib/mail/core_extensions/string.rb +12 -2
  13. data/lib/mail/elements/address.rb +38 -82
  14. data/lib/mail/elements/address_list.rb +19 -42
  15. data/lib/mail/elements/content_disposition_element.rb +3 -7
  16. data/lib/mail/elements/content_location_element.rb +2 -6
  17. data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
  18. data/lib/mail/elements/content_type_element.rb +4 -8
  19. data/lib/mail/elements/date_time_element.rb +3 -7
  20. data/lib/mail/elements/envelope_from_element.rb +3 -11
  21. data/lib/mail/elements/message_ids_element.rb +1 -6
  22. data/lib/mail/elements/mime_version_element.rb +3 -7
  23. data/lib/mail/elements/phrase_list.rb +2 -7
  24. data/lib/mail/elements/received_element.rb +3 -7
  25. data/lib/mail/encodings.rb +0 -1
  26. data/lib/mail/envelope.rb +0 -5
  27. data/lib/mail/field.rb +53 -17
  28. data/lib/mail/field_list.rb +18 -18
  29. data/lib/mail/fields/common/common_address.rb +15 -20
  30. data/lib/mail/fields/common/common_date.rb +0 -7
  31. data/lib/mail/fields/common/common_field.rb +1 -1
  32. data/lib/mail/fields/content_transfer_encoding_field.rb +0 -6
  33. data/lib/mail/fields/resent_sender_field.rb +1 -1
  34. data/lib/mail/fields/sender_field.rb +1 -1
  35. data/lib/mail/fields/unstructured_field.rb +7 -1
  36. data/lib/mail/header.rb +8 -22
  37. data/lib/mail/mail.rb +12 -0
  38. data/lib/mail/matchers/has_sent_mail.rb +34 -1
  39. data/lib/mail/message.rb +18 -11
  40. data/lib/mail/multibyte/unicode.rb +1 -1
  41. data/lib/mail/network/delivery_methods/exim.rb +10 -6
  42. data/lib/mail/network/delivery_methods/file_delivery.rb +8 -4
  43. data/lib/mail/network/delivery_methods/sendmail.rb +7 -9
  44. data/lib/mail/network/delivery_methods/smtp.rb +5 -2
  45. data/lib/mail/network/delivery_methods/smtp_connection.rb +6 -2
  46. data/lib/mail/network/delivery_methods/test_mailer.rb +8 -5
  47. data/lib/mail/network/retriever_methods/imap.rb +18 -13
  48. data/lib/mail/parsers.rb +26 -0
  49. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  50. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  51. data/lib/mail/parsers/content_location_parser.rb +35 -0
  52. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  53. data/lib/mail/parsers/content_type_parser.rb +64 -0
  54. data/lib/mail/parsers/date_time_parser.rb +36 -0
  55. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  56. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  57. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  58. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  59. data/lib/mail/parsers/ragel.rb +17 -0
  60. data/lib/mail/parsers/ragel/common.rl +184 -0
  61. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  62. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  63. data/lib/mail/parsers/ragel/ruby.rb +29 -0
  64. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  65. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  66. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  67. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  68. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  69. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  70. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  71. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  72. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  73. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  74. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  75. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  76. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  77. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  78. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  79. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  80. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  81. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  82. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  83. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  84. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  85. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  86. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  87. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  88. data/lib/mail/parsers/received_parser.rb +47 -0
  89. data/lib/mail/parts_list.rb +4 -2
  90. data/lib/mail/patterns.rb +3 -1
  91. data/lib/mail/utilities.rb +3 -1
  92. data/lib/mail/version.rb +1 -1
  93. data/lib/mail/version_specific/ruby_1_8.rb +1 -1
  94. data/lib/mail/version_specific/ruby_1_9.rb +13 -1
  95. metadata +55 -51
  96. data/lib/VERSION +0 -4
  97. data/lib/load_parsers.rb +0 -35
  98. data/lib/mail/parsers/address_lists.rb +0 -64
  99. data/lib/mail/parsers/address_lists.treetop +0 -19
  100. data/lib/mail/parsers/content_disposition.rb +0 -535
  101. data/lib/mail/parsers/content_disposition.treetop +0 -46
  102. data/lib/mail/parsers/content_location.rb +0 -139
  103. data/lib/mail/parsers/content_location.treetop +0 -20
  104. data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
  105. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
  106. data/lib/mail/parsers/content_type.rb +0 -971
  107. data/lib/mail/parsers/content_type.treetop +0 -68
  108. data/lib/mail/parsers/date_time.rb +0 -114
  109. data/lib/mail/parsers/date_time.treetop +0 -11
  110. data/lib/mail/parsers/envelope_from.rb +0 -194
  111. data/lib/mail/parsers/envelope_from.treetop +0 -32
  112. data/lib/mail/parsers/message_ids.rb +0 -45
  113. data/lib/mail/parsers/message_ids.treetop +0 -15
  114. data/lib/mail/parsers/mime_version.rb +0 -144
  115. data/lib/mail/parsers/mime_version.treetop +0 -19
  116. data/lib/mail/parsers/phrase_lists.rb +0 -45
  117. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  118. data/lib/mail/parsers/received.rb +0 -71
  119. data/lib/mail/parsers/received.treetop +0 -11
  120. data/lib/mail/parsers/rfc2045.rb +0 -421
  121. data/lib/mail/parsers/rfc2045.treetop +0 -35
  122. data/lib/mail/parsers/rfc2822.rb +0 -5397
  123. data/lib/mail/parsers/rfc2822.treetop +0 -408
  124. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  125. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  126. data/lib/tasks/corpus.rake +0 -125
  127. data/lib/tasks/treetop.rake +0 -10
@@ -1,6 +1,7 @@
1
1
  require 'mail/check_delivery_params'
2
2
 
3
3
  module Mail
4
+
4
5
  # FileDelivery class delivers emails into multiple files based on the destination
5
6
  # address. Each file is appended to if it already exists.
6
7
  #
@@ -12,20 +13,22 @@ module Mail
12
13
  # Make sure the path you specify with :location is writable by the Ruby process
13
14
  # running Mail.
14
15
  class FileDelivery
16
+ include Mail::CheckDeliveryParams
17
+
15
18
  if RUBY_VERSION >= '1.9.1'
16
19
  require 'fileutils'
17
20
  else
18
21
  require 'ftools'
19
22
  end
20
23
 
21
- attr_accessor :settings
22
-
23
24
  def initialize(values)
24
25
  self.settings = { :location => './mails' }.merge!(values)
25
26
  end
26
-
27
+
28
+ attr_accessor :settings
29
+
27
30
  def deliver!(mail)
28
- Mail::CheckDeliveryParams.check(mail)
31
+ check_delivery_params(mail)
29
32
 
30
33
  if ::File.respond_to?(:makedirs)
31
34
  ::File.makedirs settings[:location]
@@ -37,5 +40,6 @@ module Mail
37
40
  ::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
38
41
  end
39
42
  end
43
+
40
44
  end
41
45
  end
@@ -37,22 +37,20 @@ module Mail
37
37
  #
38
38
  # mail.deliver!
39
39
  class Sendmail
40
- DEFAULTS = {
41
- :location => '/usr/sbin/sendmail',
42
- :arguments => '-i'
43
- }
44
-
45
- attr_accessor :settings
40
+ include Mail::CheckDeliveryParams
46
41
 
47
42
  def initialize(values)
48
- self.settings = self.class::DEFAULTS.merge(values)
43
+ self.settings = { :location => '/usr/sbin/sendmail',
44
+ :arguments => '-i' }.merge(values)
49
45
  end
50
46
 
47
+ attr_accessor :settings
48
+
51
49
  def deliver!(mail)
52
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
50
+ smtp_from, smtp_to, message = check_delivery_params(mail)
53
51
 
54
52
  from = "-f #{self.class.shellquote(smtp_from)}"
55
- to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ')
53
+ to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
56
54
 
57
55
  arguments = "#{settings[:arguments]} #{from} --"
58
56
  self.class.call(settings[:location], arguments, to, message)
@@ -74,7 +74,7 @@ module Mail
74
74
  #
75
75
  # mail.deliver!
76
76
  class SMTP
77
- attr_accessor :settings
77
+ include Mail::CheckDeliveryParams
78
78
 
79
79
  def initialize(values)
80
80
  self.settings = { :address => "localhost",
@@ -90,10 +90,12 @@ module Mail
90
90
  }.merge!(values)
91
91
  end
92
92
 
93
+ attr_accessor :settings
94
+
93
95
  # Send the message via SMTP.
94
96
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
95
97
  def deliver!(mail)
96
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
98
+ smtp_from, smtp_to, message = check_delivery_params(mail)
97
99
 
98
100
  smtp = Net::SMTP.new(settings[:address], settings[:port])
99
101
  if settings[:tls] || settings[:ssl]
@@ -117,6 +119,7 @@ module Mail
117
119
  self
118
120
  end
119
121
  end
122
+
120
123
 
121
124
  private
122
125
 
@@ -37,7 +37,7 @@ module Mail
37
37
  #
38
38
  # mail.deliver!
39
39
  class SMTPConnection
40
- attr_accessor :smtp, :settings
40
+ include Mail::CheckDeliveryParams
41
41
 
42
42
  def initialize(values)
43
43
  raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
@@ -45,13 +45,17 @@ module Mail
45
45
  self.settings = values
46
46
  end
47
47
 
48
+ attr_accessor :smtp
49
+ attr_accessor :settings
50
+
48
51
  # Send the message via SMTP.
49
52
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
50
53
  def deliver!(mail)
51
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
54
+ smtp_from, smtp_to, message = check_delivery_params(mail)
52
55
  response = smtp.sendmail(message, smtp_from, smtp_to)
53
56
 
54
57
  settings[:return_response] ? response : self
55
58
  end
59
+
56
60
  end
57
61
  end
@@ -7,8 +7,10 @@ module Mail
7
7
  # It also provides a template of the minimum methods you require to implement
8
8
  # if you want to make a custom mailer for Mail
9
9
  class TestMailer
10
+ include Mail::CheckDeliveryParams
11
+
10
12
  # Provides a store of all the emails sent with the TestMailer so you can check them.
11
- def self.deliveries
13
+ def TestMailer.deliveries
12
14
  @@deliveries ||= []
13
15
  end
14
16
 
@@ -23,19 +25,20 @@ module Mail
23
25
  # * length
24
26
  # * size
25
27
  # * and other common Array methods
26
- def self.deliveries=(val)
28
+ def TestMailer.deliveries=(val)
27
29
  @@deliveries = val
28
30
  end
29
31
 
30
- attr_accessor :settings
31
-
32
32
  def initialize(values)
33
33
  @settings = values.dup
34
34
  end
35
+
36
+ attr_accessor :settings
35
37
 
36
38
  def deliver!(mail)
37
- Mail::CheckDeliveryParams.check(mail)
39
+ check_delivery_params(mail)
38
40
  Mail::TestMailer.deliveries << mail
39
41
  end
42
+
40
43
  end
41
44
  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,26 @@
1
+ module Mail
2
+ module Parsers
3
+
4
+ # Low-level ragel based parsers
5
+ require 'mail/parsers/ragel'
6
+
7
+ AddressListStruct = Struct.new(:addresses, :group_names, :error)
8
+ AddressStruct = Struct.new(:raw, :domain, :comments, :local,
9
+ :obs_domain_list, :display_name, :group, :error)
10
+ ContentDispositionStruct = Struct.new(:disposition_type, :parameters, :error)
11
+ ContentLocationStruct = Struct.new(:location, :error)
12
+ ContentTransferEncodingStruct = Struct.new(:encoding, :error)
13
+ ContentTypeStruct = Struct.new(:main_type, :sub_type, :parameters, :error)
14
+ DateTimeStruct = Struct.new(:date_string, :time_string, :error)
15
+ EnvelopeFromStruct = Struct.new(:address, :ctime_date, :error)
16
+ MessageIdsStruct = Struct.new(:message_ids, :error)
17
+ MimeVersionStruct = Struct.new(:major, :minor, :error)
18
+ PhraseListsStruct = Struct.new(:phrases, :error)
19
+ ReceivedStruct = Struct.new(:date, :time, :info, :error)
20
+
21
+ require 'mail/parsers/ragel/parser_info'
22
+ Ragel::FIELD_PARSERS.each do |field_parser|
23
+ require "mail/parsers/#{field_parser}_parser"
24
+ end
25
+ end
26
+ end
@@ -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