actionmailer-2.3.17-rack-upgrade 2.3.17

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 (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,164 @@
1
+ =begin rdoc
2
+
3
+ = Quoting methods
4
+
5
+ =end
6
+ module TMail
7
+ class Mail
8
+ def subject(to_charset = 'utf-8')
9
+ Unquoter.unquote_and_convert_to(quoted_subject, to_charset)
10
+ end
11
+
12
+ def unquoted_body(to_charset = 'utf-8')
13
+ from_charset = charset
14
+ case (content_transfer_encoding || "7bit").downcase
15
+ when "quoted-printable"
16
+ # the default charset is set to iso-8859-1 instead of 'us-ascii'.
17
+ # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set.
18
+ if !from_charset.blank? && from_charset.downcase == 'us-ascii'
19
+ from_charset = 'iso-8859-1'
20
+ end
21
+
22
+ Unquoter.unquote_quoted_printable_and_convert_to(quoted_body,
23
+ to_charset, from_charset, true)
24
+ when "base64"
25
+ Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset,
26
+ from_charset)
27
+ when "7bit", "8bit"
28
+ Unquoter.convert_to(quoted_body, to_charset, from_charset)
29
+ when "binary"
30
+ quoted_body
31
+ else
32
+ quoted_body
33
+ end
34
+ end
35
+
36
+ def body(to_charset = 'utf-8', &block)
37
+ attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" }
38
+
39
+ if multipart?
40
+ parts.collect { |part|
41
+ header = part["content-type"]
42
+
43
+ if part.multipart?
44
+ part.body(to_charset, &attachment_presenter)
45
+ elsif header.nil?
46
+ ""
47
+ elsif !attachment?(part)
48
+ part.unquoted_body(to_charset)
49
+ else
50
+ attachment_presenter.call(header["name"] || "(unnamed)")
51
+ end
52
+ }.join
53
+ else
54
+ unquoted_body(to_charset)
55
+ end
56
+ end
57
+ end
58
+
59
+ class Attachment
60
+
61
+ include TextUtils
62
+
63
+ def quoted?(string)
64
+ !!((string =~ /.+'\w\w'.+/) || (string =~ /=\?.+\?.\?.+\?=/))
65
+ end
66
+
67
+ # Only unquote if quoted
68
+ def original_filename(to_charset = 'utf-8')
69
+ if quoted?(quoted_filename)
70
+ Unquoter.unquote_and_convert_to(quoted_filename, to_charset).chomp
71
+ else
72
+ quoted_filename
73
+ end
74
+ end
75
+ end
76
+
77
+ class Unquoter
78
+ class << self
79
+ def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false)
80
+ return "" if text.nil?
81
+ text.gsub!(/\?=(\s*)=\?/, '?==?') # Remove whitespaces between 'encoded-word's
82
+ text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do
83
+ before = $1
84
+ from_charset = $2
85
+ quoting_method = $3
86
+ text = $4
87
+
88
+ before = convert_to(before, to_charset, from_charset) if before.length > 0
89
+ before + case quoting_method
90
+ when "q", "Q" then
91
+ unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores)
92
+ when "b", "B" then
93
+ unquote_base64_and_convert_to(text, to_charset, from_charset)
94
+ when nil then
95
+ # will be nil at the end of the string, due to the nature of
96
+ # the regex used.
97
+ ""
98
+ else
99
+ raise "unknown quoting method #{quoting_method.inspect}"
100
+ end
101
+ end
102
+ end
103
+
104
+ def convert_to_with_fallback_on_iso_8859_1(text, to, from)
105
+ return text if to == 'utf-8' and text.isutf8
106
+
107
+ if from.blank? and !text.is_binary_data?
108
+ from = CharDet.detect(text)['encoding']
109
+
110
+ # Chardet ususally detects iso-8859-2 (aka windows-1250), but the text is
111
+ # iso-8859-1 (aka windows-1252 and Latin1). http://en.wikipedia.org/wiki/ISO/IEC_8859-2
112
+ # This can cause unwanted characters, like ŕ instead of à.
113
+ # (I know, could be a very bad decision...)
114
+ from = 'iso-8859-1' if from =~ /iso-8859-2/i
115
+ end
116
+
117
+ begin
118
+ convert_to_without_fallback_on_iso_8859_1(text, to, from)
119
+ rescue Iconv::InvalidCharacter
120
+ unless from == 'iso-8859-1'
121
+ from = 'iso-8859-1'
122
+ retry
123
+ end
124
+ end
125
+ end
126
+
127
+ def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false)
128
+ text = text.gsub(/_/, " ") unless preserve_underscores
129
+ text = text.gsub(/\r\n|\r/, "\n") # normalize newlines
130
+ convert_to(text.unpack("M*").first, to, from)
131
+ end
132
+
133
+ def unquote_base64_and_convert_to(text, to, from)
134
+ convert_to(Base64.decode(text), to, from)
135
+ end
136
+
137
+ begin
138
+ require 'iconv'
139
+ def convert_to(text, to, from)
140
+ return text unless to && from
141
+ text ? Iconv.iconv(to, from, text).first : ""
142
+ rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
143
+ # the 'from' parameter specifies a charset other than what the text
144
+ # actually is...not much we can do in this case but just return the
145
+ # unconverted text.
146
+ #
147
+ # Ditto if either parameter represents an unknown charset, like
148
+ # X-UNKNOWN.
149
+ text
150
+ end
151
+ rescue LoadError
152
+ # Not providing quoting support
153
+ def convert_to(text, to, from)
154
+ warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})"
155
+ text
156
+ end
157
+ end
158
+
159
+ alias_method :convert_to_without_fallback_on_iso_8859_1, :convert_to
160
+ alias_method :convert_to, :convert_to_with_fallback_on_iso_8859_1
161
+
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,58 @@
1
+ #:stopdoc:
2
+ require 'rbconfig'
3
+
4
+ # Attempts to require anative extension.
5
+ # Falls back to pure-ruby version, if it fails.
6
+ #
7
+ # This uses Config::CONFIG['arch'] from rbconfig.
8
+
9
+ def require_arch(fname)
10
+ arch = Config::CONFIG['arch']
11
+ begin
12
+ path = File.join("tmail", arch, fname)
13
+ require path
14
+ rescue LoadError => e
15
+ # try pre-built Windows binaries
16
+ if arch =~ /mswin/
17
+ require File.join("tmail", 'mswin32', fname)
18
+ else
19
+ raise e
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ # def require_arch(fname)
26
+ # dext = Config::CONFIG['DLEXT']
27
+ # begin
28
+ # if File.extname(fname) == dext
29
+ # path = fname
30
+ # else
31
+ # path = File.join("tmail","#{fname}.#{dext}")
32
+ # end
33
+ # require path
34
+ # rescue LoadError => e
35
+ # begin
36
+ # arch = Config::CONFIG['arch']
37
+ # path = File.join("tmail", arch, "#{fname}.#{dext}")
38
+ # require path
39
+ # rescue LoadError
40
+ # case path
41
+ # when /i686/
42
+ # path.sub!('i686', 'i586')
43
+ # when /i586/
44
+ # path.sub!('i586', 'i486')
45
+ # when /i486/
46
+ # path.sub!('i486', 'i386')
47
+ # else
48
+ # begin
49
+ # require fname + '.rb'
50
+ # rescue LoadError
51
+ # raise e
52
+ # end
53
+ # end
54
+ # retry
55
+ # end
56
+ # end
57
+ # end
58
+ #:startdoc:
@@ -0,0 +1,49 @@
1
+ =begin rdoc
2
+
3
+ = Scanner for TMail
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
+ #:stopdoc:
32
+ #require 'tmail/require_arch'
33
+ require 'tmail/utils'
34
+ require 'tmail/config'
35
+
36
+ module TMail
37
+ # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and
38
+ # the native extension would have precedence. However RubyGems boffs that up b/c
39
+ # it does not gaurantee load_path order.
40
+ begin
41
+ raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT']
42
+ require('tmail/tmailscanner') # c extension
43
+ Scanner = TMailScanner
44
+ rescue LoadError
45
+ require 'tmail/scanner_r'
46
+ Scanner = TMailScanner
47
+ end
48
+ end
49
+ #:stopdoc:
@@ -0,0 +1,262 @@
1
+ # encoding: us-ascii
2
+ # scanner_r.rb
3
+ #
4
+ #--
5
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
+ # with permission of Minero Aoki.
28
+ #++
29
+ #:stopdoc:
30
+ require 'tmail/config'
31
+
32
+ module TMail
33
+
34
+ class TMailScanner
35
+
36
+ Version = '1.2.3'
37
+ Version.freeze
38
+
39
+ MIME_HEADERS = {
40
+ :CTYPE => true,
41
+ :CENCODING => true,
42
+ :CDISPOSITION => true
43
+ }
44
+
45
+ alnum = 'a-zA-Z0-9'
46
+ atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip
47
+ tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip
48
+ atomchars = alnum + Regexp.quote(atomsyms)
49
+ tokenchars = alnum + Regexp.quote(tokensyms)
50
+ iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B'
51
+
52
+ eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+"
53
+ sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+"
54
+ utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+"
55
+
56
+ quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n
57
+ domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n
58
+ comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n
59
+
60
+ quoted_without_iso2022 = /\A[^\\"]+/n
61
+ domlit_without_iso2022 = /\A[^\\\]]+/n
62
+ comment_without_iso2022 = /\A[^\\()]+/n
63
+
64
+ PATTERN_TABLE = {}
65
+ PATTERN_TABLE['EUC'] =
66
+ [
67
+ /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n,
68
+ /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n,
69
+ quoted_with_iso2022,
70
+ domlit_with_iso2022,
71
+ comment_with_iso2022
72
+ ]
73
+ PATTERN_TABLE['SJIS'] =
74
+ [
75
+ /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n,
76
+ /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n,
77
+ quoted_with_iso2022,
78
+ domlit_with_iso2022,
79
+ comment_with_iso2022
80
+ ]
81
+ PATTERN_TABLE['UTF8'] =
82
+ [
83
+ /\A(?:[#{atomchars}]+|#{utf8str})+/n,
84
+ /\A(?:[#{tokenchars}]+|#{utf8str})+/n,
85
+ quoted_without_iso2022,
86
+ domlit_without_iso2022,
87
+ comment_without_iso2022
88
+ ]
89
+ PATTERN_TABLE['NONE'] =
90
+ [
91
+ /\A[#{atomchars}]+/n,
92
+ /\A[#{tokenchars}]+/n,
93
+ quoted_without_iso2022,
94
+ domlit_without_iso2022,
95
+ comment_without_iso2022
96
+ ]
97
+
98
+
99
+ def initialize( str, scantype, comments )
100
+ init_scanner str
101
+ @comments = comments || []
102
+ @debug = false
103
+
104
+ # fix scanner mode
105
+ @received = (scantype == :RECEIVED)
106
+ @is_mime_header = MIME_HEADERS[scantype]
107
+
108
+ atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE]
109
+ @word_re = (MIME_HEADERS[scantype] ? token : atom)
110
+ end
111
+
112
+ attr_accessor :debug
113
+
114
+ def scan( &block )
115
+ if @debug
116
+ scan_main do |arr|
117
+ s, v = arr
118
+ printf "%7d %-10s %s\n",
119
+ rest_size(),
120
+ s.respond_to?(:id2name) ? s.id2name : s.inspect,
121
+ v.inspect
122
+ yield arr
123
+ end
124
+ else
125
+ scan_main(&block)
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ RECV_TOKEN = {
132
+ 'from' => :FROM,
133
+ 'by' => :BY,
134
+ 'via' => :VIA,
135
+ 'with' => :WITH,
136
+ 'id' => :ID,
137
+ 'for' => :FOR
138
+ }
139
+
140
+ def scan_main
141
+ until eof?
142
+ if skip(/\A[\n\r\t ]+/n) # LWSP
143
+ break if eof?
144
+ end
145
+
146
+ if s = readstr(@word_re)
147
+ if @is_mime_header
148
+ yield [:TOKEN, s]
149
+ else
150
+ # atom
151
+ if /\A\d+\z/ === s
152
+ yield [:DIGIT, s]
153
+ elsif @received
154
+ yield [RECV_TOKEN[s.downcase] || :ATOM, s]
155
+ else
156
+ yield [:ATOM, s]
157
+ end
158
+ end
159
+
160
+ elsif skip(/\A"/)
161
+ yield [:QUOTED, scan_quoted_word()]
162
+
163
+ elsif skip(/\A\[/)
164
+ yield [:DOMLIT, scan_domain_literal()]
165
+
166
+ elsif skip(/\A\(/)
167
+ @comments.push scan_comment()
168
+
169
+ else
170
+ c = readchar()
171
+ yield [c, c]
172
+ end
173
+ end
174
+
175
+ yield [false, '$']
176
+ end
177
+
178
+ def scan_quoted_word
179
+ scan_qstr(@quoted_re, /\A"/, 'quoted-word')
180
+ end
181
+
182
+ def scan_domain_literal
183
+ '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']'
184
+ end
185
+
186
+ def scan_qstr( pattern, terminal, type )
187
+ result = ''
188
+ until eof?
189
+ if s = readstr(pattern) then result << s
190
+ elsif skip(terminal) then return result
191
+ elsif skip(/\A\\/) then result << readchar()
192
+ else
193
+ raise "TMail FATAL: not match in #{type}"
194
+ end
195
+ end
196
+ scan_error! "found unterminated #{type}"
197
+ end
198
+
199
+ def scan_comment
200
+ result = ''
201
+ nest = 1
202
+ content = @comment_re
203
+
204
+ until eof?
205
+ if s = readstr(content) then result << s
206
+ elsif skip(/\A\)/) then nest -= 1
207
+ return result if nest == 0
208
+ result << ')'
209
+ elsif skip(/\A\(/) then nest += 1
210
+ result << '('
211
+ elsif skip(/\A\\/) then result << readchar()
212
+ else
213
+ raise 'TMail FATAL: not match in comment'
214
+ end
215
+ end
216
+ scan_error! 'found unterminated comment'
217
+ end
218
+
219
+ # string scanner
220
+
221
+ def init_scanner( str )
222
+ @src = str
223
+ end
224
+
225
+ def eof?
226
+ @src.empty?
227
+ end
228
+
229
+ def rest_size
230
+ @src.size
231
+ end
232
+
233
+ def readstr( re )
234
+ if m = re.match(@src)
235
+ @src = m.post_match
236
+ m[0]
237
+ else
238
+ nil
239
+ end
240
+ end
241
+
242
+ def readchar
243
+ readstr(/\A./)
244
+ end
245
+
246
+ def skip( re )
247
+ if m = re.match(@src)
248
+ @src = m.post_match
249
+ true
250
+ else
251
+ false
252
+ end
253
+ end
254
+
255
+ def scan_error!( msg )
256
+ raise SyntaxError, msg
257
+ end
258
+
259
+ end
260
+
261
+ end # module TMail
262
+ #:startdoc: