mail 2.4.4 → 2.5.5

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 (82) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +140 -1
  3. data/CONTRIBUTING.md +4 -4
  4. data/Gemfile +14 -8
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +24 -23
  7. data/Rakefile +3 -22
  8. data/lib/VERSION +2 -2
  9. data/lib/load_parsers.rb +35 -0
  10. data/lib/mail/attachments_list.rb +2 -2
  11. data/lib/mail/body.rb +5 -5
  12. data/lib/mail/check_delivery_params.rb +57 -0
  13. data/lib/mail/configuration.rb +1 -1
  14. data/lib/mail/core_extensions/nil.rb +4 -2
  15. data/lib/mail/core_extensions/object.rb +8 -8
  16. data/lib/mail/core_extensions/smtp.rb +12 -13
  17. data/lib/mail/core_extensions/string.rb +4 -4
  18. data/lib/mail/elements/address.rb +13 -5
  19. data/lib/mail/elements/envelope_from_element.rb +15 -2
  20. data/lib/mail/elements.rb +12 -12
  21. data/lib/mail/encodings/quoted_printable.rb +4 -3
  22. data/lib/mail/encodings.rb +66 -35
  23. data/lib/mail/field.rb +76 -99
  24. data/lib/mail/fields/bcc_field.rb +2 -2
  25. data/lib/mail/fields/cc_field.rb +2 -2
  26. data/lib/mail/fields/comments_field.rb +1 -1
  27. data/lib/mail/fields/common/common_address.rb +19 -4
  28. data/lib/mail/fields/common/common_field.rb +8 -2
  29. data/lib/mail/fields/common/common_message_id.rb +9 -5
  30. data/lib/mail/fields/content_disposition_field.rb +1 -0
  31. data/lib/mail/fields/content_id_field.rb +1 -2
  32. data/lib/mail/fields/content_transfer_encoding_field.rb +2 -2
  33. data/lib/mail/fields/content_type_field.rb +5 -2
  34. data/lib/mail/fields/date_field.rb +14 -14
  35. data/lib/mail/fields/from_field.rb +2 -2
  36. data/lib/mail/fields/in_reply_to_field.rb +2 -1
  37. data/lib/mail/fields/keywords_field.rb +1 -1
  38. data/lib/mail/fields/message_id_field.rb +2 -3
  39. data/lib/mail/fields/references_field.rb +2 -1
  40. data/lib/mail/fields/reply_to_field.rb +2 -2
  41. data/lib/mail/fields/resent_bcc_field.rb +2 -2
  42. data/lib/mail/fields/resent_cc_field.rb +2 -2
  43. data/lib/mail/fields/resent_from_field.rb +2 -2
  44. data/lib/mail/fields/resent_sender_field.rb +2 -2
  45. data/lib/mail/fields/resent_to_field.rb +2 -2
  46. data/lib/mail/fields/sender_field.rb +7 -7
  47. data/lib/mail/fields/to_field.rb +2 -2
  48. data/lib/mail/fields/unstructured_field.rb +34 -27
  49. data/lib/mail/fields.rb +32 -32
  50. data/lib/mail/header.rb +37 -14
  51. data/lib/mail/message.rb +140 -45
  52. data/lib/mail/multibyte/chars.rb +4 -4
  53. data/lib/mail/multibyte/unicode.rb +8 -0
  54. data/lib/mail/network/delivery_methods/exim.rb +6 -11
  55. data/lib/mail/network/delivery_methods/file_delivery.rb +7 -6
  56. data/lib/mail/network/delivery_methods/sendmail.rb +40 -11
  57. data/lib/mail/network/delivery_methods/smtp.rb +33 -47
  58. data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -24
  59. data/lib/mail/network/delivery_methods/test_mailer.rb +9 -8
  60. data/lib/mail/network/retriever_methods/imap.rb +14 -6
  61. data/lib/mail/network/retriever_methods/pop3.rb +2 -2
  62. data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
  63. data/lib/mail/network.rb +9 -9
  64. data/lib/mail/parsers/content_transfer_encoding.rb +81 -42
  65. data/lib/mail/parsers/content_transfer_encoding.treetop +4 -6
  66. data/lib/mail/parsers/content_type.rb +16 -12
  67. data/lib/mail/parsers/content_type.treetop +2 -2
  68. data/lib/mail/parsers/rfc2045.rb +12 -55
  69. data/lib/mail/parsers/rfc2045.treetop +1 -2
  70. data/lib/mail/parsers/rfc2822.rb +127 -71
  71. data/lib/mail/parsers/rfc2822.treetop +22 -24
  72. data/lib/mail/part.rb +6 -2
  73. data/lib/mail/parts_list.rb +1 -1
  74. data/lib/mail/patterns.rb +1 -1
  75. data/lib/mail/utilities.rb +25 -17
  76. data/lib/mail/values/unicode_tables.dat +0 -0
  77. data/lib/mail/version_specific/ruby_1_8.rb +23 -2
  78. data/lib/mail/version_specific/ruby_1_9.rb +55 -21
  79. data/lib/mail.rb +18 -18
  80. metadata +89 -37
  81. data/Gemfile.lock +0 -36
  82. data/lib/mail/core_extensions/shell_escape.rb +0 -56
