lib/imap_guard/guard.rb in imap_guard-0.0.2 vs lib/imap_guard/guard.rb in imap_guard-0.0.3
- old
+ new
@@ -2,105 +2,159 @@
require 'ostruct'
require 'mail'
require 'colored'
module IMAPGuard
+ # Guard allows you to process your mailboxes.
class Guard
+ # [Proc] Matched emails are passed to this debug lambda if present
+ attr_accessor :debug
+
+ # @return [OpenStruct] IMAPGuard settings
attr_reader :settings
+ # @return [String] Currently selected mailbox
+ attr_reader :mailbox
+
def initialize settings
self.settings = settings
end
+ # Authenticates to the given IMAP server
# @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/imap/rdoc/Net/IMAP.html#method-c-new
+ # @return [void]
def login
@imap = Net::IMAP.new(@settings.host, @settings.port, true, nil, false)
@imap.login(@settings.username, @settings.password)
verbose.puts "Logged in successfully"
end
+ # Selects a mailbox (folder)
+ # @see {settings.read_only}
+ # @return [void]
def select mailbox
if @settings.read_only
@imap.examine(mailbox) # open in read-only
else
@imap.select(mailbox) # open in read-write
end
+ @mailbox = mailbox
end
+ # Moves messages matching the query and filter block
+ # @param query IMAP query
# @param mailbox Destination mailbox
+ # @param filter Optional filter block
+ # @return [void]
def move query, mailbox, &filter
operation = lambda { |message_id|
- @imap.copy(message_id, mailbox) unless @settings.read_only
- @imap.store(message_id, "+FLAGS", [:Deleted])
- "moved to #{mailbox}".cyan
+ unless @settings.read_only
+ @imap.copy(message_id, mailbox)
+ @imap.store(message_id, "+FLAGS", [Net::IMAP::DELETED])
+ end
+
+ "moved to #{mailbox}".yellow
}
process query, operation, &filter
end
+ # Deletes messages matching the query and filter block
+ # @param query IMAP query
+ # @param filter Optional filter block
+ # @return [void]
def delete query, &filter
operation = lambda { |message_id|
- @imap.store(message_id, "+FLAGS", [:Deleted])
+ unless @settings.read_only
+ @imap.store(message_id, "+FLAGS", [Net::IMAP::DELETED])
+ end
+
'deleted'.red
}
process query, operation, &filter
end
+ # @return [Array] Sorted list of all mailboxes
+ def list
+ @imap.list("", "*").map(&:name).sort
+ end
+
+ # Sends a EXPUNGE command to permanently remove from the currently selected
+ # mailbox all messages that have the Deleted flag set.
+ # @return [void]
def expunge
- @imap.expunge
+ @imap.expunge unless @settings.read_only
end
+ # Sends a CLOSE command to close the currently selected mailbox. The CLOSE
+ # command permanently removes from the mailbox all messages that have the
+ # Deleted flag set.
+ # @return [void]
def close
- puts "Expunging deleted messages and closing mailbox..."
- @imap.close
+ @imap.close unless @settings.read_only
end
+ # Disconnects from the server.
+ # @return [void]
+ def disconnect
+ @imap.disconnect
+ end
+
private
def process query, operation
message_ids = search query
count = message_ids.size
message_ids.each_with_index do |message_id, index|
- print "Processing UID #{message_id} (#{index + 1}/#{count}): "
+ print "Processing UID #{message_id} (#{index.succ}/#{count}): "
result = true
- if block_given?
+ if block_given? or debug
mail = fetch_mail message_id
- result = yield(mail)
- verbose.print "(given filter result: #{result.inspect}) "
+
+ debug.call(mail) if debug
+
+ if block_given?
+ result = yield(mail)
+ verbose.print "(given filter result: #{result.inspect}) "
+ end
end
if result
puts operation.call(message_id)
else
- puts "ignored".yellow
+ puts "ignored".green
end
end
+
+ ensure
+ expunge
end
+ # @note We use "BODY.PEEK[]" to avoid setting the \Seen flag.
def fetch_mail message_id
- msg = @imap.fetch(message_id, 'RFC822')[0].attr['RFC822']
+ msg = @imap.fetch(message_id, 'BODY.PEEK[]').first.attr['BODY[]']
Mail.read_from_string msg
end
def search query
unless [Array, String].any? { |type| query.is_a? type }
- raise ArgumentError, "query must be either a string holding the entire search string, or a single-dimension array of search keywords and arguments"
+ raise TypeError, "query must be either a string holding the entire search string, or a single-dimension array of search keywords and arguments"
end
messages = @imap.search query
- puts "Query: #{query.inspect}: #{messages.count} results".cyan
+ puts "Query on #{mailbox}: #{query.inspect}: #{messages.count} results".cyan
messages
end
def verbose
@verbose ||= if @settings.verbose
$stdout
else
# anonymous null object
Class.new do
- def method_missing(*args, &block)
+ def method_missing(*)
nil
end
end.new
end
end