~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
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