mail 2.5.2 → 2.6.4

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 (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +124 -0
  3. data/CONTRIBUTING.md +21 -6
  4. data/Dependencies.txt +0 -1
  5. data/Gemfile +7 -22
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +86 -31
  8. data/Rakefile +11 -22
  9. data/lib/mail/attachments_list.rb +4 -2
  10. data/lib/mail/body.rb +36 -11
  11. data/lib/mail/check_delivery_params.rb +13 -22
  12. data/lib/mail/configuration.rb +1 -0
  13. data/lib/mail/{patterns.rb → constants.rb} +29 -6
  14. data/lib/mail/core_extensions/smtp.rb +13 -13
  15. data/lib/mail/core_extensions/string/access.rb +1 -0
  16. data/lib/mail/core_extensions/string/multibyte.rb +1 -0
  17. data/lib/mail/core_extensions/string.rb +5 -17
  18. data/lib/mail/elements/address.rb +86 -145
  19. data/lib/mail/elements/address_list.rb +10 -42
  20. data/lib/mail/elements/content_disposition_element.rb +4 -7
  21. data/lib/mail/elements/content_location_element.rb +8 -11
  22. data/lib/mail/elements/content_transfer_encoding_element.rb +4 -10
  23. data/lib/mail/elements/content_type_element.rb +5 -8
  24. data/lib/mail/elements/date_time_element.rb +4 -7
  25. data/lib/mail/elements/envelope_from_element.rb +19 -13
  26. data/lib/mail/elements/message_ids_element.rb +8 -11
  27. data/lib/mail/elements/mime_version_element.rb +4 -7
  28. data/lib/mail/elements/phrase_list.rb +3 -7
  29. data/lib/mail/elements/received_element.rb +4 -7
  30. data/lib/mail/elements.rb +1 -0
  31. data/lib/mail/encodings/7bit.rb +1 -0
  32. data/lib/mail/encodings/8bit.rb +8 -2
  33. data/lib/mail/encodings/base64.rb +7 -1
  34. data/lib/mail/encodings/binary.rb +1 -0
  35. data/lib/mail/encodings/quoted_printable.rb +11 -4
  36. data/lib/mail/encodings/transfer_encoding.rb +27 -17
  37. data/lib/mail/encodings/unix_to_unix.rb +18 -0
  38. data/lib/mail/encodings.rb +54 -39
  39. data/lib/mail/envelope.rb +1 -5
  40. data/lib/mail/field.rb +81 -31
  41. data/lib/mail/field_list.rb +19 -18
  42. data/lib/mail/fields/bcc_field.rb +17 -5
  43. data/lib/mail/fields/cc_field.rb +3 -3
  44. data/lib/mail/fields/comments_field.rb +2 -1
  45. data/lib/mail/fields/common/address_container.rb +1 -0
  46. data/lib/mail/fields/common/common_address.rb +34 -28
  47. data/lib/mail/fields/common/common_date.rb +2 -8
  48. data/lib/mail/fields/common/common_field.rb +9 -5
  49. data/lib/mail/fields/common/common_message_id.rb +3 -2
  50. data/lib/mail/fields/common/parameter_hash.rb +4 -3
  51. data/lib/mail/fields/content_description_field.rb +1 -0
  52. data/lib/mail/fields/content_disposition_field.rb +13 -12
  53. data/lib/mail/fields/content_id_field.rb +4 -4
  54. data/lib/mail/fields/content_location_field.rb +2 -1
  55. data/lib/mail/fields/content_transfer_encoding_field.rb +4 -9
  56. data/lib/mail/fields/content_type_field.rb +4 -3
  57. data/lib/mail/fields/date_field.rb +16 -15
  58. data/lib/mail/fields/from_field.rb +3 -3
  59. data/lib/mail/fields/in_reply_to_field.rb +3 -1
  60. data/lib/mail/fields/keywords_field.rb +2 -2
  61. data/lib/mail/fields/message_id_field.rb +4 -4
  62. data/lib/mail/fields/mime_version_field.rb +3 -2
  63. data/lib/mail/fields/optional_field.rb +1 -0
  64. data/lib/mail/fields/received_field.rb +4 -3
  65. data/lib/mail/fields/references_field.rb +3 -1
  66. data/lib/mail/fields/reply_to_field.rb +3 -3
  67. data/lib/mail/fields/resent_bcc_field.rb +3 -3
  68. data/lib/mail/fields/resent_cc_field.rb +3 -3
  69. data/lib/mail/fields/resent_date_field.rb +2 -1
  70. data/lib/mail/fields/resent_from_field.rb +3 -3
  71. data/lib/mail/fields/resent_message_id_field.rb +1 -0
  72. data/lib/mail/fields/resent_sender_field.rb +4 -4
  73. data/lib/mail/fields/resent_to_field.rb +3 -3
  74. data/lib/mail/fields/return_path_field.rb +1 -1
  75. data/lib/mail/fields/sender_field.rb +9 -9
  76. data/lib/mail/fields/structured_field.rb +1 -0
  77. data/lib/mail/fields/subject_field.rb +1 -0
  78. data/lib/mail/fields/to_field.rb +3 -3
  79. data/lib/mail/fields/unstructured_field.rb +15 -8
  80. data/lib/mail/fields.rb +1 -0
  81. data/lib/mail/header.rb +21 -29
  82. data/lib/mail/indifferent_hash.rb +1 -0
  83. data/lib/mail/mail.rb +16 -1
  84. data/lib/mail/matchers/attachment_matchers.rb +29 -0
  85. data/lib/mail/matchers/has_sent_mail.rb +61 -4
  86. data/lib/mail/message.rb +175 -72
  87. data/lib/mail/multibyte/chars.rb +3 -2
  88. data/lib/mail/multibyte/exceptions.rb +1 -0
  89. data/lib/mail/multibyte/unicode.rb +22 -15
  90. data/lib/mail/multibyte/utils.rb +1 -0
  91. data/lib/mail/multibyte.rb +1 -0
  92. data/lib/mail/network/delivery_methods/exim.rb +3 -7
  93. data/lib/mail/network/delivery_methods/file_delivery.rb +2 -1
  94. data/lib/mail/network/delivery_methods/sendmail.rb +33 -10
  95. data/lib/mail/network/delivery_methods/smtp.rb +32 -34
  96. data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -6
  97. data/lib/mail/network/delivery_methods/test_mailer.rb +3 -2
  98. data/lib/mail/network/retriever_methods/base.rb +1 -0
  99. data/lib/mail/network/retriever_methods/imap.rb +19 -13
  100. data/lib/mail/network/retriever_methods/pop3.rb +1 -0
  101. data/lib/mail/network/retriever_methods/test_retriever.rb +1 -0
  102. data/lib/mail/network.rb +1 -0
  103. data/lib/mail/parsers/address_lists_parser.rb +133 -0
  104. data/lib/mail/parsers/content_disposition_parser.rb +68 -0
  105. data/lib/mail/parsers/content_location_parser.rb +36 -0
  106. data/lib/mail/parsers/content_transfer_encoding_parser.rb +34 -0
  107. data/lib/mail/parsers/content_type_parser.rb +67 -0
  108. data/lib/mail/parsers/date_time_parser.rb +39 -0
  109. data/lib/mail/parsers/envelope_from_parser.rb +46 -0
  110. data/lib/mail/parsers/message_ids_parser.rb +40 -0
  111. data/lib/mail/parsers/mime_version_parser.rb +42 -0
  112. data/lib/mail/parsers/phrase_lists_parser.rb +36 -0
  113. data/lib/mail/parsers/ragel/common.rl +185 -0
  114. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  115. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  116. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  117. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  118. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  119. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  139. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  140. data/lib/mail/parsers/ragel/ruby.rb +40 -0
  141. data/lib/mail/parsers/ragel.rb +18 -0
  142. data/lib/mail/parsers/received_parser.rb +49 -0
  143. data/lib/mail/parsers.rb +27 -0
  144. data/lib/mail/part.rb +11 -4
  145. data/lib/mail/parts_list.rb +30 -10
  146. data/lib/mail/utilities.rb +127 -63
  147. data/lib/mail/values/unicode_tables.dat +0 -0
  148. data/lib/mail/version.rb +8 -15
  149. data/lib/mail/version_specific/ruby_1_8.rb +18 -7
  150. data/lib/mail/version_specific/ruby_1_9.rb +136 -32
  151. data/lib/mail.rb +12 -6
  152. metadata +115 -77
  153. data/lib/VERSION +0 -4
  154. data/lib/load_parsers.rb +0 -41
  155. data/lib/mail/core_extensions/nil.rb +0 -19
  156. data/lib/mail/core_extensions/object.rb +0 -13
  157. data/lib/mail/core_extensions/shell_escape.rb +0 -56
  158. data/lib/mail/parsers/address_lists.rb +0 -64
  159. data/lib/mail/parsers/address_lists.treetop +0 -19
  160. data/lib/mail/parsers/content_disposition.rb +0 -535
  161. data/lib/mail/parsers/content_disposition.treetop +0 -46
  162. data/lib/mail/parsers/content_location.rb +0 -139
  163. data/lib/mail/parsers/content_location.treetop +0 -20
  164. data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
  165. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
  166. data/lib/mail/parsers/content_type.rb +0 -967
  167. data/lib/mail/parsers/content_type.treetop +0 -68
  168. data/lib/mail/parsers/date_time.rb +0 -114
  169. data/lib/mail/parsers/date_time.treetop +0 -11
  170. data/lib/mail/parsers/envelope_from.rb +0 -194
  171. data/lib/mail/parsers/envelope_from.treetop +0 -32
  172. data/lib/mail/parsers/message_ids.rb +0 -45
  173. data/lib/mail/parsers/message_ids.treetop +0 -15
  174. data/lib/mail/parsers/mime_version.rb +0 -144
  175. data/lib/mail/parsers/mime_version.treetop +0 -19
  176. data/lib/mail/parsers/phrase_lists.rb +0 -45
  177. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  178. data/lib/mail/parsers/received.rb +0 -71
  179. data/lib/mail/parsers/received.treetop +0 -11
  180. data/lib/mail/parsers/rfc2045.rb +0 -464
  181. data/lib/mail/parsers/rfc2045.treetop +0 -36
  182. data/lib/mail/parsers/rfc2822.rb +0 -5397
  183. data/lib/mail/parsers/rfc2822.treetop +0 -410
  184. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  185. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  186. data/lib/tasks/corpus.rake +0 -125
  187. data/lib/tasks/treetop.rake +0 -10
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mail/check_delivery_params'
2
3
 
3
4
  module Mail
@@ -89,57 +90,54 @@ module Mail
89
90
  :tls => nil
90
91
  }.merge!(values)
