def rename(self, oldname, newname): """ Renames a mailbox. :param oldname: old name of the mailbox :type oldname: str :param newname: new name of the mailbox :type newname: str """ oldname = normalize_mailbox(oldname) newname = normalize_mailbox(newname) def rename_inferiors((inferiors, mailboxes)): rename_deferreds = [] inferiors = [ (o, o.replace(oldname, newname, 1)) for o in inferiors] for (old, new) in inferiors: if new in mailboxes: raise imap4.MailboxCollision(repr(new)) for (old, new) in inferiors: d = self.account.rename_mailbox(old, new) rename_deferreds.append(d) d1 = defer.gatherResults(rename_deferreds, consumeErrors=True) return d1 d1 = self._inferiorNames(oldname) d2 = self.account.list_all_mailbox_names() d = defer.gatherResults([d1, d2]) d.addCallback(rename_inferiors) return d
def listMailboxes(self, ref, wildcard): """ List the mailboxes. from rfc 3501: returns a subset of names from the complete set of all names available to the client. Zero or more untagged LIST replies are returned, containing the name attributes, hierarchy delimiter, and name. :param ref: reference name :type ref: str :param wildcard: mailbox name with possible wildcards :type wildcard: str """ wildcard = imap4.wildcardToRegexp(wildcard, '/') def get_list(mboxes, mboxes_names): return zip(mboxes_names, mboxes) def filter_inferiors(ref): mboxes = [mbox for mbox in ref if wildcard.match(mbox)] mbox_d = defer.gatherResults([self.getMailbox(m) for m in mboxes]) mbox_d.addCallback(get_list, mboxes) return mbox_d d = self._inferiorNames(normalize_mailbox(ref)) d.addCallback(filter_inferiors) return d
def select(self, name, readwrite=1): """ Selects a mailbox. :param name: the mailbox to select :type name: str :param readwrite: 1 for readwrite permissions. :type readwrite: int :rtype: IMAPMailbox """ name = normalize_mailbox(name) def check_it_exists(mailboxes): if name not in mailboxes: logger.warning("SELECT: No such mailbox!") return None return name def set_selected(_): self.selected = name def get_collection(name): if name is None: return None return self.account.get_collection_by_mailbox(name) d = self.account.list_all_mailbox_names() d.addCallback(check_it_exists) d.addCallback(get_collection) d.addCallback(partial( self._return_mailbox_from_collection, readwrite=readwrite)) return d
def addMailbox(self, name, creation_ts=None): """ Add a mailbox to the account. :param name: the name of the mailbox :type name: str :param creation_ts: an optional creation timestamp to be used as mailbox id. A timestamp will be used if no one is provided. :type creation_ts: int :returns: a Deferred that will contain the document if successful. :rtype: defer.Deferred """ name = normalize_mailbox(name) # FIXME --- return failure instead of AssertionError # See AccountTestCase... leap_assert(name, "Need a mailbox name to create a mailbox") def check_it_does_not_exist(mailboxes): if name in mailboxes: raise imap4.MailboxCollision, repr(name) return mailboxes d = self.account.list_all_mailbox_names() d.addCallback(check_it_does_not_exist) d.addCallback(lambda _: self.account.add_mailbox( name, creation_ts=creation_ts)) d.addCallback(lambda _: self.account.get_collection_by_mailbox(name)) d.addCallback(self._return_mailbox_from_collection) return d
def get_or_create_mbox(self, store, name): """ Get the mailbox with the given name, or create one if it does not exist. :param store: instance of Soledad :param name: the name of the mailbox :type name: str """ index = indexes.TYPE_MBOX_IDX mbox = normalize_mailbox(name) return MailboxWrapper.get_or_create(store, index, mbox)
def delete(self, name, force=False): """ Deletes a mailbox. :param name: the mailbox to be deleted :type name: str :param force: if True, it will not check for noselect flag or inferior names. use with care. :type force: bool :rtype: Deferred """ name = normalize_mailbox(name) _mboxes = None def check_it_exists(mailboxes): global _mboxes _mboxes = mailboxes if name not in mailboxes: raise imap4.MailboxException("No such mailbox: %r" % name) def get_mailbox(_): return self.getMailbox(name) def destroy_mailbox(mbox): return mbox.destroy() def check_can_be_deleted(mbox): global _mboxes # See if this box is flagged \Noselect mbox_flags = mbox.getFlags() if MessageFlags.NOSELECT_FLAG in mbox_flags: # Check for hierarchically inferior mailboxes with this one # as part of their root. for others in _mboxes: if others != name and others.startswith(name): raise imap4.MailboxException( "Hierarchically inferior mailboxes " "exist and \\Noselect is set") return mbox d = self.account.list_all_mailbox_names() d.addCallback(check_it_exists) d.addCallback(get_mailbox) if not force: d.addCallback(check_can_be_deleted) d.addCallback(destroy_mailbox) return d
def create(self, pathspec): """ Create a new mailbox from the given hierarchical name. :param pathspec: The full hierarchical name of a new mailbox to create. If any of the inferior hierarchical names to this one do not exist, they are created as well. :type pathspec: str :return: A deferred that will fire with a true value if the creation succeeds. The deferred might fail with a MailboxException if the mailbox cannot be added. :rtype: Deferred """ def pass_on_collision(failure): failure.trap(imap4.MailboxCollision) return True def handle_collision(failure): failure.trap(imap4.MailboxCollision) if not pathspec.endswith('/'): return defer.succeed(False) else: return defer.succeed(True) def all_good(result): return all(result) paths = filter(None, normalize_mailbox(pathspec).split('/')) subs = [] sep = '/' for accum in range(1, len(paths)): partial_path = sep.join(paths[:accum]) d = self.addMailbox(partial_path) d.addErrback(pass_on_collision) subs.append(d) df = self.addMailbox(sep.join(paths)) df.addErrback(handle_collision) subs.append(df) d1 = defer.gatherResults(subs) d1.addCallback(all_good) return d1
def subscribe(self, name): """ Subscribe to this mailbox if not already subscribed. :param name: name of the mailbox :type name: str :rtype: Deferred """ name = normalize_mailbox(name) def set_subscribed(mbox): return mbox.collection.set_mbox_attr("subscribed", True) d = self.getMailbox(name) d.addCallback(set_subscribed) return d
def isSubscribed(self, name): """ Returns True if user is subscribed to this mailbox. :param name: the mailbox to be checked. :type name: str :rtype: Deferred (will fire with bool) """ name = normalize_mailbox(name) def get_subscribed(mbox): return mbox.collection.get_mbox_attr("subscribed") d = self.getMailbox(name) d.addCallback(get_subscribed) return d
def unsubscribe(self, name): """ Unsubscribe from this mailbox :param name: name of the mailbox :type name: str :rtype: Deferred """ # TODO should raise MailboxException if attempted to unsubscribe # from a mailbox that is not currently subscribed. # TODO factor out with subscribe method. name = normalize_mailbox(name) def set_unsubscribed(mbox): return mbox.collection.set_mbox_attr("subscribed", False) d = self.getMailbox(name) d.addCallback(set_unsubscribed) return d
def getMailbox(self, name): """ Return a Mailbox with that name, without selecting it. :param name: name of the mailbox :type name: str :returns: an IMAPMailbox instance :rtype: IMAPMailbox """ name = normalize_mailbox(name) def check_it_exists(mailboxes): if name not in mailboxes: raise imap4.MailboxException("No such mailbox: %r" % name) return True d = self.account.list_all_mailbox_names() d.addCallback(check_it_exists) d.addCallback(lambda _: self.account.get_collection_by_mailbox(name)) d.addCallback(self._return_mailbox_from_collection) return d