@@ -1,3 +1,5 @@
1
+ require 'mail/check_delivery_params'
2
+
1
3
  module Mail
2
4
  # A delivery method implementation which sends via sendmail.
3
5
  #
@@ -35,28 +37,55 @@ module Mail
35
37
  #
36
38
  # mail.deliver!
37
39
  class Sendmail
40
+ DEFAULTS = {
41
+ :location => '/usr/sbin/sendmail',
42
+ :arguments => '-i'
43
+ }
44
+
45
+ attr_accessor :settings
38
46
 
39
47
  def initialize(values)
40
- self.settings = { :location => '/usr/sbin/sendmail',
41
- :arguments => '-i -t' }.merge(values)
48
+ self.settings = self.class::DEFAULTS.merge(values)
42
49
  end
43
50
 
44
- attr_accessor :settings
45
-
46
51
  def deliver!(mail)
47
- envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
48
- return_path = "-f " + '"' + envelope_from.escape_for_shell + '"' if envelope_from
52
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
49
53
 
50
- arguments = [settings[:arguments], return_path].compact.join(" ")
54
+ from = "-f #{self.class.shellquote(smtp_from)}"
55
+ to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ')
51
56
 
52
- self.class.call(settings[:location], arguments, mail.destinations.collect(&:escape_for_shell).join(" "), mail)
57
+ arguments = "#{settings[:arguments]} #{from} --"
58
+ self.class.call(settings[:location], arguments, to, message)
53
59
  end
54
60
 
55
- def self.call(path, arguments, destinations, mail)
56
- IO.popen("#{path} #{arguments} #{destinations}", "w+") do |io|
57
- io.puts mail.encoded.to_lf
61
+ def self.call(path, arguments, destinations, encoded_message)
62
+ popen "#{path} #{arguments} #{destinations}" do |io|
63
+ io.puts encoded_message.to_lf
58
64
  io.flush
59
65
  end
60
66
  end
67
+
68
+ if RUBY_VERSION < '1.9.0'
69
+ def self.popen(command, &block)
70
+ IO.popen "#{command} 2>&1", 'w+', &block
71
+ end
72
+ else
73
+ def self.popen(command, &block)
74
+ IO.popen command, 'w+', :err => :out, &block
75
+ end
76
+ end
77
+
78
+ # The following is an adaptation of ruby 1.9.2's shellwords.rb file,
79
+ # it is modified to include '+' in the allowed list to allow for
80
+ # sendmail to accept email addresses as the sender with a + in them.
81
+ def self.shellquote(address)
82
+ # Process as a single byte sequence because not all shell
83
+ # implementations are multibyte aware.
84
+ #
85
+ # A LF cannot be escaped with a backslash because a backslash + LF
86
+ # combo is regarded as line continuation and simply ignored. Strip it.
87
+ escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
88
+ %("#{escaped}")
89
+ end
61
90
  end
62
91
  end
@@ -1,3 +1,5 @@
1
+ require 'mail/check_delivery_params'
2
+
1
3
  module Mail
2
4
  # == Sending Email with SMTP
3
5
  #
@@ -72,6 +74,7 @@ module Mail
72
74
  #
73
75
  # mail.deliver!
74
76
  class SMTP
77
+ attr_accessor :settings
75
78
 
76
79
  def initialize(values)
77
80
  self.settings = { :address => "localhost",
@@ -86,68 +89,51 @@ module Mail
86
89
  :tls => nil
87
90
  }.merge!(values)
88
91
  end
89
-
90
- attr_accessor :settings
91
-
92
+
92
93
  # Send the message via SMTP.
93
94
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
94
95
  def deliver!(mail)
