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
48 def initialize(options)
49   @batch_size = options.fetch(:batch_size, DEFAULT_BATCH_SIZE)
50   @log_level  = options.fetch(:log_level,  DEFAULT_LOG_LEVEL)
51 
52   @imap = Net::IMAP.new(options[:host], options)
53   @imap.starttls(options[:starttls]) if options[:starttls]
54 
55   authenticate(options)
56   inclexcl(options)
57 end

Public Instance Methods

delete!(name, uids) { || ... } click to toggle source
    # File lib/imapget.rb
141 def delete!(name, uids)
142   return if uids.empty?
143 
144   log "#{name}: #{uids.size}"
145 
146   yield if block_given?
147 
148   imap.select(name)
149 
150   imap.store(uids, '+FLAGS', [Net::IMAP::DELETED]).size.tap { |count|
151     log "#{count} DELETED!"
152   }
153 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
125 def dupes(name, quiet = false)
126   imap.examine(name)
127 
128   hash = Hash.zipkey { |h, k| h[k] = [] }
129 
130   1.step(size(name), step = batch_size) { |i|
131     fetch_batch([[i, step]]) { |mail|
132       hash[mail.attr['RFC822']] << mail.attr['UID'] unless deleted?(mail)
133     }
134   }
135 
136   hash.flat_map { |_, uids| uids.drop(1) if uids.size > 1 }.tap { |dupes|
137     dupes.compact!; log "#{name}: #{dupes.size}" unless quiet
138   }
139 end
each() { |mailbox| ... } click to toggle source
   # File lib/imapget.rb
78 def each
79   mailboxes.each { |mailbox| yield mailbox if include?(mailbox) }
80 end
exclude?(mailbox) click to toggle source
    # File lib/imapget.rb
 86 def exclude?(mailbox)
 87   name = case mailbox
 88     when String                 then mailbox
 89     when Net::IMAP::MailboxList then mailbox.name
 90     else raise TypeError, "MailboxList or String expected, got #{mailbox.class}"
 91   end
 92 
 93   _excl = excl && name =~ excl
 94   _incl = incl && name =~ incl
 95 
 96   case strategy
 97     when :include then _excl || !_incl
 98     when :exclude then _excl && !_incl
 99   end
100 end
get(dir) click to toggle source
    # File lib/imapget.rb
102 def get(dir)
103   each { |mailbox| get_name(name = mailbox.name,
104     File.join(dir, Net::IMAP.decode_utf7(name))) }
105 end
Also aliased as: download
get_name(name, dir) click to toggle source
    # File lib/imapget.rb
109 def get_name(name, dir)
110   log "#{'=' * 10} #{name} #{'=' * 10}"
111 
112   imap.examine(name)
113 
114   imap.uid_search("SINCE #{mtime(dir)}").each_slice(batch_size) { |batch|
115     fetch_batch(batch) { |mail| fetch(mail, dir, name) }
116   }
117 end
Also aliased as: download_name
inclexcl(options) click to toggle source
   # File lib/imapget.rb
59 def inclexcl(options)
60   delim = Regexp.escape(options.fetch(:delim, DEFAULT_DELIMITER))
61 
62   %w[include exclude].each { |key|
63     instance_variable_set("@#{key[0, 4]}", case value = options[key.to_sym]
64       when String then Regexp.new(value)
65       when Array  then Regexp.new(value.map { |v|
66         "\\A#{Regexp.escape(Net::IMAP.encode_utf7(v))}(?:#{delim}|\\z)"
67       }.join('|'))
68     end)
69   }
70 
71   @strategy = options.fetch(:strategy, DEFAULT_STRATEGY).to_sym
72 end
include?(mailbox) click to toggle source
   # File lib/imapget.rb
82 def include?(mailbox)
83   !exclude?(mailbox)
84 end
mailboxes() click to toggle source
   # File lib/imapget.rb
74 def mailboxes
75   @mailboxes ||= imap.list('', '*').sort_by(&:name)
76 end
size(name, attr = 'MESSAGES') click to toggle source
    # File lib/imapget.rb
121 def size(name, attr = 'MESSAGES')
122   imap.status(name, [attr]).values.first
123 end
uniq!(name, &block) click to toggle source
    # File lib/imapget.rb
155 def uniq!(name, &block)
156   delete!(name, dupes(name, true), &block)
157 end

Private Instance Methods

authenticate(options) click to toggle source
    # File lib/imapget.rb
161 def authenticate(options)
162   if auth = options.fetch(:auth) {
163     imap.capability.grep(/\AAUTH=(.*)/) { $1 }.first
164   }
165     imap.authenticate(auth, options[:user], options[:password])
166   else
167     imap.login(options[:user], options[:password])
168   end
169 end
deleted?(mail) click to toggle source
    # File lib/imapget.rb
203 def deleted?(mail)
204   mail.attr['FLAGS'].include?(Net::IMAP::DELETED)
205 end
fetch(mail, dir, name) click to toggle source
    # File lib/imapget.rb
183 def fetch(mail, dir, name)
184   uid    = mail.attr['UID'].to_s
185   file   = File.join(dir, uid)
186   exists = File.exist?(file)
187 
188   if deleted?(mail)
189     if exists
190       info "#{dir}: #{name} <- #{uid}"
191       File.unlink(file)
192     end
193   else
194     date = mail.attr['INTERNALDATE']
195 
196     unless exists && date && File.mtime(file) >= Time.parse(date)
197       info "#{dir}: #{name} -> #{uid}"
198       File.write(file, mail.attr['RFC822'])
199     end
200   end
201 end
fetch_batch(batch, fetch_attr = FETCH_ATTR, &block) click to toggle source
    # File lib/imapget.rb
171 def fetch_batch(batch, fetch_attr = FETCH_ATTR, &block)
172   case set = batch.first
173     when Array
174       batch = set.first .. (set.first + set.last - 1)
175     when Range
176       batch = set.first .. (set.last - 1) if set.exclude_end?
177   end if batch.size == 1
178 
179   mails = imap.uid_fetch(batch, fetch_attr)
180   mails.each(&block) if mails
181 end
info(msg) click to toggle source
    # File lib/imapget.rb
216 def info(msg)
217   log(msg, 2)
218 end
log(msg, level = 1) click to toggle source
    # File lib/imapget.rb
212 def log(msg, level = 1)
213   warn msg if log_level >= level
214 end
mtime(dir) click to toggle source
    # File lib/imapget.rb
207 def mtime(dir)
208   Net::IMAP.format_date((File.directory?(dir) ?
209     File.mtime(dir) : (FileUtils.mkdir_p(dir); Time.at(0))).utc)
210 end