~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: Michael Forrest
  • Date: 2010-10-15 16:28:50 UTC
  • Revision ID: michael.forrest@canonical.com-20101015162850-tj2vchanv0kr0dun
refrozeĀ gems

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