Skip to content
This repository
Browse code

Update TMail to v1.1.0. Use an updated version of TMail if available.…

… [mikel]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8084 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 2a51c8682d44ee71a3c0411e2e30ef8ff29d6f67 1 parent 7464a39
risk danger olson authored November 06, 2007

Showing 26 changed files with 1,610 additions and 338 deletions. Show diff stats Hide diff stats

  1. 2  actionmailer/CHANGELOG
  2. 11  actionmailer/lib/action_mailer.rb
  3. 3  actionmailer/lib/action_mailer/vendor/tmail.rb
  4. 19  actionmailer/lib/action_mailer/vendor/tmail/Makefile
  5. 9  actionmailer/lib/action_mailer/vendor/tmail/address.rb
  6. 6  actionmailer/lib/action_mailer/vendor/tmail/attachments.rb
  7. 8  actionmailer/lib/action_mailer/vendor/tmail/base64.rb
  8. 39  actionmailer/lib/action_mailer/vendor/tmail/compat.rb
  9. 8  actionmailer/lib/action_mailer/vendor/tmail/config.rb
  10. 67  actionmailer/lib/action_mailer/vendor/tmail/core_extensions.rb
  11. 32  actionmailer/lib/action_mailer/vendor/tmail/encode.rb
  12. 29  actionmailer/lib/action_mailer/vendor/tmail/header.rb
  13. 540  actionmailer/lib/action_mailer/vendor/tmail/interface.rb
  14. 25  actionmailer/lib/action_mailer/vendor/tmail/mail.rb
  15. 8  actionmailer/lib/action_mailer/vendor/tmail/mailbox.rb
  16. 8  actionmailer/lib/action_mailer/vendor/tmail/net.rb
  17. 8  actionmailer/lib/action_mailer/vendor/tmail/obsolete.rb
  18. 515  actionmailer/lib/action_mailer/vendor/tmail/parser.rb
  19. 381  actionmailer/lib/action_mailer/vendor/tmail/parser.y
  20. 8  actionmailer/lib/action_mailer/vendor/tmail/port.rb
  21. 5  actionmailer/lib/action_mailer/vendor/tmail/quoting.rb
  22. 8  actionmailer/lib/action_mailer/vendor/tmail/scanner.rb
  23. 10  actionmailer/lib/action_mailer/vendor/tmail/stringio.rb
  24. 57  actionmailer/lib/action_mailer/vendor/tmail/utils.rb
  25. 38  actionmailer/lib/action_mailer/vendor/tmail/version.rb
  26. 104  actionmailer/test/fixtures/raw_email_with_invalid_characters_in_content_type
2  actionmailer/CHANGELOG
... ...
@@ -1,5 +1,7 @@
1 1
 *SVN*
2 2
 
  3
+* Update TMail to v1.1.0.  Use an updated version of TMail if available.  [mikel]
  4
+
3 5
 * Introduce a new base test class for testing Mailers.  ActionMailer::TestCase [Koz]
4 6
 
5 7
 * Fix silent failure of rxml templates.  #9879 [jstewart]
11  actionmailer/lib/action_mailer.rb
@@ -31,14 +31,23 @@
31 31
   end
32 32
 end
33 33
 
  34
+# attempt to load the TMail gem
  35
+begin
  36
+  require 'rubygems'
  37
+  gem 'TMail', '> 1.1.0'
  38
+  require 'tmail'
  39
+rescue Gem::LoadError
  40
+  # no gem, fall back to vendor copy
  41
+end
  42
+
34 43
 $:.unshift(File.dirname(__FILE__) + "/action_mailer/vendor/")
35 44
 
  45
+require 'tmail'
36 46
 require 'action_mailer/base'
37 47
 require 'action_mailer/helpers'
38 48
 require 'action_mailer/mail_helper'
39 49
 require 'action_mailer/quoting'
40 50
 require 'action_mailer/test_helper'
41  
-require 'tmail'
42 51
 require 'net/smtp'
43 52
 
44 53
 ActionMailer::Base.class_eval do
3  actionmailer/lib/action_mailer/vendor/tmail.rb
... ...
@@ -1,3 +1,4 @@
1  
-require 'tmail/info'
  1