91
92
  end
92
-
93
+
93
94
  attr_accessor :settings
94
-
95
+
95
96
  # Send the message via SMTP.
96
97
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
97
98
  def deliver!(mail)
98
- envelope_from, destinations, message = check_params(mail)
99
+ smtp_from, smtp_to, message = check_delivery_params(mail)
99
100
 
100
101
  smtp = Net::SMTP.new(settings[:address], settings[:port])
101
102
  if settings[:tls] || settings[:ssl]
102
103
  if smtp.respond_to?(:enable_tls)
103
- unless settings[:openssl_verify_mode]
104
- smtp.enable_tls
105
- else
106
- openssl_verify_mode = settings[:openssl_verify_mode]
107
- if openssl_verify_mode.kind_of?(String)
108
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
109
- end
110
- context = Net::SMTP.default_ssl_context
111
- context.verify_mode = openssl_verify_mode
112
- smtp.enable_tls(context)
113
- end
104
+ smtp.enable_tls(ssl_context)
114
105
  end
115
106
  elsif settings[:enable_starttls_auto]
116
- if smtp.respond_to?(:enable_starttls_auto)
117
- unless settings[:openssl_verify_mode]
118
- smtp.enable_starttls_auto
119
- else
120
- openssl_verify_mode = settings[:openssl_verify_mode]
121
- if openssl_verify_mode.kind_of?(String)
122
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
123
- end
124
- if RUBY_VERSION >= '1.9.0'
125
- context = Net::SMTP.default_ssl_context
126
- context.verify_mode = openssl_verify_mode
127
- smtp.enable_tls(context)
128
- else
129
- smtp.enable_tls(openssl_verify_mode)
130
- end
131
- end
107
+ if smtp.respond_to?(:enable_starttls_auto)
108
+ smtp.enable_starttls_auto(ssl_context)
132
109
  end
