class IMAPGet

Constants

DEFAULT_BATCH_SIZE
DEFAULT_DELIMITER
DEFAULT_LOG_LEVEL
DEFAULT_STRATEGY
FETCH_ATTR
VERSION

Attributes

batch_size[RW]
excl[R]
imap[R]
incl[R]
log_level[RW]
strategy[R]

Public Class Methods

new(options) click to toggle source
# File lib/imapget.rb, line 48
def initialize(options)
  @batch_size = options.fetch(:batch_size, DEFAULT_BATCH_SIZE)
  @log_level  = options.fetch(:log_level,  DEFAULT_LOG_LEVEL)

  @imap = Net::IMAP.new(options[:host], options)
  @imap.starttls(options[:starttls]) if options[:starttls]

  authenticate(options)
  inclexcl(options)
end

Public Instance Methods

delete!(name, uids) { || ... } click to toggle source
# File lib/imapget.rb, line 141
def delete!(name, uids)
  return if uids.empty?

  log "#{name}: #{uids.size}"

  yield if block_given?

  imap.select(name)

  imap.store(uids, '+FLAGS', [Net::IMAP::DELETED]).size.tap { |count|
    log "#{count} DELETED!"
  }
end
download(dir)
Alias for: get
download_name(name, dir)
Alias for: get_name
dupes(name, quiet = false) click to toggle source
# File lib/imapget.rb, line 125
def dupes(name, quiet = false)
  imap.examine(name)

  hash = Hash.zipkey { |h, k| h[k] = [] }

  1.step(size(name), step = batch_size) { |i|
    fetch_batch([[i, step]]) { |mail|
      hash[mail.attr['RFC822']] << mail.attr['UID'] unless deleted?(mail)
    }
  }

  hash.flat_map { |_, uids| uids.drop(1) if uids.size > 1 }.tap { |dupes|
    dupes.compact!; log "#{name}: #{dupes.size}" unless quiet
  }
end
each() { |mailbox| ... } click to toggle source
# File lib/imapget.rb, line 78
def each
  mailboxes.each { |mailbox| yield mailbox if include?(mailbox) }
end
exclude?(mailbox) click to toggle source
# File lib/imapget.rb, line 86
def exclude?(mailbox)
  name = case mailbox
    when String                 then mailbox
    when Net::IMAP::MailboxList then mailbox.name
    else raise TypeError, "MailboxList or String expected, got #{mailbox.class}"
  end

  _excl = excl && name =~ excl
  _incl = incl && name =~ incl

  case strategy
    when :include then _excl || !_incl
    when :exclude then _excl && !_incl
  end
end
get(dir) click to toggle source
# File lib/imapget.rb, line 102
def get(dir)
  each { |mailbox| get_name(name = mailbox.name,
    File.join(dir, Net::IMAP.decode_utf7(name))) }
end
Also aliased as: download
get_name(name, dir) click to toggle source
# File lib/imapget.rb, line 109
def get_name(name, dir)
  log "#{'=' * 10} #{name} #{'=' * 10}"

  imap.examine(name)

  imap.uid_search("SINCE #{mtime(dir)}").each_slice(batch_size) { |batch|
    fetch_batch(batch) { |mail| fetch(mail, dir, name) }
  }
end
Also aliased as: download_name
inclexcl(options) click to toggle source
# File lib/imapget.rb, line 59
def inclexcl(options)
  delim = Regexp.escape(options.fetch(:delim, DEFAULT_DELIMITER))

  %w[include exclude].each { |key|
    instance_variable_set("@#{key[0, 4]}", case value = options[key.to_sym]
      when String then Regexp.new(value)
      when Array  then Regexp.new(value.map { |v|
        "\\A#{Regexp.escape(Net::IMAP.encode_utf7(v))}(?:#{delim}|\\z)"
      }.join('|'))
    end)
  }

  @strategy = options.fetch(:strategy, DEFAULT_STRATEGY)
end
include?(mailbox) click to toggle source
# File lib/imapget.rb, line 82
def include?(mailbox)
  !exclude?(mailbox)
end
mailboxes() click to toggle source
# File lib/imapget.rb, line 74
def mailboxes
  @mailboxes ||= imap.list('', '*').sort_by(&:name)
end
size(name, attr = 'MESSAGES') click to toggle source
# File lib/imapget.rb, line 121
def size(name, attr = 'MESSAGES')
  imap.status(name, [attr]).values.first
end
uniq!(name, &block) click to toggle source
# File lib/imapget.rb, line 155
def uniq!(name, &block)
  delete!(name, dupes(name, true), &block)
end

Private Instance Methods

authenticate(options) click to toggle source
# File lib/imapget.rb, line 161
def authenticate(options)
  if auth = options.fetch(:auth) {
    imap.capability.grep(/\AAUTH=(.*)/) { $1 }.first
  }
    imap.authenticate(auth, options[:user], options[:password])
  else
    imap.login(options[:user], options[:password])
  end
end
deleted?(mail) click to toggle source
# File lib/imapget.rb, line 203
def deleted?(mail)
  mail.attr['FLAGS'].include?(Net::IMAP::DELETED)
end
fetch(mail, dir, name) click to toggle source
# File lib/imapget.rb, line 183
def fetch(mail, dir, name)
  uid    = mail.attr['UID'].to_s
  file   = File.join(dir, uid)
  exists = File.exists?(file)

  if deleted?(mail)
    if exists
      info "#{dir}: #{name} <- #{uid}"
      File.unlink(file)
    end
  else
    date = mail.attr['INTERNALDATE']

    unless exists && date && File.mtime(file) >= Time.parse(date)
      info "#{dir}: #{name} -> #{uid}"
      File.write(file, mail.attr['RFC822'])
    end
  end
end
fetch_batch(batch, fetch_attr = FETCH_ATTR, &block) click to toggle source
# File lib/imapget.rb, line 171
def fetch_batch(batch, fetch_attr = FETCH_ATTR, &block)
  case set = batch.first
    when Array
      batch = set.first .. (set.first + set.last - 1)
    when Range
      batch = set.first .. (set.last - 1) if set.exclude_end?
  end if batch.size == 1

  mails = imap.uid_fetch(batch, fetch_attr)
  mails.each(&block) if mails
end
info(msg) click to toggle source
# File lib/imapget.rb, line 216
def info(msg)
  log(msg, 2)
end
log(msg, level = 1) click to toggle source
# File lib/imapget.rb, line 212
def log(msg, level = 1)
  warn msg if log_level >= level
end
mtime(dir) click to toggle source
# File lib/imapget.rb, line 207
def mtime(dir)
  Net::IMAP.format_date((File.directory?(dir) ?
    File.mtime(dir) : (FileUtils.mkdir_p(dir); Time.at(0))).utc)
end