/* eslint no-invalid-this:0 */ 'use strict'; const db = require('../db'); const tools = require('../tools'); const consts = require('../consts'); // EXPUNGE deletes all messages in selected mailbox marked with \Delete module.exports = (server, messageHandler) => (mailbox, update, session, callback) => { server.logger.debug( { tnx: 'expunge', cid: session.id }, '[%s] Deleting messages from "%s"', session.id, mailbox ); db.database.collection('mailboxes').findOne( { _id: mailbox }, { maxTimeMS: consts.DB_MAX_TIME_MAILBOXES }, (err, mailboxData) => { if (err) { return callback(err); } if (!mailboxData) { return callback(null, 'NONEXISTENT'); } if (!mailboxData.user.equals(session.user.id)) { return callback(null, 'NONEXISTENT'); } let query = { mailbox: mailboxData._id, undeleted: false }; if (update.isUid) { query.uid = tools.checkRangeQuery(update.messages); } let logdata = { short_message: '[EXPUNGE]', _mail_action: 'expunge', _user: session.user.id.toString(), _mailbox: mailboxData._id.toString(), _sess: session.id, _deleted: 0 }; let deletedSize = 0; let updateQuota = done => { if (!deletedSize) { return done(); } // try to update quota messageHandler.updateQuota( session.user.id, { storageUsed: -deletedSize, mailbox: mailboxData._id }, { session }, () => done() ); }; // fetch entire messages as these need to be copied to the archive let cursor = db.database .collection('messages') .find(query) .sort({ uid: 1 }) .maxTimeMS(consts.DB_MAX_TIME_MESSAGES); let processNext = () => { cursor.next((err, messageData) => { if (err) { return updateQuota(() => callback(err)); } if (!messageData) { //server.loggelf(logdata); return cursor.close(() => { server.notifier.fire(session.user.id); if (!update.silent && session && session.selected && session.selected.uidList) { session.writeStream.write({ tag: '*', command: String(session.selected.uidList.length), attributes: [ { type: 'atom', value: 'EXISTS' } ] }); } return updateQuota(() => callback(null, true)); }); } messageHandler.del( { messageData, session, // do not archive drafts nor copied messages archive: !messageData.flags.includes('\\Draft') && !messageData.copied, delayNotifications: true }, (err, deleted) => { if (err) { server.logger.error( { tnx: 'EXPUNGE', err }, 'Failed to delete message id=%s. %s', messageData._id, err.message ); logdata._error = err.message; logdata._code = err.code; logdata._response = err.response; server.loggelf(logdata); return cursor.close(() => updateQuota(() => callback(err))); } if (!deleted) { // nothing was deleted, so skip return setImmediate(processNext); } logdata._deleted++; deletedSize += messageData.size; server.logger.debug( { tnx: 'EXPUNGE', err }, 'Deleted message id=%s', messageData._id ); if (!update.silent) { session.writeStream.write(session.formatResponse('EXPUNGE', messageData.uid)); } setImmediate(processNext); } ); }); }; processNext(); } ); };