lib/gmail/message.rb in gmail-0.4.2 vs lib/gmail/message.rb in gmail-0.5.0
- old
+ new
@@ -1,135 +1,169 @@
module Gmail
class Message
+ PREFETCH_ATTRS = ["UID", "ENVELOPE", "BODY.PEEK[]", "FLAGS", "X-GM-LABELS", "X-GM-MSGID", "X-GM-THRID"]
+
# Raised when given label doesn't exists.
- class NoLabelError < Exception; end
-
- attr_reader :uid
-
- def initialize(mailbox, uid)
+ class NoLabelError < Exception; end
+
+ def initialize(mailbox, uid, _attrs = nil)
@uid = uid
@mailbox = mailbox
- @gmail = mailbox.instance_variable_get("@gmail") if mailbox
+ @gmail = mailbox.instance_variable_get("@gmail") if mailbox # UGLY
+ @_attrs = _attrs
end
-
- def labels
- @gmail.conn.uid_fetch(uid, "X-GM-LABELS")[0].attr["X-GM-LABELS"]
- end
-
+
def uid
- @uid ||= @gmail.conn.uid_search(['HEADER', 'Message-ID', message_id])[0]
+ @uid ||= fetch("UID")
end
-
+
+ def msg_id
+ @msg_id ||= fetch("X-GM-MSGID")
+ end
+ alias_method :message_id, :msg_id
+
+ def thr_id
+ @thr_id ||= fetch("X-GM-THRID")
+ end
+ alias_method :thread_id, :thr_id
+
+ def envelope
+ @envelope ||= fetch("ENVELOPE")
+ end
+
+ def message
+ @message ||= Mail.new(fetch("BODY[]"))
+ end
+ alias_method :raw_message, :message
+
+ def flags
+ @flags ||= fetch("FLAGS")
+ end
+
+ def labels
+ @labels ||= fetch("X-GM-LABELS")
+ end
+
# Mark message with given flag.
def flag(name)
- !!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "+FLAGS", [name]) }
+ !!@gmail.mailbox(@mailbox.name) do
+ @gmail.conn.uid_store(uid, "+FLAGS", [name])
+ clear_cached_attributes
+ end
end
-
- # Unmark message.
+
+ # Unmark message.
def unflag(name)
- !!@gmail.mailbox(@mailbox.name) { @gmail.conn.uid_store(uid, "-FLAGS", [name]) }
+ !!@gmail.mailbox(@mailbox.name) do
+ @gmail.conn.uid_store(uid, "-FLAGS", [name])
+ clear_cached_attributes
+ end
end
-
- # Do commonly used operations on message.
+
+ # Do commonly used operations on message.
def mark(flag)
case flag
- when :read then read!
- when :unread then unread!
- when :deleted then delete!
- when :spam then spam!
+ when :read then read!
+ when :unread then unread!
+ when :deleted then delete!
+ when :spam then spam!
else
flag(flag)
end
end
-
- # Mark this message as a spam.
- def spam!
- move_to('[Gmail]/Spam')
+
+ # Check whether message is read
+ def read?
+ flags.include?(:Seen)
end
-
+
# Mark as read.
def read!
flag(:Seen)
end
-
+
# Mark as unread.
def unread!
unflag(:Seen)
end
-
+
+ # Check whether message is starred
+ def starred?
+ flags.include?(:Flagged)
+ end
+
# Mark message with star.
def star!
- flag('[Gmail]/Starred')
+ flag(:Flagged)
end
-
+
# Remove message from list of starred.
def unstar!
- unflag('[Gmail]/Starred')
+ unflag(:Flagged)
end
-
- # Move to trash / bin.
- def delete!
- @mailbox.messages.delete(uid)
- flag(:deleted)
- # For some, it's called "Trash", for others, it's called "Bin". Support both.
- trash = @gmail.labels.exist?('[Gmail]/Bin') ? '[Gmail]/Bin' : '[Gmail]/Trash'
- move_to(trash) unless %w[[Gmail]/Spam [Gmail]/Bin [Gmail]/Trash].include?(@mailbox.name)
+ # Marking as spam is done by adding the `\Spam` label. To undo this,
+ # you just re-apply the `\Inbox` label (see `#unspam!`)
+ def spam!
+ add_label("\\Spam")
end
- # Archive this message.
+ # Deleting is done by adding the `\Trash` label. To undo this,
+ # you just re-apply the `\Inbox` label (see `#undelete!`)
+ def delete!
+ add_label("\\Trash")
+ end
+
+ # Archiving is done by adding the `\Trash` label. To undo this,
+ # you just re-apply the `\Inbox` label (see `#unarchive!`)
def archive!
- move_to('[Gmail]/All Mail')
+ remove_label("\\Inbox")
end
-
- # Move to given box and delete from others.
- def move_to(name, from=nil)
- label(name, from)
- delete! if !%w[[Gmail]/Bin [Gmail]/Trash].include?(name)
+
+ def unarchive!
+ add_label("\\Inbox")
end
- alias :move :move_to
-
- # Move message to given and delete from others. When given mailbox doesn't
- # exist then it will be automaticaly created.
- def move_to!(name, from=nil)
- label!(name, from) && delete!
+ alias_method :unspam!, :unarchive!
+ alias_method :undelete!, :unarchive!
+
+ # Move to given box and delete from others.
+ # Apply a given label and optionally remove one.
+ # TODO: We should probably deprecate this method. It doesn't really add a lot
+ # of value, especially since the concept of "moving" a message from one
+ # label to another doesn't totally make sense in the Gmail world.
+ def move_to(name, from = nil)
+ add_label(name)
+ remove_label(from) if from
end
- alias :move! :move_to!
-
- # Mark this message with given label. When given label doesn't exist then
- # it will raise <tt>NoLabelError</tt>.
- #
- # See also <tt>Gmail::Message#label!</tt>.
- def label(name, from=nil)
- @gmail.mailbox(Net::IMAP.encode_utf7(from || @mailbox.external_name)) { @gmail.conn.uid_copy(uid, Net::IMAP.encode_utf7(name)) }
- rescue Net::IMAP::NoResponseError
- raise NoLabelError, "Label '#{name}' doesn't exist!"
+ alias_method :move, :move_to
+ alias_method :move!, :move_to
+ alias_method :move_to!, :move_to
+
+ # Use Gmail IMAP Extensions to add a Label to an email
+ def add_label(name)
+ @gmail.mailbox(@mailbox.name) do
+ @gmail.conn.uid_store(uid, "+X-GM-LABELS", [Net::IMAP.encode_utf7(name.to_s)])
+ clear_cached_attributes
+ end
end
+ alias_method :label, :add_label
+ alias_method :label!, :add_label
+ alias_method :add_label!, :add_label
- # Mark this message with given label. When given label doesn't exist then
- # it will be automaticaly created.
- #
- # See also <tt>Gmail::Message#label</tt>.
- def label!(name, from=nil)
- label(name, from)
- rescue NoLabelError
- @gmail.labels.add(Net::IMAP.encode_utf7(name))
- label(name, from)
+ # Use Gmail IMAP Extensions to remove a Label from an email
+ def remove_label(name)
+ @gmail.mailbox(@mailbox.name) do
+ @gmail.conn.uid_store(uid, "-X-GM-LABELS", [Net::IMAP.encode_utf7(name.to_s)])
+ clear_cached_attributes
+ end
end
- alias :add_label :label!
- alias :add_label! :label!
-
- # Remove given label from this message.
- def remove_label!(name)
- move_to('[Gmail]/All Mail', name)
- end
- alias :delete_label! :remove_label!
-
+ alias_method :remove_label!, :remove_label
+
def inspect
- "#<Gmail::Message#{'0x%04x' % (object_id << 1)} mailbox=#{@mailbox.external_name}#{' uid='+@uid.to_s if @uid}#{' message_id='+@message_id.to_s if @message_id}>"
+ "#<Gmail::Message#{'0x%04x' % (object_id << 1)} mailbox=#{@mailbox.name}#{' uid=' + @uid.to_s if @uid}#{' message_id=' + @msg_id.to_s if @msg_id}>"
end
-
+
def method_missing(meth, *args, &block)
# Delegate rest directly to the message.
if envelope.respond_to?(meth)
envelope.send(meth, *args, &block)
elsif message.respond_to?(meth)
@@ -147,20 +181,27 @@
else
super(meth, *args, &block)
end
end
- def envelope
- @envelope ||= @gmail.mailbox(@mailbox.name) {
- @gmail.conn.uid_fetch(uid, "ENVELOPE")[0].attr["ENVELOPE"]
- }
+ private
+
+ def clear_cached_attributes
+ @_attrs = nil
+ @msg_id = nil
+ @thr_id = nil
+ @envelope = nil
+ @message = nil
+ @flags = nil
+ @labels = nil
end
-
- def message
- @message ||= Mail.new(@gmail.mailbox(@mailbox.name) {
- @gmail.conn.uid_fetch(uid, "RFC822")[0].attr["RFC822"] # RFC822
- })
- end
- alias_method :raw_message, :message
+ def fetch(value)
+ @_attrs ||= begin
+ @gmail.mailbox(@mailbox.name) do
+ @gmail.conn.uid_fetch(uid, PREFETCH_ATTRS)[0]
+ end
+ end
+ @_attrs.attr[value]
+ end
end # Message
end # Gmail