mail 2.1.3 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

Files changed (106) hide show
  1. data/CHANGELOG.rdoc +37 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +2 -3
  4. data/TODO.rdoc +2 -12
  5. data/lib/mail.rb +7 -4
  6. data/lib/mail/attachments_list.rb +28 -10
  7. data/lib/mail/body.rb +44 -15
  8. data/lib/mail/core_extensions/string.rb +4 -0
  9. data/lib/mail/elements/content_transfer_encoding_element.rb +4 -1
  10. data/lib/mail/encodings/7bit.rb +29 -0
  11. data/lib/mail/encodings/8bit.rb +29 -0
  12. data/lib/mail/encodings/base64.rb +18 -5
  13. data/lib/mail/encodings/binary.rb +29 -0
  14. data/lib/mail/encodings/encodings.rb +22 -6
  15. data/lib/mail/encodings/quoted_printable.rb +27 -4
  16. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  17. data/lib/mail/field.rb +4 -2
  18. data/lib/mail/fields/common/parameter_hash.rb +12 -3
  19. data/lib/mail/fields/content_disposition_field.rb +12 -2
  20. data/lib/mail/fields/content_location_field.rb +2 -2
  21. data/lib/mail/fields/content_transfer_encoding_field.rb +5 -3
  22. data/lib/mail/fields/content_type_field.rb +14 -4
  23. data/lib/mail/fields/mime_version_field.rb +2 -2
  24. data/lib/mail/fields/received_field.rb +8 -4
  25. data/lib/mail/fields/structured_field.rb +4 -0
  26. data/lib/mail/fields/unstructured_field.rb +5 -0
  27. data/lib/mail/header.rb +13 -6
  28. data/lib/mail/mail.rb +1 -1
  29. data/lib/mail/message.rb +100 -28
  30. data/lib/mail/network/delivery_methods/smtp.rb +1 -1
  31. data/lib/mail/parsers/address_lists.rb +4 -1
  32. data/lib/mail/parsers/content_disposition.rb +24 -6
  33. data/lib/mail/parsers/content_location.rb +8 -2
  34. data/lib/mail/parsers/content_transfer_encoding.rb +73 -83
  35. data/lib/mail/parsers/content_transfer_encoding.treetop +5 -10
  36. data/lib/mail/parsers/content_type.rb +36 -9
  37. data/lib/mail/parsers/date_time.rb +4 -1
  38. data/lib/mail/parsers/envelope_from.rb +8 -2
  39. data/lib/mail/parsers/message_ids.rb +4 -1
  40. data/lib/mail/parsers/mime_version.rb +4 -1
  41. data/lib/mail/parsers/phrase_lists.rb +4 -1
  42. data/lib/mail/parsers/received.rb +4 -1
  43. data/lib/mail/parsers/rfc2045.rb +75 -17
  44. data/lib/mail/parsers/rfc2045.treetop +2 -1
  45. data/lib/mail/parsers/rfc2822.rb +316 -79
  46. data/lib/mail/parsers/rfc2822_obsolete.rb +200 -50
  47. data/lib/mail/part.rb +21 -6
  48. data/lib/mail/patterns.rb +3 -3
  49. data/lib/mail/utilities.rb +4 -4
  50. data/lib/mail/vendor/treetop-1.4.3/Or +0 -0
  51. data/lib/mail/vendor/treetop-1.4.3/Rakefile +11 -6
  52. data/lib/mail/vendor/treetop-1.4.3/Treetop.tmbundle/Preferences/Comments.tmPreferences +22 -0
  53. data/lib/mail/vendor/treetop-1.4.3/Treetop.tmbundle/Syntaxes/Treetop Grammar.tmLanguage +28 -1
  54. data/lib/mail/vendor/treetop-1.4.3/bin/tt +5 -5
  55. data/lib/mail/vendor/treetop-1.4.3/lib/treetop.rb +3 -19
  56. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/bootstrap_gen_1_metagrammar.rb +4 -7
  57. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/compiler.rb +7 -6
  58. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/compiler/metagrammar.rb +1 -1
  59. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/compiler/node_classes.rb +19 -20
  60. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/polyglot.rb +9 -0
  61. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/ruby_extensions.rb +1 -2
  62. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/runtime.rb +6 -5
  63. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/runtime/interval_skip_list.rb +3 -4
  64. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/runtime/syntax_node.rb +7 -7
  65. data/lib/mail/vendor/treetop-1.4.3/lib/treetop/version.rb +1 -1
  66. data/lib/mail/vendor/treetop-1.4.3/script/generate_metagrammar.rb +3 -4
  67. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/and_predicate_spec.rb +2 -2
  68. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/anything_symbol_spec.rb +2 -2
  69. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/character_class_spec.rb +1 -1
  70. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/choice_spec.rb +2 -2
  71. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/circular_compilation_spec.rb +3 -1
  72. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/failure_propagation_functional_spec.rb +2 -2
  73. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/grammar_compiler_spec.rb +1 -1
  74. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/grammar_spec.rb +1 -1
  75. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/multibyte_chars_spec.rb +1 -9
  76. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/nonterminal_symbol_spec.rb +2 -2
  77. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/not_predicate_spec.rb +2 -2
  78. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/one_or_more_spec.rb +2 -2
  79. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/optional_spec.rb +1 -1
  80. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/parenthesized_expression_spec.rb +1 -1
  81. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/parsing_rule_spec.rb +1 -1
  82. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/repeated_subrule_spec.rb +1 -1
  83. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/semantic_predicate_spec.rb +1 -1
  84. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/sequence_spec.rb +1 -1
  85. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/terminal_spec.rb +1 -1
  86. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/terminal_symbol_spec.rb +1 -1
  87. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/tt_compiler_spec.rb +1 -1
  88. data/lib/mail/vendor/treetop-1.4.3/spec/compiler/zero_or_more_spec.rb +1 -1
  89. data/lib/mail/vendor/treetop-1.4.3/spec/composition/grammar_composition_spec.rb +1 -1
  90. data/lib/mail/vendor/treetop-1.4.3/spec/ruby_extensions/string_spec.rb +1 -1
  91. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/compiled_parser_spec.rb +1 -1
  92. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/delete_spec.rb +2 -2
  93. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/expire_range_spec.rb +2 -2
  94. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/insert_spec.rb +1 -1
  95. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +2 -2
  96. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +2 -3
  97. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/interval_skip_list/spec_helper.rb +2 -2
  98. data/lib/mail/vendor/treetop-1.4.3/spec/runtime/syntax_node_spec.rb +1 -1
  99. data/lib/mail/vendor/treetop-1.4.3/spec/spec_helper.rb +4 -5
  100. data/lib/mail/vendor/treetop-1.4.3/treetop.gemspec +2 -2
  101. data/lib/mail/version.rb +1 -1
  102. data/lib/mail/version_specific/ruby_1_8.rb +1 -3
  103. data/lib/mail/version_specific/ruby_1_9.rb +1 -2
  104. data/lib/tasks/treetop.rake +1 -1
  105. metadata +33 -14
  106. data/lib/mail/vendor/treetop-1.4.3/spec/spec_suite.rb +0 -4