96
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
95
97
 
96
- # Set the envelope from to be either the return-path, the sender or the first from address
97
- envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
98
- if envelope_from.blank?
99
- raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
100
- end
101
-
102
- destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
103
- if destinations.blank?
104
- raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
105
- end
106
-
107
- message ||= mail.encoded if mail.respond_to?(:encoded)
108
- if message.blank?
109
- raise ArgumentError.new('A encoded content is required to send a message')
110
- end
111
-
112
98
  smtp = Net::SMTP.new(settings[:address], settings[:port])
113
99
  if settings[:tls] || settings[:ssl]
114
100
  if smtp.respond_to?(:enable_tls)
115
- unless settings[:openssl_verify_mode]
116
- smtp.enable_tls
117
- else
118
- openssl_verify_mode = settings[:openssl_verify_mode]
119
- if openssl_verify_mode.kind_of?(String)
120
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
121
- end
122
- context = Net::SMTP.default_ssl_context
123
- context.verify_mode = openssl_verify_mode
124
- smtp.enable_tls(context)
125
- end
101
+ smtp.enable_tls(ssl_context)
126
102
  end
127
103
  elsif settings[:enable_starttls_auto]
128
- if smtp.respond_to?(:enable_starttls_auto)
129
- unless settings[:openssl_verify_mode]
130
- smtp.enable_starttls_auto
131
- else
132
- openssl_verify_mode = settings[:openssl_verify_mode]
133
- if openssl_verify_mode.kind_of?(String)
134
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
135
- end
136
- context = Net::SMTP.default_ssl_context
137
- context.verify_mode = openssl_verify_mode
138
- smtp.enable_starttls_auto(context)
139
- end
104
+ if smtp.respond_to?(:enable_starttls_auto)
105
+ smtp.enable_starttls_auto(ssl_context)
140
106
  end
141
107
  end
142
-
108
+
143
109
  response = nil
144
110
  smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
145
- response = smtp_obj.sendmail(message, envelope_from, destinations)
111
+ response = smtp_obj.sendmail(message, smtp_from, smtp_to)
112
+ end
113
+
114
+ if settings[:return_response]
115
+ response
116
+ else
117
+ self
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
124
+ # Just returns openssl verify mode for Ruby 1.8.x
125
+ def ssl_context
126
+ openssl_verify_mode = settings[:openssl_verify_mode]
127
+
128
+ if openssl_verify_mode.kind_of?(String)
129
+ openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
146
130
  end
147
131
 
148
- return settings[:return_response] ? response : self
132
+ context = Net::SMTP.default_ssl_context
133
+ context.verify_mode = openssl_verify_mode
134
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
135
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
136
+ context
149
137
  end
150
-
151
-
152
138
  end
153
139
  end
@@ -1,3 +1,5 @@
1
+ require 'mail/check_delivery_params'
2
+
1
3
  module Mail
2
4
  # == Sending Email with SMTP
3
5
  #
@@ -35,40 +37,21 @@ module Mail
35
37
  #
36
38
  # mail.deliver!
37
39
  class SMTPConnection
40
+ attr_accessor :smtp, :settings
38
41
 
39
42
  def initialize(values)
40
43
  raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
41
44
  self.smtp = values[:connection]
42
45
  self.settings = values
43
46
  end
44
-
45
- attr_accessor :smtp
46
- attr_accessor :settings
47
-
47
+
48
48
  # Send the message via SMTP.
49
49
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
50
50
  def deliver!(mail)
51
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
52
+ response = smtp.sendmail(message, smtp_from, smtp_to)
51
53
 
52
- # Set the envelope from to be either the return-path, the sender or the first from address
53
- envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
54
- if envelope_from.blank?
55
- raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
56
- end
57
-
58
- destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
59
- if destinations.blank?
60
- raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
61
- end
62
-
63
- message ||= mail.encoded if mail.respond_to?(:encoded)
64
- if message.blank?
65
- raise ArgumentError.new('A encoded content is required to send a message')
66
- end
67
-
68
- response = smtp.sendmail(message, envelope_from, destinations)
69
-
70
- settings[:return_response] ? response : self
54
+ settings[:return_response] ? response : self
71
55
  end
72
-
73
56
  end
74
57
  end
@@ -1,3 +1,5 @@
1
+ require 'mail/check_delivery_params'
2
+
1
3
  module Mail
