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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ecb5e9115e61802f251480eef90c6698ac665d0b
4
+ data.tar.gz: a1105d5defc2c7b374598a392e5f5dc4d1452a21
5
+ SHA512:
6
+ metadata.gz: 103d2126c02d1aeb5ffd4982f261407af16652fd181f6e0fc63bf12702e5aa1ea3c7f863a3c39f822ba3b8e8cf704782d1beb7c4e2e28cba5f4fc2931151cf0e
7
+ data.tar.gz: 6f25c0decaf77a0314b42d0fbf6c61edfc7f2fe9b4bbeef004e34a7127882093b660108cd7728a108f26b1b3dcf2664beac4e5e6d0d0d3e68565f78fdd273d4e
data/CHANGELOG.rdoc CHANGED
@@ -1,9 +1,10 @@
1
1
  == HEAD
2
2
 
3
-
4
- == Version 2.5.4 - Tue May 14 14:45:00 +1100 2013 Mikel Lindsaar <mikel@lindsaar.net>
3
+ == Version 2.6.0 - Mon Jun 2 22:49 +1100 2014 Mikel Lindsaar <mikel@reinteractive.net>
5
4
 
6
5
  Features:
6
+ * Allow interceptors and observers to be unregistered (zuhao)
7
+ * Added feature to find the mail in uid (taketin)
7
8
  * Save settings passed to TestMailer#new (svanderbleek)
8
9
  * Allow the setting of envelope from directly (jeremy)
9
10
  * Accept other IETF/IANA-registered Content-Types and Content-Transfer-Encodings (jeremy)
@@ -19,9 +20,13 @@ Features:
19
20
  * Close pull request 389 - Don't add superfluous message headers to MIME parts (djmaze, jeremy)
20
21
 
21
22
  Performance:
23
+ * Migrate to RAGEL based parser, awesome work by (bpot)
24
+ * Performance improvements for people parsing email headers (ConradIrwin)
22
25
  * Close pull request 488 - Speed up field construction & comparison (bpot)
23
26
 
24
27
  Bugs:
28
+ * Fix for when content looks like field name (kjg)
29
+ * Don't change original when you change a copy (TylerRick)
25
30
  * Don't include separating semicolon in paramter value when sanitizing (bpot)
26
31
  * Fix fencepost encoding problem with binhex strings and only one token (drasch)
27
32
  * Fix sendmail delivery to addresses with a leading hyphen (lifo, jeremy)
data/CONTRIBUTING.md CHANGED
@@ -43,3 +43,16 @@ Syntax:
43
43
  * Follow the conventions you see used in the source already.
44
44
 
45
45
  And in case we didn't emphasize it enough: we love specs!