data/lib/mail/mail.rb CHANGED
@@ -231,4 +231,4 @@ module Mail
231
231
 
232
232
  @@uniq = Mail.something_random
233
233
 
234
- end
234
+ end
data/lib/mail/message.rb CHANGED
@@ -10,7 +10,7 @@ module Mail
10
10
  #
11
11
  # * A Header object which contians all information and settings of the header of the email
12
12
  # * Body object which contains all parts of the email that are not part of the header, this
13
- # includes any attachments, body text, mime parts etc.
13
+ # includes any attachments, body text, MIME parts etc.
14
14
  #
15
15
  # ==Per RFC2822
16
16
  #
@@ -99,6 +99,7 @@ module Mail
99
99
  @body = nil
100
100
  @text_part = nil
101
101
  @html_part = nil
102
+ @errors = nil
102
103
 
103
104
  @perform_deliveries = true
104
105
  @raise_delivery_errors = true
@@ -106,7 +107,9 @@ module Mail
106
107
  @delivery_handler = nil
107
108
 
108
109
  @delivery_method = Mail.delivery_method.dup
109
-
110
+
111
+ @transport_encoding = Mail::Encodings.get_encoding('7bit')
112
+
110
113
  if args.flatten.first.respond_to?(:each_pair)
111
114
  init_with_hash(args.flatten.first)