133
110
  end
134
-
111
+
135
112
  response = nil
136
113
  smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
137
- response = smtp_obj.sendmail(message, envelope_from, destinations)
114
+ response = smtp_obj.sendmail(message, smtp_from, smtp_to)
138
115
  end
139
116
 
140
- return settings[:return_response] ? response : self
117
+ if settings[:return_response]
118
+ response
119
+ else
120
+ self
121
+ end
141
122
  end
142
123
 
143
-
124
+
125
+ private
126
+
127
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
128
+ # Just returns openssl verify mode for Ruby 1.8.x
129
+ def ssl_context
130
+ openssl_verify_mode = settings[:openssl_verify_mode]
131
+
132
+ if openssl_verify_mode.kind_of?(String)
133
+ openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
134
+ end
135
+
136
+ context = Net::SMTP.default_ssl_context
137
+ context.verify_mode = openssl_verify_mode
138
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
139
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
140
+ context
141
+ end
144
142
  end
145
143
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mail/check_delivery_params'
2
3
 
3
4
  module Mail
@@ -44,18 +45,18 @@ module Mail
44
45
  self.smtp = values[:connection]
45
46
  self.settings = values
46
47
  end
47
-
48
+
48
49
  attr_accessor :smtp
49
50
  attr_accessor :settings
