From: Sebastian Spaeth Date: Thu, 16 Jun 2011 12:41:02 +0000 (+0200) Subject: Implement Message.tags_to_maildir_flags X-Git-Tag: debian/0.6_254~26 X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=commitdiff_plain;h=d8c0e0c72dd19b50d51f07c70b880f21d69c2590;hp=b4049316cc3bc933453268ed8d3e89b1ee0098a1;ds=sidebyside Implement Message.tags_to_maildir_flags and also maildir_flags_to_tags. The methods will be invoked by db.add_message() and also (if not overridden via function parameter) by add|remove_tag and remove_all_tags. Documentation on the usage has been updated. Signed-off-by: Sebastian Spaeth --- diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 7f0091de..9016f0ae 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -273,6 +273,9 @@ class Database(object): notmuch database will reference the filename, and will not copy the entire contents of the file. + If the message contains Maildir flags, we will -depending on the + notmuch configuration- sync those tags to initial notmuch tags. + :returns: On success, we return 1) a :class:`Message` object that can be used for things @@ -310,11 +313,12 @@ class Database(object): filename, byref(msg_p)) - if not status in [STATUS.SUCCESS,STATUS.DUPLICATE_MESSAGE_ID]: + if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: raise NotmuchError(status) - #construct Message() and return + #construct Message(), sync initial tags from Maildir flags and return msg = Message(msg_p, self) + msg.maildir_flags_to_tags() return (msg, status) def remove_message(self, filename): diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 950d632a..8944af42 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth ' """ -from ctypes import c_char_p, c_void_p, c_long, c_uint +from ctypes import c_char_p, c_void_p, c_long, c_uint, c_int from datetime import date from notmuch.globals import nmlib, STATUS, NotmuchError, Enum from notmuch.tag import Tags @@ -268,6 +268,14 @@ class Message(object): _get_header = nmlib.notmuch_message_get_header _get_header.restype = c_char_p + """notmuch_status_t ..._maildir_flags_to_tags (notmuch_message_t *)""" + _tags_to_maildir_flags = nmlib.notmuch_message_tags_to_maildir_flags + _tags_to_maildir_flags.restype = c_int + + """notmuch_status_t ..._tags_to_maildir_flags (notmuch_message_t *)""" + _maildir_flags_to_tags = nmlib.notmuch_message_maildir_flags_to_tags + _maildir_flags_to_tags.restype = c_int + #Constants: Flags that can be set/get with set_flag FLAG = Enum(['MATCH']) @@ -461,13 +469,22 @@ class Message(object): raise NotmuchError(STATUS.NULL_POINTER) return Tags(tags_p, self) - def add_tag(self, tag): + def add_tag(self, tag, sync_maildir_flags=True): """Adds a tag to the given message Adds a tag to the current message. The maximal tag length is defined in the notmuch library and is currently 200 bytes. :param tag: String with a 'tag' to be added. + + :param sync_maildir_flags: If notmuch configuration is set to do + this, add maildir flags corresponding to notmuch tags. See + :meth:`tags_to_maildir_flags`. Use False if you want to + add/remove many tags on a message without having to + physically rename the file every time. Do note, that this + will do nothing when a message is frozen, as tag changes + will not be committed to the database yet. + :returns: STATUS.SUCCESS if the tag was successfully added. Raises an exception otherwise. :exception: :exc:`NotmuchError`. They have the following meaning: @@ -488,19 +505,29 @@ class Message(object): status = nmlib.notmuch_message_add_tag (self._msg, tag) - if STATUS.SUCCESS == status: - # return on success - return status + # bail out on failure + if status != STATUS.SUCCESS: + raise NotmuchError(status) - raise NotmuchError(status) + if sync_maildir_flags: + self.tags_to_maildir_flags() + return STATUS.SUCCESS - def remove_tag(self, tag): + def remove_tag(self, tag, sync_maildir_flags=True): """Removes a tag from the given message If the message has no such tag, this is a non-operation and will report success anyway. :param tag: String with a 'tag' to be removed. + :param sync_maildir_flags: If notmuch configuration is set to do + this, add maildir flags corresponding to notmuch tags. See + :meth:`tags_to_maildir_flags`. Use False if you want to + add/remove many tags on a message without having to + physically rename the file every time. Do note, that this + will do nothing when a message is frozen, as tag changes + will not be committed to the database yet. + :returns: STATUS.SUCCESS if the tag was successfully removed or if the message had no such tag. Raises an exception otherwise. @@ -521,19 +548,30 @@ class Message(object): raise NotmuchError(STATUS.NOT_INITIALIZED) status = nmlib.notmuch_message_remove_tag(self._msg, tag) + # bail out on error + if status != STATUS.SUCCESS: + raise NotmuchError(status) - if STATUS.SUCCESS == status: - # return on success - return status + if sync_maildir_flags: + self.tags_to_maildir_flags() + return STATUS.SUCCESS - raise NotmuchError(status) - def remove_all_tags(self): + + def remove_all_tags(self, sync_maildir_flags=True): """Removes all tags from the given message. See :meth:`freeze` for an example showing how to safely replace tag values. + :param sync_maildir_flags: If notmuch configuration is set to do + this, add maildir flags corresponding to notmuch tags. See + :meth:`tags_to_maildir_flags`. Use False if you want to + add/remove many tags on a message without having to + physically rename the file every time. Do note, that this + will do nothing when a message is frozen, as tag changes + will not be committed to the database yet. + :returns: STATUS.SUCCESS if the tags were successfully removed. Raises an exception otherwise. :exception: :exc:`NotmuchError`. They have the following meaning: @@ -549,11 +587,13 @@ class Message(object): status = nmlib.notmuch_message_remove_all_tags(self._msg) - if STATUS.SUCCESS == status: - # return on success - return status + # bail out on error + if status != STATUS.SUCCESS: + raise NotmuchError(status) - raise NotmuchError(status) + if sync_maildir_flags: + self.tags_to_maildir_flags() + return STATUS.SUCCESS def freeze(self): """Freezes the current state of 'message' within the database @@ -571,10 +611,11 @@ class Message(object): have a given set of tags might look like this:: msg.freeze() - msg.remove_all_tags() + msg.remove_all_tags(False) for tag in new_tags: - msg.add_tag(tag) + msg.add_tag(tag, False) msg.thaw() + msg.tags_to_maildir_flags() With freeze/thaw used like this, the message in the database is guaranteed to have either the full set of original tag values, or @@ -646,6 +687,61 @@ class Message(object): """(Not implemented)""" return self.get_flag(Message.FLAG.MATCH) + def tags_to_maildir_flags(self): + """Synchronize notmuch tags to file Maildir flags + + 'D' if the message has the "draft" tag + 'F' if the message has the "flagged" tag + 'P' if the message has the "passed" tag + 'R' if the message has the "replied" tag + 'S' if the message does not have the "unread" tag + + Any existing flags unmentioned in the list above will be + preserved in the renaming. + + Also, if this filename is in a directory named "new", rename it + to be within the neighboring directory named "cur". + + Usually, you do not need to call this manually as + tag changing methods should be implicitly calling it. + + :returns: a :class:`STATUS`. In short, you want to see + notmuch.STATUS.SUCCESS here. See there for details.""" + if self._msg is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + status = Message._tags_to_maildir_flags(self._msg) + + def maildir_flags_to_tags(self): + """Synchronize file Maildir flags to notmuch tags + + Flag Action if present + ---- ----------------- + 'D' Adds the "draft" tag to the message + 'F' Adds the "flagged" tag to the message + 'P' Adds the "passed" tag to the message + 'R' Adds the "replied" tag to the message + 'S' Removes the "unread" tag from the message + + For each flag that is not present, the opposite action + (add/remove) is performed for the corresponding tags. If there + are multiple filenames associated with this message, the flag is + considered present if it appears in one or more filenames. (That + is, the flags from the multiple filenames are combined with the + logical OR operator.) + + Usually, you do not need to call this manually as + :meth:`Database.add_message` implicitly calls it. + + :returns: a :class:`STATUS`. In short, you want to see + notmuch.STATUS.SUCCESS here. See there for details.""" + if self._msg is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + status = Message._tags_to_maildir_flags(self._msg) + + def __repr__(self): + """Represent a Message() object by str()""" + return self.__str__() + def __str__(self): """A message() is represented by a 1-line summary""" msg = {} @@ -653,8 +749,8 @@ class Message(object): msg['tags'] = str(self.get_tags()) msg['date'] = date.fromtimestamp(self.get_date()) replies = self.get_replies() - msg['replies'] = len(replies) if replies is not None else -1 - return "%(from)s (%(date)s) (%(tags)s) (%(replies)d) replies" % (msg) + msg['replies'] = len(replies) if replies is not None else 0 + return "%(from)s (%(date)s) (%(tags)s) %(replies)d replies" % (msg) def get_message_parts(self):