2
4
  # The TestMailer is a bare bones mailer that does nothing. It is useful
3
5
  # when you are testing.
@@ -5,9 +7,8 @@ module Mail
5
7
  # It also provides a template of the minimum methods you require to implement
6
8
  # if you want to make a custom mailer for Mail
7
9
  class TestMailer
8
-
9
10
  # Provides a store of all the emails sent with the TestMailer so you can check them.
10
- def TestMailer.deliveries
11
+ def self.deliveries
11
12
  @@deliveries ||= []
12
13
  end
13
14
 
@@ -22,19 +23,19 @@ module Mail
22
23
  # * length
23
24
  # * size
24
25
  # * and other common Array methods
25
- def TestMailer.deliveries=(val)
26
+ def self.deliveries=(val)
26
27
  @@deliveries = val
27
28
  end
28
29
 
30
+ attr_accessor :settings
31
+
29
32
  def initialize(values)
30
- @settings = {}
33
+ @settings = values.dup
31
34
  end
32
-
33
- attr_accessor :settings
34
35
 
35
36
  def deliver!(mail)
37
+ Mail::CheckDeliveryParams.check(mail)
36
38
  Mail::TestMailer.deliveries << mail
37
39
  end
38
-
39
40
  end
40
- end
41
+ end
@@ -18,7 +18,7 @@ module Mail
18
18
  #
19
19
  # Mail.all #=> Returns an array of all emails
20
20
  # Mail.first #=> Returns the first unread email
21
- # Mail.last #=> Returns the first unread email
21
+ # Mail.last #=> Returns the last unread email
22
22
  #
23
23
  # You can also pass options into Mail.find to locate an email in your imap mailbox
24
24
  # with the following options:
@@ -28,12 +28,15 @@ module Mail
28
28
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
29
29
  # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
30
30
  # instance of Message, not an array of Message instances.
31
+ # keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
32
+ # or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
33
+ # The default is 'ALL'
31
34
  #
32
- # Mail.find(:what => :first, :count => 10, :order => :asc)
35
+ # Mail.find(:what => :first, :count => 10, :order => :asc, :keys=>'ALL')
33
36
  # #=> Returns the first 10 emails in ascending order
34
37
  #
35
38
  class IMAP < Retriever
36
- require 'net/imap'
39
+ require 'net/imap' unless defined?(Net::IMAP)
37
40
 
38
41
  def initialize(values)