50
-
51
+
51
52
  # Send the message via SMTP.
52
53
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
53
54
  def deliver!(mail)
54
- envelope_from, destinations, message = check_params(mail)
55
- response = smtp.sendmail(message, envelope_from, destinations)
55
+ smtp_from, smtp_to, message = check_delivery_params(mail)
56
+ response = smtp.sendmail(message, smtp_from, smtp_to)
56
57
 
57
- settings[:return_response] ? response : self
58
+ settings[:return_response] ? response : self
58
59
  end
59
-
60
+
60
61
  end
61
62
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mail/check_delivery_params'
2
3
 
3
4
  module Mail
@@ -30,13 +31,13 @@ module Mail
30
31
  end
31
32
 
32
33
  def initialize(values)
33
- @settings = {}
34
+ @settings = values.dup
34
35
  end
35
36
 
36
37
  attr_accessor :settings
37
38
 
38
39
  def deliver!(mail)
39
- check_params(mail)
40
+ check_delivery_params(mail)
40
41
  Mail::TestMailer.deliveries << mail
41
42
  end
42
43
 
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Mail
4
5
 
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Mail
4
5
  # The IMAP retriever allows to get the last, first or all emails from a IMAP server.
@@ -73,31 +74,35 @@ module Mail
73
74
  start do |imap|
74
75
  options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
75
76
 
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) ||
77
+ uids = imap.uid_search(options[:keys])
78
+ uids.reverse! if options[:what].to_sym == :last
79
+ uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
80
+ uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
80
81
  (options[:what].to_sym != :last && options[:order].to_sym == :desc)