+require 'tmail/version'
2 2
 require 'tmail/mail'
3 3
 require 'tmail/mailbox'
  4
+require 'tmail/core_extensions'
19  actionmailer/lib/action_mailer/vendor/tmail/Makefile
... ...
@@ -0,0 +1,19 @@
  1
+#
  2
+# lib/tmail/Makefile
  3
+#
  4
+
  5
+debug:
  6
+	rm -f parser.rb
  7
+	make parser.rb DEBUG=true
  8
+
  9
+parser.rb: parser.y
  10
+	if [ "$(DEBUG)" = true ]; then \
  11
+	    racc -v -g -o$@ parser.y ;\
  12
+	else \
  13
+	    racc -E -o$@ parser.y ;\
  14
+	fi
  15
+
  16
+clean:
  17
+	rm -f parser.rb parser.output
  18
+
  19
+distclean: clean
9  actionmailer/lib/action_mailer/vendor/tmail/address.rb
... ...
@@ -1,5 +1,8 @@
1  
-#
2  
-# address.rb
  1
+=begin rdoc
  2
+
  3
+= Address handling class
  4
+
  5
+=end
3 6
 #
4 7
 #--
5 8
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
@@ -51,6 +54,7 @@ def initialize( local, domain )
51 54
           raise SyntaxError, 'empty word in domain' if s.empty?
52 55
         end
53 56
       end
  57
+
54 58
       @local = local
55 59
       @domain = domain
56 60
       @name   = nil
@@ -96,7 +100,6 @@ def spec
96 100
 
97 101
     alias address  spec
98 102
 
99  
-
100 103
     def ==( other )
101 104
       other.respond_to? :spec and self.spec == other.spec
102 105
     end
6  actionmailer/lib/action_mailer/vendor/tmail/attachments.rb
... ...
@@ -1,3 +1,9 @@
  1
+=begin rdoc
  2
+
  3
+= Attachment handling class
  4
+
  5
+=end
  6
+
1 7
 require 'stringio'
2 8
 
3 9
 module TMail
8  actionmailer/lib/action_mailer/vendor/tmail/base64.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# base64.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Base64 handling class
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
39  actionmailer/lib/action_mailer/vendor/tmail/compat.rb
... ...
@@ -0,0 +1,39 @@
  1
+unless Enumerable.method_defined?(:map)
  2
+  module Enumerable
  3
+    alias map collect
  4
+  end
  5
+end
  6
+
  7
+unless Enumerable.method_defined?(:select)
  8
+  module Enumerable
  9
+    alias select find_all
  10
+  end
  11
+end
  12
+
  13
+unless Enumerable.method_defined?(:reject)
  14
+  module Enumerable
  15
+    def reject
  16
+      result = []
  17
+      each do |i|
  18
+        result.push i unless yield(i)
  19
+      end
  20
+      result
  21
+    end
  22
+  end
  23
+end
  24
+
  25
+unless Enumerable.method_defined?(:sort_by)
  26
+  module Enumerable
  27
+    def sort_by
  28
+      map {|i| [yield(i), i] }.sort.map {|val, i| i }
  29
+    end
  30
+  end
  31
+end
  32
+
  33
+unless File.respond_to?(:read)
  34
+  def File.read(fname)
  35
+    File.open(fname) {|f|
  36
+      return f.read
  37
+    }
  38
+  end
  39
+end
8  actionmailer/lib/action_mailer/vendor/tmail/config.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# config.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Configuration Class
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
67  actionmailer/lib/action_mailer/vendor/tmail/core_extensions.rb
... ...
@@ -0,0 +1,67 @@
  1
+=begin rdoc
  2
+
  3
+= Ruby on Rails Core Extensions
  4
+
  5
+provides .blank?
  6
+
  7
+=end
  8
+unless Object.respond_to?(:blank?) #:nodoc:
  9
+  # Check first to see if we are in a Rails environment, no need to 
  10
+  # define these methods if we are
  11
+  class Object
  12
+    # An object is blank if it's nil, empty, or a whitespace string.
  13
+    # For example, "", "   ", nil, [], and {} are blank.
  14
+    #
  15
+    # This simplifies
  16
+    #   if !address.nil? && !address.empty?
  17
