class Redwood::Source

Attributes

cur_offset[R]
id[RW]
uri[R]

Public Class Methods

new(uri, initial_offset=nil, usual=true, archived=false, id=nil) click to toggle source
# File lib/sup/source.rb, line 70
def initialize uri, initial_offset=nil, usual=true, archived=false, id=nil
  raise ArgumentError, "id must be an integer: #{id.inspect}" unless id.is_a? Fixnum if id

  @uri = uri
  @cur_offset = initial_offset
  @usual = usual
  @archived = archived
  @id = id
  @dirty = false
end
parse_raw_email_header(f) click to toggle source

utility method to read a raw email header from an IO stream and turn it into a hash of key-value pairs. minor special semantics for certain headers.

THIS IS A SPEED-CRITICAL SECTION. Everything you do here will have a significant effect on Sup's processing speed of email from ALL sources. Little things like string interpolation, regexp interpolation, += vs <<, all have DRAMATIC effects. BE CAREFUL WHAT YOU DO!

# File lib/sup/source.rb, line 115
def self.parse_raw_email_header f
  header = {}
  last = nil

  while(line = f.gets)
    case line
    ## these three can occur multiple times, and we want the first one
    when /^(Delivered-To|X-Original-To|Envelope-To):\s*(.*?)\s*$/i; header[last = $1.downcase] ||= $2
    ## regular header: overwrite (not that we should see more than one)
    ## TODO: figure out whether just using the first occurrence changes
    ## anything (which would simplify the logic slightly)
    when /^([^:\s]+):\s*(.*?)\s*$/i; header[last = $1.downcase] = $2
    when /^\r*$/; break # blank line signifies end of header
    else
      if last
        header[last] << " " unless header[last].empty?
        header[last] << line.strip
      end
    end
  end

  %w(subject from to cc bcc).each do |k|
    v = header[k] or next
    next unless Rfc2047.is_encoded? v
    header[k] = begin
      Rfc2047.decode_to $encoding, v
    rescue Errno::EINVAL, Iconv::InvalidEncoding, Iconv::IllegalSequence => e
      #debug "warning: error decoding RFC 2047 header (#{e.class.name}): #{e.message}"
      v
    end
  end
  header
end

Protected Class Methods

expand_filesystem_uri(uri) click to toggle source
# File lib/sup/source.rb, line 154
def Source.expand_filesystem_uri uri
  uri.gsub "~", File.expand_path("~")
end

Public Instance Methods

==(o;) click to toggle source
# File lib/sup/source.rb, line 87
def == o; o.uri == uri; end
check() click to toggle source

check should throw a FatalSourceError or an OutOfSyncSourcError if it can detect a problem. it is called when the sup starts up to proactively notify the user of any source problems.

# File lib/sup/source.rb, line 94
def check; end
done?() click to toggle source
# File lib/sup/source.rb, line 88
def done?; start_offset.nil? || (self.cur_offset ||= start_offset) >= end_offset; end
each() { |offset, labels| ... } click to toggle source

yields successive offsets and labels, starting at cur_offset.

when implementing a source, you can overwrite either each or next. the default each just calls next over and over.

# File lib/sup/source.rb, line 100
def each
  self.cur_offset ||= start_offset
  until done?
    offset, labels = self.next
    yield offset, labels
  end
end
file_path() click to toggle source

overwrite me if you have a disk incarnation (currently used only for sup-sync-back)

# File lib/sup/source.rb, line 82
def file_path; nil end
is_source_for?(uri;) click to toggle source
# File lib/sup/source.rb, line 89
def is_source_for? uri; uri == @uri; end
reset!() click to toggle source
# File lib/sup/source.rb, line 86
def reset!; seek_to! start_offset; end
seek_to!(o;) click to toggle source
# File lib/sup/source.rb, line 85
def seek_to! o; self.cur_offset = o; end
to_s() click to toggle source
# File lib/sup/source.rb, line 84
def to_s; @uri.to_s; end

Protected Instance Methods

cur_offset=(o) click to toggle source
# File lib/sup/source.rb, line 158
def cur_offset= o
  @cur_offset = o
  @dirty = true
end
parse_raw_email_header(f;) click to toggle source

convenience function

# File lib/sup/source.rb, line 152
def parse_raw_email_header f; self.class.parse_raw_email_header f end