diff --git a/package.json b/package.json index b12c4cf..7285942 100644 --- a/package.json +++ b/package.json @@ -62,13 +62,13 @@ "grunt-string-replace": "~1.0.0", "grunt-svgmin": "~1.0.0", "grunt-svgstore": "~0.3.4", - "imap-client": "~0.10.0", + "imap-client": "~0.11.0", "jquery": "~2.1.1", "mailreader": "~0.4.0", "mocha": "^1.21.4", "ng-infinite-scroll": "~1.1.2", - "pgpbuilder": "~0.5.0", - "pgpmailer": "~0.8.0", + "pgpbuilder": "~0.6.0", + "pgpmailer": "~0.9.0", "sinon": "~1.7.3", "tcp-socket": "~0.5.0", "time-grunt": "^1.0.0", diff --git a/src/js/email/email.js b/src/js/email/email.js index 709c71d..3c6d477 100644 --- a/src/js/email/email.js +++ b/src/js/email/email.js @@ -188,23 +188,16 @@ Email.prototype.unlock = function(options) { */ Email.prototype.openFolder = function(options) { var self = this; - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { self.checkOnline(); + resolve(); - if (options.folder.path === config.outboxMailboxPath) { - resolve(); - return; + }).then(function() { + if (options.folder.path !== config.outboxMailboxPath) { + return self._imapClient.selectMailbox({ + path: options.folder.path + }); } - - self._imapClient.selectMailbox({ - path: options.folder.path - }, function(err, folder) { - if (err) { - reject(err); - } else { - resolve(folder); - } - }); }); }; /** @@ -499,6 +492,12 @@ Email.prototype.setFlags = function(options) { }).then(function(storedMessages) { // set the flags var storedMessage = storedMessages[0]; + + if (!storedMessage) { + // the message has been deleted in the meantime + return; + } + storedMessage.unread = options.message.unread; storedMessage.flagged = options.message.flagged; storedMessage.answered = options.message.answered; @@ -610,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. @@ -731,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; }); @@ -960,15 +966,7 @@ Email.prototype._sendGeneric = function(options, mailer) { }).then(function() { // send the email - return new Promise(function(resolve, reject) { - self._pgpMailer.send(options, function(err, rfcText) { - if (err) { - reject(err); - } else { - resolve(rfcText); - } - }); - }); + return self._pgpMailer.send(options); }).then(function(rfcText) { // try to upload to sent, but we don't actually care if the upload failed or not // this should not negatively impact the process of sending @@ -990,20 +988,14 @@ Email.prototype._sendGeneric = function(options, mailer) { * Signs and encrypts a message * * @param {Object} options.email The message to be encrypted - * @param {Function} callback(error, message) Invoked when the message was encrypted, or an error occurred + * @param {Function} callback(message) Invoked when the message was encrypted, or an error occurred */ Email.prototype.encrypt = function(options) { var self = this; self.busy(); - return new Promise(function(resolve, reject) { - self._pgpbuilder.encrypt(options, function(err, message) { - self.done(); - if (err) { - reject(err); - } else { - resolve(message); - } - }); + return self._pgpbuilder.encrypt(options).then(function(message) { + self.done(); + return message; }); }; @@ -1043,15 +1035,7 @@ Email.prototype.onConnect = function(imap) { }).then(function() { // imap login - return new Promise(function(resolve, reject) { - self._imapClient.login(function(err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); + return self._imapClient.login(); }).then(function() { self._account.loggingIn = false; @@ -1185,7 +1169,7 @@ Email.prototype._onSyncUpdate = function(options) { folder: folder, firstUid: Math.min.apply(null, options.list), lastUid: Math.max.apply(null, options.list) - }, self._dialog.error); + }).then(self._dialog.error).catch(self._dialog.error); } else if (options.type === SYNC_TYPE_DELETED) { // messages have been deleted, remove from local storage and memory options.list.forEach(function(uid) { @@ -1201,7 +1185,7 @@ Email.prototype._onSyncUpdate = function(options) { folder: folder, message: message, localOnly: true - }, self._dialog.error); + }).then(self._dialog.error).catch(self._dialog.error); }); } else if (options.type === SYNC_TYPE_MSGS) { // NB! several possible reasons why this could be called. @@ -1228,7 +1212,7 @@ Email.prototype._onSyncUpdate = function(options) { folder: folder, message: message, localOnly: true - }, self._dialog.error); + }).then(self._dialog.error).catch(self._dialog.error); }); } }; @@ -1276,7 +1260,7 @@ Email.prototype._initFoldersFromImap = function() { self.busy(); // start the spinner // fetch list from imap server - return listWellknownFolder().then(function(wellKnownFolders) { + return self._imapClient.listWellKnownFolders().then(function(wellKnownFolders) { var foldersChanged = false, // indicates if we need to persist anything to disk imapFolders = []; // aggregate all the imap folders @@ -1409,18 +1393,6 @@ Email.prototype._initFoldersFromImap = function() { self.done(); // stop the spinner throw err; }); - - function listWellknownFolder() { - return new Promise(function(resolve, reject) { - self._imapClient.listWellKnownFolders(function(err, wellKnownFolders) { - if (err) { - reject(err); - } else { - resolve(wellKnownFolders); - } - }); - }); - } }; /** @@ -1475,17 +1447,13 @@ Email.prototype.done = function() { */ Email.prototype._imapMark = function(options) { var self = this; - return new Promise(function(resolve, reject) { - self.checkOnline(); + return new Promise(function(resolve) { + self.checkOnline(); + resolve(); + }).then(function() { options.path = options.folder.path; - self._imapClient.updateFlags(options, function(err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); + return self._imapClient.updateFlags(options); }); }; @@ -1510,7 +1478,10 @@ Email.prototype._imapDeleteMessage = function(options) { // there's no known trash folder to move the mail to or we're in the trash folder, so we can purge the message if (!trash || options.folder === trash) { - return imapDelete(); + return self._imapClient.deleteMessage({ + path: options.folder.path, + uid: options.uid + }); } return self._imapMoveMessage({ @@ -1519,21 +1490,6 @@ Email.prototype._imapDeleteMessage = function(options) { uid: options.uid }); }); - - function imapDelete() { - return new Promise(function(resolve, reject) { - self._imapClient.deleteMessage({ - path: options.folder.path, - uid: options.uid - }, function(err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); - } }; /** @@ -1546,19 +1502,14 @@ Email.prototype._imapDeleteMessage = function(options) { */ Email.prototype._imapMoveMessage = function(options) { var self = this; - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { self.checkOnline(); - - self._imapClient.moveMessage({ + resolve(); + }).then(function() { + return self._imapClient.moveMessage({ path: options.folder.path, destination: options.destination.path, uid: options.uid - }, function(err) { - if (err) { - reject(err); - } else { - resolve(); - } }); }); }; @@ -1575,17 +1526,12 @@ Email.prototype._imapMoveMessage = function(options) { */ Email.prototype._imapListMessages = function(options) { var self = this; - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { self.checkOnline(); - + resolve(); + }).then(function() { options.path = options.folder.path; - self._imapClient.listMessages(options, function(err, messages) { - if (err) { - reject(err); - } else { - resolve(messages); - } - }); + return self._imapClient.listMessages(options); }); }; @@ -1597,17 +1543,10 @@ Email.prototype._imapListMessages = function(options) { */ Email.prototype._imapUploadMessage = function(options) { var self = this; - return new Promise(function(resolve, reject) { - self._imapClient.uploadMessage({ - path: options.folder.path, - message: options.message - }, function(err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); + + return self._imapClient.uploadMessage({ + path: options.folder.path, + message: options.message }); }; @@ -1619,26 +1558,22 @@ Email.prototype._imapUploadMessage = function(options) { */ Email.prototype._getBodyParts = function(options) { var self = this; - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { self.checkOnline(); - + resolve(); + }).then(function() { options.path = options.folder.path; - self._imapClient.getBodyParts(options, function(err) { - if (err) { - reject(err); - return; - } + 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; + } - // interpret the raw content of the email - self._mailreader.parse(options, function(err, message) { - if (err) { - reject(err); - return; - } - - resolve(message); - }); - }); + return self._parse(options); }); }; diff --git a/src/js/util/connection-doctor.js b/src/js/util/connection-doctor.js index eada553..538b20a 100644 --- a/src/js/util/connection-doctor.js +++ b/src/js/util/connection-doctor.js @@ -218,25 +218,21 @@ ConnectionDoctor.prototype._checkImap = function() { } }; - self._imap.login(function() { + self._imap.login().then(function() { loggedIn = true; + return self._imap.listWellKnownFolders(); + }).then(function(wellKnownFolders) { + if (wellKnownFolders.Inbox.length === 0) { + // the client needs at least an inbox folder to work properly + reject(createError(NO_INBOX, str.connDocNoInbox.replace('{0}', host))); + return; + } - self._imap.listWellKnownFolders(function(error, wellKnownFolders) { - if (error) { - reject(createError(GENERIC_ERROR, str.connDocGenericError.replace('{0}', host).replace('{1}', error.message), error)); - return; - } - - if (wellKnownFolders.Inbox.length === 0) { - // the client needs at least an inbox folder to work properly - reject(createError(NO_INBOX, str.connDocNoInbox.replace('{0}', host))); - return; - } - - self._imap.logout(function() { - resolve(); - }); - }); + return self._imap.logout(); + }).then(function(){ + resolve(); + }).catch(function(error) { + reject(createError(GENERIC_ERROR, str.connDocGenericError.replace('{0}', host).replace('{1}', error.message), error)); }); }); }; diff --git a/src/tpl/mail-list.html b/src/tpl/mail-list.html index e0c758e..7a230f0 100644 --- a/src/tpl/mail-list.html +++ b/src/tpl/mail-list.html @@ -28,7 +28,7 @@
  • + ng-repeat="email in displayMessages track by email.uid">