+    # to
  18
+    #   if !address.blank?
  19
+    def blank?
  20
+      if respond_to?(:empty?) && respond_to?(:strip)
  21
+        empty? or strip.empty?
  22
+      elsif respond_to?(:empty?)
  23
+        empty?
  24
+      else
  25
+        !self
  26
+      end
  27
+    end
  28
+  end
  29
+
  30
+  class NilClass #:nodoc:
  31
+    def blank?
  32
+      true
  33
+    end
  34
+  end
  35
+
  36
+  class FalseClass #:nodoc:
  37
+    def blank?
  38
+      true
  39
+    end
  40
+  end
  41
+
  42
+  class TrueClass #:nodoc:
  43
+    def blank?
  44
+      false
  45
+    end
  46
+  end
  47
+
  48
+  class Array #:nodoc:
  49
+    alias_method :blank?, :empty?
  50
+  end
  51
+
  52
+  class Hash #:nodoc:
  53
+    alias_method :blank?, :empty?
  54
+  end
  55
+
  56
+  class String #:nodoc:
  57
+    def blank?
  58
+      empty? || strip.empty?
  59
+    end
  60
+  end
  61
+
  62
+  class Numeric #:nodoc:
  63
+    def blank?
  64
+      false
  65
+    end
  66
+  end
  67
+end
32  actionmailer/lib/action_mailer/vendor/tmail/encode.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# encode.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Text Encoding class
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
@@ -50,23 +52,25 @@ def create_dest( obj )
50 52
       end
51 53
     end
52 54
     module_function :create_dest
53  
-
  55
+    
54 56
     def encoded( eol = "\r\n", charset = 'j', dest = nil )
55 57
       accept_strategy Encoder, eol, charset, dest
56 58
     end
57  
-
  59
+    
58 60
     def decoded( eol = "\n", charset = 'e', dest = nil )
  61
+      # Turn the E-Mail into a string and return it with all
  62
+      # encoded characters decoded.  alias for to_s
59 63
       accept_strategy Decoder, eol, charset, dest
60 64
     end
61  
-
  65
+    
62 66
     alias to_s decoded
63  
-  
  67
+    
64 68
     def accept_strategy( klass, eol, charset, dest = nil )
65 69
       dest ||= ''
66  
-      accept klass.new(create_dest(dest), charset, eol)
  70
+      accept klass.new( create_dest(dest), charset, eol )
67 71
       dest
68 72
     end
69  
-
  73
+    
70 74
   end
71 75
 
72 76
 
@@ -141,6 +145,7 @@ def phrase( str )
141 145
     end
142 146
 
143 147
     def kv_pair( k, v )
  148
+      v = dquote(v) unless token_safe?(v)
144 149
       @f << k << '=' << v
145 150
     end
146 151
 
@@ -190,9 +195,18 @@ def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil )
190 195
       @f = StrategyInterface.create_dest(dest)
191 196
       @opt = OPTIONS[$KCODE]
192 197
       @eol = eol
  198
+      @preserve_quotes = true
193 199
       reset
194 200
     end
195 201
 
  202
+    def preserve_quotes=( bool )
  203
+      @preserve_quotes
  204
+    end
  205
+    
  206
+    def preserve_quotes
  207
+      @preserve_quotes
  208
+    end
  209
+
196 210
     def normalize_encoding( str )
197 211
       if @opt
198 212
       then NKF.nkf(@opt, str)
29  actionmailer/lib/action_mailer/vendor/tmail/header.rb
... ...
@@ -1,5 +1,10 @@
1  
-#
2  
-# header.rb
  1
+=begin rdoc
  2
+
  3
+= Header handling class
  4
+
  5
+=end
  6
+# RFC #822 ftp://ftp.isi.edu/in-notes/rfc822.txt
  7
+# 
3 8
 #
4 9
 #--
5 10
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
@@ -76,6 +81,7 @@ def initialize( body, conf, intern = false )
76 81
 
77 82
       @illegal = false
78 83
       @parsed = false
  84
+      
79 85
       if intern
80 86
         @parsed = true
81 87
         parse_init
@@ -129,7 +135,7 @@ def body=( str )
129 135
 
