Object
Represents an IMAP mailbox.
Maximum number of message headers to fetch with a single IMAP command.
Regex to capture a Message-Id header.
Minimum time (in seconds) allowed between mailbox scans.
# File lib/larch/imap/mailbox.rb, line 16 def initialize(imap, name, delim, subscribed, *attr) raise ArgumentError, "must provide a Larch::IMAP instance" unless imap.is_a?(Larch::IMAP) @attr = attr.flatten @delim = delim @flags = [] @imap = imap @last_scan = nil @name = name @name_utf7 = Net::IMAP.encode_utf7(@name) @perm_flags = [] @subscribed = subscribed # Valid mailbox states are :closed (no mailbox open), :examined (mailbox # open and read-only), or :selected (mailbox open and read-write). @state = :closed # Create/update this mailbox in the database. mb_data = { :name => @name, :delim => @delim, :attr => @attr.map{|a| a.to_s }.join(','), :subscribed => @subscribed ? 1 : 0 } @db_mailbox = imap.db_account.mailboxes_dataset.filter(:name => @name).first if @db_mailbox @db_mailbox.update(mb_data) else @db_mailbox = Database::Mailbox.create(mb_data) imap.db_account.add_mailbox(@db_mailbox) end # Create private convenience methods (debug, info, warn, etc.) to make # logging easier. Logger::LEVELS.each_key do |level| next if Mailbox.private_method_defined?(level) Mailbox.class_eval do define_method(level) do |msg| Larch.log.log(level, "#{@imap.options[:log_label]} #{@name}: #{msg}") end private level end end end
Appends the specified Larch::IMAP::Message to this mailbox if it doesn't already exist. Returns true if the message was appended successfully, false if the message already exists in the mailbox.
# File lib/larch/imap/mailbox.rb, line 68 def append(message) raise ArgumentError, "must provide a Larch::IMAP::Message object" unless message.is_a?(Larch::IMAP::Message) return false if has_guid?(message.guid) @imap.safely do unless imap_select(!!@imap.options[:create_mailbox]) raise Larch::IMAP::Error, "mailbox cannot contain messages: #{@name}" end debug "appending message: #{message.guid}" @imap.conn.append(@name_utf7, message.rfc822, get_supported_flags(message.flags), message.internaldate) unless @imap.options[:dry_run] end true end
Deletes the message in this mailbox with the specified guid. Returns true on success, false on failure.
# File lib/larch/imap/mailbox.rb, line 87 def delete_message(guid) if @imap.quirks[:gmail] return false unless db_message = fetch_db_message(guid) debug "moving message to Gmail trash: #{guid}" @imap.safely { @imap.conn.uid_copy(db_message.uid, '[Gmail]/Trash') } && set_flags(guid, [:Deleted], true) else set_flags(guid, [:Deleted], true) end end
Iterates through messages in this mailbox, yielding a Larch::Database::Message object for each to the provided block.
# File lib/larch/imap/mailbox.rb, line 102 def each_db_message # :yields: db_message scan @db_mailbox.messages_dataset.all {|db_message| yield db_message } end
Iterates through messages in this mailbox, yielding the Larch message guid of each to the provided block.
# File lib/larch/imap/mailbox.rb, line 109 def each_guid # :yields: guid each_db_message {|db_message| yield db_message.guid } end
Iterates through mailboxes that are first-level children of this mailbox, yielding a Larch::IMAP::Mailbox object for each to the provided block.
# File lib/larch/imap/mailbox.rb, line 115 def each_mailbox # :yields: mailbox mailboxes.each {|mb| yield mb } end
Expunges this mailbox, permanently removing all messages with the Deleted flag.
# File lib/larch/imap/mailbox.rb, line 121 def expunge return false unless imap_select @imap.safely do debug "expunging deleted messages" @last_scan = nil @imap.conn.expunge unless @imap.options[:dry_run] end end
Returns a Larch::IMAP::Message struct representing the message with the specified Larch guid, or nil if the specified guid was not found in this mailbox.
# File lib/larch/imap/mailbox.rb, line 135 def fetch(guid, peek = false) scan unless db_message = fetch_db_message(guid) warning "message not found in local db: #{guid}" return nil end debug "#{peek ? 'peeking at' : 'fetching'} message: #{guid}" imap_uid_fetch([db_message.uid], [(peek ? 'BODY.PEEK[]' : 'BODY[]'), 'FLAGS', 'INTERNALDATE', 'ENVELOPE']) do |fetch_data| data = fetch_data.first check_response_fields(data, 'BODY[]', 'FLAGS', 'INTERNALDATE', 'ENVELOPE') return Message.new(guid, data.attr['ENVELOPE'], data.attr['BODY[]'], data.attr['FLAGS'], Time.parse(data.attr['INTERNALDATE'])) end warning "message not found on server: #{guid}" return nil end
Returns a Larch::Database::Message object representing the message with the specified Larch guid, or nil if the specified guide was not found in this mailbox.
# File lib/larch/imap/mailbox.rb, line 161 def fetch_db_message(guid) scan @db_mailbox.messages_dataset.filter(:guid => guid).first end
Returns true if a message with the specified Larch guid exists in this mailbox, false otherwise.
# File lib/larch/imap/mailbox.rb, line 168 def has_guid?(guid) scan @db_mailbox.messages_dataset.filter(:guid => guid).count > 0 end
Gets the number of messages in this mailbox.
# File lib/larch/imap/mailbox.rb, line 174 def length scan @db_mailbox.messages_dataset.count end
Returns an Array of Larch::IMAP::Mailbox objects representing mailboxes that are first-level children of this mailbox.
# File lib/larch/imap/mailbox.rb, line 182 def mailboxes return [] if @attr.include?(:Noinferiors) all = @imap.safely{ @imap.conn.list('', "#{@name_utf7}#{@delim}%") } || [] subscribed = @imap.safely{ @imap.conn.lsub('', "#{@name_utf7}#{@delim}%") } || [] all.map{|mb| Mailbox.new(@imap, mb.name, mb.delim, subscribed.any?{|s| s.name == mb.name}, mb.attr) } end
Same as fetch, but doesn't mark the message as seen.
# File lib/larch/imap/mailbox.rb, line 193 def peek(guid) fetch(guid, true) end
Resets the mailbox state.
# File lib/larch/imap/mailbox.rb, line 198 def reset @state = :closed end
Fetches message headers from this mailbox.
# File lib/larch/imap/mailbox.rb, line 203 def scan now = Time.now.to_i return if @last_scan && (now - @last_scan) < SCAN_INTERVAL first_scan = @last_scan.nil? @last_scan = now # Compare the mailbox's current status with its last known status. begin return unless status = imap_status('MESSAGES', 'UIDNEXT', 'UIDVALIDITY') rescue Error => e return if @imap.options[:create_mailbox] raise end flag_range = nil full_range = nil if @db_mailbox.uidvalidity && @db_mailbox.uidnext && status['UIDVALIDITY'] == @db_mailbox.uidvalidity # The UIDVALIDITY is the same as what we saw last time we scanned this # mailbox, which means that all the existing messages in the database are # still valid. We only need to request headers for new messages. # # If this is the first scan of this mailbox during this Larch session, # then we'll also update the flags of all messages in the mailbox. flag_range = 1...@db_mailbox.uidnext if first_scan full_range = @db_mailbox.uidnext...status['UIDNEXT'] else # The UIDVALIDITY has changed or this is the first time we've scanned this # mailbox (ever). Either way, all existing messages in the database are no # longer valid, so we have to throw them out and re-request everything. @db_mailbox.remove_all_messages full_range = 1...status['UIDNEXT'] end @db_mailbox.update(:uidvalidity => status['UIDVALIDITY']) need_flag_scan = flag_range && flag_range.max && flag_range.min && flag_range.max - flag_range.min > 0 need_full_scan = full_range && full_range.max && full_range.min && full_range.max - full_range.min > 0 return unless need_flag_scan || need_full_scan fetch_flags(flag_range) if need_flag_scan if need_full_scan fetch_headers(full_range, { :progress_start => @db_mailbox.messages_dataset.count + 1, :progress_total => status['MESSAGES'] }) end @db_mailbox.update(:uidnext => status['UIDNEXT']) return end
Sets the IMAP flags for the message specified by guid. flags should be an array of symbols for standard flags, strings for custom flags.
If merge is true, the specified flags will be merged with the message's existing flags. Otherwise, all existing flags will be cleared and replaced with the specified flags.
Note that the :Recent flag cannot be manually set or removed.
Returns true on success, false on failure.
# File lib/larch/imap/mailbox.rb, line 274 def set_flags(guid, flags, merge = false) raise ArgumentError, "flags must be an Array" unless flags.is_a?(Array) return false unless db_message = fetch_db_message(guid) merged_flags = merge ? (db_message.flags + flags).uniq : flags supported_flags = get_supported_flags(merged_flags) return true if db_message.flags == supported_flags return false if !imap_select @imap.safely { @imap.conn.uid_store(db_message.uid, 'FLAGS.SILENT', supported_flags) } unless @imap.options[:dry_run] true end
Subscribes to this mailbox.
# File lib/larch/imap/mailbox.rb, line 291 def subscribe(force = false) return false if subscribed? && !force @imap.safely { @imap.conn.subscribe(@name_utf7) } unless @imap.options[:dry_run] @subscribed = true @db_mailbox.update(:subscribed => 1) true end
Returns true if this mailbox is subscribed, false otherwise.
# File lib/larch/imap/mailbox.rb, line 302 def subscribed? @subscribed end
Unsubscribes from this mailbox.
# File lib/larch/imap/mailbox.rb, line 307 def unsubscribe(force = false) return false unless subscribed? || force @imap.safely { @imap.conn.unsubscribe(@name_utf7) } unless @imap.options[:dry_run] @subscribed = false @db_mailbox.update(:subscribed => 0) true end
Generated with the Darkfish Rdoc Generator 2.