46
+
47
+ ### Testing against mime-types versions:
48
+
49
+ Use [appraisal](https://github.com/thoughtbot/appraisal) to run against all supported versions of mime-types.
50
+
51
+ 1. Run `(bundle check || bundle) && appraisal` so that all the 'appraised' gemfiles are bundled.
52
+ 2. Run either `appraisal rake` or `rake appraisal` to run all the tests.
53
+
54
+ To run only one 'appraised' gemfile, run. e.g. `BUNDLE_GEMFILE=gemfiles/mime_types_edge.gemfile (bundle check || bundle) && rake`
55
+
56
+ To change the appraisals, modify the `Appraisals` file, run `appraisal`, commit the generated gemfiles, and modify the .travis.yml matrix.
57
+
58
+ To run on all rubies / gemfiles, just like TravisCI, see [WWTD](https://github.com/grosser/wwtd).
data/Dependencies.txt CHANGED
@@ -1,3 +1,2 @@
1
- treetop: we need to include this in the gem spec
2
1
  tlsmail: if ruby < 1.8.6... we could make it optional, or embed it in Mail
3
2
  mime/types: I think we embed a simplified version, or help maintain it, it is old (2006)
data/Gemfile CHANGED
@@ -1,13 +1,15 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "treetop", "~> 1.4.10"
6
- gem "mime-types", "~> 1.16"
7
- gem "tlsmail" if RUBY_VERSION <= '1.8.6'
5
+ gem "tlsmail", "~> 0.0.1" if RUBY_VERSION <= "1.8.6"
6
+ gem "jruby-openssl", :platforms => :jruby
8
7
 
9
- gem 'jruby-openssl', :platform => :jruby
8
+ group :development, :test do
9
+ gem "appraisal", "~> 1.0"
10
+ end
10
11
 
11
- group :test do
12
- gem "ruby-debug", :platform => :mri_18
12
+ # For gems not required to run tests
13
+ group :local_development, :test do
14
+ gem "ruby-debug", :platforms => :mri_18
13
15
  end
data/README.md CHANGED
@@ -15,11 +15,11 @@ Built from my experience with TMail, it is designed to be a pure ruby
15
15
  implementation that makes generating, sending and parsing emails a no
16
16
  brainer.
17
17
 
18
- It is also designed form the ground up to work with Ruby 1.9. This is because
19
- Ruby 1.9 handles text encodings much more magically than Ruby 1.8.x and so
20
- these features have been taken full advantage of in this library allowing
21
- Mail to handle a lot more messages more cleanly than TMail. Mail does run on
22
- Ruby 1.8.x... it's just not as fun to code.
18
+ It is also designed form the ground up to work with the more modern versions
19
+ of Ruby. This is because Ruby > 1.9 handles text encodings much more wonderfully
20
+ than Ruby 1.8.x and so these features have been taken full advantage of in this
21
+ library allowing Mail to handle a lot more messages more cleanly than TMail.
22
+ Mail does run on Ruby 1.8.x... it's just not as fun to code.
23
23
 
24
24
  Finally, Mail has been designed with a very simple object oriented system
25
25
  that really opens up the email messages you are parsing, if you know what
@@ -44,14 +44,23 @@ Compatibility
44
44
 
45
45
  Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
46
46
 
47
- * ruby-1.8.7-p370 [ i686 ]
48
- * ruby-1.9.2-p290 [ x86_64 ]
47
+ * ruby-1.8.7-p374 [ i686 ]
48
+ * ruby-1.9.2-p320 [ x86_64 ]
49
49
  * ruby-1.9.3-p327 [ x86_64 ]
50
- * ruby-2.0.0-rc1 [ x86_64 ]
51
- * jruby-1.6.8 [ x86_64 ]
52
- * jruby-1.7.0 [ x86_64 ]
53
- * rbx-d18 [ x86_64 ]
54
- * rbx-d19 [ x86_64 ]
50
+ * ruby-2.0.0-p451 [ x86_64 ]
51
+ * ruby-2.1.2 [ x86_64 ]
52
+ * ruby-head [ x86_64 ]
53
+ * jruby [ x86_64 ]
54
+ * jruby-head [ x86_64 ]
55
+ * rbx-2 [ x86_64 ]
56
+
57
+ Testing a specific mime type (needed for 1.8.7 for example) can be done manually with:
58
+
59
+ $ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile bundle check
60
+ $ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile bundle
61
+ $ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile rake
62
+
63
+
55
64
 
56
65
  Discussion
57
66
  ----------
@@ -186,6 +195,8 @@ mail['from'] = 'mikel@test.lindsaar.net'
186
195
  mail[:to] = 'you@test.lindsaar.net'
187
196
  mail.subject = 'This is a test email'
188
197
 
198
+ mail.header['X-Custom-Header'] = 'custom value'
199
+
189
200
  mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
190
201
  ```
191
202
 
@@ -228,10 +239,10 @@ easy as:
228
239
 
229
240
  ```ruby
230
241
  Mail.deliver do
231
- from 'me@test.lindsaar.net'
232
- to 'you@test.lindsaar.net'
233
- subject 'Here is the image you wanted'
234
- body File.read('body.txt')
242
+ from 'me@test.lindsaar.net'
243
+ to 'you@test.lindsaar.net'
244
+ subject 'Here is the image you wanted'
245
+ body File.read('body.txt')
235
246
  add_file '/full/path/to/somefile.png'
236
247
  end
237
248
  ```
@@ -266,6 +277,15 @@ mail.delivery_method :sendmail
266
277
  mail.deliver
267
278
  ```
268
279
 
280
+ Sending via smtp (for example to [mailcatcher](https://github.com/sj26/mailcatcher))
281
+ ```ruby
282
+
283
+ Mail.defaults do
284
+ delivery_method :smtp, address: "localhost", port: 1025
285
+ end
286
+ ```
287
+
288
+
269
289
  Exim requires its own delivery manager, and can be used like so:
270
290
 
271
291
  ```ruby
@@ -319,7 +339,7 @@ emails.length #=> LOTS!
319
339
  ```ruby
320
340
  mail = Mail.read('/path/to/message.eml')
321
341
 
322
- mail.envelope.from #=> 'mikel@test.lindsaar.net'
342
+ mail.envelope_from #=> 'mikel@test.lindsaar.net'
323
343
  mail.from.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
324
344
  mail.sender.address #=> 'mikel@test.lindsaar.net'
325
345
  mail.to #=> 'bob@test.lindsaar.net'
@@ -350,7 +370,7 @@ mail.parts[1].content_type_parameters #=> {'name' => 'my.pdf'}
350
370
  Mail generates a tree of parts. Each message has many or no parts. Each part
351
371
  is another message which can have many or no parts.
352
372
 
353
- A message will only have parts if it is a multipart/mixed or related/mixed
373
+ A message will only have parts if it is a multipart/mixed or multipart/related
354
374
  content type and has a boundary defined.
355
375
 
356
376
  ### Testing and extracting attachments
@@ -363,7 +383,7 @@ mail.attachments.each do | attachment |
363
383
  filename = attachment.filename
364
384
  begin
365
385
  File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.body.decoded}
366
- rescue Exception => e
386
+ rescue => e
367
387
  puts "Unable to save data for #{filename} because #{e.message}"
368
388
  end
369
389
  end
@@ -546,7 +566,7 @@ Using Mail with Testing or Spec'ing Libraries
546
566
  If mail is part of your system, you'll need a way to test it without actually
547
567
  sending emails, the TestMailer can do this for you.
548
568
 
549
- ```
569
+ ```ruby
550
570
  require 'mail'
551
571
  => true
552
572
  Mail.defaults do
@@ -572,7 +592,7 @@ Mail::TestMailer.deliveries.clear
572
592
 
573
593
  There is also a set of RSpec matchers stolen fr^H^H^H^H^H^H^H^H inspired by Shoulda's ActionMailer matchers (you'll want to set <code>delivery_method</code> as above too):
574
594
 
575
- ```
595
+ ```ruby
576
596
  Mail.defaults do
577
597
  delivery_method :test # in practice you'd do this in spec_helper.rb
578
598
  end
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
- ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __FILE__)
1
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
3
+ end
2
4
  require 'rubygems'
3
5
  require 'bundler/setup'
4
6
 
@@ -17,5 +19,11 @@ RSpec::Core::RakeTask.new(:spec) do |t|
17
19
  t.rspec_opts = %w(--backtrace --color)
18
20
  end
19
21
 
22
+ begin
23
+ require "appraisal"
24
+ rescue LoadError
25
+ warn "Appraisal is only available in test/development"
26
+ end
27
+
20
28
  # load custom rake tasks
21
- Dir["#{File.dirname(__FILE__)}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
29
+ Dir["#{File.dirname(__FILE__)}/tasks/**/*.rake"].sort.each { |ext| load ext }
data/VERSION ADDED
@@ -0,0 +1,4 @@
1
+ major:2
2
+ minor:6
3
+ patch:0
4
+ build:
data/lib/mail/body.rb CHANGED
@@ -127,9 +127,9 @@ module Mail
127
127
  def sort_parts!
128
128
  @parts.each do |p|
129
129
  p.body.set_sort_order(@part_sort_order)
130
- @parts.sort!(@part_sort_order)
131
130
  p.body.sort_parts!
132
131
  end
132
+ @parts.sort!(@part_sort_order)
133
133
  end
134
134
 
135
135
  # Returns the raw source that the body was initialized with, without
@@ -257,7 +257,7 @@ module Mail
257
257
 
258
258
  def split!(boundary)
259
259
  self.boundary = boundary
260
- parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary)}(?=(?:--)?\s*$)/)
260
+ parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary || "")}(?=(?:--)?\s*$)/)
261
261
  # Make the preamble equal to the preamble (if any)