130 136
     include StrategyInterface
131 137
 
132  
-    def accept( strategy, dummy1 = nil, dummy2 = nil )
  138
+    def accept( strategy )
133 139
       ensure_parsed
134 140
       do_accept strategy
135 141
       strategy.terminate
@@ -207,6 +213,7 @@ def parse_init
207 213
     end
208 214
 
209 215
     def do_parse
  216
+      quote_boundary
210 217
       obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments)
211 218
       set obj if obj
212 219
     end
@@ -739,12 +746,17 @@ def content_type
739 746
 
740 747
     def params
741 748
       ensure_parsed
  749
+      unless @params.blank?
  750
+        @params.each do |k, v|
  751
+          @params[k] = unquote(v)
  752
+        end
  753
+      end
742 754
       @params
743 755
     end
744 756
 
745 757
     def []( key )
746 758
       ensure_parsed
747  
-      @params and @params[key]
  759
+      @params and unquote(@params[key])
748 760
     end
749 761
 
750 762
     def []=( key, val )
@@ -835,12 +847,17 @@ def disposition=( str )
835 847
 
836 848
     def params
837 849
       ensure_parsed
  850
+      unless @params.blank?
  851
+        @params.each do |k, v|
  852
+          @params[k] = unquote(v)
  853
+        end
  854
+      end
838 855
       @params
839 856
     end
840 857
 
841 858
     def []( key )
842 859
       ensure_parsed
843  
-      @params and @params[key]
  860
+      @params and unquote(@params[key])
844 861
     end
845 862
 
846 863
     def []=( key, val )
@@ -867,7 +884,7 @@ def do_accept( strategy )
867 884
       @params.each do |k,v|
868 885
         strategy.meta ';'
869 886
         strategy.space
870  
-        strategy.kv_pair k, v
  887
+        strategy.kv_pair k, unquote(v)
871 888
       end
872 889
     end
873 890
       
540  actionmailer/lib/action_mailer/vendor/tmail/interface.rb
... ...
@@ -0,0 +1,540 @@
  1
+=begin rdoc
  2
+
  3
+= Facade.rb Provides an interface to the TMail object
  4
+
  5
+=end
  6
+#--
  7
+# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
  8
+#
  9
+# Permission is hereby granted, free of charge, to any person obtaining
  10
+# a copy of this software and associated documentation files (the
  11
+# "Software"), to deal in the Software without restriction, including
  12
+# without limitation the rights to use, copy, modify, merge, publish,
  13
+# distribute, sublicense, and/or sell copies of the Software, and to
  14
+# permit persons to whom the Software is furnished to do so, subject to
  15
+# the following conditions:
  16
+#
  17
+# The above copyright notice and this permission notice shall be
  18
+# included in all copies or substantial portions of the Software.
  19
+#
  20
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27
+#
  28
+# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
  29
+# with permission of Minero Aoki.
  30
+#++
  31
+
  32
+require 'tmail/utils'
  33
+
  34
+module TMail
  35
+
  36
+  class Mail
  37
+
  38
+    def header_string( name, default = nil )
  39
+      h = @header[name.downcase] or return default
  40
+      h.to_s
  41
+    end
  42
+
  43
+    ###
  44
+    ### attributes
  45
+    ###
  46
+
  47
+    include TextUtils
  48
+
  49
+    def set_string_array_attr( key, strs )
  50
+      strs.flatten!
  51
+      if strs.empty?
  52
+        @header.delete key.downcase
  53
+      else
  54
+        store key, strs.join(', ')
  55
+      end
  56
+      strs
  57
+    end
  58
+    private :set_string_array_attr
  59
+
  60
+    def set_string_attr( key, str )
  61
+      if str
  62
+        store key, str
  63
+      else
  64
+        @header.delete key.downcase
  65
+      end
  66
+      str
  67
+    end
  68
+    private :set_string_attr
  69
+
  70
+    def set_addrfield( name, arg )
  71
+      if arg
  72
+        h = HeaderField.internal_new(name, @config)
  73
+        h.addrs.replace [arg].flatten
  74
+        @header[name] = h
  75
+      else
  76
+        @header.delete name
  77
+      end
  78
+      arg
  79
+    end
  80
