From 54d495d8d9bc49991d3756724a3f3afc63bafc5f Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Fri, 13 Feb 2015 17:10:44 +0100 Subject: [PATCH] [WO-804] Fix bug where message cannot be parsed when deleted from IMAP --- src/js/email/email.js | 23 +++++- test/unit/email/email-dao-test.js | 129 +++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/js/email/email.js b/src/js/email/email.js index 04da5b5..3c6d477 100644 --- a/src/js/email/email.js +++ b/src/js/email/email.js @@ -609,12 +609,15 @@ Email.prototype.getBody = function(options) { folder: folder, uid: message.uid }).then(function(localMessages) { - if (localMessages.length === 0) { - return; - } - localMessage = localMessages[0]; + if (!localMessage) { + // the message has been deleted in the meantime + var error = new Error('Can not get the contents of this message. It has already been deleted!'); + error.hide = true; + throw error; + } + // treat attachment and non-attachment body parts separately: // we need to fetch the content for non-attachment body parts (encrypted, signed, text, html, resources referenced from the html) // but we spare the effort and fetch attachment content later upon explicit user request. @@ -730,6 +733,10 @@ Email.prototype.getBody = function(options) { }).catch(function(err) { self.done(); message.loadingBody = false; + if (err.hide) { + // ignore errors with err.hide + return message; + } throw err; }); @@ -1558,6 +1565,14 @@ Email.prototype._getBodyParts = function(options) { options.path = options.folder.path; return self._imapClient.getBodyParts(options); }).then(function() { + if (options.bodyParts.filter(function(bodyPart) { + return !(bodyPart.raw || bodyPart.content); + }).length) { + var error = new Error('Can not get the contents of this message. It has already been deleted!'); + error.hide = true; + throw error; + } + return self._parse(options); }); }; diff --git a/test/unit/email/email-dao-test.js b/test/unit/email/email-dao-test.js index ec92765..b1c6298 100644 --- a/test/unit/email/email-dao-test.js +++ b/test/unit/email/email-dao-test.js @@ -1250,6 +1250,80 @@ describe('Email DAO unit tests', function() { expect(message.loadingBody).to.be.true; }); + it('should not error when message is deleted from imap', function(done) { + var error = new Error('Can not get the contents of this message. It has already been deleted!'); + error.hide = true; + + var message = { + uid: uid, + encrypted: true, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).returns(resolves([message])); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).returns(resolves()); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).returns(rejects(error)); + + + dao.getBody({ + message: message, + folder: inboxFolder + }).then(function(msg) { + expect(msg).to.equal(message); + expect(msg.body).to.not.exist; + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.called).to.be.false; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should not error when message has already been removed from memory', function(done) { + var message = { + uid: uid, + encrypted: true, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.returns(resolves([])); + + dao.getBody({ + message: message, + folder: inboxFolder + }).then(function(msg) { + expect(msg).to.equal(message); + expect(msg.body).to.not.exist; + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.called).to.be.false; + expect(localStoreStub.called).to.be.false; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + it('fail to stream from imap due to error when persisting', function(done) { var message = { uid: uid, @@ -2393,18 +2467,23 @@ describe('Email DAO unit tests', function() { describe('#_getBodyParts', function() { it('should get bodyParts', function(done) { + var bp = [{ + type: 'text', + content: 'bender is great! bender is great!' + }]; + imapClientStub.getBodyParts.withArgs({ folder: inboxFolder, path: inboxFolder.path, uid: 123, - bodyParts: [] - }).returns(resolves({})); + bodyParts: bp + }).returns(resolves(bp)); parseStub.yieldsAsync(null, []); dao._getBodyParts({ folder: inboxFolder, uid: 123, - bodyParts: [] + bodyParts: bp }).then(function(parts) { expect(parts).to.exist; @@ -2415,6 +2494,50 @@ describe('Email DAO unit tests', function() { }); }); + it('should fail when deleted on IMAP', function(done) { + var bp = [{ + type: 'text' + }]; + + imapClientStub.getBodyParts.withArgs({ + folder: inboxFolder, + path: inboxFolder.path, + uid: 123, + bodyParts: bp + }).returns(resolves()); + parseStub.yieldsAsync(null, []); + + dao._getBodyParts({ + folder: inboxFolder, + uid: 123, + bodyParts: bp + }).catch(function(err) { + expect(err).to.exist; + + expect(imapClientStub.getBodyParts.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; + + done(); + }); + }); + + it('should fail when getBody fails', function(done) { + imapClientStub.getBodyParts.returns(rejects({})); + + dao._getBodyParts({ + folder: inboxFolder, + uid: 123, + bodyParts: [] + }).catch(function(err) { + expect(err).to.exist; + + expect(imapClientStub.getBodyParts.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; + + done(); + }); + }); + it('should fail when getBody fails', function(done) { imapClientStub.getBodyParts.returns(rejects({}));