262
262
  self.preamble = parts[0].to_s.strip
263
263
  # Make the epilogue equal to the epilogue (if any)
@@ -1,11 +1,21 @@
1
1
  # encoding: utf-8
2
2
  class String #:nodoc:
3
+
4
+ if RUBY_VERSION >= '1.9'
5
+ # This 1.9 only regex can save a reasonable amount of time (~20%)
6
+ # by not matching "\r\n" so the string is returned unchanged in
7
+ # the common case.
8
+ CRLF_REGEX = Regexp.new("(?<!\r)\n|\r(?!\n)")
9
+ else
10
+ CRLF_REGEX = /\n|\r\n|\r/
11
+ end
12
+
3
13
  def to_crlf
4
- to_str.gsub(/\n|\r\n|\r/) { "\r\n" }
14
+ to_str.gsub(CRLF_REGEX, "\r\n")
5
15
  end
6
16
 
7
17
  def to_lf
8
- to_str.gsub(/\n|\r\n|\r/) { "\n" }
18
+ to_str.gsub(/\r\n|\r/, "\n")
9
19
  end
10
20
 
11
21
  unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  module Mail
3
3
  class Address
4
-
4
+
5
5
  include Mail::Utilities
6
6
 
7
7
  # Mail::Address handles all email addresses in Mail. It takes an email address string
