Froze rails gems
[depot.git] / vendor / rails / actionmailer / lib / action_mailer / vendor / tmail-1.2.3 / tmail / port.rb
1 =begin rdoc
2
3 = Port class
4
5 =end
6 #--
7 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
8 #
9 # Permission is hereby granted, free of charge, to any person obtaining
10 # a copy of this software and associated documentation files (the
11 # "Software"), to deal in the Software without restriction, including
12 # without limitation the rights to use, copy, modify, merge, publish,
13 # distribute, sublicense, and/or sell copies of the Software, and to
14 # permit persons to whom the Software is furnished to do so, subject to
15 # the following conditions:
16 #
17 # The above copyright notice and this permission notice shall be
18 # included in all copies or substantial portions of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #
28 # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
29 # with permission of Minero Aoki.
30 #++
31
32 require 'tmail/stringio'
33
34
35 module TMail
36
37 class Port
38 def reproducible?
39 false
40 end
41 end
42
43
44 ###
45 ### FilePort
46 ###
47
48 class FilePort < Port
49
50 def initialize( fname )
51 @filename = File.expand_path(fname)
52 super()
53 end
54
55 attr_reader :filename
56
57 alias ident filename
58
59 def ==( other )
60 other.respond_to?(:filename) and @filename == other.filename
61 end
62
63 alias eql? ==
64
65 def hash
66 @filename.hash
67 end
68
69 def inspect
70 "#<#{self.class}:#{@filename}>"
71 end
72
73 def reproducible?
74 true
75 end
76
77 def size
78 File.size @filename
79 end
80
81
82 def ropen( &block )
83 File.open(@filename, &block)
84 end
85
86 def wopen( &block )
87 File.open(@filename, 'w', &block)
88 end
89
90 def aopen( &block )
91 File.open(@filename, 'a', &block)
92 end
93
94
95 def read_all
96 ropen {|f|
97 return f.read
98 }
99 end
100
101
102 def remove
103 File.unlink @filename
104 end
105
106 def move_to( port )
107 begin
108 File.link @filename, port.filename
109 rescue Errno::EXDEV
110 copy_to port
111 end
112 File.unlink @filename
113 end
114
115 alias mv move_to
116
117 def copy_to( port )
118 if FilePort === port
119 copy_file @filename, port.filename
120 else
121 File.open(@filename) {|r|
122 port.wopen {|w|
123 while s = r.sysread(4096)
124 w.write << s
125 end
126 } }
127 end
128 end
129
130 alias cp copy_to
131
132 private
133
134 # from fileutils.rb
135 def copy_file( src, dest )
136 st = r = w = nil
137
138 File.open(src, 'rb') {|r|
139 File.open(dest, 'wb') {|w|
140 st = r.stat
141 begin
142 while true
143 w.write r.sysread(st.blksize)
144 end
145 rescue EOFError
146 end
147 } }
148 end
149
150 end
151
152
153 module MailFlags
154
155 def seen=( b )
156 set_status 'S', b
157 end
158
159 def seen?
160 get_status 'S'
161 end
162
163 def replied=( b )
164 set_status 'R', b
165 end
166
167 def replied?
168 get_status 'R'
169 end
170
171 def flagged=( b )
172 set_status 'F', b
173 end
174
175 def flagged?
176 get_status 'F'
177 end
178
179 private
180
181 def procinfostr( str, tag, true_p )
182 a = str.upcase.split(//)
183 a.push true_p ? tag : nil
184 a.delete tag unless true_p
185 a.compact.sort.join('').squeeze
186 end
187
188 end
189
190
191 class MhPort < FilePort
192
193 include MailFlags
194
195 private
196
197 def set_status( tag, flag )
198 begin
199 tmpfile = @filename + '.tmailtmp.' + $$.to_s
200 File.open(tmpfile, 'w') {|f|
201 write_status f, tag, flag
202 }
203 File.unlink @filename
204 File.link tmpfile, @filename
205 ensure
206 File.unlink tmpfile
207 end
208 end
209
210 def write_status( f, tag, flag )
211 stat = ''
212 File.open(@filename) {|r|
213 while line = r.gets
214 if line.strip.empty?
215 break
216 elsif m = /\AX-TMail-Status:/i.match(line)
217 stat = m.post_match.strip
218 else
219 f.print line
220 end
221 end
222
223 s = procinfostr(stat, tag, flag)
224 f.puts 'X-TMail-Status: ' + s unless s.empty?
225 f.puts
226
227 while s = r.read(2048)
228 f.write s
229 end
230 }
231 end
232
233 def get_status( tag )
234 File.foreach(@filename) {|line|
235 return false if line.strip.empty?
236 if m = /\AX-TMail-Status:/i.match(line)
237 return m.post_match.strip.include?(tag[0])
238 end
239 }
240 false
241 end
242
243 end
244
245
246 class MaildirPort < FilePort
247
248 def move_to_new
249 new = replace_dir(@filename, 'new')
250 File.rename @filename, new
251 @filename = new
252 end
253
254 def move_to_cur
255 new = replace_dir(@filename, 'cur')
256 File.rename @filename, new
257 @filename = new
258 end
259
260 def replace_dir( path, dir )
261 "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}"
262 end
263 private :replace_dir
264
265
266 include MailFlags
267
268 private
269
270 MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/
271
272 def set_status( tag, flag )
273 if m = MAIL_FILE.match(File.basename(@filename))
274 s, uniq, type, info, = m.to_a
275 return if type and type != '2' # do not change anything
276 newname = File.dirname(@filename) + '/' +
277 uniq + ':2,' + procinfostr(info.to_s, tag, flag)
278 else
279 newname = @filename + ':2,' + tag
280 end
281
282 File.link @filename, newname
283 File.unlink @filename
284 @filename = newname
285 end
286
287 def get_status( tag )
288 m = MAIL_FILE.match(File.basename(@filename)) or return false
289 m[2] == '2' and m[3].to_s.include?(tag[0])
290 end
291
292 end
293
294
295 ###
296 ### StringPort
297 ###
298
299 class StringPort < Port
300
301 def initialize( str = '' )
302 @buffer = str
303 super()
304 end
305
306 def string
307 @buffer
308 end
309
310 def to_s
311 @buffer.dup
312 end
313
314 alias read_all to_s
315
316 def size
317 @buffer.size
318 end
319
320 def ==( other )
321 StringPort === other and @buffer.equal? other.string
322 end
323
324 alias eql? ==
325
326 def hash
327 @buffer.object_id.hash
328 end
329
330 def inspect
331 "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>"
332 end
333
334 def reproducible?
335 true
336 end
337
338 def ropen( &block )
339 @buffer or raise Errno::ENOENT, "#{inspect} is already removed"
340 StringInput.open(@buffer, &block)
341 end
342
343 def wopen( &block )
344 @buffer = ''
345 StringOutput.new(@buffer, &block)
346 end
347
348 def aopen( &block )
349 @buffer ||= ''
350 StringOutput.new(@buffer, &block)
351 end
352
353 def remove
354 @buffer = nil
355 end
356
357 alias rm remove
358
359 def copy_to( port )
360 port.wopen {|f|
361 f.write @buffer
362 }
363 end
364
365 alias cp copy_to
366
367 def move_to( port )
368 if StringPort === port
369 str = @buffer
370 port.instance_eval { @buffer = str }
371 else
372 copy_to port
373 end
374 remove
375 end
376
377 end
378
379 end # module TMail