+    private :set_addrfield
  81
+
  82
+    def addrs2specs( addrs )
  83
+      return nil unless addrs
  84
+      list = addrs.map {|addr|
  85
+          if addr.address_group?
  86
+          then addr.map {|a| a.spec }
  87
+          else addr.spec
  88
+          end
  89
+      }.flatten
  90
+      return nil if list.empty?
  91
+      list
  92
+    end
  93
+    private :addrs2specs
  94
+
  95
+    #
  96
+    # date time
  97
+    #
  98
+
  99
+    def date( default = nil )
  100
+      if h = @header['date']
  101
+        h.date
  102
+      else
  103
+        default
  104
+      end
  105
+    end
  106
+
  107
+    def date=( time )
  108
+      if time
  109
+        store 'Date', time2str(time)
  110
+      else
  111
+        @header.delete 'date'
  112
+      end
  113
+      time
  114
+    end
  115
+
  116
+    def strftime( fmt, default = nil )
  117
+      if t = date
  118
+        t.strftime(fmt)
  119
+      else
  120
+        default
  121
+      end
  122
+    end
  123
+
  124
+    #
  125
+    # destination
  126
+    #
  127
+
  128
+    def to_addrs( default = nil )
  129
+      if h = @header['to']
  130
+        h.addrs
  131
+      else
  132
+        default
  133
+      end
  134
+    end
  135
+
  136
+    def cc_addrs( default = nil )
  137
+      if h = @header['cc']
  138
+        h.addrs
  139
+      else
  140
+        default
  141
+      end
  142
+    end
  143
+
  144
+    def bcc_addrs( default = nil )
  145
+      if h = @header['bcc']
  146
+        h.addrs
  147
+      else
  148
+        default
  149
+      end
  150
+    end
  151
+
  152
+    def to_addrs=( arg )
  153
+      set_addrfield 'to', arg
  154
+    end
  155
+
  156
+    def cc_addrs=( arg )
  157
+      set_addrfield 'cc', arg
  158
+    end
  159
+
  160
+    def bcc_addrs=( arg )
  161
+      set_addrfield 'bcc', arg
  162
+    end
  163
+
  164
+    def to( default = nil )
  165
+      addrs2specs(to_addrs(nil)) || default
  166
+    end
  167
+
  168
+    def cc( default = nil )
  169
+      addrs2specs(cc_addrs(nil)) || default
  170
+    end
  171
+
  172
+    def bcc( default = nil )
  173
+      addrs2specs(bcc_addrs(nil)) || default
  174
+    end
  175
+
  176
+    def to=( *strs )
  177
+      set_string_array_attr 'To', strs
  178
+    end
  179
+
  180
+    def cc=( *strs )
  181
+      set_string_array_attr 'Cc', strs
  182
+    end
  183
+
  184
+    def bcc=( *strs )
  185
+      set_string_array_attr 'Bcc', strs
  186
+    end
  187
+
  188
+    #
  189
+    # originator
  190
+    #
  191
+
  192
+    def from_addrs( default = nil )
  193
+      if h = @header['from']
  194
+        h.addrs
  195
+      else
  196
+        default
  197
+      end
  198
+    end
  199
+
  200
+    def from_addrs=( arg )
  201
+      set_addrfield 'from', arg
  202
+    end
  203
+
  204
+    def from( default = nil )
  205
+      addrs2specs(from_addrs(nil)) || default
  206
+    end
  207
+
  208
+    def from=( *strs )
  209
+      set_string_array_attr 'From', strs
  210
+    end
  211
+
  212
+    def friendly_from( default = nil )
  213
+      h = @header['from']
  214
+      a, = h.addrs
  215
+      return default unless a
  216
+      return a.phrase if a.phrase
  217
+      return h.comments.join(' ') unless h.comments.empty?
  218
+      a.spec
  219
+    end
  220
+
  221
+
  222
+    def reply_to_addrs( default = nil )
  223
+      if h = @header['reply-to']
  224
+        h.addrs
  225
+      else
  226
+        default
  227
+      end
  228
+    end
  229
+
  230
+    def reply_to_addrs=( arg )
  231
+      set_addrfield 'reply-to', arg
  232
+    end
  233
