lib/imap_guard/guard.rb in imap_guard-0.0.1 vs lib/imap_guard/guard.rb in imap_guard-0.0.2
- old
+ new
@@ -1,71 +1,123 @@
require 'net/imap'
-require 'mail'
require 'ostruct'
+require 'mail'
+require 'colored'
module IMAPGuard
class Guard
+ attr_reader :settings
+
def initialize settings
- @settings = OpenStruct.new(settings).freeze
+ self.settings = settings
+ end
- # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/imap/rdoc/Net/IMAP.html#method-c-new
+ # @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/imap/rdoc/Net/IMAP.html#method-c-new
+ 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
def select mailbox
if @settings.read_only
@imap.examine(mailbox) # open in read-only
else
@imap.select(mailbox) # open in read-write
end
end
- def delete query
- unless query.is_a? String
- if query.respond_to? :to_s
- query = query.to_s
- else
- raise ArgumentError, "query must provide #to_s"
- end
- end
+ # @param mailbox Destination mailbox
+ 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
+ }
+ process query, operation, &filter
+ end
- messages = @imap.search query
- count = messages.size
- puts "Query: #{query.inspect}: #{count} results"
+ def delete query, &filter
+ operation = lambda { |message_id|
+ @imap.store(message_id, "+FLAGS", [:Deleted])
+ 'deleted'.red
+ }
+ process query, operation, &filter
+ end
- counter = 0
- messages.each do |message_id|
- counter += 1
- # puts message_id
- mail = nil
+ def expunge
+ @imap.expunge
+ end
+
+ def close
+ puts "Expunging deleted messages and closing mailbox..."
+ @imap.close
+ 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}): "
+
+ result = true
if block_given?
- msg = @imap.fetch(message_id, 'RFC822')[0].attr['RFC822']
- mail = Mail.read_from_string msg
- result = yield mail
- if result
- # puts "Given filter matched"
- else
- # puts "Given filter returned falsy"
- next
- end
+ mail = fetch_mail message_id
+ result = yield(mail)
+ verbose.print "(given filter result: #{result.inspect}) "
end
- print "Deleting UID #{message_id} (#{counter}/#{count})"
- print " (DRY-RUN)" if @settings.read_only
- if mail
- puts ": #{mail.subject} (#{mail.body.to_s.length})"
+ if result
+ puts operation.call(message_id)
else
- puts
+ puts "ignored".yellow
end
- @imap.store(message_id, "+FLAGS", [:Deleted])
end
end
- def close
- puts "Expunging deleted messages and closing mailbox..."
- # p imap.expunge
- @imap.close
+ def fetch_mail message_id
+ msg = @imap.fetch(message_id, 'RFC822')[0].attr['RFC822']
+ 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"
+ end
+
+ messages = @imap.search query
+ puts "Query: #{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)
+ nil
+ end
+ end.new
+ end
+ end
+
+ def settings= settings
+ required = %w(host port username password).map!(&:to_sym)
+ missing = required - settings.keys
+ raise ArgumentError, "Missing settings: #{missing}" unless missing.empty?
+
+ optional = %w(read_only verbose).map!(&:to_sym)
+ unknown = settings.keys - required - optional
+ raise ArgumentError, "Unknown settings: #{unknown}" unless unknown.empty?
+
+ @settings = OpenStruct.new(settings).freeze
+ puts "DRY-RUN MODE ENABLED".yellow.bold.reversed if @settings.read_only
end
end
end