81
82
 
82
83
  if block_given?
83
- message_ids.each do |message_id|
84
- fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
84
+ uids.each do |uid|
85
+ uid = options[:uid].to_i unless options[:uid].nil?
86
+ fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
85
87
  new_message = Mail.new(fetchdata.attr['RFC822'])
86
88
  new_message.mark_for_delete = true if options[:delete_after_find]
87
89
  if block.arity == 3
88
- yield new_message, imap, message_id
90
+ yield new_message, imap, uid
89
91
  else
90
92
  yield new_message
91
93
  end
92
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
94
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
95
+ break unless options[:uid].nil?
93
96
  end
94
97
  imap.expunge if options[:delete_after_find]
95
98
  else
96
99
  emails = []
97
- message_ids.each do |message_id|
98
- fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0]
100
+ uids.each do |uid|
101
+ uid = options[:uid].to_i unless options[:uid].nil?
102
+ fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
99
103
  emails << Mail.new(fetchdata.attr['RFC822'])
100
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
104
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find]
105
+ break unless options[:uid].nil?
101
106
  end
102
107
  imap.expunge if options[:delete_after_find]
103
108
  emails.size == 1 && options[:count] == 1 ? emails.first : emails
@@ -111,8 +116,8 @@ module Mail
111
116
  mailbox = Net::IMAP.encode_utf7(mailbox)
112
117
 
113
118
  start do |imap|
114
- imap.uid_search(['ALL']).each do |message_id|
115
- imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED])
119
+ imap.uid_search(['ALL']).each do |uid|
120
+ imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED])
116
121
  end
117
122
  imap.expunge
118
123
  end
@@ -137,6 +142,7 @@ module Mail
137
142
  options[:order] ||= :asc
138
143
  options[:what] ||= :first
139
144
  options[:keys] ||= 'ALL'
145
+ options[:uid] ||= nil
140
146
  options[:delete_after_find] ||= false
141
147
  options[:mailbox] = Net::IMAP.encode_utf7(options[:mailbox])
142
148
  options[:read_only] ||= false
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Mail
4
5
  # The Pop3 retriever allows to get the last, first or all emails from a POP3 server.
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Mail
4
5
 
data/lib/mail/network.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mail/network/retriever_methods/base'
2
3
 