+
  234
+    def reply_to( default = nil )
  235
+      addrs2specs(reply_to_addrs(nil)) || default
  236
+    end
  237
+
  238
+    def reply_to=( *strs )
  239
+      set_string_array_attr 'Reply-To', strs
  240
+    end
  241
+
  242
+
  243
+    def sender_addr( default = nil )
  244
+      f = @header['sender'] or return default
  245
+      f.addr                or return default
  246
+    end
  247
+
  248
+    def sender_addr=( addr )
  249
+      if addr
  250
+        h = HeaderField.internal_new('sender', @config)
  251
+        h.addr = addr
  252
+        @header['sender'] = h
  253
+      else
  254
+        @header.delete 'sender'
  255
+      end
  256
+      addr
  257
+    end
  258
+
  259
+    def sender( default )
  260
+      f = @header['sender'] or return default
  261
+      a = f.addr            or return default
  262
+      a.spec
  263
+    end
  264
+
  265
+    def sender=( str )
  266
+      set_string_attr 'Sender', str
  267
+    end
  268
+
  269
+
  270
+    #
  271
+    # subject
  272
+    #
  273
+
  274
+    def subject( default = nil )
  275
+      if h = @header['subject']
  276
+        h.body
  277
+      else
  278
+        default
  279
+      end
  280
+    end
  281
+    alias quoted_subject subject
  282
+
  283
+    def subject=( str )
  284
+      set_string_attr 'Subject', str
  285
+    end
  286
+
  287
+    #
  288
+    # identity & threading
  289
+    #
  290
+
  291
+    def message_id( default = nil )
  292
+      if h = @header['message-id']
  293
+        h.id || default
  294
+      else
  295
+        default
  296
+      end
  297
+    end
  298
+
  299
+    def message_id=( str )
  300
+      set_string_attr 'Message-Id', str
  301
+    end
  302
+
  303
+    def in_reply_to( default = nil )
  304
+      if h = @header['in-reply-to']
  305
+        h.ids
  306
+      else
  307
+        default
  308
+      end
  309
+    end
  310
+
  311
+    def in_reply_to=( *idstrs )
  312
+      set_string_array_attr 'In-Reply-To', idstrs
  313
+    end
  314
+
  315
+    def references( default = nil )
  316
+      if h = @header['references']
  317
+        h.refs
  318
+      else
  319
+        default
  320
+      end
  321
+    end
  322
+
  323
+    def references=( *strs )
  324
+      set_string_array_attr 'References', strs
  325
+    end
  326
+
  327
+    #
  328
+    # MIME headers
  329
+    #
  330
+
  331
+    def mime_version( default = nil )
  332
+      if h = @header['mime-version']
  333
+        h.version || default
  334
+      else
  335
+        default
  336
+      end
  337
+    end
  338
+
  339
+    def mime_version=( m, opt = nil )
  340
+      if opt
  341
+        if h = @header['mime-version']
  342
+          h.major = m
  343
+          h.minor = opt
  344
+        else
  345
+          store 'Mime-Version', "#{m}.#{opt}"
  346
+        end
  347
+      else
  348
+        store 'Mime-Version', m
  349
+      end
  350
+      m
  351
+    end
  352
+
  353
+    def content_type( default = nil )
  354
+      if h = @header['content-type']
  355
+        h.content_type || default
  356
+      else
  357
+        default
  358
+      end
  359
+    end
  360
+
  361
+    def main_type( default = nil )
  362
+      if h = @header['content-type']
  363
+        h.main_type || default
  364
+      else
  365
+        default
  366
+      end
  367
+    end
  368
+
  369
+    def sub_type( default = nil )
  370
+      if h = @header['content-type']
  371
+        h.sub_type || default
  372
+      else
  373
+        default
  374
+      end
  375
+    end
  376
+
  377
+    def set_content_type( str, sub = nil, param = nil )
  378
+      if sub
  379
+        main, sub = str, sub
  380
+      else
  381
+        main, sub = str.split(%r</>, 2)
  382
+        raise ArgumentError, "sub type missing: #{str.inspect}" unless sub
  383
+      end
  384
+      if h = @header['content-type']
  385
+        h.main_type = main
  386