112
115
  else
@@ -374,6 +377,27 @@ module Mail
374
377
  end
375
378
  end
376
379
 
380
+ # Returns a list of parser errors on the header, each field that had an error
381
+ # will be reparsed as an unstructured field to preserve the data inside, but
382
+ # will not be used for further processing.
383
+ #
384
+ # It returns a nested array of [field_name, value, original_error_message]
385
+ # per error found.
386
+ #
387
+ # Example:
388
+ #
389
+ # message = Mail.new("Content-Transfer-Encoding: weirdo\r\n")
390
+ # message.errors.size #=> 1
391
+ # message.errors.first[0] #=> "Content-Transfer-Encoding"
392
+ # message.errors.first[1] #=> "weirdo"
393
+ # message.errors.first[3] #=> <The original error message exception>
394
+ #
395
+ # This is a good first defence on detecting spam by the way. Some spammers send
396
+ # invalid emails to try and get email parsers to give up parsing them.
397
+ def errors
398
+ header.errors
399
+ end
400
+
377
401
  # Returns the Bcc value of the mail object as an array of strings of
378
402
  # address specs.
379
403
  #
@@ -519,7 +543,19 @@ module Mail
519
543
  def date=( val )
520
544
  header[:date] = val
521
545
  end
522
-
546
+
547
+ def transport_encoding( val = nil)
548
+ if val
549
+ self.transport_encoding = val
550
+ else
551
+ @transport_encoding
552
+ end
553
+ end
554
+
555
+ def transport_encoding=( val )
556
+ @transport_encoding = Mail::Encodings.get_encoding(val)
557
+ end
558
+
523
559
  # Returns the From value of the mail object as an array of strings of
524
560
  # address specs.
525
561
  #
@@ -603,14 +639,14 @@ module Mail
603
639
  header[:message_id] = val
604
640
  end
605
641
 
606
- # Returns the mime version of the email as a string
642
+ # Returns the MIME version of the email as a string
607
643
  #
608
644
  # Example:
609
645
  #
610
646
  # mail.mime_version = '1.0'
611
647
  # mail.mime_version #=> '1.0'
612
648
  #
613
- # Also allows you to set the mime version by passing a string as a parameter.
649
+ # Also allows you to set the MIME version by passing a string as a parameter.
614
650
  #
615
651
  # Example:
616
652
  #
@@ -620,7 +656,7 @@ module Mail
620
656
  default :mime_version, val
621
657
  end
622
658
 
623
- # Sets the mime version of the email by accepting a string
659
+ # Sets the MIME version of the email by accepting a string
624
660
  #
625
661
  # Example:
626
662
  #
@@ -1052,7 +1088,7 @@ module Mail
1052
1088
  case
1053
1089
  when value == nil
1054
1090
  @body = Mail::Body.new('')
1055
- when @body && !@body.parts.empty?
1091
+ when @body && @body.multipart?
1056
1092
  @body << Mail::Part.new(value)
1057
1093
  else
1058
1094
  @body = Mail::Body.new(value)
@@ -1078,7 +1114,19 @@ module Mail
1078
1114
  @body
1079
1115
  end
1080
1116
  end
1081
-
1117
+
1118
+ def body_encoding(value)
1119
+ if value.nil?
1120
+ body.encoding
1121
+ else
1122
+ body.encoding = value
1123
+ end
1124
+ end
1125
+
1126
+ def body_encoding=(value)
1127
+ body.encoding = value
1128
+ end
1129
+
1082
1130
  # Returns the list of addresses this message should be sent to by
1083
1131
  # collecting the addresses off the to, cc and bcc fields.
1084
1132
  #
@@ -1232,7 +1280,8 @@ module Mail
1232
1280
  end
1233
1281
 
1234
1282
  def has_content_transfer_encoding?
