7
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
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:
17
# The above copyright notice and this permission notice shall be
18
# included in all copies or substantial portions of the Software.
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.
28
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
29
# with permission of Minero Aoki.
32
require 'tmail/stringio'
50
def initialize( fname )
51
@filename = File.expand_path(fname)
60
other.respond_to?(:filename) and @filename == other.filename
70
"#<#{self.class}:#{@filename}>"
83
File.open(@filename, &block)
87
File.open(@filename, 'w', &block)
91
File.open(@filename, 'a', &block)
103
File.unlink @filename
108
File.link @filename, port.filename
112
File.unlink @filename
119
copy_file @filename, port.filename
121
File.open(@filename) {|r|
123
while s = r.sysread(4096)
135
def copy_file( src, dest )
138
File.open(src, 'rb') {|r|
139
File.open(dest, 'wb') {|w|
143
w.write r.sysread(st.blksize)
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
191
class MhPort < FilePort
197
def set_status( tag, flag )
199
tmpfile = @filename + '.tmailtmp.' + $$.to_s
200
File.open(tmpfile, 'w') {|f|
201
write_status f, tag, flag
203
File.unlink @filename
204
File.link tmpfile, @filename
210
def write_status( f, tag, flag )
212
File.open(@filename) {|r|
216
elsif m = /\AX-TMail-Status:/i.match(line)
217
stat = m.post_match.strip
223
s = procinfostr(stat, tag, flag)
224
f.puts 'X-TMail-Status: ' + s unless s.empty?
227
while s = r.read(2048)
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])
246
class MaildirPort < FilePort
249
new = replace_dir(@filename, 'new')
250
File.rename @filename, new
255
new = replace_dir(@filename, 'cur')
256
File.rename @filename, new
260
def replace_dir( path, dir )
261
"#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}"
270
MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/
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)
279
newname = @filename + ':2,' + tag
282
File.link @filename, newname
283
File.unlink @filename
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])
299
class StringPort < Port
301
def initialize( str = '' )
321
StringPort === other and @buffer.equal? other.string
327
@buffer.object_id.hash
331
"#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>"
339
@buffer or raise Errno::ENOENT, "#{inspect} is already removed"
340
StringInput.open(@buffer, &block)
345
StringOutput.new(@buffer, &block)
350
StringOutput.new(@buffer, &block)
368
if StringPort === port
370
port.instance_eval { @buffer = str }