+        h.sub_type  = sub
  387
+        h.params.clear
  388
+      else
  389
+        store 'Content-Type', "#{main}/#{sub}"
  390
+      end
  391
+      @header['content-type'].params.replace param if param
  392
+      str
  393
+    end
  394
+
  395
+    alias content_type= set_content_type
  396
+    
  397
+    def type_param( name, default = nil )
  398
+      if h = @header['content-type']
  399
+        h[name] || default
  400
+      else
  401
+        default
  402
+      end
  403
+    end
  404
+
  405
+    def charset( default = nil )
  406
+      if h = @header['content-type']
  407
+        h['charset'] or default
  408
+      else
  409
+        default
  410
+      end
  411
+    end
  412
+
  413
+    def charset=( str )
  414
+      if str
  415
+        if h = @header[ 'content-type' ]
  416
+          h['charset'] = str
  417
+        else
  418
+          store 'Content-Type', "text/plain; charset=#{str}"
  419
+        end
  420
+      end
  421
+      str
  422
+    end
  423
+
  424
+    def transfer_encoding( default = nil )
  425
+      if h = @header['content-transfer-encoding']
  426
+        h.encoding || default
  427
+      else
  428
+        default
  429
+      end
  430
+    end
  431
+
  432
+    def transfer_encoding=( str )
  433
+      set_string_attr 'Content-Transfer-Encoding', str
  434
+    end
  435
+
  436
+    alias encoding                   transfer_encoding
  437
+    alias encoding=                  transfer_encoding=
  438
+    alias content_transfer_encoding  transfer_encoding
  439
+    alias content_transfer_encoding= transfer_encoding=
  440
+
  441
+    def disposition( default = nil )
  442
+      if h = @header['content-disposition']
  443
+        h.disposition || default
  444
+      else
  445
+        default
  446
+      end
  447
+    end
  448
+
  449
+    alias content_disposition     disposition
  450
+
  451
+    def set_disposition( str, params = nil )
  452
+      if h = @header['content-disposition']
  453
+        h.disposition = str
  454
+        h.params.clear
  455
+      else
  456
+        store('Content-Disposition', str)
  457
+        h = @header['content-disposition']
  458
+      end
  459
+      h.params.replace params if params
  460
+    end
  461
+
  462
+    alias disposition=            set_disposition
  463
+    alias set_content_disposition set_disposition
  464
+    alias content_disposition=    set_disposition
  465
+    
  466
+    def disposition_param( name, default = nil )
  467
+      if h = @header['content-disposition']
  468
+        h[name] || default
  469
+      else
  470
+        default
  471
+      end
  472
+    end
  473
+
  474
+    ###
  475
+    ### utils
  476
+    ###
  477
+
  478
+    def create_reply
  479
+      mail = TMail::Mail.parse('')
  480
+      mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '')
  481
+      mail.to_addrs = reply_addresses([])
  482
+      mail.in_reply_to = [message_id(nil)].compact
  483
+      mail.references = references([]) + [message_id(nil)].compact
  484
+      mail.mime_version = '1.0'
  485
+      mail
  486
+    end
  487
+
  488
+    def base64_encode
  489
+      store 'Content-Transfer-Encoding', 'Base64'
  490
+      self.body = Base64.folding_encode(self.body)
  491
+    end
  492
+
  493
+    def base64_decode
  494
+      if /base64/i === self.transfer_encoding('')
  495
+        store 'Content-Transfer-Encoding', '8bit'
  496
+        self.body = Base64.decode(self.body, @config.strict_base64decode?)
  497
+      end
  498
+    end
  499
+
  500
+    def destinations( default = nil )
  501
+      ret = []
  502
+      %w( to cc bcc ).each do |nm|
  503
+        if h = @header[nm]
  504
+          h.addrs.each {|i| ret.push i.address }
  505
+        end
  506
+      end
  507
+      ret.empty? ? default : ret
  508
+    end
  509
+
  510
+    def each_destination( &block )
  511
+      destinations([]).each do |i|
  512
+        if Address === i
  513
+          yield i
  514
+        else
  515
+          i.each(&block)
  516
+        end
  517
+      end
  518
+    end
  519
+
  520
+    alias each_dest each_destination
  521