39
42
  self.settings = { :address => "localhost",
@@ -54,16 +57,21 @@ module Mail
54
57
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
55
58
  # count: number of emails to retrieve. The default value is 10. A value of 1 returns an
56
59
  # instance of Message, not an array of Message instances.
57
- # ready_only: will ensure that no writes are made to the inbox during the session.
58
- # This is helpful when you don't want your messages to be set to read automatically. Default is false.
60
+ # read_only: will ensure that no writes are made to the inbox during the session. Specifically, if this is
61
+ # set to true, the code will use the EXAMINE command to retrieve the mail. If set to false, which
62
+ # is the default, a SELECT command will be used to retrieve the mail
63
+ # This is helpful when you don't want your messages to be set to read automatically. Default is false.
59
64
  # delete_after_find: flag for whether to delete each retreived email after find. Default
60
65
  # is false. Use #find_and_delete if you would like this to default to true.
66
+ # keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
67
+ # or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
68
+ # The default is 'ALL'
61
69
  #
62
70
  def find(options={}, &block)
63
71
  options = validate_options(options)
64
72
 
65
73
  start do |imap|
66
- options[:read_only] ? imap.select(options[:mailbox]) : imap.examine(options[:mailbox])
74
+ options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
67
75
 
68
76
  message_ids = imap.uid_search(options[:keys])
69
77
  message_ids.reverse! if options[:what].to_sym == :last
@@ -18,7 +18,7 @@ module Mail
18
18
  #
19
19
  # Mail.all #=> Returns an array of all emails
20
20
  # Mail.first #=> Returns the first unread email
21
- # Mail.last #=> Returns the first unread email
21
+ # Mail.last #=> Returns the last unread email
22
22
  #
23
23
  # You can also pass options into Mail.find to locate an email in your pop mailbox
24
24
  # with the following options:
@@ -32,7 +32,7 @@ module Mail
32
32
  # #=> Returns the first 10 emails in ascending order
33
33
  #
34
34
  class POP3 < Retriever
35
- require 'net/pop'
35
+ require 'net/pop' unless defined?(Net::POP)
36
36
 
37
37
  def initialize(values)
38
38
  self.settings = { :address => "localhost",
@@ -20,26 +20,22 @@ module Mail
20
20
  options[:count] ||= :all
21
21
  options[:order] ||= :asc
22
22
  options[:what] ||= :first
23
- emails = @@emails.dup
24
- emails.reverse! if options[:what] == :last
25
- emails = case count = options[:count]
26
- when :all then emails
27
- when 1 then emails.first
28
- when Fixnum then emails[0, count]
23
+ emails_index = (0...@@emails.size).to_a
24
+ emails_index.reverse! if options[:what] == :last
25
+ emails_index = case count = options[:count]
26
+ when :all then emails_index
27
+ when Fixnum then emails_index[0, count]
29
28
  else
30
29
  raise 'Invalid count option value: ' + count.inspect
31
30
  end
32
31
  if options[:what] == :last && options[:order] == :asc || options[:what] == :first && options[:order] == :desc
33
- emails.reverse!
34
- end
35
- emails.each { |email| email.mark_for_delete = true } if options[:delete_after_find]
36
- if block_given?
37
- emails.each { |email| yield email }
38
- else
39
- emails
40
- end.tap do |results|
41
- emails.each { |email| @@emails.delete(email) if email.is_marked_for_delete? } if options[:delete_after_find]
32
+ emails_index.reverse!
42
33
  end
34
+ emails_index.each { |idx| @@emails[idx].mark_for_delete = true } if options[:delete_after_find]
35
+ emails = emails_index.map { |idx| @@emails[idx] }
36
+ emails.each { |email| yield email } if block_given?
37
+ @@emails.reject!(&:is_marked_for_delete?) if options[:delete_after_find]
38
+ emails.size == 1 && options[:count] == 1 ? emails.first : emails
43
39
  end
44
40
 
45
41
  end
data/lib/mail/network.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'mail/network/retriever_methods/base'
2
2
 
3
3
  module Mail
4
- autoload :SMTP, 'mail/network/delivery_methods/smtp'
5
- autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
6
- autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
7
- autoload :Exim, 'mail/network/delivery_methods/exim'
8
- autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
9
- autoload :TestMailer, 'mail/network/delivery_methods/test_mailer'
4
+ register_autoload :SMTP, 'mail/network/delivery_methods/smtp'
5
+ register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
6
+ register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
7
+ register_autoload :Exim, 'mail/network/delivery_methods/exim'
8
+ register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
9
+ register_autoload :TestMailer, 'mail/network/delivery_methods/test_mailer'
10
10
 
11
- autoload :POP3, 'mail/network/retriever_methods/pop3'
12
- autoload :IMAP, 'mail/network/retriever_methods/imap'
13
- autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever'
11
+ register_autoload :POP3, 'mail/network/retriever_methods/pop3'
12
+ register_autoload :IMAP, 'mail/network/retriever_methods/imap'
13
+ register_autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever'
14
14
  end
@@ -85,19 +85,6 @@ module Mail
85
85
  r0
86
86
  end
87
87
 
88
- module Encoding0
89
- def ietf_token
90
- elements[0]
91
- end
92
-
93
- end
94
-
95
- module Encoding1
96
- def text_value
97
- ietf_token.text_value
98
- end
99
- end
100
-
101
88
  def _nt_encoding
102
89
  start_index = index
103
90
  if node_cache[:encoding].has_key?(index)
@@ -110,41 +97,93 @@ module Mail
110
97
  end
111
98
 
112
99
  i0 = index
113
- i1, s1 = index, []
114
- r2 = _nt_ietf_token
115
- s1 << r2
116
- if r2
117
- if has_terminal?("s", false, index)
118
- r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
119
- @index += 1
120
- else
121
- terminal_parse_failure("s")
122
- r4 = nil
123
- end
124
- if r4
125
- r3 = r4
126
- else
127
- r3 = instantiate_node(SyntaxNode,input, index...index)
128
- end
129
- s1 << r3
130
- end
131
- if s1.last
132
- r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
133
- r1.extend(Encoding0)
134
- r1.extend(Encoding1)
100
+ if has_terminal?("7bits", false, index)
101
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 5))
102
+ @index += 5
135
103
  else
136
- @index = i1
104
+ terminal_parse_failure("7bits")
137
105
  r1 = nil
138
106
  end
139
107
  if r1
140
108
  r0 = r1
