def create_imap_message(db_session, log, account, folder, msg): """ IMAP-specific message creation logic. This is the one function in this file that gets to take an account object instead of an account_id, because we need to relate the account to ImapUids for versioning to work, since it needs to look up the namespace. Returns ------- imapuid : inbox.models.tables.imap.ImapUid New db object, which links to new Message and Block objects through relationships. All new objects are uncommitted. """ new_msg = Message.create_from_synced(account=account, mid=msg.uid, folder_name=folder.name, received_date=msg.internaldate, body_string=msg.body) # Check to see if this is a copy of a message that was first created # by the Inbox API. If so, don't create a new object; just use the old one. existing_copy = reconcile_message(new_msg, db_session) if existing_copy is not None: new_msg = existing_copy imapuid = ImapUid(account=account, folder=folder, msg_uid=msg.uid, message=new_msg) imapuid.update_flags_and_labels(msg.flags, msg.g_labels) new_msg.is_draft = imapuid.is_draft new_msg.is_read = imapuid.is_seen update_contacts_from_message(db_session, new_msg, account.namespace) return imapuid
def resync_uids_impl(self): # NOTE: first, let's check if the UIVDALIDITY change was spurious, if # it is, just discard it and go on, if it isn't, drop the relevant # entries (filtering by account and folder IDs) from the imapuid table, # download messages, if necessary - in case a message has changed UID - # update UIDs, and discard orphaned messages. -siro with mailsync_session_scope() as db_session: folder_info = db_session.query(ImapFolderInfo). \ filter_by(account_id=self.account_id, folder_id=self.folder_id).one() cached_uidvalidity = folder_info.uidvalidity with self.conn_pool.get() as crispin_client: crispin_client.select_folder(self.folder_name, lambda *args: True) uidvalidity = crispin_client.selected_uidvalidity if uidvalidity <= cached_uidvalidity: log.debug('UIDVALIDITY unchanged') return invalid_uids = db_session.query(ImapUid). \ filter_by(account_id=self.account_id, folder_id=self.folder_id) data_sha256_message = { uid.message.data_sha256: uid.message for uid in invalid_uids } for uid in invalid_uids: db_session.delete(uid) # NOTE: this is necessary (and OK since it doesn't persist any # data) to maintain the order between UIDs deletion and # insertion. Without this, I was seeing constraints violation # on the imapuid table. -siro db_session.flush() remote_uids = crispin_client.all_uids() for remote_uid in remote_uids: raw_message = crispin_client.uids([remote_uid])[0] data_sha256 = sha256(raw_message.body).hexdigest() if data_sha256 in data_sha256_message: message = data_sha256_message[data_sha256] uid = ImapUid(msg_uid=raw_message.uid, message_id=message.id, account_id=self.account_id, folder_id=self.folder_id) uid.update_flags_and_labels(raw_message.flags, raw_message.g_labels) db_session.add(uid) del data_sha256_message[data_sha256] else: self.download_and_commit_uids(crispin_client, self.folder_name, [remote_uid]) self.heartbeat_status.publish() # FIXME: do we want to throttle the account when recovering # from UIDVALIDITY changes? -siro for message in data_sha256_message.itervalues(): db_session.delete(message) folder_info.uidvalidity = uidvalidity folder_info.highestmodseq = None
def resync_uids_impl(self): # NOTE: first, let's check if the UIVDALIDITY change was spurious, if # it is, just discard it and go on, if it isn't, drop the relevant # entries (filtering by account and folder IDs) from the imapuid table, # download messages, if necessary - in case a message has changed UID - # update UIDs, and discard orphaned messages. -siro with mailsync_session_scope() as db_session: folder_info = db_session.query(ImapFolderInfo). \ filter_by(account_id=self.account_id, folder_id=self.folder_id).one() cached_uidvalidity = folder_info.uidvalidity with self.conn_pool.get() as crispin_client: crispin_client.select_folder(self.folder_name, lambda *args: True) uidvalidity = crispin_client.selected_uidvalidity if uidvalidity <= cached_uidvalidity: log.debug('UIDVALIDITY unchanged') return invalid_uids = db_session.query(ImapUid). \ filter_by(account_id=self.account_id, folder_id=self.folder_id) data_sha256_message = {uid.message.data_sha256: uid.message for uid in invalid_uids} for uid in invalid_uids: db_session.delete(uid) # NOTE: this is necessary (and OK since it doesn't persist any # data) to maintain the order between UIDs deletion and # insertion. Without this, I was seeing constraints violation # on the imapuid table. -siro db_session.flush() remote_uids = crispin_client.all_uids() for remote_uid in remote_uids: raw_message = crispin_client.uids([remote_uid])[0] data_sha256 = sha256(raw_message.body).hexdigest() if data_sha256 in data_sha256_message: message = data_sha256_message[data_sha256] uid = ImapUid(msg_uid=raw_message.uid, message_id=message.id, account_id=self.account_id, folder_id=self.folder_id) uid.update_flags_and_labels(raw_message.flags, raw_message.g_labels) db_session.add(uid) del data_sha256_message[data_sha256] else: self.download_and_commit_uids(crispin_client, self.folder_name, [remote_uid]) self.heartbeat_status.publish() # FIXME: do we want to throttle the account when recovering # from UIDVALIDITY changes? -siro for message in data_sha256_message.itervalues(): db_session.delete(message) folder_info.uidvalidity = uidvalidity folder_info.highestmodseq = None