+
  522
+    def reply_addresses( default = nil )
  523
+      reply_to_addrs(nil) or from_addrs(nil) or default
  524
+    end
  525
+
  526
+    def error_reply_addresses( default = nil )
  527
+      if s = sender(nil)
  528
+        [s]
  529
+      else
  530
+        from_addrs(default)
  531
+      end
  532
+    end
  533
+
  534
+    def multipart?
  535
+      main_type('').downcase == 'multipart'
  536
+    end
  537
+
  538
+  end   # class Mail
  539
+
  540
+end   # module TMail
25  actionmailer/lib/action_mailer/vendor/tmail/mail.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# mail.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Mail class
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
@@ -27,7 +29,7 @@
27 29
 # with permission of Minero Aoki.
28 30
 #++
29 31
 
30  
-require 'tmail/facade'
  32
+require 'tmail/interface'
31 33
 require 'tmail/encode'
32 34
 require 'tmail/header'
33 35
 require 'tmail/port'
@@ -37,7 +39,6 @@
37 39
 require 'tmail/quoting'
38 40
 require 'socket'
39 41
 
40  
-
41 42
 module TMail
42 43
 
43 44
   class Mail
@@ -53,6 +54,7 @@ def load( fname )
53 54
       def parse( str )
54 55
         new(StringPort.new(str))
55 56
       end
  57
+
56 58
     end
57 59
 
58 60
     def initialize( port = nil, conf = DEFAULT_CONFIG )
@@ -355,6 +357,19 @@ def quoted_body
355 357
     end
356 358
 
357 359
     def body=( str )
  360
+      # Sets the body of the email to a new (encoded) string.
  361
+      # 
  362
+      # We also reparses the email if the body is ever reassigned, this is a performance hit, however when
  363
+      # you assign the body, you usually want to be able to make sure that you can access the attachments etc.
  364
+      # 
  365
+      # Usage:
  366
+      # 
  367
+      #  mail.body = "Hello, this is\nthe body text"
  368
+      #  # => "Hello, this is\nthe body"
  369
+      #  mail.body
  370
+      #  # => "Hello, this is\nthe body"
  371
+      @body_parsed = false
  372
+      parse_body(StringInput.new(str))
358 373
       parse_body
359 374
       @body_port.wopen {|f| f.write str }
360 375
       str
8  actionmailer/lib/action_mailer/vendor/tmail/mailbox.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# mailbox.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Mailbox and Mbox interaction class
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
8  actionmailer/lib/action_mailer/vendor/tmail/net.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# net.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Net provides SMTP wrapping
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
8  actionmailer/lib/action_mailer/vendor/tmail/obsolete.rb
... ...
@@ -1,6 +1,8 @@
1  
-#
2  
-# obsolete.rb
3  
-#
  1
+=begin rdoc
  2
+
  3
+= Obsolete methods that are depriciated
  4
+
  5
+=end
4 6
 #--
5 7
 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 8
 #
515  actionmailer/lib/action_mailer/vendor/tmail/parser.rb
... ...
@@ -1,38 +1,32 @@
1  
-#
2 1
 # DO NOT MODIFY!!!!
3  
-# This file is automatically generated by racc 1.4.3
  2
+# This file is automatically generated by racc 1.4.5
4 3
 # from racc grammer file "parser.y".
5 4
 #
6 5
 #
7 6
 # parser.rb: generated by racc (runtime embedded)
8 7
 #
9  
-
10  
-###### racc/parser.rb
11  
-
  8
+###### racc/parser.rb begin
12 9
 unless $".index 'racc/parser.rb'
13 10
 $".push 'racc/parser.rb'
14 11
 
15  
-self.class.module_eval <<'..end /home/aamine/lib/ruby/racc/parser.rb modeval..idb76f2e220d', '/home/aamine/lib/ruby/racc/parser.rb', 1
  12
+self.class.module_eval <<'..end racc/parser.rb modeval..id8076474214', 'racc/parser.rb', 1
16 13
 #
17  
-# parser.rb
18  
-#
19  
-#   Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
  14
+# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $
20 15
 #
21  
-#   This program is free software.
22  
-#   You can distribute/modify this program under the same terms of ruby.
  16