@@ -22,21 +22,19 @@ module Mail
22
22
  # a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
23
23
  def initialize(value = nil)
24
24
  @output_type = :decode
25
- @tree = nil
26
- @raw_text = value
27
- case
28
- when value.nil?
25
+ if value.nil?
29
26
  @parsed = false
27
+ @data = nil
30
28
  return
31
29
  else
32
30
  parse(value)
33
31
  end
34
32
  end
35
33
 
36
- # Returns the raw imput of the passed in string, this is before it is passed
34
+ # Returns the raw input of the passed in string, this is before it is passed
37
35
  # by the parser.
38
36
  def raw
39
- @raw_text
37
+ @data.raw
40
38
  end
41
39
 
42
40
  # Returns a correctly formatted address for the email going out. If given
@@ -48,15 +46,14 @@ module Mail
48
46
  # a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
49
47
  def format
50
48
  parse unless @parsed
51
- case
52
- when tree.nil?
49
+ if @data.nil?
53
50
  ''
54
- when display_name
51
+ elsif display_name
55
52
  [quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ")
56
- when address
53
+ elsif address
57
54
  [address, format_comments].compact.join(" ")
58
55
  else
59
- tree.text_value
56
+ raw
60
57
  end
61
58
  end
62
59
 
@@ -106,7 +103,7 @@ module Mail
106
103
  # a.local #=> 'mikel'
107
104
  def local
108
105
  parse unless @parsed
109
- "#{obs_domain_list}#{get_local.strip}" if get_local
106
+ "#{@data.obs_domain_list}#{get_local.strip}" if get_local
110
107
  end
111
108
 
112
109
  # Returns the domain part (the right hand side of the @ sign in the email address) of
@@ -174,29 +171,24 @@ module Mail
174
171
 
175
172
  def parse(value = nil)
176
173
  @parsed = true
177
- case
178
- when value.nil?
174
+
175
+ case value
176
+ when NilClass
177
+ @data = nil
179
178
  nil
180
- when value.class == String
181
- self.tree = Mail::AddressList.new(value).address_nodes.first
182
- else
183
- self.tree = value
179
+ when Mail::Parsers::AddressStruct
180
+ @data = value
181
+ when String
182
+ @raw_text = value
183
+ if value.blank?
184
+ @data = nil
185
+ else
186
+ address_list = Mail::Parsers::AddressListsParser.new.parse(value)
187
+ @data = address_list.addresses.first
188
+ end
184
189
  end
185
190
  end
186
191
 
187
-
188
- def get_domain
189
- if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
190
- @domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
191
- elsif tree.respond_to?(:domain)
192
- @domain_text ||= tree.domain.text_value.strip
193
- elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
194
- tree.addr_spec.domain.text_value.strip
195
- else
196
- nil
197
- end
198
- end
199
-
200
192
  def strip_all_comments(string)
201
193
  unless comments.blank?
202
194
  comments.each do |comment|
@@ -209,7 +201,7 @@ module Mail
209
201
  def strip_domain_comments(value)
210
202
  unless comments.blank?
211
203
  comments.each do |comment|
212
- if get_domain && get_domain.include?("(#{comment})")
204
+ if @data.domain && @data.domain.include?("(#{comment})")
213
205
  value = value.gsub("(#{comment})", '')
214
206
  end
215
207
  end
@@ -217,20 +209,11 @@ module Mail
217
209
  value.to_s.strip
218
210
  end
219
211
 
220
- def get_comments
221
- if tree.respond_to?(:comments)
222
- @comments = tree.comments.map { |c| unparen(c.text_value.to_str) }
223
- else
224
- @comments = []
225
- end
226
- end
227
-
228
212
  def get_display_name
229
- if tree.respond_to?(:display_name)
230
- name = unquote(tree.display_name.text_value.strip)
231
- str = strip_all_comments(name.to_s)
232
- elsif comments
233
- if domain
213
+ if @data.display_name
214
+ str = strip_all_comments(@data.display_name.to_s)
215
+ elsif @data.comments
216
+ if @data.domain
234
217
  str = strip_domain_comments(format_comments)
235
218
  else
236
219
  str = nil
@@ -263,15 +246,6 @@ module Mail
263
246
  end
264
247
  end
265
248
 
266
- # Provides access to the Treetop parse tree for this address
267
- def tree
268
- @tree
269
- end
270
-
271
- def tree=(value)
272
- @tree = value
273
- end
274
-
275
249
  def format_comments
276
250
  if comments
277
251
  comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ")
@@ -280,35 +254,17 @@ module Mail
280
254
  nil
281
255
  end
282
256
  end
283
-
284
- def obs_domain_list
285
- if tree.respond_to?(:angle_addr)
286
- obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) }
287
- !obs.empty? ? obs.first.text_value : nil
288
- else
289
- nil
290
- end
291
- end
292
-
257
+
293
258
  def get_local
