diff --git a/api.js b/api.js index a902a2a3..54a7c8fc 100644 --- a/api.js +++ b/api.js @@ -1688,6 +1688,7 @@ server.get({ name: 'search', path: '/users/:user/search' }, (req, res, next) => let filter = { user, + searchable: true, $text: { $search: query, $language: 'none' } }; diff --git a/indexes.yaml b/indexes.yaml index b282877c..960a8494 100644 --- a/indexes.yaml +++ b/indexes.yaml @@ -145,12 +145,10 @@ indexes: name: fulltext key: user: 1 + searchable: 1 headers.value: text - subject: text text: text - weights: - subject: 10 - text: 5 + sparse: true - collection: messages index: # in most cases we only care about unseen, not seen messages diff --git a/lib/handlers/on-copy.js b/lib/handlers/on-copy.js index 0c5488d1..6f0999fd 100644 --- a/lib/handlers/on-copy.js +++ b/lib/handlers/on-copy.js @@ -121,6 +121,21 @@ module.exports = server => (path, update, session, callback) => { message.exp = !!target.retention; message.rdate = Date.now() + (target.retention || 0); + if (['\\Junk', '\\Trash'].includes(target.specialUse)) { + delete message.searchable; + } else { + message.searchable = true; + } + + let junk = false; + if (target.specialUse === '\\Junk' && !message.junk) { + message.junk = true; + junk = 1; + } else if (target.specialUse !== '\\Trash' && message.junk) { + delete message.junk; + junk = -1; + } + if (!message.meta) { message.meta = {}; } @@ -138,17 +153,16 @@ module.exports = server => (path, update, session, callback) => { let attachments = Object.keys(message.map || {}).map(key => message.map[key]); if (!attachments.length) { - return server.notifier.addEntries( - session.user.id, - target.path, - { - command: 'EXISTS', - uid: message.uid, - message: message._id, - unseen: message.unseen - }, - processNext - ); + let entry = { + command: 'EXISTS', + uid: message.uid, + message: message._id, + unseen: message.unseen + }; + if (junk) { + entry.junk = junk; + } + return server.notifier.addEntries(session.user.id, target.path, entry, processNext); } // update attachments @@ -168,17 +182,16 @@ module.exports = server => (path, update, session, callback) => { if (err) { // should we care about this error? } - server.notifier.addEntries( - session.user.id, - target.path, - { - command: 'EXISTS', - uid: message.uid, - message: message._id, - unseen: message.unseen - }, - processNext - ); + let entry = { + command: 'EXISTS', + uid: message.uid, + message: message._id, + unseen: message.unseen + }; + if (junk) { + entry.junk = junk; + } + server.notifier.addEntries(session.user.id, target.path, entry, processNext); }); }); }); diff --git a/lib/message-handler.js b/lib/message-handler.js index 543d3dd7..6a2f7139 100644 --- a/lib/message-handler.js +++ b/lib/message-handler.js @@ -81,13 +81,13 @@ class MessageHandler { let flags = Array.isArray(options.flags) ? options.flags : [].concat(options.flags || []); let maildata = options.maildata || this.indexer.getMaildata(id, mimeTree); - this.getMailbox(options, (err, mailbox) => { + this.getMailbox(options, (err, mailboxData) => { if (err) { return callback(err); } this.checkExistingMessage( - mailbox._id, + mailboxData._id, { hdate, msgid, @@ -132,8 +132,8 @@ class MessageHandler { v: consts.SCHEMA_VERSION, // if true then expires after rdate + retention - exp: !!mailbox.retention, - rdate: Date.now() + (mailbox.retention || 0), + exp: !!mailboxData.retention, + rdate: Date.now() + (mailboxData.retention || 0), idate, hdate, @@ -208,7 +208,7 @@ class MessageHandler { } this.database.collection('users').findOneAndUpdate({ - _id: mailbox.user + _id: mailboxData.user }, { $inc: { storageUsed: size @@ -220,7 +220,7 @@ class MessageHandler { let rollback = err => { this.database.collection('users').findOneAndUpdate({ - _id: mailbox.user + _id: mailboxData.user }, { $inc: { storageUsed: -size @@ -232,7 +232,7 @@ class MessageHandler { // acquire new UID+MODSEQ this.database.collection('mailboxes').findOneAndUpdate({ - _id: mailbox._id + _id: mailboxData._id }, { $inc: { // allocate bot UID and MODSEQ values so when journal is later sorted by @@ -252,15 +252,23 @@ class MessageHandler { return rollback(err); } - let mailbox = item.value; + let mailboxData = item.value; // updated message object by setting mailbox specific values - message.mailbox = mailbox._id; - message.user = mailbox.user; - message.uid = mailbox.uidNext; - message.modseq = mailbox.modifyIndex + 1; + message.mailbox = mailboxData._id; + message.user = mailboxData.user; + message.uid = mailboxData.uidNext; + message.modseq = mailboxData.modifyIndex + 1; - this.getThreadId(mailbox.user, subject, mimeTree, (err, thread) => { + if (!['\\Junk', '\\Trash'].includes(mailboxData.specialUse)) { + message.searchable = true; + } + + if (mailboxData.specialUse === '\\Junk') { + message.junk = true; + } + + this.getThreadId(mailboxData.user, subject, mimeTree, (err, thread) => { if (err) { return rollback(err); } @@ -272,15 +280,15 @@ class MessageHandler { return rollback(err); } - let uidValidity = mailbox.uidValidity; + let uidValidity = mailboxData.uidValidity; let uid = message.uid; - if (options.session && options.session.selected && options.session.selected.mailbox === mailbox.path) { + if (options.session && options.session.selected && options.session.selected.mailbox === mailboxData.path) { options.session.writeStream.write(options.session.formatResponse('EXISTS', message.uid)); } this.notifier.addEntries( - mailbox, + mailboxData, false, { command: 'EXISTS', @@ -291,7 +299,7 @@ class MessageHandler { unseen: message.unseen }, () => { - this.notifier.fire(mailbox.user, mailbox.path); + this.notifier.fire(mailboxData.user, mailboxData.path); return cleanup(null, true, { uidValidity, uid, @@ -652,6 +660,21 @@ class MessageHandler { let unseen = message.unseen; + if (['\\Junk', '\\Trash'].includes(target.specialUse)) { + delete message.searchable; + } else { + message.searchable = true; + } + + let junk = false; + if (target.specialUse === '\\Junk' && !message.junk) { + message.junk = true; + junk = 1; + } else if (target.specialUse !== '\\Trash' && message.junk) { + delete message.junk; + junk = -1; + } + if (options.markAsSeen) { message.unseen = false; if (!message.flags.includes('\\Seen')) { @@ -688,12 +711,16 @@ class MessageHandler { unseen }); - existsEntries.push({ + let entry = { command: 'EXISTS', uid: uidNext, message: insertId, unseen: message.unseen - }); + }; + if (junk) { + entry.junk = junk; + } + existsEntries.push(entry); if (existsEntries.length >= consts.BULK_BATCH_SIZE) { // mark messages as deleted from old mailbox