def poll_from source, opts={}
    debug "trying to acquire poll lock for: #{source}..."
    if source.try_lock
      begin
        source.poll do |sym, args|
          case sym
          when :add
            m = Message.build_from_source source, args[:info]
            old_m = Index.build_message m.id
            m.labels += args[:labels]
            m.labels.delete :inbox  if source.archived?
            m.labels.delete :unread if source.read?
            m.labels.delete :unread if m.source_marked_read? # preserve read status if possible
            m.labels.each { |l| LabelManager << l }
            m.labels = old_m.labels + (m.labels - [:unread, :inbox]) if old_m
            m.locations = old_m.locations + m.locations if old_m
            HookManager.run "before-add-message", :message => m
            yield :add, m, old_m, args[:progress] if block_given?
            Index.sync_message m, true

            if Index.message_joining_killed? m
              m.labels += [:killed]
              Index.sync_message m, true
            end

            ## We need to add or unhide the message when it either did not exist
            ## before at all or when it was updated. We do *not* add/unhide when
            ## the same message was found at a different location
            if old_m
              UpdateManager.relay self, :updated, m
            elsif !old_m or not old_m.locations.member? m.location
              UpdateManager.relay self, :added, m
            end
          when :delete
            Index.each_message({:location => [source.id, args[:info]]}, false) do |m|
              m.locations.delete Location.new(source, args[:info])
              Index.sync_message m, false
              if m.locations.size == 0
                yield :delete, m, [source,args[:info]], args[:progress] if block_given?
                Index.delete m.id
                UpdateManager.relay self, :location_deleted, m
              end
            end
          when :update
            Index.each_message({:location => [source.id, args[:old_info]]}, false) do |m|
              old_m = Index.build_message m.id
              m.locations.delete Location.new(source, args[:old_info])
              m.locations.push Location.new(source, args[:new_info])
              ## Update labels that might have been modified remotely
              m.labels -= source.supported_labels?
              m.labels += args[:labels]
              yield :update, m, old_m if block_given?
              Index.sync_message m, true
              UpdateManager.relay self, :updated, m
            end
          end
        end

      rescue SourceError => e
        warn "problem getting messages from #{source}: #{e.message}"

      ensure
        source.go_idle
        source.unlock
      end
    else
      debug "source #{source} is already being polled."
    end
  end
def poll_from source, opts={}
    debug "trying to acquire poll lock for: #{source}..."
    if source.try_lock
      begin
        source.poll do |sym, args|
          case sym
          when :add
            m = Message.build_from_source source, args[:info]
            old_m = Index.build_message m.id
            m.labels += args[:labels]
            m.labels.delete :inbox  if source.archived?
            m.labels.delete :unread if source.read?
            m.labels.delete :unread if m.source_marked_read? # preserve read status if possible
            m.labels.each { |l| LabelManager << l }
            m.labels = old_m.labels + (m.labels - [:unread, :inbox]) if old_m
            m.locations = old_m.locations + m.locations if old_m
            HookManager.run "before-add-message", :message => m
            yield :add, m, old_m, args[:progress] if block_given?
            Index.sync_message m, true

            if Index.message_joining_killed? m
              m.labels += [:killed]
              Index.sync_message m, true
            end

            ## We need to add or unhide the message when it either did not exist
            ## before at all or when it was updated. We do *not* add/unhide when
            ## the same message was found at a different location
            if old_m
              UpdateManager.relay self, :updated, m
            elsif !old_m or not old_m.locations.member? m.location
              UpdateManager.relay self, :added, m
            end
          when :delete
            Index.each_message({:location => [source.id, args[:info]]}, false) do |m|
              m.locations.delete Location.new(source, args[:info])
              Index.sync_message m, false
              if m.locations.size == 0
                yield :delete, m, [source,args[:info]], args[:progress] if block_given?
                Index.delete m.id
                UpdateManager.relay self, :location_deleted, m
              end
            end
          when :update
            Index.each_message({:location => [source.id, args[:old_info]]}, false) do |m|
              old_m = Index.build_message m.id
              m.locations.delete Location.new(source, args[:old_info])
              m.locations.push Location.new(source, args[:new_info])
              ## Update labels that might have been modified remotely
              m.labels -= source.supported_labels?
              m.labels += args[:labels]
              yield :update, m, old_m if block_given?
              Index.sync_message m, true
              UpdateManager.relay self, :updated, m
            end
          end
        end

      rescue SourceError => e
        warn "problem getting messages from #{source}: #{e.message}"

      ensure
        source.go_idle
        source.unlock
      end
    else
      debug "source #{source} is already being polled."
    end
  end
like Source#poll, but yields successive Message objects, which have their
 labels and locations set correctly. The Messages are saved to or removed
 from the index after being yielded.