141
109
  else
142
- r5 = _nt_custom_x_token
143
- if r5
144
- r0 = r5
110
+ if has_terminal?("8bits", false, index)
111
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 5))
112
+ @index += 5
113
+ else
114
+ terminal_parse_failure("8bits")
115
+ r2 = nil
116
+ end
117
+ if r2
118
+ r0 = r2
145
119
  else
146
- @index = i0
147
- r0 = nil
120
+ if has_terminal?("7bit", false, index)
121
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 4))
122
+ @index += 4
123
+ else
124
+ terminal_parse_failure("7bit")
125
+ r3 = nil
126
+ end
127
+ if r3
128
+ r0 = r3
129
+ else
130
+ if has_terminal?("8bit", false, index)
131
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 4))
132
+ @index += 4
133
+ else
134
+ terminal_parse_failure("8bit")
135
+ r4 = nil
136
+ end
137
+ if r4
138
+ r0 = r4
139
+ else
140
+ if has_terminal?("binary", false, index)
141
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 6))
142
+ @index += 6
143
+ else
144
+ terminal_parse_failure("binary")
145
+ r5 = nil
146
+ end
147
+ if r5
148
+ r0 = r5
149
+ else
150
+ if has_terminal?("quoted-printable", false, index)
151
+ r6 = instantiate_node(SyntaxNode,input, index...(index + 16))
152
+ @index += 16
153
+ else
154
+ terminal_parse_failure("quoted-printable")
155
+ r6 = nil
156
+ end
157
+ if r6
158
+ r0 = r6
159
+ else
160
+ if has_terminal?("base64", false, index)
161
+ r7 = instantiate_node(SyntaxNode,input, index...(index + 6))
162
+ @index += 6
163
+ else
164
+ terminal_parse_failure("base64")
165
+ r7 = nil
166
+ end
167
+ if r7
168
+ r0 = r7
169
+ else
170
+ r8 = _nt_ietf_token
171
+ if r8
172
+ r0 = r8
173
+ else
174
+ r9 = _nt_custom_x_token
175
+ if r9
176
+ r0 = r9
177
+ else
178
+ @index = i0
179
+ r0 = nil
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
148
187
  end
149
188
  end
150
189
 
@@ -159,4 +198,4 @@ module Mail
159
198
  include ContentTransferEncoding
160
199
  end
161
200
 
162
- end
201
+ end
@@ -9,12 +9,10 @@ module Mail
9
9
  end
10
10
 
11
11
  rule encoding
12
- ietf_token "s"? {
13
- def text_value
14
- ietf_token.text_value
15
- end
16
- } / custom_x_token
12
+ "7bits" / "8bits" /
13
+ "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" /
14
+ ietf_token / custom_x_token
17
15
  end
18
16
 
19
17
  end
20
- end
18
+ end
@@ -82,18 +82,22 @@ module Mail
82
82
  r6 = _nt_CFWS
83
83
  s5 << r6
84
84
  if r6
85
- if has_terminal?(";", false, index)
86
- r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
87
- @index += 1
88
- else
89
- terminal_parse_failure(";")
90
- r8 = nil
91
- end
92
- if r8
93
- r7 = r8
94
- else
95
- r7 = instantiate_node(SyntaxNode,input, index...index)
85
+ s7, i7 = [], index
86
+ loop do
87
+ if has_terminal?(";", false, index)
88
+ r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
89
+ @index += 1
90
+ else
91
+ terminal_parse_failure(";")
92
+ r8 = nil
93
+ end
94
+ if r8
95
+ s7 << r8
96
+ else
97
+ break
98
+ end
96
99
  end
100
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
97
101
  s5 << r7
98
102
  if r7
99
103
  r9 = _nt_parameter
@@ -964,4 +968,4 @@ module Mail
964
968
  include ContentType
965
969
  end
966
970
 
967
- end
971
+ end
@@ -5,7 +5,7 @@ module Mail
5
5
  include RFC2045
6
6
 
7
7
  rule content_type
8
- main_type "/" sub_type param_hashes:(CFWS ";"? parameter CFWS)* {
8
+ main_type "/" sub_type param_hashes:(CFWS ";"* parameter CFWS)* {
9
9
  def parameters
10
10
  param_hashes.elements.map do |param|
11
11
  param.parameter.param_hash
@@ -65,4 +65,4 @@ module Mail
65
65
  end
66
66
 
67
67
  end
68
- end
68
+ end