allow configure autoexpunge

This commit is contained in:
Andris Reinman 2017-12-15 11:02:47 +02:00
parent 6c406c11f5
commit 97d004bd53
10 changed files with 566 additions and 536 deletions

View file

@ -49,6 +49,9 @@ ignoredHosts=[]
#secure=false #secure=false
#ignoreSTARTTLS=true #ignoreSTARTTLS=true
# If true then EXPUNGE is called after a message gets a \Deleted flag set
autoExpunge=true
[setup] [setup]
# Public configuration for IMAP # Public configuration for IMAP
hostname="localhost" hostname="localhost"

View file

@ -9,3 +9,6 @@
redis="redis://127.0.0.1:6379/13" redis="redis://127.0.0.1:6379/13"
dbname="wildduck-test" dbname="wildduck-test"
[imap]
autoExpunge=false

View file

@ -477,11 +477,11 @@ class IMAPConnection extends EventEmitter {
conn._listenerData.lock = true; conn._listenerData.lock = true;
conn._server.notifier.getUpdates(selectedMailbox, conn.selected.modifyIndex, (err, updates) => { conn._server.notifier.getUpdates(selectedMailbox, conn.selected.modifyIndex, (err, updates) => {
conn._listenerData.lock = false; if (!conn._listenerData || conn._listenerData.cleared) {
if (conn._listenerData.cleared) {
// already logged out // already logged out
return; return;
} }
conn._listenerData.lock = false;
if (err) { if (err) {
conn.logger.info( conn.logger.info(

View file

@ -1089,8 +1089,8 @@ describe('IMAP Protocol integration tests', function() {
describe('EXPUNGE', function() { describe('EXPUNGE', function() {
// EXPUNGE is a NO OP with autoexpunge // EXPUNGE is a NO OP with autoexpunge
it.skip('should automatically expunge messages', function(done) { it('should expunge all deleted messages', function(done) {
let cmds = ['T1 LOGIN testuser pass', 'T2 SELECT INBOX', 'T3 STORE 2:* +FLAGS (\\Deleted)', 'SLEEP', 'T4 EXPUNGE', 'T6 LOGOUT']; let cmds = ['T1 LOGIN testuser pass', 'T2 SELECT INBOX', 'T3 STORE 2:* +FLAGS (\\Deleted)', 'T4 EXPUNGE', 'T6 LOGOUT'];
testClient( testClient(
{ {
@ -1100,7 +1100,6 @@ describe('IMAP Protocol integration tests', function() {
}, },
function(resp) { function(resp) {
resp = resp.toString(); resp = resp.toString();
console.log(resp);
expect(resp.match(/^\* \d+ EXPUNGE/gm).length).to.equal(5); expect(resp.match(/^\* \d+ EXPUNGE/gm).length).to.equal(5);
expect(/^T4 OK/m.test(resp)).to.be.true; expect(/^T4 OK/m.test(resp)).to.be.true;
done(); done();
@ -1111,8 +1110,8 @@ describe('IMAP Protocol integration tests', function() {
describe('UID EXPUNGE', function() { describe('UID EXPUNGE', function() {
// UID EXPUNGE is a NO OP with autoexpunge // UID EXPUNGE is a NO OP with autoexpunge
it.skip('should automatically expunge messages', function(done) { it('should expunge specific messages', function(done) {
let cmds = ['T1 LOGIN testuser pass', 'T2 SELECT INBOX', 'T3 STORE 1:* +FLAGS (\\Deleted)', 'SLEEP', 'T4 UID EXPUNGE 50', 'T5 LOGOUT']; let cmds = ['T1 LOGIN testuser pass', 'T2 SELECT INBOX', 'T3 STORE 1:* +FLAGS (\\Deleted)', 'T4 UID EXPUNGE 103,105', 'T5 LOGOUT'];
testClient( testClient(
{ {
@ -1122,8 +1121,9 @@ describe('IMAP Protocol integration tests', function() {
}, },
function(resp) { function(resp) {
resp = resp.toString(); resp = resp.toString();
expect(resp.match(/^\* \d+ EXPUNGE/gm).length).to.equal(1); expect(resp.match(/^\* \d+ EXPUNGE/gm).length).to.equal(2);
expect(resp.match(/^\* 3 EXPUNGE/gm).length).to.equal(1); expect(resp.match(/^\* 3 EXPUNGE/gm).length).to.equal(1);
expect(resp.match(/^\* 4 EXPUNGE/gm).length).to.equal(1);
expect(/^T4 OK/m.test(resp)).to.be.true; expect(/^T4 OK/m.test(resp)).to.be.true;
done(); done();
} }

View file

@ -28,7 +28,8 @@ module.exports = (db, server, messageHandler) => {
function sendMessage(options, callback) { function sendMessage(options, callback) {
let user = options.user; let user = options.user;
db.users.collection('users').findOne({ _id: user }, db.users.collection('users').findOne(
{ _id: user },
{ {
fields: { fields: {
username: true, username: true,
@ -84,7 +85,8 @@ module.exports = (db, server, messageHandler) => {
return done(null, false); return done(null, false);
} }
query.user = user; query.user = user;
db.users.collection('messages').findOne(query, db.users.collection('messages').findOne(
query,
{ {
fields: { fields: {
'mimeTree.parsedHeader': true, 'mimeTree.parsedHeader': true,
@ -178,7 +180,8 @@ module.exports = (db, server, messageHandler) => {
subject, subject,
thread: messageData.thread thread: messageData.thread
}); });
}); }
);
}; };
getReferencedMessage((err, referenceData) => { getReferencedMessage((err, referenceData) => {
@ -291,7 +294,9 @@ module.exports = (db, server, messageHandler) => {
if (!success) { if (!success) {
log.info('API', 'RCPTDENY denied sent=%s allowed=%s expires=%ss.', sent, userData.recipients, ttl); log.info('API', 'RCPTDENY denied sent=%s allowed=%s expires=%ss.', sent, userData.recipients, ttl);
let err = new Error('You reached a daily sending limit for your account' + (ttl ? '. Limit expires in ' + ttlHuman : '')); let err = new Error(
'You reached a daily sending limit for your account' + (ttl ? '. Limit expires in ' + ttlHuman : '')
);
err.code = 'ERRSENDINGLIMIT'; err.code = 'ERRSENDINGLIMIT';
return setImmediate(() => callback(err)); return setImmediate(() => callback(err));
} }
@ -397,7 +402,8 @@ module.exports = (db, server, messageHandler) => {
); );
}); });
}); });
}); }
);
} }
/** /**

View file

@ -13,7 +13,8 @@ module.exports = (options, callback) => {
} }
let curtime = new Date(); let curtime = new Date();
db.database.collection('autoreplies').findOne({ db.database.collection('autoreplies').findOne(
{
user: options.userData._id, user: options.userData._id,
start: { start: {
$lte: curtime $lte: curtime
@ -127,7 +128,8 @@ module.exports = (options, callback) => {
} }
return callback(err, ...args); return callback(err, ...args);
} }
db.database.collection('messagelog').insertOne({ db.database.collection('messagelog').insertOne(
{
id: args[0].id, id: args[0].id,
messageId: args[0].messageId, messageId: args[0].messageId,
parentId: options.parentId, parentId: options.parentId,
@ -136,7 +138,8 @@ module.exports = (options, callback) => {
to: options.sender, to: options.sender,
created: new Date() created: new Date()
}, },
() => callback(err, args && args[0].id)); () => callback(err, args && args[0].id)
);
} }
); );
@ -169,5 +172,6 @@ module.exports = (options, callback) => {
}; };
setImmediate(writeNextChunk); setImmediate(writeNextChunk);
}); });
}); }
);
}; };

View file

@ -28,7 +28,8 @@ module.exports = (options, callback) => {
} }
return callback(err, ...args); return callback(err, ...args);
} }
db.database.collection('messagelog').insertOne({ db.database.collection('messagelog').insertOne(
{
id: args[0].id, id: args[0].id,
messageId: args[0].messageId, messageId: args[0].messageId,
action: 'FORWARD', action: 'FORWARD',
@ -38,7 +39,8 @@ module.exports = (options, callback) => {
targets: options.targets, targets: options.targets,
created: new Date() created: new Date()
}, },
() => callback(err, args && args[0] && args[0].id)); () => callback(err, args && args[0] && args[0].id)
);
}); });
if (message) { if (message) {
if (options.stream) { if (options.stream) {

View file

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const db = require('../db'); const db = require('../db');
const tools = require('../tools');
// EXPUNGE deletes all messages in selected mailbox marked with \Delete // EXPUNGE deletes all messages in selected mailbox marked with \Delete
module.exports = (server, messageHandler) => (mailbox, update, session, callback) => { module.exports = (server, messageHandler) => (mailbox, update, session, callback) => {
@ -25,18 +26,24 @@ module.exports = (server, messageHandler) => (mailbox, update, session, callback
return callback(null, 'NONEXISTENT'); return callback(null, 'NONEXISTENT');
} }
let cursor = db.database let query = {
.collection('messages')
.find({
user: session.user.id, user: session.user.id,
mailbox: mailboxData._id, mailbox: mailboxData._id,
undeleted: false, undeleted: false,
// uid is part of the sharding key so we need it somehow represented in the query // uid is part of the sharding key so we need it somehow represented in the query
uid: { uid: {}
$gt: 0, };
$lt: mailboxData.uidNext
if (update.isUid) {
query.uid = tools.checkRangeQuery(update.messages);
} else {
query.uid.$gt = 0;
query.uid.$lt = mailboxData.uidNext;
} }
})
let cursor = db.database
.collection('messages')
.find(query)
.sort([['uid', 1]]); .sort([['uid', 1]]);
let deletedMessages = 0; let deletedMessages = 0;

View file

@ -1,5 +1,6 @@
'use strict'; 'use strict';
const config = require('wild-config');
const imapTools = require('../../imap-core/lib/imap-tools'); const imapTools = require('../../imap-core/lib/imap-tools');
const db = require('../db'); const db = require('../db');
const tools = require('../tools'); const tools = require('../tools');
@ -114,7 +115,7 @@ module.exports = server => (mailbox, update, session, callback) => {
// first argument is an error // first argument is an error
return callback(...args); return callback(...args);
} else { } else {
if (shouldExpunge) { if (config.imap.autoExpunge && shouldExpunge) {
// shcedule EXPUNGE command for current folder // shcedule EXPUNGE command for current folder
let expungeOptions = { let expungeOptions = {
// create new temporary session so it would not mix with the active one // create new temporary session so it would not mix with the active one

View file

@ -279,7 +279,8 @@ module.exports = (options, callback) => {
documents.push(delivery); documents.push(delivery);
} }
db.senderDb.collection(config.sender.collection).insertMany(documents, db.senderDb.collection(config.sender.collection).insertMany(
documents,
{ {
w: 1, w: 1,
ordered: false ordered: false
@ -290,7 +291,8 @@ module.exports = (options, callback) => {
} }
callback(null, envelope); callback(null, envelope);
}); }
);
}); });
}); });
}); });
@ -352,7 +354,8 @@ function removeMessage(id, callback) {
} }
function setMeta(id, data, callback) { function setMeta(id, data, callback) {
db.senderDb.collection(config.sender.gfs + '.files').findOneAndUpdate({ db.senderDb.collection(config.sender.gfs + '.files').findOneAndUpdate(
{
filename: 'message ' + id filename: 'message ' + id
}, },
{ {
@ -366,5 +369,6 @@ function setMeta(id, data, callback) {
return callback(err); return callback(err);
} }
return callback(); return callback();
}); }
);
} }