1235
- !!content_transfer_encoding
1283
+ header[:content_transfer_encoding] &&
1284
+ header[:content_transfer_encoding].errors.blank?
1236
1285
  end
1237
1286
 
1238
1287
  def has_transfer_encoding? # :nodoc:
@@ -1262,8 +1311,8 @@ module Mail
1262
1311
 
1263
1312
  # Creates a new empty Mime Version field and inserts it in the correct order
1264
1313
  # into the Header. The MimeVersion object will automatically generate
1265
- # DateTime.now's date if you try and encode it or output it to_s without
1266
- # specifying a date yourself.
1314
+ # set itself to '1.0' if you try and encode it or output it to_s without
1315
+ # specifying a version yourself.
1267
1316
  #
1268
1317
  # It will preserve any date you specify if you do.
1269
1318
  def add_mime_version(ver_val = '')
@@ -1281,9 +1330,9 @@ module Mail
1281
1330
  #
1282
1331
  # Otherwise raises a warning
1283
1332
  def add_charset
1284
- if body.only_us_ascii?
1333
+ if body.only_us_ascii? and !body.empty?
1285
1334
  header[:content_type].parameters['charset'] = 'US-ASCII'
1286
- else
1335
+ elsif !body.empty?
1287
1336
  warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
1288
1337
  STDERR.puts(warning)
1289
1338
  header[:content_type].parameters['charset'] = 'UTF-8'
@@ -1313,7 +1362,7 @@ module Mail
1313
1362
  content_transfer_encoding
1314
1363
  end
1315
1364
 
1316
- # Returns the mime type of part we are on, this is taken from the content-type header
1365
+ # Returns the MIME media type of part we are on, this is taken from the content-type header
1317
1366
  def mime_type
1318
1367
  content_type ? header[:content_type].string : nil
1319
1368
  end
@@ -1425,7 +1474,7 @@ module Mail
1425
1474
  #
1426
1475
  # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
1427
1476
  #
1428
- # If you do this, then Mail will take the file name and work out the mime type
1477
+ # If you do this, then Mail will take the file name and work out the MIME media type
1429
1478
  # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and
1430
1479
  # base64 encode the contents of the attachment all for you.
1431
1480
  #
@@ -1509,7 +1558,7 @@ module Mail
1509
1558
 
1510
1559
  # Adds a part to the parts list or creates the part list
1511
1560
  def add_part(part)
1512
- if body.parts.empty? && !self.body.decoded.blank?
1561
+ if !body.multipart? && !self.body.decoded.blank?
1513
1562
  @text_part = Mail::Part.new('Content-Type: text/plain;')
1514
1563
  @text_part.body = body.decoded
1515
1564
  self.body << @text_part
@@ -1537,7 +1586,7 @@ module Mail
1537
1586
 
1538
1587
  # Adds a file to the message. You have two options with this method, you can
1539
1588
  # just pass in the absolute path to the file you want and Mail will read the file,
1540
- # get the filename from the path you pass in and guess the mime type, or you
1589
+ # get the filename from the path you pass in and guess the MIME media type, or you
1541
1590
  # can pass in the filename as a string, and pass in the file content as a blob.
1542
1591
  #
1543
1592
  # Example:
@@ -1588,10 +1637,14 @@ module Mail
1588
1637
  # Encodes the message, calls encode on all it's parts, gets an email message
1589
1638
  # ready to send
1590
1639
  def ready_to_send!
1591
- parts.each { |part| part.ready_to_send! }
1640
+ identify_and_set_transfer_encoding
1641
+ parts.each do |part|
1642
+ part.transport_encoding = transport_encoding
1643
+ part.ready_to_send!
1644
+ end
1592
1645
  add_required_fields
1593
1646
  end
1594
-
1647
+
1595
1648
  def encode!