294
- case
295
- when tree.respond_to?(:local_dot_atom_text)
296
- tree.local_dot_atom_text.text_value
297
- when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_part)
298
- tree.angle_addr.addr_spec.local_part.text_value
299
- when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part)
300
- tree.addr_spec.local_part.text_value
301
- when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_dot_atom_text)
302
- # Ignore local dot atom text when in angle brackets
303
- nil
304
- when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_dot_atom_text)
305
- # Ignore local dot atom text when in angle brackets
306
- nil
307
- else
308
- tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil
309
- end
259
+ @data && @data.local
260
+ end
261
+
262
+ def get_domain
263
+ @data && @data.domain
310
264
  end
311
265
 
312
-
266
+ def get_comments
267
+ @data && @data.comments
268
+ end
313
269
  end
314
270
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  module Mail
3
3
  class AddressList # :nodoc:
4
-
4
+
5
5
  # Mail::AddressList is the class that parses To, From and other address fields from
6
6
  # emails passed into Mail.
7
7
  #
@@ -18,57 +18,34 @@ module Mail
18
18
  # a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
19
19
  # a.group_names #=> ["My Group"]
20
20
  def initialize(string)
21
- if string.blank?
22
- @address_nodes = []
23
- return self
24
- end
25
- parser = Mail::AddressListsParser.new
26
- if tree = parser.parse(string)
27
- @address_nodes = tree.addresses
28
- else
29
- raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason)
30
- end
21
+ @addresses_grouped_by_group = nil
22
+ @address_list = Parsers::AddressListsParser.new.parse(string)
31
23
  end
32
24
 
33
25
  # Returns a list of address objects from the parsed line
34
26
  def addresses
35
- @addresses ||= get_addresses.map do |address_tree|
36
- Mail::Address.new(address_tree)
27
+ @addresses ||= @address_list.addresses.map do |address_data|
28
+ Mail::Address.new(address_data)
37
29
  end
38
30
  end
39
-
40
- # Returns a list of all recipient syntax trees that are not part of a group
41
- def individual_recipients # :nodoc:
42
- @individual_recipients ||= @address_nodes - group_recipients
43
- end
44
-
45
- # Returns a list of all recipient syntax trees that are part of a group
46
- def group_recipients # :nodoc:
47
- @group_recipients ||= @address_nodes.select { |an| an.respond_to?(:group_name) }
31
+
32
+ def addresses_grouped_by_group
33
+ return @addresses_grouped_by_group if @addresses_grouped_by_group
34
+
35
+ @addresses_grouped_by_group = {}
36
+
37
+ @address_list.addresses.each do |address_data|
38
+ if group = address_data.group
39
+ @addresses_grouped_by_group[group] ||= []
40
+ @addresses_grouped_by_group[group] << Mail::Address.new(address_data)
41
+ end
42
+ end
43
+ @addresses_grouped_by_group
48
44
  end
