lib/gmail/mailbox.rb in gmail-0.6.0 vs lib/gmail/mailbox.rb in gmail-0.7.0

- old
+ new

@@ -1,175 +1,178 @@ -module Gmail - class Mailbox - MAILBOX_ALIASES = { - :all => ['ALL'], - :seen => ['SEEN'], - :unseen => ['UNSEEN'], - :read => ['SEEN'], - :unread => ['UNSEEN'], - :flagged => ['FLAGGED'], - :unflagged => ['UNFLAGGED'], - :starred => ['FLAGGED'], - :unstarred => ['UNFLAGGED'], - :deleted => ['DELETED'], - :undeleted => ['UNDELETED'], - :draft => ['DRAFT'], - :undrafted => ['UNDRAFT'] - } - - attr_reader :name - attr_reader :encoded_name - - def initialize(gmail, name = "INBOX") - @name = Net::IMAP.decode_utf7(name) - @encoded_name = Net::IMAP.encode_utf7(name) - @gmail = gmail - end - - def fetch_uids(*args) - args << :all if args.size == 0 - - if args.first.is_a?(Symbol) - search = MAILBOX_ALIASES[args.shift].dup - opts = args.first.is_a?(Hash) ? args.first : {} - - opts[:after] and search.concat ['SINCE', opts[:after].to_imap_date] - opts[:before] and search.concat ['BEFORE', opts[:before].to_imap_date] - opts[:on] and search.concat ['ON', opts[:on].to_imap_date] - opts[:from] and search.concat ['FROM', opts[:from]] - opts[:to] and search.concat ['TO', opts[:to]] - opts[:subject] and search.concat ['SUBJECT', opts[:subject]] - opts[:label] and search.concat ['LABEL', opts[:label]] - opts[:attachment] and search.concat ['HAS', 'attachment'] - opts[:search] and search.concat ['BODY', opts[:search]] - opts[:body] and search.concat ['BODY', opts[:body]] - opts[:uid] and search.concat ['UID', opts[:uid]] - opts[:gm] and search.concat ['X-GM-RAW', opts[:gm]] - opts[:query] and search.concat opts[:query] - - @gmail.mailbox(name) { - @gmail.conn.uid_search(search) - } - elsif args.first.is_a?(Hash) - fetch_uids(:all, args.first) - else - raise ArgumentError, "Invalid search criteria" - end - end - - # Returns list of emails which meets given criteria. - # - # ==== Examples - # - # gmail.inbox.emails(:all) - # gmail.inbox.emails(:unread, :from => "friend@gmail.com") - # gmail.inbox.emails(:all, :after => Time.now-(20*24*3600)) - # gmail.mailbox("Test").emails(:read) - # - # gmail.mailbox("Test") do |box| - # box.emails(:read) - # box.emails(:unread) do |email| - # ... do something with each email... - # end - # end - def emails(*args, &block) - fetch_uids(*args).collect do |uid| - message = Message.new(self, uid) - yield(message) if block_given? - message - end - end - alias :search :emails - alias :find :emails - - def emails_in_batches(*args, &block) - messages = Array.new - - uids = fetch_uids(*args) - if uids && uids.any? - uids.each_slice(100) do |slice| - @gmail.conn.uid_fetch(slice, Message::PREFETCH_ATTRS).each do |data| - message = Message.new(self, nil, data) - yield(message) if block_given? - messages << message - end - end - end - - messages - end - alias :search_in_batches :emails_in_batches - alias :find_in_batches :emails_in_batches - - # This is a convenience method that really probably shouldn't need to exist, - # but it does make code more readable, if seriously all you want is the count - # of messages. - # - # ==== Examples - # - # gmail.inbox.count(:all) - # gmail.inbox.count(:unread, :from => "friend@gmail.com") - # gmail.mailbox("Test").count(:all, :after => Time.now-(20*24*3600)) - def count(*args) - emails(*args).size - end - - # This permanently removes messages which are marked as deleted - def expunge - @gmail.mailbox(name) { @gmail.conn.expunge } - end - - def wait(options = {}, &block) - loop do - wait_once(options, &block) - end - end - - def wait_once(options = {}) - options[:idle_timeout] ||= 29 * 60 - - response = nil - loop do - complete_cond = @gmail.conn.new_cond - complete_now = false - - @gmail.conn.idle do |resp| - if resp.kind_of?(Net::IMAP::ContinuationRequest) && resp.data.text == 'idling' - Thread.new do - @gmail.conn.synchronize do - complete_cond.wait(options[:idle_timeout]) unless complete_now - @gmail.conn.idle_done - end - end - elsif resp.kind_of?(Net::IMAP::UntaggedResponse) && resp.name == 'EXISTS' - response = resp - - @gmail.conn.synchronize do - complete_now = true - complete_cond.signal - end - end - end - - break if response - end - - yield response if block_given? - - nil - end - - def inspect - "#<Gmail::Mailbox#{'0x%04x' % (object_id << 1)} name=#{name}>" - end - - def to_s - name - end - - MAILBOX_ALIASES.each_key { |mailbox| - define_method(mailbox) do |*args, &block| - emails(mailbox, *args, &block) - end - } - end # Message -end # Gmail +module Gmail + class Mailbox + MAILBOX_ALIASES = { + :all => ['ALL'], + :seen => ['SEEN'], + :unseen => ['UNSEEN'], + :read => ['SEEN'], + :unread => ['UNSEEN'], + :flagged => ['FLAGGED'], + :unflagged => ['UNFLAGGED'], + :starred => ['FLAGGED'], + :unstarred => ['UNFLAGGED'], + :deleted => ['DELETED'], + :undeleted => ['UNDELETED'], + :draft => ['DRAFT'], + :undrafted => ['UNDRAFT'] + }.freeze + + attr_reader :name + attr_reader :encoded_name + + def initialize(gmail, name = "INBOX") + @name = Net::IMAP.decode_utf7(name) + @encoded_name = Net::IMAP.encode_utf7(name) + @gmail = gmail + end + + def fetch_uids(*args) + args << :all if args.empty? + + if args.first.is_a?(Symbol) + search = MAILBOX_ALIASES[args.shift].dup + opts = args.first.is_a?(Hash) ? args.first : {} + + opts[:after] and search.concat ['SINCE', Net::IMAP.format_date(opts[:after])] + opts[:before] and search.concat ['BEFORE', Net::IMAP.format_date(opts[:before])] + opts[:on] and search.concat ['ON', opts[:on].to_imap_date] + opts[:from] and search.concat ['FROM', opts[:from]] + opts[:to] and search.concat ['TO', opts[:to]] + opts[:subject] and search.concat ['SUBJECT', opts[:subject]] + opts[:label] and search.concat ['LABEL', opts[:label]] + opts[:attachment] and search.concat ['HAS', 'attachment'] + opts[:search] and search.concat ['BODY', opts[:search]] + opts[:body] and search.concat ['BODY', opts[:body]] + opts[:uid] and search.concat ['UID', opts[:uid]] + opts[:gm] and search.concat ['X-GM-RAW', opts[:gm]] + opts[:message_id] and search.concat ['X-GM-MSGID', opts[:message_id].to_s] + opts[:query] and search.concat opts[:query] + + @gmail.mailbox(name) do + @gmail.conn.uid_search(search) + end + elsif args.first.is_a?(Hash) + fetch_uids(:all, args.first) + else + raise ArgumentError, "Invalid search criteria" + end + end + + # Returns list of emails which meets given criteria. + # + # ==== Examples + # + # gmail.inbox.emails(:all) + # gmail.inbox.emails(:unread, :from => "friend@gmail.com") + # gmail.inbox.emails(:all, :after => Time.now-(20*24*3600)) + # gmail.mailbox("Test").emails(:read) + # + # gmail.mailbox("Test") do |box| + # box.emails(:read) + # box.emails(:unread) do |email| + # ... do something with each email... + # end + # end + def emails(*args, &block) + fetch_uids(*args).collect do |uid| + message = Message.new(self, uid) + yield(message) if block_given? + message + end + end + alias :search :emails + alias :find :emails + + def emails_in_batches(*args, &block) + return [] unless uids.is_a?(Array) && uids.any? + + uids.each_slice(100).flat_map do |slice| + find_for_slice(slice, &block) + end + end + + alias :search_in_batches :emails_in_batches + alias :find_in_batches :emails_in_batches + + # This is a convenience method that really probably shouldn't need to exist, + # but it does make code more readable, if seriously all you want is the count + # of messages. + # + # ==== Examples + # + # gmail.inbox.count(:all) + # gmail.inbox.count(:unread, :from => "friend@gmail.com") + # gmail.mailbox("Test").count(:all, :after => Time.now-(20*24*3600)) + def count(*args) + emails(*args).size + end + + # This permanently removes messages which are marked as deleted + def expunge + @gmail.mailbox(name) { @gmail.conn.expunge } + end + + def wait(options = {}, &block) + loop do + wait_once(options, &block) + end + end + + def wait_once(options = {}) + options[:idle_timeout] ||= 29 * 60 + + response = nil + loop do + complete_cond = @gmail.conn.new_cond + complete_now = false + + @gmail.conn.idle do |resp| + if resp.is_a?(Net::IMAP::ContinuationRequest) && resp.data.text == 'idling' + Thread.new do + @gmail.conn.synchronize do + complete_cond.wait(options[:idle_timeout]) unless complete_now + @gmail.conn.idle_done + end + end + elsif resp.is_a?(Net::IMAP::UntaggedResponse) && resp.name == 'EXISTS' + response = resp + + @gmail.conn.synchronize do + complete_now = true + complete_cond.signal + end + end + end + + break if response + end + + yield response if block_given? + + nil + end + + def inspect + "#<Gmail::Mailbox#{'0x%04x' % (object_id << 1)} name=#{name}>" + end + + def to_s + name + end + + MAILBOX_ALIASES.each_key do |mailbox| + define_method(mailbox) do |*args, &block| + emails(mailbox, *args, &block) + end + end + + private + + def find_for_slice(slice, &block) + @gmail.conn.uid_fetch(slice, Message::PREFETCH_ATTRS).map do |data| + message = Message.new(self, nil, data) + yield(message) if block_given? + message + end + end + end # Message +end # Gmail