class Redwood::IMAP

Constants

RECOVERABLE_ERRORS

upon these errors we'll try to rereconnect a few times

SCAN_INTERVAL

Attributes

password[RW]
username[RW]

Public Class Methods

new(uri, username, password, last_idate=nil, usual=true, archived=false, id=nil, labels=[]) click to toggle source
# File lib/sup/imap.rb, line 61
def initialize uri, username, password, last_idate=nil, usual=true, archived=false, id=nil, labels=[]
  raise ArgumentError, "username and password must be specified" unless username && password
  raise ArgumentError, "not an imap uri" unless uri =~ %rimaps?://!

  super uri, last_idate, usual, archived, id

  @parsed_uri = URI(uri)
  @username = username
  @password = password
  @imap = nil
  @imap_state = {}
  @ids = []
  @last_scan = nil
  @labels = Set.new((labels || []) - LabelManager::RESERVED_LABELS)
  @say_id = nil
  @mutex = Mutex.new
end
suggest_labels_for(path) click to toggle source
# File lib/sup/imap.rb, line 79
def self.suggest_labels_for path
  path =~ %r([^\/]*inbox[^\/]*)/ ? [$1.downcase.intern] : []
end

Public Instance Methods

==(o;) click to toggle source

is this necessary? TODO: remove maybe

# File lib/sup/imap.rb, line 95
def == o; o.is_a?(IMAP) && o.uri == self.uri && o.username == self.username; end
check() click to toggle source
# File lib/sup/imap.rb, line 91
def check; end
connect() click to toggle source
# File lib/sup/imap.rb, line 146
def connect
  return if @imap
  safely { } # do nothing!
end
each() { |id, labels| ... } click to toggle source
# File lib/sup/imap.rb, line 174
def each
  return unless start_offset

  ids = 
    @mutex.synchronize do
      unsynchronized_scan_mailbox
      @ids
    end

  start = ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}."

  start.upto(ids.length - 1) do |i|
    id = ids[i]
    state = @mutex.synchronize { @imap_state[id] } or next
    self.cur_offset = id 
    labels = { :Flagged => :starred,
               :Deleted => :deleted
             }.inject(@labels) do |cur, (imap, sup)|
      cur + (state[:flags].include?(imap) ? [sup] : [])
    end

    labels += [:unread] unless state[:flags].include?(:Seen)

    yield id, labels
  end
end
each_raw_message_line(id) { |l| ... } click to toggle source
# File lib/sup/imap.rb, line 105
def each_raw_message_line id
  StringIO.new(raw_message(id)).each { |l| yield l }
end
end_offset() click to toggle source
# File lib/sup/imap.rb, line 207
def end_offset
  unsynchronized_scan_mailbox
  @ids.last + 1
end
expunge() click to toggle source
# File lib/sup/imap.rb, line 139
def expunge
  @imap.expunge
  unsynchronized_scan_mailbox true
  true
end
host() click to toggle source
# File lib/sup/imap.rb, line 83
def host; @parsed_uri.host; end
load_header(id) click to toggle source
# File lib/sup/imap.rb, line 97
def load_header id
  parse_raw_email_header StringIO.new(raw_header(id))
end
load_message(id) click to toggle source
# File lib/sup/imap.rb, line 101
def load_message id
  RMail::Parser.read raw_message(id)
end
mailbox() click to toggle source
# File lib/sup/imap.rb, line 85
def mailbox
  x = @parsed_uri.path[1..-1]
  (x.nil? || x.empty?) ? 'INBOX' : CGI.unescape(x)
end
mark_as_deleted(ids) click to toggle source
# File lib/sup/imap.rb, line 130
def mark_as_deleted ids
  ids = [ids].flatten # accept single arguments
  unsynchronized_scan_mailbox
  imap_ids = ids.map { |i| @imap_state[i] && @imap_state[i][:id] }.compact
  return if imap_ids.empty?
  @imap.store imap_ids, "+FLAGS", [:Deleted]
end
pct_done() click to toggle source
# File lib/sup/imap.rb, line 213
def pct_done; 100.0 * (@ids.index(cur_offset) || 0).to_f / (@ids.length - 1).to_f; end
port() click to toggle source
# File lib/sup/imap.rb, line 84
def port; @parsed_uri.port || (ssl? ? 993 : 143); end
raw_header(id) click to toggle source
# File lib/sup/imap.rb, line 109
def raw_header id
  unsynchronized_scan_mailbox
  header, flags = get_imap_fields id, 'RFC822.HEADER'
  header.gsub(%r\r\n/, "\n")
end
raw_message(id) click to toggle source
# File lib/sup/imap.rb, line 124
def raw_message id
  unsynchronized_scan_mailbox
  get_imap_fields(id, 'RFC822').first.gsub(%r\r\n/, "\n")
end
scan_mailbox(force=false) click to toggle source
# File lib/sup/imap.rb, line 152
def scan_mailbox force=false
  return if !force && @last_scan && (Time.now - @last_scan) < SCAN_INTERVAL
  last_id = safely do
    @imap.examine mailbox
    @imap.responses["EXISTS"].last
  end
  @last_scan = Time.now

  @ids = [] if force
  return if last_id == @ids.length

  range = (@ids.length + 1) .. last_id
  debug "fetching IMAP headers #{range}"
  fetch(range, ['RFC822.SIZE', 'INTERNALDATE', 'FLAGS']).each do |v|
    id = make_id v
    @ids << id
    @imap_state[id] = { :id => v.seqno, :flags => v.attr["FLAGS"] }
  end
  debug "done fetching IMAP headers"
end
ssl?() click to toggle source
# File lib/sup/imap.rb, line 89
def ssl?; @parsed_uri.scheme == 'imaps' end
start_offset() click to toggle source
# File lib/sup/imap.rb, line 201
def start_offset
  unsynchronized_scan_mailbox
  @ids.first
end
store_message(date, from_email) { |message| ... } click to toggle source
# File lib/sup/imap.rb, line 116
def store_message date, from_email, &block
  message = StringIO.new
  yield message
  message.string.gsub! %r\n/, "\r\n"

  safely { @imap.append mailbox, message.string, [:Seen], Time.now }
end