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,962 @@
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
+
27
+ require 'tmail/encode'
28
+ require 'tmail/address'
29
+ require 'tmail/parser'
30
+ require 'tmail/config'
31
+ require 'tmail/utils'
32
+
33
+ #:startdoc:
34
+ module TMail
35
+
36
+ # Provides methods to handle and manipulate headers in the email
37
+ class HeaderField
38
+
39
+ include TextUtils
40
+
41
+ class << self
42
+
43
+ alias newobj new
44
+
45
+ def new( name, body, conf = DEFAULT_CONFIG )
46
+ klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader
47
+ klass.newobj body, conf
48
+ end
49
+
50
+ # Returns a HeaderField object matching the header you specify in the "name" param.
51
+ # Requires an initialized TMail::Port to be passed in.
52
+ #
53
+ # The method searches the header of the Port you pass into it to find a match on
54
+ # the header line you pass. Once a match is found, it will unwrap the matching line
55
+ # as needed to return an initialized HeaderField object.
56
+ #
57
+ # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender",
58
+ # if you want the From address of the email itself, pass in 'From'.
59
+ #
60
+ # This is because a mailbox doesn't have the : after the From that designates the
61
+ # beginning of the envelope sender (which can be different to the from address of
62
+ # the email)
63
+ #
64
+ # Other fields can be passed as normal, "Reply-To", "Received" etc.
65
+ #
66
+ # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified
67
+ # header field, otherwise returns an instantiated object of the correct header class
68
+ #
69
+ # For example:
70
+ # port = TMail::FilePort.new("/test/fixtures/raw_email_simple")
71
+ # h = TMail::HeaderField.new_from_port(port, "From")
72
+ # h.addrs.to_s #=> "Mikel Lindsaar <mikel@nowhere.com>"
73
+ # h = TMail::HeaderField.new_from_port(port, "EvelopeSender")
74
+ # h.addrs.to_s #=> "mike@anotherplace.com.au"
75
+ # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField")
76
+ # h #=> nil
77
+ def new_from_port( port, name, conf = DEFAULT_CONFIG )
78
+ if name == "EnvelopeSender"
79
+ name = "From"
80
+ re = Regexp.new('\A(From) ', 'i')
81
+ else
82
+ re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i')
83
+ end
84
+ str = nil
85
+ port.ropen {|f|
86
+ f.each do |line|
87
+ if m = re.match(line) then str = m.post_match.strip
88
+ elsif str and /\A[\t ]/ === line then str << ' ' << line.strip
89
+ elsif /\A-*\s*\z/ === line then break
90
+ elsif str then break
91
+ end
92
+ end
93
+ }
94
+ new(name, str, Config.to_config(conf)) if str
95
+ end
96
+
97
+ def internal_new( name, conf )
98
+ FNAME_TO_CLASS[name].newobj('', conf, true)
99
+ end
100
+
101
+ end # class << self
102
+
103
+ def initialize( body, conf, intern = false )
104
+ @body = body
105
+ @config = conf
106
+
107
+ @illegal = false
108
+ @parsed = false
109
+
110
+ if intern
111
+ @parsed = true
112
+ parse_init
113
+ end
114
+ end
115
+
116
+ def inspect
117
+ "#<#{self.class} #{@body.inspect}>"
118
+ end
119
+
120
+ def illegal?
121
+ @illegal
122
+ end
123
+
124
+ def empty?
125
+ ensure_parsed
126
+ return true if @illegal
127
+ isempty?
128
+ end
129
+
130
+ private
131
+
132
+ def ensure_parsed
133
+ return if @parsed
134
+ @parsed = true
135
+ parse
136
+ end
137
+
138
+ # defabstract parse
139
+ # end
140
+
141
+ def clear_parse_status
142
+ @parsed = false
143
+ @illegal = false
144
+ end
145
+
146
+ public
147
+
148
+ def body
149
+ ensure_parsed
150
+ v = Decoder.new(s = '')
151
+ do_accept v
152
+ v.terminate
153
+ s
154
+ end
155
+
156
+ def body=( str )
157
+ @body = str
158
+ clear_parse_status
159
+ end
160
+
161
+ include StrategyInterface
162
+
163
+ def accept( strategy )
164
+ ensure_parsed
165
+ do_accept strategy
166
+ strategy.terminate
167
+ end
168
+
169
+ # abstract do_accept
170
+
171
+ end
172
+
173
+
174
+ class UnstructuredHeader < HeaderField
175
+
176
+ def body
177
+ ensure_parsed
178
+ @body
179
+ end
180
+
181
+ def body=( arg )
182
+ ensure_parsed
183
+ @body = arg
184
+ end
185
+
186
+ private
187
+
188
+ def parse_init
189
+ end
190
+
191
+ def parse
192
+ @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, ''))
193
+ end
194
+
195
+ def isempty?
196
+ not @body
197
+ end
198
+
199
+ def do_accept( strategy )
200
+ strategy.text @body
201
+ end
202
+
203
+ end
204
+
205
+
206
+ class StructuredHeader < HeaderField
207
+
208
+ def comments
209
+ ensure_parsed
210
+ if @comments[0]
211
+ [Decoder.decode(@comments[0])]
212
+ else
213
+ @comments
214
+ end
215
+ end
216
+
217
+ private
218
+
219
+ def parse
220
+ save = nil
221
+
222
+ begin
223
+ parse_init
224
+ do_parse
225
+ rescue SyntaxError
226
+ if not save and mime_encoded? @body
227
+ save = @body
228
+ @body = Decoder.decode(save)
229
+ retry
230
+ elsif save
231
+ @body = save
232
+ end
233
+
234
+ @illegal = true
235
+ raise if @config.strict_parse?
236
+ end
237
+ end
238
+
239
+ def parse_init
240
+ @comments = []
241
+ init
242
+ end
243
+
244
+ def do_parse
245
+ quote_boundary
246
+ quote_unquoted_name
247
+ quote_unquoted_bencode
248
+ obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments)
249
+ set obj if obj
250
+ end
251
+
252
+ end
253
+
254
+
255
+ class DateTimeHeader < StructuredHeader
256
+
257
+ PARSE_TYPE = :DATETIME
258
+
259
+ def date
260
+ ensure_parsed
261
+ @date
262
+ end
263
+
264
+ def date=( arg )
265
+ ensure_parsed
266
+ @date = arg
267
+ end
268
+
269
+ private
270
+
271
+ def init
272
+ @date = nil
273
+ end
274
+
275
+ def set( t )
276
+ @date = t
277
+ end
278
+
279
+ def isempty?
280
+ not @date
281
+ end
282
+
283
+ def do_accept( strategy )
284
+ strategy.meta time2str(@date)
285
+ end
286
+
287
+ end
288
+
289
+
290
+ class AddressHeader < StructuredHeader
291
+
292
+ PARSE_TYPE = :MADDRESS
293
+
294
+ def addrs
295
+ ensure_parsed
296
+ @addrs
297
+ end
298
+
299
+ private
300
+
301
+ def init
302
+ @addrs = []
303
+ end
304
+
305
+ def set( a )
306
+ @addrs = a
307
+ end
308
+
309
+ def isempty?
310
+ @addrs.empty?
311
+ end
312
+
313
+ def do_accept( strategy )
314
+ first = true
315
+ @addrs.each do |a|
316
+ if first
317
+ first = false
318
+ else
319
+ strategy.puts_meta ','
320
+ strategy.space
321
+ end
322
+ a.accept strategy
323
+ end
324
+
325
+ @comments.each do |c|
326
+ strategy.space
327
+ strategy.meta '('
328
+ strategy.text c
329
+ strategy.meta ')'
330
+ end
331
+ end
332
+
333
+ end
334
+
335
+
336
+ class ReturnPathHeader < AddressHeader
337
+
338
+ PARSE_TYPE = :RETPATH
339
+
340
+ def addr
341
+ addrs()[0]
342
+ end
343
+
344
+ def spec
345
+ a = addr() or return nil
346
+ a.spec
347
+ end
348
+
349
+ def routes
350
+ a = addr() or return nil
351
+ a.routes
352
+ end
353
+
354
+ private
355
+
356
+ def do_accept( strategy )
357
+ a = addr()
358
+
359
+ strategy.meta '<'
360
+ unless a.routes.empty?
361
+ strategy.meta a.routes.map {|i| '@' + i }.join(',')
362
+ strategy.meta ':'
363
+ end
364
+ spec = a.spec
365
+ strategy.meta spec if spec
366
+ strategy.meta '>'
367
+ end
368
+
369
+ end
370
+
371
+
372
+ class SingleAddressHeader < AddressHeader
373
+
374
+ def addr
375
+ addrs()[0]
376
+ end
377
+
378
+ private
379
+
380
+ def do_accept( strategy )
381
+ a = addr()
382
+ a.accept strategy
383
+ @comments.each do |c|
384
+ strategy.space
385
+ strategy.meta '('
386
+ strategy.text c
387
+ strategy.meta ')'
388
+ end
389
+ end
390
+
391
+ end
392
+
393
+
394
+ class MessageIdHeader < StructuredHeader
395
+
396
+ def id
397
+ ensure_parsed
398
+ @id
399
+ end
400
+
401
+ def id=( arg )
402
+ ensure_parsed
403
+ @id = arg
404
+ end
405
+
406
+ private
407
+
408
+ def init
409
+ @id = nil
410
+ end
411
+
412
+ def isempty?
413
+ not @id
414
+ end
415
+
416
+ def do_parse
417
+ @id = @body.slice(MESSAGE_ID) or
418
+ raise SyntaxError, "wrong Message-ID format: #{@body}"
419
+ end
420
+
421
+ def do_accept( strategy )
422
+ strategy.meta @id
423
+ end
424
+
425
+ end
426
+
427
+
428
+ class ReferencesHeader < StructuredHeader
429
+
430
+ def refs
431
+ ensure_parsed
432
+ @refs
433
+ end
434
+
435
+ def each_id
436
+ self.refs.each do |i|
437
+ yield i if MESSAGE_ID === i
438
+ end
439
+ end
440
+
441
+ def ids
442
+ ensure_parsed
443
+ @ids
444
+ end
445
+
446
+ def each_phrase
447
+ self.refs.each do |i|
448
+ yield i unless MESSAGE_ID === i
449
+ end
450
+ end
451
+
452
+ def phrases
453
+ ret = []
454
+ each_phrase {|i| ret.push i }
455
+ ret
456
+ end
457
+
458
+ private
459
+
460
+ def init
461
+ @refs = []
462
+ @ids = []
463
+ end
464
+
465
+ def isempty?
466
+ @ids.empty?
467
+ end
468
+
469
+ def do_parse
470
+ str = @body
471
+ while m = MESSAGE_ID.match(str)
472
+ pre = m.pre_match.strip
473
+ @refs.push pre unless pre.empty?
474
+ @refs.push s = m[0]
475
+ @ids.push s
476
+ str = m.post_match
477
+ end
478
+ str = str.strip
479
+ @refs.push str unless str.empty?
480
+ end
481
+
482
+ def do_accept( strategy )
483
+ first = true
484
+ @ids.each do |i|
485
+ if first
486
+ first = false
487
+ else
488
+ strategy.space
489
+ end
490
+ strategy.meta i
491
+ end
492
+ end
493
+
494
+ end
495
+
496
+
497
+ class ReceivedHeader < StructuredHeader
498
+
499
+ PARSE_TYPE = :RECEIVED
500
+
501
+ def from
502
+ ensure_parsed
503
+ @from
504
+ end
505
+
506
+ def from=( arg )
507
+ ensure_parsed
508
+ @from = arg
509
+ end
510
+
511
+ def by
512
+ ensure_parsed
513
+ @by
514
+ end
515
+
516
+ def by=( arg )
517
+ ensure_parsed
518
+ @by = arg
519
+ end
520
+
521
+ def via
522
+ ensure_parsed
523
+ @via
524
+ end
525
+
526
+ def via=( arg )
527
+ ensure_parsed
528
+ @via = arg
529
+ end
530
+
531
+ def with
532
+ ensure_parsed
533
+ @with
534
+ end
535
+
536
+ def id
537
+ ensure_parsed
538
+ @id
539
+ end
540
+
541
+ def id=( arg )
542
+ ensure_parsed
543
+ @id = arg
544
+ end
545
+
546
+ def _for
547
+ ensure_parsed
548
+ @_for
549
+ end
550
+
551
+ def _for=( arg )
552
+ ensure_parsed
553
+ @_for = arg
554
+ end
555
+
556
+ def date
557
+ ensure_parsed
558
+ @date
559
+ end
560
+
561
+ def date=( arg )
562
+ ensure_parsed
563
+ @date = arg
564
+ end
565
+
566
+ private
567
+
568
+ def init
569
+ @from = @by = @via = @with = @id = @_for = nil
570
+ @with = []
571
+ @date = nil
572
+ end
573
+
574
+ def set( args )
575
+ @from, @by, @via, @with, @id, @_for, @date = *args
576
+ end
577
+
578
+ def isempty?
579
+ @with.empty? and not (@from or @by or @via or @id or @_for or @date)
580
+ end
581
+
582
+ def do_accept( strategy )
583
+ list = []
584
+ list.push 'from ' + @from if @from
585
+ list.push 'by ' + @by if @by
586
+ list.push 'via ' + @via if @via
587
+ @with.each do |i|
588
+ list.push 'with ' + i
589
+ end
590
+ list.push 'id ' + @id if @id
591
+ list.push 'for <' + @_for + '>' if @_for
592
+
593
+ first = true
594
+ list.each do |i|
595
+ strategy.space unless first
596
+ strategy.meta i
597
+ first = false
598
+ end
599
+ if @date
600
+ strategy.meta ';'
601
+ strategy.space
602
+ strategy.meta time2str(@date)
603
+ end
604
+ end
605
+
606
+ end
607
+
608
+
609
+ class KeywordsHeader < StructuredHeader
610
+
611
+ PARSE_TYPE = :KEYWORDS
612
+
613
+ def keys
614
+ ensure_parsed
615
+ @keys
616
+ end
617
+
618
+ private
619
+
620
+ def init
621
+ @keys = []
622
+ end
623
+
624
+ def set( a )
625
+ @keys = a
626
+ end
627
+
628
+ def isempty?
629
+ @keys.empty?
630
+ end
631
+
632
+ def do_accept( strategy )
633
+ first = true
634
+ @keys.each do |i|
635
+ if first
636
+ first = false
637
+ else
638
+ strategy.meta ','
639
+ end
640
+ strategy.meta i
641
+ end
642
+ end
643
+
644
+ end
645
+
646
+
647
+ class EncryptedHeader < StructuredHeader
648
+
649
+ PARSE_TYPE = :ENCRYPTED
650
+
651
+ def encrypter
652
+ ensure_parsed
653
+ @encrypter
654
+ end
655
+
656
+ def encrypter=( arg )
657
+ ensure_parsed
658
+ @encrypter = arg
659
+ end
660
+
661
+ def keyword
662
+ ensure_parsed
663
+ @keyword
664
+ end
665
+
666
+ def keyword=( arg )
667
+ ensure_parsed
668
+ @keyword = arg
669
+ end
670
+
671
+ private
672
+
673
+ def init
674
+ @encrypter = nil
675
+ @keyword = nil
676
+ end
677
+
678
+ def set( args )
679
+ @encrypter, @keyword = args
680
+ end
681
+
682
+ def isempty?
683
+ not (@encrypter or @keyword)
684
+ end
685
+
686
+ def do_accept( strategy )
687
+ if @key
688
+ strategy.meta @encrypter + ','
689
+ strategy.space
690
+ strategy.meta @keyword
691
+ else
692
+ strategy.meta @encrypter
693
+ end
694
+ end
695
+
696
+ end
697
+
698
+
699
+ class MimeVersionHeader < StructuredHeader
700
+
701
+ PARSE_TYPE = :MIMEVERSION
702
+
703
+ def major
704
+ ensure_parsed
705
+ @major
706
+ end
707
+
708
+ def major=( arg )
709
+ ensure_parsed
710
+ @major = arg
711
+ end
712
+
713
+ def minor
714
+ ensure_parsed
715
+ @minor
716
+ end
717
+
718
+ def minor=( arg )
719
+ ensure_parsed
720
+ @minor = arg
721
+ end
722
+
723
+ def version
724
+ sprintf('%d.%d', major, minor)
725
+ end
726
+
727
+ private
728
+
729
+ def init
730
+ @major = nil
731
+ @minor = nil
732
+ end
733
+
734
+ def set( args )
735
+ @major, @minor = *args
736
+ end
737
+
738
+ def isempty?
739
+ not (@major or @minor)
740
+ end
741
+
742
+ def do_accept( strategy )
743
+ strategy.meta sprintf('%d.%d', @major, @minor)
744
+ end
745
+
746
+ end
747
+
748
+
749
+ class ContentTypeHeader < StructuredHeader
750
+
751
+ PARSE_TYPE = :CTYPE
752
+
753
+ def main_type
754
+ ensure_parsed
755
+ @main
756
+ end
757
+
758
+ def main_type=( arg )
759
+ ensure_parsed
760
+ @main = arg.downcase
761
+ end
762
+
763
+ def sub_type
764
+ ensure_parsed
765
+ @sub
766
+ end
767
+
768
+ def sub_type=( arg )
769
+ ensure_parsed
770
+ @sub = arg.downcase
771
+ end
772
+
773
+ def content_type
774
+ ensure_parsed
775
+ @sub ? sprintf('%s/%s', @main, @sub) : @main
776
+ end
777
+
778
+ def params
779
+ ensure_parsed
780
+ unless @params.blank?
781
+ @params.each do |k, v|
782
+ @params[k] = unquote(v)
783
+ end
784
+ end
785
+ @params
786
+ end
787
+
788
+ def []( key )
789
+ ensure_parsed
790
+ @params and unquote(@params[key])
791
+ end
792
+
793
+ def []=( key, val )
794
+ ensure_parsed
795
+ (@params ||= {})[key] = val
796
+ end
797
+
798
+ private
799
+
800
+ def init
801
+ @main = @sub = @params = nil
802
+ end
803
+
804
+ def set( args )
805
+ @main, @sub, @params = *args
806
+ end
807
+
808
+ def isempty?
809
+ not (@main or @sub)
810
+ end
811
+
812
+ def do_accept( strategy )
813
+ if @sub
814
+ strategy.meta sprintf('%s/%s', @main, @sub)
815
+ else
816
+ strategy.meta @main
817
+ end
818
+ @params.each do |k,v|
819
+ if v
820
+ strategy.meta ';'
821
+ strategy.space
822
+ strategy.kv_pair k, unquote(v)
823
+ end
824
+ end
825
+ end
826
+
827
+ end
828
+
829
+
830
+ class ContentTransferEncodingHeader < StructuredHeader
831
+
832
+ PARSE_TYPE = :CENCODING
833
+
834
+ def encoding
835
+ ensure_parsed
836
+ @encoding
837
+ end
838
+
839
+ def encoding=( arg )
840
+ ensure_parsed
841
+ @encoding = arg
842
+ end
843
+
844
+ private
845
+
846
+ def init
847
+ @encoding = nil
848
+ end
849
+
850
+ def set( s )
851
+ @encoding = s
852
+ end
853
+
854
+ def isempty?
855
+ not @encoding
856
+ end
857
+
858
+ def do_accept( strategy )
859
+ strategy.meta @encoding.capitalize
860
+ end
861
+
862
+ end
863
+
864
+
865
+ class ContentDispositionHeader < StructuredHeader
866
+
867
+ PARSE_TYPE = :CDISPOSITION
868
+
869
+ def disposition
870
+ ensure_parsed
871
+ @disposition
872
+ end
873
+
874
+ def disposition=( str )
875
+ ensure_parsed
876
+ @disposition = str.downcase
877
+ end
878
+
879
+ def params
880
+ ensure_parsed
881
+ unless @params.blank?
882
+ @params.each do |k, v|
883
+ @params[k] = unquote(v)
884
+ end
885
+ end
886
+ @params
887
+ end
888
+
889
+ def []( key )
890
+ ensure_parsed
891
+ @params and unquote(@params[key])
892
+ end
893
+
894
+ def []=( key, val )
895
+ ensure_parsed
896
+ (@params ||= {})[key] = val
897
+ end
898
+
899
+ private
900
+
901
+ def init
902
+ @disposition = @params = nil
903
+ end
904
+
905
+ def set( args )
906
+ @disposition, @params = *args
907
+ end
908
+
909
+ def isempty?
910
+ not @disposition and (not @params or @params.empty?)
911
+ end
912
+
913
+ def do_accept( strategy )
914
+ strategy.meta @disposition
915
+ @params.each do |k,v|
916
+ strategy.meta ';'
917
+ strategy.space
918
+ strategy.kv_pair k, unquote(v)
919
+ end
920
+ end
921
+
922
+ end
923
+
924
+
925
+ class HeaderField # redefine
926
+
927
+ FNAME_TO_CLASS = {
928
+ 'date' => DateTimeHeader,
929
+ 'resent-date' => DateTimeHeader,
930
+ 'to' => AddressHeader,
931
+ 'cc' => AddressHeader,
932
+ 'bcc' => AddressHeader,
933
+ 'from' => AddressHeader,
934
+ 'reply-to' => AddressHeader,
935
+ 'resent-to' => AddressHeader,
936
+ 'resent-cc' => AddressHeader,
937
+ 'resent-bcc' => AddressHeader,
938
+ 'resent-from' => AddressHeader,
939
+ 'resent-reply-to' => AddressHeader,
940
+ 'sender' => SingleAddressHeader,
941
+ 'resent-sender' => SingleAddressHeader,
942
+ 'return-path' => ReturnPathHeader,
943
+ 'message-id' => MessageIdHeader,
944
+ 'resent-message-id' => MessageIdHeader,
945
+ 'in-reply-to' => ReferencesHeader,
946
+ 'received' => ReceivedHeader,
947
+ 'references' => ReferencesHeader,
948
+ 'keywords' => KeywordsHeader,
949
+ 'encrypted' => EncryptedHeader,
950
+ 'mime-version' => MimeVersionHeader,
951
+ 'content-type' => ContentTypeHeader,
952
+ 'content-transfer-encoding' => ContentTransferEncodingHeader,
953
+ 'content-disposition' => ContentDispositionHeader,
954
+ 'content-id' => MessageIdHeader,
955
+ 'subject' => UnstructuredHeader,
956
+ 'comments' => UnstructuredHeader,
957
+ 'content-description' => UnstructuredHeader
958
+ }
959
+
960
+ end
961
+
962
+ end # module TMail