def get_collection(self, mbox_collection=True, mbox_name=None, mbox_uuid=None): """ Get a collection for tests. """ adaptor = SoledadMailAdaptor() store = self._soledad adaptor.store = store if mbox_collection: mbox_indexer = MailboxIndexer(store) mbox_name = mbox_name or "TestMbox" mbox_uuid = mbox_uuid or str(uuid.uuid4()) else: mbox_indexer = mbox_name = None def get_collection_from_mbox_wrapper(wrapper): wrapper.uuid = mbox_uuid return MessageCollection( adaptor, store, mbox_indexer=mbox_indexer, mbox_wrapper=wrapper) d = adaptor.initialize_store(store) if mbox_collection: d.addCallback(lambda _: mbox_indexer.create_table(mbox_uuid)) d.addCallback(lambda _: adaptor.get_or_create_mbox(store, mbox_name)) d.addCallback(get_collection_from_mbox_wrapper) return d
def get_lastuid(self, mbox): if isinstance(mbox, str): mbox = (yield defer.maybeDeferred(self.get_mbox, mbox))[0] indexer = MailboxIndexer(self.soledad) yield indexer.create_table(mbox.content['uuid']) last_uuid = yield indexer.get_last_uid(mbox.content['uuid']) defer.returnValue(last_uuid)
def __init__(self, store, ready_cb=None): self.store = store self.adaptor = self.adaptor_class() # this is a mapping to collection instances so that we always # return a reference to them instead of creating new ones. however, # being a dictionary of weakrefs values, they automagically vanish # from the dict when no hard refs is left to them (so they can be # garbage collected) this is important because the different wrappers # rely on several kinds of deferredlocks that are kept as class or # instance variables self._collection_mapping = weakref.WeakValueDictionary() self.mbox_indexer = MailboxIndexer(self.store) # This flag is only used from the imap service for the moment. # In the future, we should prevent any public method to continue if # this is set to True. Also, it would be good to plug to the # authentication layer. self.session_ended = False self.deferred_initialization = defer.Deferred() self._ready_cb = ready_cb self._init_d = self._initialize_storage() self._initialize_sync_hooks()
def __init__(self, store, ready_cb=None): self.store = store self.adaptor = self.adaptor_class() self.mbox_indexer = MailboxIndexer(self.store) # This flag is only used from the imap service for the moment. # In the future, we should prevent any public method to continue if # this is set to True. Also, it would be good to plug to the # authentication layer. self.session_ended = False self.deferred_initialization = defer.Deferred() self._ready_cb = ready_cb self._init_d = self._initialize_storage() self._initialize_sync_hooks()
class Account(object): """ Account is the top level abstraction to access collections of messages associated with a LEAP Mail Account. It primarily handles creation and access of Mailboxes, which will be the basic collection handled by traditional MUAs, but it can also handle other types of Collections (tag based, for instance). leap.mail.imap.IMAPAccount partially proxies methods in this class. """ # Adaptor is passed to the returned MessageCollections, so if you want to # use a different adaptor this is the place to change it, by subclassing # the Account class. adaptor_class = SoledadMailAdaptor def __init__(self, store, ready_cb=None): self.store = store self.adaptor = self.adaptor_class() # this is a mapping to collection instances so that we always # return a reference to them instead of creating new ones. however, # being a dictionary of weakrefs values, they automagically vanish # from the dict when no hard refs is left to them (so they can be # garbage collected) this is important because the different wrappers # rely on several kinds of deferredlocks that are kept as class or # instance variables self._collection_mapping = weakref.WeakValueDictionary() self.mbox_indexer = MailboxIndexer(self.store) # This flag is only used from the imap service for the moment. # In the future, we should prevent any public method to continue if # this is set to True. Also, it would be good to plug to the # authentication layer. self.session_ended = False self.deferred_initialization = defer.Deferred() self._ready_cb = ready_cb self._init_d = self._initialize_storage() self._initialize_sync_hooks() def _initialize_storage(self): def add_mailbox_if_none(mboxes): if not mboxes: return self.add_mailbox(INBOX_NAME) def finish_initialization(result): self.deferred_initialization.callback(None) if self._ready_cb is not None: self._ready_cb() d = self.adaptor.initialize_store(self.store) d.addCallback(lambda _: self.list_all_mailbox_names()) d.addCallback(add_mailbox_if_none) d.addCallback(finish_initialization) return d def callWhenReady(self, cb, *args, **kw): """ Execute the callback when the initialization of the Account is ready. Note that the callback will receive a first meaningless parameter. """ # TODO this should ignore the first parameter explicitely # lambda _: cb(*args, **kw) self.deferred_initialization.addCallback(cb, *args, **kw) return self.deferred_initialization # Sync hooks def _initialize_sync_hooks(self): soledad_sync_hooks.post_sync_uid_reindexer.set_account(self) def _teardown_sync_hooks(self): soledad_sync_hooks.post_sync_uid_reindexer.set_account(None) # # Public API Starts # def list_all_mailbox_names(self): def filter_names(mboxes): return [m.mbox for m in mboxes] d = self.get_all_mailboxes() d.addCallback(filter_names) return d def get_all_mailboxes(self): d = self.adaptor.get_all_mboxes(self.store) return d def add_mailbox(self, name, creation_ts=None): if creation_ts is None: # by default, we pass an int value # taken from the current time # we make sure to take enough decimals to get a unique # mailbox-uidvalidity. creation_ts = int(time.time() * 10E2) def set_creation_ts(wrapper): wrapper.created = creation_ts d = wrapper.update(self.store) d.addCallback(lambda _: wrapper) return d def create_uuid(wrapper): if not wrapper.uuid: wrapper.uuid = str(uuid.uuid4()) d = wrapper.update(self.store) d.addCallback(lambda _: wrapper) return d return wrapper def create_uid_table_cb(wrapper): d = self.mbox_indexer.create_table(wrapper.uuid) d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(set_creation_ts) d.addCallback(create_uuid) d.addCallback(create_uid_table_cb) return d def delete_mailbox(self, name): def delete_uid_table_cb(wrapper): d = self.mbox_indexer.delete_table(wrapper.uuid) d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(delete_uid_table_cb) d.addCallback( lambda wrapper: self.adaptor.delete_mbox(self.store, wrapper)) return d def rename_mailbox(self, oldname, newname): def _rename_mbox(wrapper): wrapper.mbox = newname d = wrapper.update(self.store) d.addCallback(lambda result: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, oldname) d.addCallback(_rename_mbox) return d # Get Collections def get_collection_by_mailbox(self, name): """ :rtype: deferred :return: a deferred that will fire with a MessageCollection """ collection = self._collection_mapping.get(name, None) if collection: return defer.succeed(collection) # imap select will use this, passing the collection to SoledadMailbox def get_collection_for_mailbox(mbox_wrapper): collection = MessageCollection( self.adaptor, self.store, self.mbox_indexer, mbox_wrapper) self._collection_mapping[name] = collection return collection d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(get_collection_for_mailbox) return d def get_collection_by_docs(self, docs): """ :rtype: MessageCollection """ # get a collection of docs by a list of doc_id # get.docs(...) --> it should be a generator. does it behave in the # threadpool? raise NotImplementedError() def get_collection_by_tag(self, tag): """ :rtype: MessageCollection """ raise NotImplementedError() # Session handling def end_session(self): self._teardown_sync_hooks() self.session_ended = True
class Account(object): """ Account is the top level abstraction to access collections of messages associated with a LEAP Mail Account. It primarily handles creation and access of Mailboxes, which will be the basic collection handled by traditional MUAs, but it can also handle other types of Collections (tag based, for instance). leap.mail.imap.IMAPAccount partially proxies methods in this class. """ # Adaptor is passed to the returned MessageCollections, so if you want to # use a different adaptor this is the place to change it, by subclassing # the Account class. adaptor_class = SoledadMailAdaptor # This is a mapping to collection instances so that we always # return a reference to them instead of creating new ones. However, being a # dictionary of weakrefs values, they automagically vanish from the dict # when no hard refs is left to them (so they can be garbage collected) # This is important because the different wrappers rely on several # kinds of deferredLocks that are kept as class or instance variables _collection_mapping = weakref.WeakValueDictionary() def __init__(self, store, ready_cb=None): self.store = store self.adaptor = self.adaptor_class() self.mbox_indexer = MailboxIndexer(self.store) # This flag is only used from the imap service for the moment. # In the future, we should prevent any public method to continue if # this is set to True. Also, it would be good to plug to the # authentication layer. self.session_ended = False self.deferred_initialization = defer.Deferred() self._ready_cb = ready_cb self._init_d = self._initialize_storage() self._initialize_sync_hooks() def _initialize_storage(self): def add_mailbox_if_none(mboxes): if not mboxes: return self.add_mailbox(INBOX_NAME) def finish_initialization(result): self.deferred_initialization.callback(None) if self._ready_cb is not None: self._ready_cb() d = self.adaptor.initialize_store(self.store) d.addCallback(lambda _: self.list_all_mailbox_names()) d.addCallback(add_mailbox_if_none) d.addCallback(finish_initialization) return d def callWhenReady(self, cb, *args, **kw): """ Execute the callback when the initialization of the Account is ready. Note that the callback will receive a first meaningless parameter. """ # TODO this should ignore the first parameter explicitely # lambda _: cb(*args, **kw) self.deferred_initialization.addCallback(cb, *args, **kw) return self.deferred_initialization # Sync hooks def _initialize_sync_hooks(self): soledad_sync_hooks.post_sync_uid_reindexer.set_account(self) def _teardown_sync_hooks(self): soledad_sync_hooks.post_sync_uid_reindexer.set_account(None) # # Public API Starts # def list_all_mailbox_names(self): def filter_names(mboxes): return [m.mbox for m in mboxes] d = self.get_all_mailboxes() d.addCallback(filter_names) return d def get_all_mailboxes(self): d = self.adaptor.get_all_mboxes(self.store) return d def add_mailbox(self, name, creation_ts=None): if creation_ts is None: # by default, we pass an int value # taken from the current time # we make sure to take enough decimals to get a unique # mailbox-uidvalidity. creation_ts = int(time.time() * 10E2) def set_creation_ts(wrapper): wrapper.created = creation_ts d = wrapper.update(self.store) d.addCallback(lambda _: wrapper) return d def create_uuid(wrapper): if not wrapper.uuid: wrapper.uuid = str(uuid.uuid4()) d = wrapper.update(self.store) d.addCallback(lambda _: wrapper) return d return wrapper def create_uid_table_cb(wrapper): d = self.mbox_indexer.create_table(wrapper.uuid) d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(set_creation_ts) d.addCallback(create_uuid) d.addCallback(create_uid_table_cb) return d def delete_mailbox(self, name): def delete_uid_table_cb(wrapper): d = self.mbox_indexer.delete_table(wrapper.uuid) d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(delete_uid_table_cb) d.addCallback( lambda wrapper: self.adaptor.delete_mbox(self.store, wrapper)) return d def rename_mailbox(self, oldname, newname): def _rename_mbox(wrapper): wrapper.mbox = newname d = wrapper.update(self.store) d.addCallback(lambda result: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, oldname) d.addCallback(_rename_mbox) return d # Get Collections def get_collection_by_mailbox(self, name): """ :rtype: deferred :return: a deferred that will fire with a MessageCollection """ collection = self._collection_mapping.get(name, None) if collection: return defer.succeed(collection) # imap select will use this, passing the collection to SoledadMailbox def get_collection_for_mailbox(mbox_wrapper): collection = MessageCollection( self.adaptor, self.store, self.mbox_indexer, mbox_wrapper) self._collection_mapping[name] = collection return collection d = self.adaptor.get_or_create_mbox(self.store, name) d.addCallback(get_collection_for_mailbox) return d def get_collection_by_docs(self, docs): """ :rtype: MessageCollection """ # get a collection of docs by a list of doc_id # get.docs(...) --> it should be a generator. does it behave in the # threadpool? raise NotImplementedError() def get_collection_by_tag(self, tag): """ :rtype: MessageCollection """ raise NotImplementedError() # Session handling def end_session(self): self._teardown_sync_hooks() self.session_ended = True