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,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: