actionmailer-2.3.17-rack-upgrade 2.3.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +387 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +149 -0
  4. data/Rakefile +97 -0
  5. data/install.rb +30 -0
  6. data/lib/action_mailer.rb +62 -0
  7. data/lib/action_mailer/adv_attr_accessor.rb +30 -0
  8. data/lib/action_mailer/base.rb +739 -0
  9. data/lib/action_mailer/helpers.rb +113 -0
  10. data/lib/action_mailer/mail_helper.rb +17 -0
  11. data/lib/action_mailer/part.rb +107 -0
  12. data/lib/action_mailer/part_container.rb +55 -0
  13. data/lib/action_mailer/quoting.rb +62 -0
  14. data/lib/action_mailer/test_case.rb +64 -0
  15. data/lib/action_mailer/test_helper.rb +68 -0
  16. data/lib/action_mailer/utils.rb +7 -0
  17. data/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +1466 -0
  18. data/lib/action_mailer/vendor/text_format.rb +10 -0
  19. data/lib/action_mailer/vendor/tmail-1.2.7/tmail.rb +6 -0
  20. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/Makefile +18 -0
  21. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/address.rb +392 -0
  22. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/attachments.rb +65 -0
  23. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/base64.rb +46 -0
  24. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/compat.rb +41 -0
  25. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/config.rb +67 -0
  26. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/core_extensions.rb +63 -0
  27. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/encode.rb +590 -0
  28. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/header.rb +962 -0
  29. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/index.rb +9 -0
  30. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/interface.rb +1162 -0
  31. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/loader.rb +3 -0
  32. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/mail.rb +578 -0
  33. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/mailbox.rb +496 -0
  34. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/main.rb +6 -0
  35. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/mbox.rb +3 -0
  36. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/net.rb +250 -0
  37. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/obsolete.rb +132 -0
  38. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/parser.rb +1060 -0
  39. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/parser.y +416 -0
  40. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/port.rb +379 -0
  41. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/quoting.rb +164 -0
  42. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/require_arch.rb +58 -0
  43. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/scanner.rb +49 -0
  44. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/scanner_r.rb +262 -0
  45. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/stringio.rb +280 -0
  46. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/utils.rb +362 -0
  47. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/COPYING +504 -0
  48. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/README +12 -0
  49. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet.rb +67 -0
  50. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/big5freq.rb +927 -0
  51. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/big5prober.rb +42 -0
  52. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/chardistribution.rb +238 -0
  53. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/charsetgroupprober.rb +112 -0
  54. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/charsetprober.rb +75 -0
  55. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/codingstatemachine.rb +64 -0
  56. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/constants.rb +42 -0
  57. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/escprober.rb +89 -0
  58. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/escsm.rb +244 -0
  59. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/eucjpprober.rb +88 -0
  60. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/euckrfreq.rb +596 -0
  61. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/euckrprober.rb +42 -0
  62. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/euctwfreq.rb +430 -0
  63. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/euctwprober.rb +42 -0
  64. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/gb2312freq.rb +474 -0
  65. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/gb2312prober.rb +42 -0
  66. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/hebrewprober.rb +289 -0
  67. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/jisfreq.rb +570 -0
  68. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/jpcntx.rb +229 -0
  69. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langbulgarianmodel.rb +229 -0
  70. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langcyrillicmodel.rb +330 -0
  71. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langgreekmodel.rb +227 -0
  72. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langhebrewmodel.rb +202 -0
  73. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langhungarianmodel.rb +226 -0
  74. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/langthaimodel.rb +201 -0
  75. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/latin1prober.rb +147 -0
  76. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/mbcharsetprober.rb +89 -0
  77. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/mbcsgroupprober.rb +45 -0
  78. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/mbcssm.rb +542 -0
  79. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/sbcharsetprober.rb +124 -0
  80. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/sbcsgroupprober.rb +56 -0
  81. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/sjisprober.rb +88 -0
  82. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/universaldetector.rb +168 -0
  83. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/vendor/rchardet-1.3/lib/rchardet/utf8prober.rb +87 -0
  84. data/lib/action_mailer/vendor/tmail-1.2.7/tmail/version.rb +39 -0
  85. data/lib/action_mailer/vendor/tmail.rb +17 -0
  86. data/lib/action_mailer/version.rb +9 -0
  87. data/lib/actionmailer.rb +2 -0
  88. data/test/abstract_unit.rb +62 -0
  89. data/test/asset_host_test.rb +54 -0
  90. data/test/delivery_method_test.rb +51 -0
  91. data/test/fixtures/asset_host_mailer/email_with_asset.html.erb +1 -0
  92. data/test/fixtures/auto_layout_mailer/hello.html.erb +1 -0
  93. data/test/fixtures/auto_layout_mailer/multipart.text.html.erb +1 -0
  94. data/test/fixtures/auto_layout_mailer/multipart.text.plain.erb +1 -0
  95. data/test/fixtures/explicit_layout_mailer/logout.html.erb +1 -0
  96. data/test/fixtures/explicit_layout_mailer/signup.html.erb +1 -0
  97. data/test/fixtures/first_mailer/share.erb +1 -0
  98. data/test/fixtures/helper_mailer/use_example_helper.erb +1 -0
  99. data/test/fixtures/helper_mailer/use_helper.erb +1 -0
  100. data/test/fixtures/helper_mailer/use_helper_method.erb +1 -0
  101. data/test/fixtures/helper_mailer/use_mail_helper.erb +5 -0
  102. data/test/fixtures/helpers/example_helper.rb +5 -0
  103. data/test/fixtures/layouts/auto_layout_mailer.html.erb +1 -0
  104. data/test/fixtures/layouts/auto_layout_mailer.text.erb +1 -0
  105. data/test/fixtures/layouts/spam.html.erb +1 -0
  106. data/test/fixtures/path.with.dots/funky_path_mailer/multipart_with_template_path_with_dots.erb +1 -0
  107. data/test/fixtures/raw_email +14 -0
  108. data/test/fixtures/raw_email10 +20 -0
  109. data/test/fixtures/raw_email12 +32 -0
  110. data/test/fixtures/raw_email13 +29 -0
  111. data/test/fixtures/raw_email2 +114 -0
  112. data/test/fixtures/raw_email3 +70 -0
  113. data/test/fixtures/raw_email4 +59 -0
  114. data/test/fixtures/raw_email5 +19 -0
  115. data/test/fixtures/raw_email6 +20 -0
  116. data/test/fixtures/raw_email7 +66 -0
  117. data/test/fixtures/raw_email8 +47 -0
  118. data/test/fixtures/raw_email9 +28 -0
  119. data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
  120. data/test/fixtures/raw_email_with_invalid_characters_in_content_type +104 -0
  121. data/test/fixtures/raw_email_with_nested_attachment +100 -0
  122. data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
  123. data/test/fixtures/second_mailer/share.erb +1 -0
  124. data/test/fixtures/templates/signed_up.erb +3 -0
  125. data/test/fixtures/test_mailer/_subtemplate.text.plain.erb +1 -0
  126. data/test/fixtures/test_mailer/body_ivar.erb +2 -0
  127. data/test/fixtures/test_mailer/custom_templating_extension.text.html.haml +6 -0
  128. data/test/fixtures/test_mailer/custom_templating_extension.text.plain.haml +6 -0
  129. data/test/fixtures/test_mailer/implicitly_multipart_example.ignored.erb +1 -0
  130. data/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
  131. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb +10 -0
  132. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb~ +10 -0
  133. data/test/fixtures/test_mailer/implicitly_multipart_example.text.plain.erb +2 -0
  134. data/test/fixtures/test_mailer/implicitly_multipart_example.text.yaml.erb +1 -0
  135. data/test/fixtures/test_mailer/included_subtemplate.text.plain.erb +1 -0
  136. data/test/fixtures/test_mailer/rxml_template.builder +2 -0
  137. data/test/fixtures/test_mailer/rxml_template.rxml +2 -0
  138. data/test/fixtures/test_mailer/signed_up.html.erb +3 -0
  139. data/test/fixtures/test_mailer/signed_up_with_url.erb +5 -0
  140. data/test/mail_helper_test.rb +95 -0
  141. data/test/mail_layout_test.rb +123 -0
  142. data/test/mail_render_test.rb +116 -0
  143. data/test/mail_service_test.rb +1145 -0
  144. data/test/quoting_test.rb +105 -0
  145. data/test/test_helper_test.rb +129 -0
  146. data/test/tmail_test.rb +22 -0
  147. data/test/url_test.rb +76 -0
  148. metadata +209 -0