1596
1649
  STDERR.puts("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
1597
1650
  ready_to_send!
@@ -1604,7 +1657,7 @@ module Mail
1604
1657
  ready_to_send!
1605
1658
  buffer = header.encoded
1606
1659
  buffer << "\r\n"
1607
- buffer << body.encoded
1660
+ buffer << body.encoded(content_transfer_encoding)
1608
1661
  buffer
1609
1662
  end
1610
1663
 
@@ -1617,8 +1670,11 @@ module Mail
1617
1670
  end
1618
1671
 
1619
1672
  def decoded
1620
- if self.attachment?
1673
+ case
1674
+ when self.attachment?
1621
1675
  decode_body
1676
+ when !self.multipart?
1677
+ body.decoded
1622
1678
  else
1623
1679
  raise NoMethodError, 'Can not decode an entire message, try calling #decoded on the various fields and body or parts if it is a multipart message.'
1624
1680
  end
@@ -1633,11 +1689,7 @@ module Mail
1633
1689
  end
1634
1690
 
1635
1691
  def decode_body
1636
- if Mail::Encodings.defined?(content_transfer_encoding)
1637
- Mail::Encodings.get_encoding(content_transfer_encoding).decode(body.encoded)
1638
- else
1639
- raise UnknownEncodingType, "Don't know how to decode #{content_transfer_encoding}, please call #encoded and decode it yourself."
1640
- end
1692
+ body.decoded
1641
1693
  end
1642
1694
 
1643
1695
  # Returns true if this part is an attachment
@@ -1697,13 +1749,21 @@ module Mail
1697
1749
  end
1698
1750
 
1699
1751
  def add_encoding_to_body
1700
- unless content_transfer_encoding.blank?
1752
+ if has_content_transfer_encoding?
1701
1753
  body.encoding = content_transfer_encoding
1702
1754
  end
1703
1755
  end
1756
+
1757
+ def identify_and_set_transfer_encoding
1758
+ if body.multipart?
1759
+ self.content_transfer_encoding = @transport_encoding
1760
+ else
1761
+ self.content_transfer_encoding = body.get_best_encoding(@transport_encoding)
1762
+ end
1763
+ end
1704
1764
 
1705
1765
  def add_required_fields
1706
- add_multipart_mixed_header unless parts.empty?
1766
+ add_multipart_mixed_header unless !body.multipart?
1707
1767
  @body = Mail::Body.new('') if body.nil?
1708
1768
  add_message_id unless (has_message_id? || self.class == Mail::Part)
1709
1769
  add_date unless has_date?
@@ -1739,14 +1799,26 @@ module Mail
1739
1799
  @header = Mail::Header.new
1740
1800
  @body = Mail::Body.new
1741
1801
 
1802
+ # We need to store the body until last, as we need all headers added first
1803
+ body_content = nil
1804
+
1742
1805
  passed_in_options.each_pair do |k,v|
1743
1806
  k = underscoreize(k).to_sym if k.class == String
1744
1807
  if k == :headers
1745
1808
  self.headers(v)
1809
+ elsif k == :body
1810
+ body_content = v
1746
1811
  else
1747
1812
  self[k] = v
1748
1813
  end
1749
1814
  end
1815
+
1816
+ if body_content
1817
+ self.body = body_content
1818
+ if has_content_transfer_encoding?
1819
+ body.encoding = content_transfer_encoding
1820
+ end
1821
+ end
1750
1822
  end
1751
1823
 
1752
1824
  def init_with_string(string)
@@ -27,7 +27,7 @@ module Mail
27
27
  # Mail.defaults do
28
28
  # delivery_method :smtp, { :address => "smtp.gmail.com",
29
29
  # :port => 587,
30
- # :domain => 'baci.lindsaar.net',
30
+ # :domain => 'your.host.name',
31
31
  # :user_name => '<username>',
32
32
  # :password => '<password>',
33
33
  # :authentication => 'plain',
@@ -27,7 +27,10 @@ module Mail
27
27
  start_index = index
28
28
  if node_cache[:primary_address].has_key?(index)
29
29
  cached = node_cache[:primary_address][index]
30
- @index = cached.interval.end if cached
30
+ if cached
31
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
32
+ @index = cached.interval.end
33
+ end
31
34
  return cached
32
35
  end
33
36
 
@@ -49,7 +49,10 @@ module Mail
49
49
  start_index = index
50
50
  if node_cache[:content_disposition].has_key?(index)
51
51
  cached = node_cache[:content_disposition][index]
52
- @index = cached.interval.end if cached
52
+ if cached
53
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
54
+ @index = cached.interval.end
55
+ end
53
56
  return cached
54
57
  end
55
58
 
@@ -114,7 +117,10 @@ module Mail
114
117
  start_index = index
115
118
  if node_cache[:disposition_type].has_key?(index)
116
119
  cached = node_cache[:disposition_type][index]
117
- @index = cached.interval.end if cached
120
+ if cached
121
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
122
+ @index = cached.interval.end
123
+ end
118
124
  return cached
119
125
  end
120
126
 
@@ -169,7 +175,10 @@ module Mail
169
175
  start_index = index
170
176
  if node_cache[:extension_token].has_key?(index)
171
177
  cached = node_cache[:extension_token][index]
172
- @index = cached.interval.end if cached
178
+ if cached
179
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
180
+ @index = cached.interval.end
181
+ end
173
182
  return cached
174
183
  end
175
184
 
@@ -213,7 +222,10 @@ module Mail
213
222
  start_index = index
214
223
  if node_cache[:parameter].has_key?(index)
215
224
  cached = node_cache[:parameter][index]
216
- @index = cached.interval.end if cached
225
+ if cached
226
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
227
+ @index = cached.interval.end
228
+ end
217
229
  return cached
218
230
  end
219
231
 
@@ -270,7 +282,10 @@ module Mail
270
282
  start_index = index
271
283
  if node_cache[:attribute].has_key?(index)
272
284
  cached = node_cache[:attribute][index]
273
- @index = cached.interval.end if cached
285
+ if cached
286
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
287
+ @index = cached.interval.end
288
+ end
274
289
  return cached
275
290
  end
276
291
 
@@ -305,7 +320,10 @@ module Mail
305
320
  start_index = index
306
321
  if node_cache[:value].has_key?(index)
307
322
  cached = node_cache[:value][index]
308
- @index = cached.interval.end if cached
323
+ if cached
324
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
325
+ @index = cached.interval.end
326
+ end
309
327
  return cached
310
328
  end
311
329
 
@@ -31,7 +31,10 @@ module Mail
31
31
  start_index = index
32
32
  if node_cache[:primary].has_key?(index)
33
33
  cached = node_cache[:primary][index]
34
- @index = cached.interval.end if cached
34
+ if cached
35
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
36
+ @index = cached.interval.end
37
+ end
35
38
  return cached
36
39
  end
37
40
 
@@ -69,7 +72,10 @@ module Mail
69
72
  start_index = index
70
73
  if node_cache[:location].has_key?(index)
71
74
  cached = node_cache[:location][index]
72
- @index = cached.interval.end if cached
75
+ if cached
76
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
77
+ @index = cached.interval.end
78
+ end
73
79
  return cached
74
80
  end
75
81
 
@@ -25,13 +25,20 @@ module Mail
25
25
  def CFWS2
26
26
  elements[2]
27
27
  end
28
+
29
+ def CFWS3
30
+ elements[4]
31
+ end
28
32
  end
29
33
 
30
34
  def _nt_primary
31
35
  start_index = index
32
36
  if node_cache[:primary].has_key?(index)
33
37
  cached = node_cache[:primary][index]
34
- @index = cached.interval.end if cached
38
+ if cached
39
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
40
+ @index = cached.interval.end
41
+ end
35
42
  return cached
36
43
  end
37
44
 
@@ -44,6 +51,25 @@ module Mail
44
51
  if r2
45
52
  r3 = _nt_CFWS
46
53
  s0 << r3
54
+ if r3
55
+ if has_terminal?(";", false, index)
56
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
57
+ @index += 1
58
+ else
59
+ terminal_parse_failure(";")
60
+ r5 = nil
61
+ end
62
+ if r5
63
+ r4 = r5
64
+ else
65
+ r4 = instantiate_node(SyntaxNode,input, index...index)
66
+ end
67
+ s0 << r4
68
+ if r4
69
+ r6 = _nt_CFWS
70
+ s0 << r6
71
+ end
72
+ end
47
73
  end
48
74
  end
49
75
  if s0.last
@@ -60,8 +86,21 @@ module Mail
60
86
  end
61
87
 
62
88
  module Encoding0
63
- def encoding
64
- known_tokens.text_value || ietf_token.text_value || x_token.text_value
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
+ module Encoding2
102
+ def text_value
103
+ x_token.text_value
65
104
  end
66
105
  end
67
106
 
@@ -69,103 +108,54 @@ module Mail
69
108
  start_index = index
70
109
  if node_cache[:encoding].has_key?(index)
71
110
  cached = node_cache[:encoding][index]
72
- @index = cached.interval.end if cached
111
+ if cached
112
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
113
+ @index = cached.interval.end
114
+ end
73
115
  return cached
74
116
  end
75
117
 
76
118
  i0 = index
77
- r1 = _nt_known_tokens
78
- if r1
79
- r0 = r1
80
- else
81
- r2 = _nt_ietf_token
82
- if r2
83
- r0 = r2
119
+ i1, s1 = index, []
120
+ r2 = _nt_ietf_token
121
+ s1 << r2
122
+ if r2
123
+ if has_terminal?("s", false, index)
124
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
125
+ @index += 1
84
126
  else
85
- r3 = _nt_x_token
86
- r3.extend(Encoding0)
87
- if r3
88
- r0 = r3
89
- else
90
- @index = i0
91
- r0 = nil
92
- end
127
+ terminal_parse_failure("s")
128
+ r4 = nil
93
129
  end
130
+ if r4
131
+ r3 = r4
132
+ else
133
+ r3 = instantiate_node(SyntaxNode,input, index...index)
134
+ end
135
+ s1 << r3
94
136
  end
95
-
96
- node_cache[:encoding][start_index] = r0
97
-
98
- r0
99
- end
100
-
101
- def _nt_known_tokens
102
- start_index = index
103
- if node_cache[:known_tokens].has_key?(index)
104
- cached = node_cache[:known_tokens][index]
105
- @index = cached.interval.end if cached
106
- return cached
107
- end
108
-
109
- i0 = index
110
- if has_terminal?("7bit", false, index)
111
- r1 = instantiate_node(SyntaxNode,input, index...(index + 4))
112
- @index += 4
137
+ if s1.last
138
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
139
+ r1.extend(Encoding0)
140
+ r1.extend(Encoding1)
113
141
  else
114
- terminal_parse_failure("7bit")
142
+ @index = i1
115
143
  r1 = nil
116
144
  end
117
145
  if r1
118
146
  r0 = r1
119
147
  else
120
- if has_terminal?("8bit", false, index)
121
- r2 = instantiate_node(SyntaxNode,input, index...(index + 4))
122
- @index += 4
148
+ r5 = _nt_x_token
149
+ r5.extend(Encoding2)
150
+ if r5
151
+ r0 = r5
123
152
  else
124
- terminal_parse_failure("8bit")
125
- r2 = nil
126
- end
127
- if r2
128
- r0 = r2
129
- else
130
- if has_terminal?("binary", false, index)
131
- r3 = instantiate_node(SyntaxNode,input, index...(index + 6))
132
- @index += 6
133
- else
134
- terminal_parse_failure("binary")
135
- r3 = nil
136
- end
137
- if r3
138
- r0 = r3
139
- else
140
- if has_terminal?("quoted-printable", false, index)
141
- r4 = instantiate_node(SyntaxNode,input, index...(index + 16))
142
- @index += 16
143
- else
144
- terminal_parse_failure("quoted-printable")
145
- r4 = nil
146
- end
147
- if r4
148
- r0 = r4
149
- else
150
- if has_terminal?("base64", false, index)
151
- r5 = instantiate_node(SyntaxNode,input, index...(index + 6))
152
- @index += 6
153
- else
154
- terminal_parse_failure("base64")
155
- r5 = nil
156
- end
157
- if r5
158
- r0 = r5
159
- else
160
- @index = i0
161
- r0 = nil
162
- end
163
- end
164
- end
153
+ @index = i0
154
+ r0 = nil
165
155
  end
166
156
  end
167
157
 
168
- node_cache[:known_tokens][start_index] = r0
158
+ node_cache[:encoding][start_index] = r0
169
159
 
170
160
  r0
171
161
  end