3
4
  module Mail
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class AddressListsParser
4
+ include Mail::Utilities
5
+
6
+ def parse(s)
7
+ address_list = AddressListStruct.new([],[])
8
+
9
+ if Mail::Utilities.blank?(s)
10
+ return address_list
11
+ end
12
+
13
+ actions, error = Ragel.parse(:address_lists, s)
14
+ if error
15
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, error)
16
+ end
17
+
18
+
19
+ phrase_s = phrase_e = qstr_s = qstr = comment_s = nil
20
+ group_name_s = domain_s = group_name = nil
21
+ local_dot_atom_s = local_dot_atom_e = nil
22
+ local_dot_atom_pre_comment_e = nil
23
+ obs_domain_list_s = nil
24
+
25
+ address_s = 0
26
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
27
+ actions.each_slice(2) do |action_id, p|
28
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
29
+ case action
30
+
31
+ # Phrase
32
+ when :phrase_s then phrase_s = p
33
+ when :phrase_e then phrase_e = 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
+ # Comment
40
+ when :comment_s
41
+ comment_s = p unless comment_s
42
+ when :comment_e
43
+ if address
44
+ address.comments << s[comment_s..(p-2)]
45
+ end
46
+ comment_s = nil
47
+
48
+ # Group Name
49
+ when :group_name_s then group_name_s = p
50
+ when :group_name_e
51
+ if qstr
52
+ group = qstr
53
+ qstr = nil
54
+ else
55
+ group = s[group_name_s..(p-1)]
56
+ group_name_s = nil
57
+ end
58
+ address_list.group_names << group
59
+ group_name = group
60
+
61
+ # Start next address
62
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
63
+ address_s = p
64
+ address.group = group_name
65
+
66
+ # Address
67
+ when :address_s
68
+ address_s = p
69
+ when :address_e
70
+ # Ignore address end events if they don't have
71
+ # a matching address start event.
72
+ next if address_s.nil?
73
+ if address.local.nil? && local_dot_atom_pre_comment_e && local_dot_atom_s && local_dot_atom_e
74
+ if address.domain
75
+ address.local = s[local_dot_atom_s..local_dot_atom_e] if address
76
+ else
77
+ address.local = s[local_dot_atom_s..local_dot_atom_pre_comment_e] if address
78
+ end
79
+ end
80
+ address.raw = s[address_s..(p-1)]
81
+ address_list.addresses << address if address
82
+
83
+ # Start next address
84
+ address = AddressStruct.new(nil, nil, [], nil, nil, nil, nil)
85
+ address.group = group_name
86
+ address_s = nil
87
+
88
+ # Don't set the display name until the
89
+ # address has actually started. This allows
90
+ # us to choose quoted_s version if it
91
+ # exists and always use the 'full' phrase
92
+ # version.
93
+ when :angle_addr_s
94
+ if qstr
95
+ address.display_name = qstr
96
+ qstr = nil
97
+ elsif phrase_e
98
+ address.display_name = s[phrase_s..phrase_e].strip
99
+ phrase_e = phrase_s = nil
100
+ end
101
+
102
+ # Domain
103
+ when :domain_s
104
+ domain_s = p
105
+ when :domain_e
106
+ address.domain = s[domain_s..(p-1)].rstrip if address
107
+
108
+ # Local
109
+ when :local_dot_atom_s then local_dot_atom_s = p
110
+ when :local_dot_atom_e then local_dot_atom_e = p-1
111
+ when :local_dot_atom_pre_comment_e
112
+ local_dot_atom_pre_comment_e = p-1
113
+ when :local_quoted_string_e
114
+ address.local = '"' + qstr + '"' if address
115
+
116
+ # obs_domain_list
117
+ when :obs_domain_list_s then obs_domain_list_s = p
118
+ when :obs_domain_list_e
119
+ address.obs_domain_list = s[obs_domain_list_s..(p-1)]
120
+
121
+ else
122
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, "Failed to process unknown action: #{action}")
123
+ end
124
+ end
125
+
126
+ if address_list.addresses.empty? && address_list.group_names.empty?
127
+ raise Mail::Field::ParseError.new(Mail::AddressList, s, "Didn't find any addresses or groups")
128
+ end
129
+
130
+ address_list
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class ContentDispositionParser
4
+ include Mail::Utilities
5
+
6
+ def parse(s)
7
+ content_disposition = ContentDispositionStruct.new("", nil)
8
+ if Mail::Utilities.blank?(s)
9
+ return content_disposition
10
+ end
11
+
12
+ actions, error = Ragel.parse(:content_disposition, s)
13
+ if error
14
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, error)
15
+ end
16
+
17
+ content_disposition.parameters = []
18
+
19
+ disp_type_s = param_attr_s = param_attr = qstr_s = qstr = param_val_s = nil
20
+ actions.each_slice(2) do |action_id, p|
21
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
22
+ case action
23
+
24
+ # Disposition Type
25
+ when :disp_type_s then disp_type_s = p
26
+ when :disp_type_e
27
+ content_disposition.disposition_type = s[disp_type_s..(p-1)].downcase
28
+
29
+ # Parameter Attribute
30
+ when :param_attr_s then param_attr_s = p
31
+ when :param_attr_e then param_attr = s[param_attr_s..(p-1)]
32
+
33
+ # Quoted String.
34
+ when :qstr_s then qstr_s = p
35
+ when :qstr_e then qstr = s[qstr_s..(p-1)]
36
+
37
+ # Parameter Value
38
+ when :param_val_s then param_val_s = p
39
+ when :param_val_e
40
+ if param_attr.nil?
41
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, "no attribute for value")
42
+ end
43
+
44
+ # Use quoted string value if one exists, otherwise use parameter value
45
+ if qstr
46
+ value = qstr
47
+ else
48
+ value = s[param_val_s..(p-1)]
49
+ end
50
+
51
+ content_disposition.parameters << { param_attr => value }
52
+ param_attr = nil
53
+ qstr = nil
54
+
55
+ else
56
+ raise Mail::Field::ParseError.new(Mail::ContentDispositionElement, s, "Failed to process unknown action: #{action}")
57
+ end
58
+ end
59
+
60
+ content_disposition
61
+ end
62
+
63
+ private
64
+ def cleaned(string)
65
+ string =~ /(.+);\s*$/ ? $1 : string
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class ContentLocationParser
4
+ def parse(s)
5
+ content_location = ContentLocationStruct.new(nil)
6
+ if Mail::Utilities.blank?(s)
7
+ return content_location
8
+ end
9
+
10
+ actions, error = Ragel.parse(:content_location, s)
11
+ if error
12
+ raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, error)
13
+ end
14
+
15
+ qstr_s = token_string_s = nil
16
+ actions.each_slice(2) do |action_id, p|
17
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
18
+ case action
19
+
20
+ # Quoted String.
21
+ when :qstr_s then qstr_s = p
22
+ when :qstr_e then content_location.location = s[qstr_s..(p-1)]
23
+
24
+ # Token String
25
+ when :token_string_s then token_string_s = p
26
+ when :token_string_e
27
+ content_location.location = s[token_string_s..(p-1)]
28
+
29
+ else
30
+ raise Mail::Field::ParseError.new(Mail::ContentLocationElement, s, "Failed to process unknown action: #{action}")
31
+ end
32
+ end
33
+ content_location
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class ContentTransferEncodingParser
4
+
5
+ def parse(s)
6
+ content_transfer_encoding = ContentTransferEncodingStruct.new("")
7
+ if Mail::Utilities.blank?(s)
8
+ return content_transfer_encoding
9
+ end
10
+
11
+ actions, error = Ragel.parse(:content_transfer_encoding, s)
12
+ if error
13
+ raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, error)
14
+ end
15
+
16
+ encoding_s = nil
17
+ actions.each_slice(2) do |action_id, p|
18
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
19
+ case action
20
+
21
+ # Encoding
22
+ when :encoding_s then encoding_s = p
23
+ when :encoding_e
24
+ content_transfer_encoding.encoding = s[encoding_s..(p-1)].downcase
25
+
26
+ else
27
+ raise Mail::Field::ParseError.new(Mail::ContentTransferEncodingElement, s, "Failed to process unknown action: #{action}")
28
+ end
29
+ end
30
+
31
+ content_transfer_encoding
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class ContentTypeParser
4
+ include Mail::Utilities
5
+
6
+ def parse(s)
7
+ actions, error = Ragel.parse(:content_type, s)
8
+ if error
9
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, error)
10
+ end
11
+
12
+ content_type = ContentTypeStruct.new(nil,nil,[])
13
+
14
+ content_type.parameters = []
15
+
16
+ main_type_s = sub_type_s = param_attr_s = param_attr = nil
17
+ qstr_s = qstr = param_val_s = nil
18
+ actions.each_slice(2) do |action_id, p|
19
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
20
+ case action
21
+
22
+ # Main Type
23
+ when :main_type_s then main_type_s = p
24
+ when :main_type_e then
25
+ content_type.main_type = s[main_type_s..(p-1)]
26
+ content_type.main_type.downcase!
27
+
28
+ # Sub Type
29
+ when :sub_type_s then sub_type_s = p
30
+ when :sub_type_e
31
+ content_type.sub_type = s[sub_type_s..(p-1)]
32
+ content_type.sub_type.downcase!
33
+
34
+ # Parameter Attribute
35
+ when :param_attr_s then param_attr_s = p
36
+ when :param_attr_e then param_attr = s[param_attr_s..(p-1)]
37
+
38
+ # Quoted String.
39
+ when :qstr_s then qstr_s = p
40
+ when :qstr_e then qstr = s[qstr_s..(p-1)]
41
+
42
+ # Parameter Value
43
+ when :param_val_s then param_val_s = p
44
+ when :param_val_e
45
+ if param_attr.nil?
46
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "no attribute for value")
47
+ end
48
+
49
+ # Use quoted s value if one exists, otherwise use parameter value
50
+ if qstr
51
+ value = qstr
52
+ else
53
+ value = s[param_val_s..(p-1)]
54
+ end
55
+
56
+ content_type.parameters << { param_attr => value }
57
+ param_attr = nil
58
+ qstr = nil
59
+
60
+ else
61
+ raise Mail::Field::ParseError.new(Mail::ContentTypeElement, s, "Failed to process unknown action: #{action}")
62
+ end
63
+ end
64
+ content_type
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class DateTimeParser
4
+ include Mail::Utilities
5
+
6
+ def parse(s)
7
+ raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, "nil is an invalid DateTime") if s.nil?
8
+
9
+ date_time = DateTimeStruct.new([])
10
+
11
+ actions, error = Ragel.parse(:date_time, s)
12
+ if error
13
+ raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, error)
14
+ end
15
+
16
+ date_s = time_s = nil
17
+ actions.each_slice(2) do |action_id, p|
18
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
19
+ case action
20
+
21
+ # Date
22
+ when :date_s then date_s = p
23
+ when :date_e
24
+ date_time.date_string = s[date_s..(p-1)]
25
+
26
+ # Time
27
+ when :time_s then time_s = p
28
+ when :time_e
29
+ date_time.time_string = s[time_s..(p-1)]
30
+
31
+ else
32
+ raise Mail::Field::ParseError.new(Mail::DateTimeElement, s, "Failed to process unknown action: #{action}")
33
+ end
34
+ end
35
+
36
+ date_time
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ module Mail::Parsers
3
+ class EnvelopeFromParser
4
+ def parse(s)
5
+ envelope_from = EnvelopeFromStruct.new
6
+ if Mail::Utilities.blank?(s)
7
+ return envelope_from
8
+ end
9
+
10
+ actions, error = Ragel.parse(:envelope_from, s)
11
+ if error
12
+ raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, error)
13
+ end
14
+
15
+ address_s = ctime_date_s = nil
16
+ envelope_from = EnvelopeFromStruct.new
17
+ actions.each_slice(2) do |action_id, p|
18
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
19
+ case action
20
+
21
+ # Address
22
+ when :address_s then address_s = p
23
+ when :address_e
24
+ envelope_from.address = s[address_s..(p-1)].rstrip
25
+
26
+ # ctime_date
27
+ when :ctime_date_s then ctime_date_s = p
28
+ when :ctime_date_e
29
+ envelope_from.ctime_date = s[ctime_date_s..(p-1)]
30
+
31
+ # ignored actions
32
+ when :angle_addr_s, :comment_e, :comment_s,
33
+ :domain_e, :domain_s, :local_dot_atom_e,
34
+ :local_dot_atom_pre_comment_e,
35
+ :local_dot_atom_pre_comment_s,
36
+ :local_dot_atom_s, :qstr_e, :qstr_s
37
+ nil
38
+
39
+ else
40
+ raise Mail::Field::ParseError.new(Mail::EnvelopeFromElement, s, "Failed to process unknown action: #{action}")
41
+ end
42
+ end
43
+ envelope_from
44
+ end
45
+ end
46
+ end