@@ -0,0 +1,46 @@
1
+ #--
2
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
24
+ # with permission of Minero Aoki.
25
+ #++
26
+ #:stopdoc:
27
+ module TMail
28
+ module Base64
29
+
30
+ module_function
31
+
32
+ def folding_encode( str, eol = "\n", limit = 60 )
33
+ [str].pack('m')
34
+ end
35
+
36
+ def encode( str )
37
+ [str].pack('m').tr( "\r\n", '' )
38
+ end
39
+
40
+ def decode( str, strict = false )
41
+ str.unpack('m').first
42
+ end
43
+
44
+ end
45
+ end
46
+ #:startdoc:
@@ -0,0 +1,41 @@
1
+ #:stopdoc:
2
+ unless Enumerable.method_defined?(:map)
3
+ module Enumerable #:nodoc:
4
+ alias map collect
5
+ end
6
+ end
7
+
8
+ unless Enumerable.method_defined?(:select)
9
+ module Enumerable #:nodoc:
10
+ alias select find_all
11
+ end
12
+ end
13
+
14
+ unless Enumerable.method_defined?(:reject)
15
+ module Enumerable #:nodoc:
16
+ def reject
17
+ result = []
18
+ each do |i|
19
+ result.push i unless yield(i)
20
+ end
21
+ result
22
+ end
23
+ end
24
+ end
25
+
26
+ unless Enumerable.method_defined?(:sort_by)
27
+ module Enumerable #:nodoc:
28
+ def sort_by
29
+ map {|i| [yield(i), i] }.sort.map {|val, i| i }
30
+ end
31
+ end
32
+ end
33
+
34
+ unless File.respond_to?(:read)
35
+ def File.read(fname) #:nodoc:
36
+ File.open(fname) {|f|
37
+ return f.read
38
+ }
39
+ end
40
+ end
41
+ #:startdoc:
@@ -0,0 +1,67 @@
1
+ #--
2
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
24
+ # with permission of Minero Aoki.
25
+ #++
26
+ #:stopdoc:
27
+ module TMail
28
+
29
+ class Config
30
+
31
+ def initialize( strict )
32
+ @strict_parse = strict
33
+ @strict_base64decode = strict
34
+ end
35
+
36
+ def strict_parse?
37
+ @strict_parse
38
+ end
39
+
40
+ attr_writer :strict_parse
41
+
42
+ def strict_base64decode?
43
+ @strict_base64decode
44
+ end
45
+
46
+ attr_writer :strict_base64decode
47
+
48
+ def new_body_port( mail )
49
+ StringPort.new
50
+ end
51
+
52
+ alias new_preamble_port new_body_port
53
+ alias new_part_port new_body_port
54
+
55
+ end
56
+
57
+ DEFAULT_CONFIG = Config.new(false)
58
+ DEFAULT_STRICT_CONFIG = Config.new(true)
59
+
60
+ def Config.to_config( arg )
61
+ return DEFAULT_STRICT_CONFIG if arg == true
62
+ return DEFAULT_CONFIG if arg == false
63
+ arg or DEFAULT_CONFIG
64
+ end
65
+
66
+ end
67
+ #:startdoc:
@@ -0,0 +1,63 @@
1
+ #:stopdoc:
2
+ unless Object.respond_to?(:blank?)
3
+ class Object
4
+ # Check first to see if we are in a Rails environment, no need to
5
+ # define these methods if we are
6
+
7
+ # An object is blank if it's nil, empty, or a whitespace string.
8
+ # For example, "", " ", nil, [], and {} are blank.
9
+ #
10
+ # This simplifies
11
+ # if !address.nil? && !address.empty?
12
+ # to
13
+ # if !address.blank?
14
+ def blank?
15
+ if respond_to?(:empty?) && respond_to?(:strip)
16
+ empty? or strip.empty?
17
+ elsif respond_to?(:empty?)
18
+ empty?
19
+ else
20
+ !self
21
+ end
22
+ end
23
+ end
24
+
25
+ class NilClass
26
+ def blank?
27
+ true
28
+ end
29
+ end
30
+
31
+ class FalseClass
32
+ def blank?
33
+ true
34
+ end
35
+ end
36
+
37
+ class TrueClass
38
+ def blank?
39
+ false
40
+ end
41
+ end
42
+
43
+ class Array
44
+ alias_method :blank?, :empty?
45
+ end
46
+
47
+ class Hash
48
+ alias_method :blank?, :empty?
49
+ end
50
+
51
+ class String
52
+ def blank?
53
+ empty? || strip.empty?
54
+ end
55
+ end
56
+
57
+ class Numeric
58
+ def blank?
59
+ false
60
+ end
61
+ end
62
+ end
63
+ #:startdoc:
@@ -0,0 +1,590 @@
1
+ #--
2
+ # = COPYRIGHT:
3
+ #
4
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #
25
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
26
+ # with permission of Minero Aoki.
27
+ #++
28
+ #:stopdoc:
29
+ require 'nkf'
30
+ require 'tmail/base64'
31
+ require 'tmail/stringio'
32
+ require 'tmail/utils'
33
+ #:startdoc:
34
+
35
+
36
+ module TMail
37
+
38
+ #:stopdoc:
39
+ class << self
40
+ attr_accessor :KCODE
41
+ end
42
+ self.KCODE = 'NONE'
43
+
44
+ module StrategyInterface
45
+
46
+ def create_dest( obj )
47
+ case obj
48
+ when nil
49
+ StringOutput.new
50
+ when String
51
+ StringOutput.new(obj)
52
+ when IO, StringOutput
53
+ obj
54
+ else
55
+ raise TypeError, 'cannot handle this type of object for dest'
56
+ end
57
+ end
58
+ module_function :create_dest
59
+
60
+ #:startdoc:
61
+ # Returns the TMail object encoded and ready to be sent via SMTP etc.
62
+ # You should call this before you are packaging up your email to
63
+ # correctly escape all the values that need escaping in the email, line
64
+ # wrap the email etc.
65
+ #
66
+ # It is also a good idea to call this before you marshal or serialize
67
+ # a TMail object.
68
+ #
69
+ # For Example:
70
+ #
71
+ # email = TMail::Load(my_email_file)
72
+ # email_to_send = email.encoded
73
+ def encoded( eol = "\r\n", charset = 'j', dest = nil )
74
+ accept_strategy Encoder, eol, charset, dest
75
+ end
76
+
77
+ # Returns the TMail object decoded and ready to be used by you, your
78
+ # program etc.
79
+ #
80
+ # You should call this before you are packaging up your email to
81
+ # correctly escape all the values that need escaping in the email, line
82
+ # wrap the email etc.
83
+ #
84
+ # For Example:
85
+ #
86
+ # email = TMail::Load(my_email_file)
87
+ # email_to_send = email.encoded
88
+ def decoded( eol = "\n", charset = 'e', dest = nil )
89
+ # Turn the E-Mail into a string and return it with all
90
+ # encoded characters decoded. alias for to_s
91
+ accept_strategy Decoder, eol, charset, dest
92
+ end
93
+
94
+ alias to_s decoded
95
+
96
+ def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc:
97
+ dest ||= ''
98
+ accept klass.new( create_dest(dest), charset, eol )
99
+ dest
100
+ end
101
+
102
+ end
103
+
104
+ #:stopdoc:
105
+
106
+ ###
107
+ ### MIME B encoding decoder
108
+ ###
109
+
110
+ class Decoder
111
+
112
+ include TextUtils
113
+
114
+ encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?='
115
+ ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i
116
+ SPACER = "\t"
117
+
118
+ OUTPUT_ENCODING = {
119
+ 'EUC' => 'e',
120
+ 'SJIS' => 's',
121
+ }
122
+
123
+ def self.decode( str, encoding = nil )
124
+ encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j')
125
+ opt = '-mS' + encoding
126
+ str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) }
127
+ end
128
+
129
+ def initialize( dest, encoding = nil, eol = "\n" )
130
+ @f = StrategyInterface.create_dest(dest)
131
+ @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil
132
+ @eol = eol
133
+ end
134
+
135
+ def decode( str )
136
+ self.class.decode(str, @encoding)
137
+ end
138
+ private :decode
139
+
140
+ def terminate
141
+ end
142
+
143
+ def header_line( str )
144
+ @f << decode(str)
145
+ end
146
+
147
+ def header_name( nm )
148
+ @f << nm << ': '
149
+ end
150
+
151
+ def header_body( str )
152
+ @f << decode(str)
153
+ end
154
+
155
+ def space
156
+ @f << ' '
157
+ end
158
+
159
+ alias spc space
160
+
161
+ def lwsp( str )
162
+ @f << str
163
+ end
164
+
165
+ def meta( str )
166
+ @f << str
167
+ end
168
+
169
+ def puts_meta( str )
170
+ @f << str
171
+ end
172
+
173
+ def text( str )
174
+ @f << decode(str)
175
+ end
176
+
177
+ def phrase( str )
178
+ @f << quote_phrase(decode(str))
179
+ end
180
+
181
+ def kv_pair( k, v )
182
+ v = dquote(v) unless token_safe?(v)
183
+ @f << k << '=' << v
184
+ end
185
+
186
+ def puts( str = nil )
187
+ @f << str if str
188
+ @f << @eol
189
+ end
190
+
191
+ def write( str )
192
+ @f << str
193
+ end
194
+
195
+ end
196
+
197
+
198
+ ###
199
+ ### MIME B-encoding encoder
200
+ ###
201
+
202
+ #
203
+ # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp).
204
+ #
205
+ class Encoder
206
+
207
+ include TextUtils
208
+
209
+ BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG)
210
+
211
+ def Encoder.encode( str )
212
+ e = new()
213
+ e.header_body str
214
+ e.terminate
215
+ e.dest.string
216
+ end
217
+
218
+ SPACER = "\t"
219
+ MAX_LINE_LEN = 78
220
+ RFC_2822_MAX_LENGTH = 998
221
+
222
+ OPTIONS = {
223
+ 'EUC' => '-Ej -m0',
224
+ 'SJIS' => '-Sj -m0',
225
+ 'UTF8' => nil, # FIXME
226
+ 'NONE' => nil
227
+ }
228
+
229
+ def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil )
230
+ @f = StrategyInterface.create_dest(dest)
231
+ @opt = OPTIONS[TMail.KCODE]
232
+ @eol = eol
233
+ @folded = false
234
+ @preserve_quotes = true
235
+ reset
236
+ end
237
+
238
+ def preserve_quotes=( bool )
239
+ @preserve_quotes
240
+ end
241
+
242
+ def preserve_quotes
243
+ @preserve_quotes
244
+ end
245
+
246
+ def normalize_encoding( str )
247
+ if @opt
248
+ then NKF.nkf(@opt, str)
249
+ else str
250
+ end
251
+ end
252
+
253
+ def reset
254
+ @text = ''
255
+ @lwsp = ''
256
+ @curlen = 0
257
+ end
258
+
259
+ def terminate
260
+ add_lwsp ''
261
+ reset
262
+ end
263
+
264
+ def dest
265
+ @f
266
+ end
267
+
268
+ def puts( str = nil )
269
+ @f << str if str
270
+ @f << @eol
271
+ end
272
+
273
+ def write( str )
274
+ @f << str
275
+ end
276
+
277
+ #
278
+ # add
279
+ #
280
+
281
+ def header_line( line )
282
+ scanadd line
283
+ end
284
+
285
+ def header_name( name )
286
+ add_text name.split(/-/).map {|i| i.capitalize }.join('-')
287
+ add_text ':'
288
+ add_lwsp ' '
289
+ end
290
+
291
+ def header_body( str )
292
+ scanadd normalize_encoding(str)
293
+ end
294
+
295
+ def space
296
+ add_lwsp ' '
297
+ end
298
+
299
+ alias spc space
300
+
301
+ def lwsp( str )
302
+ add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '')
303
+ end
304
+
305
+ def meta( str )
306
+ add_text str
307
+ end
308
+
309
+ def puts_meta( str )
310
+ add_text str + @eol + SPACER
311
+ end
312
+
313
+ def text( str )
314
+ scanadd normalize_encoding(str)
315
+ end
316
+
317
+ def phrase( str )
318
+ str = normalize_encoding(str)
319
+ if CONTROL_CHAR === str
320
+ scanadd str
321
+ else
322
+ add_text quote_phrase(str)
323
+ end
324
+ end
325
+
326
+ # FIXME: implement line folding
327
+ #
328
+ def kv_pair( k, v )
329
+ return if v.nil?
330
+ v = normalize_encoding(v)
331
+ if token_safe?(v)
332
+ add_text k + '=' + v
333
+ elsif not CONTROL_CHAR === v
334
+ add_text k + '=' + quote_token(v)
335
+ else
336
+ # apply RFC2231 encoding
337
+ kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v)
338
+ add_text kv
339
+ end
340
+ end
341
+
342
+ def encode_value( str )
343
+ str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] }
344
+ end
345
+
346
+ private
347
+
348
+ def scanadd( str, force = false )
349
+ types = ''
350
+ strs = []
351
+ if str.respond_to?(:encoding)
352
+ enc = str.encoding
353
+ str.force_encoding(Encoding::ASCII_8BIT)
354
+ end
355
+ until str.empty?
356
+ if m = /\A[^\e\t\r\n ]+/.match(str)
357
+ types << (force ? 'j' : 'a')
358
+ if str.respond_to?(:encoding)
359
+ strs.push m[0].force_encoding(enc)
360
+ else
361
+ strs.push m[0]
362
+ end
363
+ elsif m = /\A[\t\r\n ]+/.match(str)
364
+ types << 's'
365
+ if str.respond_to?(:encoding)
366
+ strs.push m[0].force_encoding(enc)
367
+ else
368
+ strs.push m[0]
369
+ end
370
+
371
+ elsif m = /\A\e../.match(str)
372
+ esc = m[0]
373
+ str = m.post_match
374
+ if esc != "\e(B" and m = /\A[^\e]+/.match(str)
375
+ types << 'j'
376
+ if str.respond_to?(:encoding)
377
+ strs.push m[0].force_encoding(enc)
378
+ else
379
+ strs.push m[0]
380
+ end
381
+ end
382
+
383
+ else
384
+ raise 'TMail FATAL: encoder scan fail'
385
+ end
386
+ (str = m.post_match) unless m.nil?
387
+ end
388
+
389
+ do_encode types, strs
390
+ end
391
+
392
+ def do_encode( types, strs )
393
+ #
394
+ # result : (A|E)(S(A|E))*
395
+ # E : W(SW)*
396
+ # W : (J|A)+ but must contain J # (J|A)*J(J|A)*
397
+ # A : <<A character string not to be encoded>>
398
+ # J : <<A character string to be encoded>>
399
+ # S : <<LWSP>>
400
+ #
401
+ # An encoding unit is `E'.
402
+ # Input (parameter `types') is (J|A)(J|A|S)*(J|A)
403
+ #
404
+ if BENCODE_DEBUG
405
+ puts
406
+ puts '-- do_encode ------------'
407
+ puts types.split(//).join(' ')
408
+ p strs
409
+ end
410
+
411
+ e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/
412
+
413
+ while m = e.match(types)
414
+ pre = m.pre_match
415
+ concat_A_S pre, strs[0, pre.size] unless pre.empty?
416
+ concat_E m[0], strs[m.begin(0) ... m.end(0)]
417
+ types = m.post_match
418
+ strs.slice! 0, m.end(0)
419
+ end
420
+ concat_A_S types, strs
421
+ end
422
+
423
+ def concat_A_S( types, strs )
424
+ if RUBY_VERSION < '1.9'
425
+ a = ?a; s = ?s
426
+ else
427
+ a = 'a'.ord; s = 's'.ord
428
+ end
429
+ i = 0
430
+ types.each_byte do |t|
431
+ case t
432
+ when a then add_text strs[i]
433
+ when s then add_lwsp strs[i]
434
+ else
435
+ raise "TMail FATAL: unknown flag: #{t.chr}"
436
+ end
437
+ i += 1
438
+ end
439
+ end
440
+
441
+ METHOD_ID = {
442
+ ?j => :extract_J,
443
+ ?e => :extract_E,
444
+ ?a => :extract_A,
445
+ ?s => :extract_S
446
+ }
447
+
448
+ def concat_E( types, strs )
449
+ if BENCODE_DEBUG
450
+ puts '---- concat_E'
451
+ puts "types=#{types.split(//).join(' ')}"
452
+ puts "strs =#{strs.inspect}"
453
+ end
454
+
455
+ flush() unless @text.empty?
456
+
457
+ chunk = ''
458
+ strs.each_with_index do |s,i|
459
+ mid = METHOD_ID[types[i]]
460
+ until s.empty?
461
+ unless c = __send__(mid, chunk.size, s)
462
+ add_with_encode chunk unless chunk.empty?
463
+ flush
464
+ chunk = ''
465
+ fold
466
+ c = __send__(mid, 0, s)
467
+ raise 'TMail FATAL: extract fail' unless c
468
+ end
469
+ chunk << c
470
+ end
471
+ end
472
+ add_with_encode chunk unless chunk.empty?
473
+ end
474
+
475
+ def extract_J( chunksize, str )
476
+ size = max_bytes(chunksize, str.size) - 6
477
+ size = (size % 2 == 0) ? (size) : (size - 1)
478
+ return nil if size <= 0
479
+ if str.respond_to?(:encoding)
480
+ enc = str.encoding
481
+ str.force_encoding(Encoding::ASCII_8BIT)
482
+ "\e$B#{str.slice!(0, size)}\e(B".force_encoding(enc)
483
+ else
484
+ "\e$B#{str.slice!(0, size)}\e(B"
485
+ end
486
+ end
487
+
488
+ def extract_A( chunksize, str )
489
+ size = max_bytes(chunksize, str.size)
490
+ return nil if size <= 0
491
+ str.slice!(0, size)
492
+ end
493
+
494
+ alias extract_S extract_A
495
+
496
+ def max_bytes( chunksize, ssize )
497
+ (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize
498
+ end
499
+
500
+ #
501
+ # free length buffer
502
+ #
503
+
504
+ def add_text( str )
505
+ @text << str
506
+ # puts '---- text -------------------------------------'
507
+ # puts "+ #{str.inspect}"
508
+ # puts "txt >>>#{@text.inspect}<<<"
509
+ end
510
+
511
+ def add_with_encode( str )
512
+ @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?="
513
+ end
514
+
515
+ def add_lwsp( lwsp )
516
+ # puts '---- lwsp -------------------------------------'
517
+ # puts "+ #{lwsp.inspect}"
518
+ fold if restsize() <= 0
519
+ flush(@folded)
520
+ @lwsp = lwsp
521
+ end
522
+
523
+ def flush(folded = false)
524
+ # puts '---- flush ----'
525
+ # puts "spc >>>#{@lwsp.inspect}<<<"
526
+ # puts "txt >>>#{@text.inspect}<<<"
527
+ @f << @lwsp << @text
528
+ if folded
529
+ @curlen = 0
530
+ else
531
+ @curlen += (@lwsp.size + @text.size)
532
+ end
533
+ @text = ''
534
+ @lwsp = ''
535
+ end
536
+
537
+ def fold
538
+ # puts '---- fold ----'
539
+ unless @f.string =~ /^.*?:$/
540
+ @f << @eol
541
+ @lwsp = SPACER
542
+ else
543
+ fold_header
544
+ @folded = true
545
+ end
546
+ @curlen = 0
547
+ end
548
+
549
+ def fold_header
550
+ # Called because line is too long - so we need to wrap.
551
+ # First look for whitespace in the text
552
+ # if it has text, fold there
553
+ # check the remaining text, if too long, fold again
554
+ # if it doesn't, then don't fold unless the line goes beyond 998 chars
555
+
556
+ # Check the text to see if there is whitespace, or if not
557
+ @wrapped_text = []
558
+ until @text.blank?
559
+ fold_the_string
560
+ end
561
+ @text = @wrapped_text.join("#{@eol}#{SPACER}")
562
+ end
563
+
564
+ def fold_the_string
565
+ whitespace_location = @text =~ /\s/ || @text.length
566
+ # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH?
567
+ # if there is no whitespace in the string, then this
568
+ unless mazsize(whitespace_location) <= 0
569
+ @text.strip!
570
+ @wrapped_text << @text.slice!(0...whitespace_location)
571
+ # If it is not less, we have to wrap it destructively
572
+ else
573
+ slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length
574
+ @text.strip!
575
+ @wrapped_text << @text.slice!(0...slice_point)
576
+ end
577
+ end
578
+
579
+ def restsize
580
+ MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size)
581
+ end
582
+
583
+ def mazsize(whitespace_location)
584
+ # Per RFC2822, the maximum length of a line is 998 chars
585
+ RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location)
586
+ end
587
+
588
+ end
589
+ #:startdoc:
590
+ end # module TMail