49
45
 
50
46
  # Returns the names as an array of strings of all groups
51
47
  def group_names # :nodoc:
52
- group_recipients.map { |g| g.group_name.text_value }
53
- end
54
-
55
- # Returns a list of address syntax trees
56
- def address_nodes # :nodoc:
57
- @address_nodes
58
- end
59
-
60
- private
61
-
62
- def get_addresses
63
- (individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten
64
- end
65
-
66
- def get_group_addresses(g)
67
- if g.group_list.respond_to?(:addresses)
68
- g.group_list.addresses
69
- else
70
- []
71
- end
48
+ @address_list.group_names
72
49
  end
73
50
  end
74
51
  end
@@ -5,13 +5,9 @@ module Mail
5
5
  include Mail::Utilities
6
6
 
7
7
  def initialize( string )
8
- parser = Mail::ContentDispositionParser.new
9
- if tree = parser.parse(cleaned(string))
10
- @disposition_type = tree.disposition_type.text_value.downcase
11
- @parameters = tree.parameters
12
- else
13
- raise Mail::Field::ParseError.new(ContentDispositionElement, string, parser.failure_reason)
14
- end
8
+ content_disposition = Mail::Parsers::ContentDispositionParser.new.parse(cleaned(string))
9
+ @disposition_type = content_disposition.disposition_type
10
+ @parameters = content_disposition.parameters
15
11
  end
16
12
 
17
13
  def disposition_type
@@ -5,12 +5,8 @@ module Mail
5
5
  include Mail::Utilities
6
6
 
7
7
  def initialize( string )
8
- parser = Mail::ContentLocationParser.new
9
- if tree = parser.parse(string)
10
- @location = tree.location.text_value
11
- else
12
- raise Mail::Field::ParseError.new(ContentLocationElement, string, parser.failure_reason)
13
- end
8
+ content_location = Mail::Parsers::ContentLocationParser.new.parse(string)
9
+ @location = content_location.location
14
10
  end
15
11
 
16
12
  def location
@@ -4,16 +4,9 @@ module Mail
4
4
 
5
5
  include Mail::Utilities
6
6
 
7
- def initialize( string )
8
- parser = Mail::ContentTransferEncodingParser.new
9
- case
10
- when string.blank?
11
- @encoding = ''
12
- when tree = parser.parse(string.to_s.downcase)
13
- @encoding = tree.encoding.text_value
14
- else
15
- raise Mail::Field::ParseError.new(ContentTransferEncodingElement, string, parser.failure_reason)
16
- end
7
+ def initialize(string)
8
+ content_transfer_encoding = Mail::Parsers::ContentTransferEncodingParser.new.parse(string)
9
+ @encoding = content_transfer_encoding.encoding
17
10
  end
18
11
 
19
12
  def encoding
@@ -5,14 +5,10 @@ module Mail
5
5
  include Mail::Utilities
6
6
 
7
7
  def initialize( string )
8
- parser = Mail::ContentTypeParser.new
9
- if tree = parser.parse(cleaned(string))
10
- @main_type = tree.main_type.text_value.downcase
11
- @sub_type = tree.sub_type.text_value.downcase
12
- @parameters = tree.parameters
13
- else
14
- raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
15
- end
8
+ content_type = Mail::Parsers::ContentTypeParser.new.parse(cleaned(string))
9
+ @main_type = content_type.main_type
10
+ @sub_type = content_type.sub_type
11
+ @parameters = content_type.parameters
16
12
  end
17
13
 
18
14
  def main_type
@@ -5,13 +5,9 @@ module Mail
5
5
  include Mail::Utilities
6
6
 
7
7
  def initialize( string )
8
- parser = Mail::DateTimeParser.new
9
- if tree = parser.parse(string)
10
- @date_string = tree.date.text_value
11
- @time_string = tree.time.text_value
12
- else
13
- raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason)
14
- end
8
+ date_time = Mail::Parsers::DateTimeParser.new.parse(string)
9
+ @date_string = date_time.date_string
10
+ @time_string = date_time.time_string
15
11
  end
16
12
 
17
13
  def date_string