mirror of
https://github.com/moparisthebest/mail
synced 2024-11-25 18:32:20 -05:00
add documentation to email dao
This commit is contained in:
parent
088519f4f8
commit
c71e1482c9
@ -6,6 +6,16 @@ define(function(require) {
|
||||
config = require('js/app-config').config,
|
||||
str = require('js/app-config').string;
|
||||
|
||||
/**
|
||||
* High-level data access object that orchestrates everything around the handling of encrypted mails:
|
||||
* PGP de-/encryption, receiving via IMAP, sending via SMTP, MIME parsing, local db persistence
|
||||
*
|
||||
* @param {Object} keychain The keychain DAO handles keys transparently
|
||||
* @param {Object} crypto Orchestrates decryption
|
||||
* @param {Object} devicestorage Handles persistence to the local indexed db
|
||||
* @param {Object} pgpbuilder Generates and encrypts MIME and SMTP messages
|
||||
* @param {Object} mailreader Parses MIME messages received from IMAP
|
||||
*/
|
||||
var EmailDAO = function(keychain, crypto, devicestorage, pgpbuilder, mailreader) {
|
||||
this._keychain = keychain;
|
||||
this._crypto = crypto;
|
||||
@ -22,6 +32,16 @@ define(function(require) {
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the email dao:
|
||||
* - validates the email address
|
||||
* - retrieves the user's key pair (if available)
|
||||
* - initializes _account.folders with the content from memory
|
||||
*
|
||||
* @param {Object} options.account The account
|
||||
* @param {String} options.account.emailAddress The user's id
|
||||
* @param {Function} callback(error, keypair) Invoked with the keypair or error information when the email dao is initialized
|
||||
*/
|
||||
EmailDAO.prototype.init = function(options, callback) {
|
||||
var self = this,
|
||||
keypair;
|
||||
@ -70,6 +90,11 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlocks the keychain by either decrypting an existing private key or generating a new keypair
|
||||
* @param {String} options.passphrase The passphrase to decrypt the private key
|
||||
* @param {Function} callback(error) Invoked when the the keychain is unlocked or when an error occurred buring unlocking
|
||||
*/
|
||||
EmailDAO.prototype.unlock = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -170,6 +195,14 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a folder in IMAP so that we can receive updates for it.
|
||||
* Please note that this is a no-op if you try to open the outbox, since it is not an IMAP folder
|
||||
* but a virtual folder that only exists on disk.
|
||||
*
|
||||
* @param {Object} options.folder The folder to be opened
|
||||
* @param {Function} callback(error) Invoked when the folder has been opened
|
||||
*/
|
||||
EmailDAO.prototype.openFolder = function(options, callback) {
|
||||
var self = this,
|
||||
err;
|
||||
@ -190,6 +223,14 @@ define(function(require) {
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronizes a folder's contents from disk to memory, i.e. if
|
||||
* a message has disappeared from the disk, this method will remove it from folder.messages, and
|
||||
* it adds any messages from disk to memory the are not yet in folder.messages
|
||||
*
|
||||
* @param {Object} options.folder The folder to synchronize
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.refreshFolder = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder;
|
||||
@ -205,8 +246,8 @@ define(function(require) {
|
||||
|
||||
var storedUids = _.pluck(storedMessages, 'uid'),
|
||||
memoryUids = _.pluck(folder.messages, 'uid'),
|
||||
newUids = _.difference(storedUids, memoryUids),
|
||||
removedUids = _.difference(memoryUids, storedUids);
|
||||
newUids = _.difference(storedUids, memoryUids), // uids of messages that are not yet in memory
|
||||
removedUids = _.difference(memoryUids, storedUids); // uids of messages that are no longer stored on the disk
|
||||
|
||||
// which messages are new on the disk that are not yet in memory?
|
||||
_.filter(storedMessages, function(msg) {
|
||||
@ -240,6 +281,15 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches a message's headers from IMAP.
|
||||
*
|
||||
* NB! If we fetch a message whose subject line correspond's to that of a verification message,
|
||||
* we try to verify that, and if that worked, we delete the verified message from IMAP.
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to fetch the message
|
||||
* @param {Function} callback(error) Invoked when the message is persisted and added to folder.messages
|
||||
*/
|
||||
EmailDAO.prototype.fetchMessages = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder;
|
||||
@ -328,6 +378,7 @@ define(function(require) {
|
||||
callback(err);
|
||||
}
|
||||
|
||||
// Handles verification of public keys, deletion of messages with verified keys
|
||||
function handleVerification(message, localCallback) {
|
||||
self._getBodyParts({
|
||||
folder: folder,
|
||||
@ -375,6 +426,17 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a message from IMAP, disk and folder.messages.
|
||||
*
|
||||
* Please note that this deletes from disk only if you delete from the outbox,
|
||||
* since it is not an IMAP folder but a virtual folder that only exists on disk.
|
||||
*
|
||||
* @param {Object} options.folder The folder from which to delete the messages
|
||||
* @param {Object} options.message The message that should be deleted
|
||||
* @param {Boolean} options.localOnly Indicated if the message should not be removed from IMAP
|
||||
* @param {Function} callback(error) Invoked when the message was delete, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.deleteMessage = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder,
|
||||
@ -384,6 +446,7 @@ define(function(require) {
|
||||
|
||||
folder.messages.splice(folder.messages.indexOf(message), 1);
|
||||
|
||||
// delete only locally
|
||||
if (options.localOnly || options.folder.path === config.outboxMailboxPath) {
|
||||
deleteLocal();
|
||||
return;
|
||||
@ -393,6 +456,7 @@ define(function(require) {
|
||||
|
||||
function deleteImap() {
|
||||
if (!self._account.online) {
|
||||
// no action if we're not online
|
||||
done({
|
||||
errMsg: 'Client is currently offline!',
|
||||
code: 42
|
||||
@ -400,6 +464,7 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete from IMAP
|
||||
self._imapDeleteMessage({
|
||||
folder: folder,
|
||||
uid: message.uid
|
||||
@ -414,6 +479,7 @@ define(function(require) {
|
||||
}
|
||||
|
||||
function deleteLocal() {
|
||||
// delete from indexed db
|
||||
self._localDeleteMessage({
|
||||
folder: folder,
|
||||
uid: message.uid
|
||||
@ -430,24 +496,37 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates a message's 'unread' and 'answered' flags
|
||||
*
|
||||
* Please note if you set flags on disk only if you delete from the outbox,
|
||||
* since it is not an IMAP folder but a virtual folder that only exists on disk.
|
||||
*
|
||||
* @param {[type]} options [description]
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.setFlags = function(options, callback) {
|
||||
var self = this,
|
||||
folder = options.folder,
|
||||
message = options.message;
|
||||
|
||||
self._account.busy = true;
|
||||
self._account.busy = true; // start the spinner
|
||||
|
||||
// no-op if the message if not present anymore (for whatever reason)
|
||||
if (folder.messages.indexOf(message) < 0) {
|
||||
self._account.busy = false; // stop the spinner
|
||||
return;
|
||||
}
|
||||
|
||||
// don't do a roundtrip to IMAP,
|
||||
// especially if you want to mark outbox messages
|
||||
if (options.localOnly || options.folder.path === config.outboxMailboxPath) {
|
||||
markStorage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self._account.online) {
|
||||
// no action if we're not online
|
||||
done({
|
||||
errMsg: 'Client is currently offline!',
|
||||
code: 42
|
||||
@ -458,6 +537,7 @@ define(function(require) {
|
||||
markImap();
|
||||
|
||||
function markImap() {
|
||||
// mark a message unread/answered on IMAP
|
||||
self._imapMark({
|
||||
folder: folder,
|
||||
uid: options.message.uid,
|
||||
@ -474,6 +554,9 @@ define(function(require) {
|
||||
}
|
||||
|
||||
function markStorage() {
|
||||
// angular pollutes that data transfer objects with helper properties (e.g. $$hashKey),
|
||||
// which we do not want to persist to disk. in order to avoid that, we load the pristine
|
||||
// message from disk, change the flags and re-persist it to disk
|
||||
self._localListMessages({
|
||||
folder: folder,
|
||||
uid: options.message.uid,
|
||||
@ -483,10 +566,13 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set the flags
|
||||
var storedMessage = storedMessages[0];
|
||||
storedMessage.unread = options.message.unread;
|
||||
storedMessage.answered = options.message.answered;
|
||||
storedMessage.modseq = options.message.modseq || storedMessage.modseq;
|
||||
|
||||
// store
|
||||
self._localStoreMessages({
|
||||
folder: folder,
|
||||
emails: [storedMessage]
|
||||
@ -663,6 +749,14 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves an attachment matching a body part for a given uid and a folder
|
||||
*
|
||||
* @param {Object} options.folder The folder where to find the attachment
|
||||
* @param {Number} options.uid The uid for the message the attachment body part belongs to
|
||||
* @param {Object} options.attachment The attachment body part to fetch and parse from IMAP
|
||||
* @param {Function} callback(error, attachment) Invoked when the attachment body part was retrieved and parsed, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.getAttachment = function(options, callback) {
|
||||
this._getBodyParts({
|
||||
folder: options.folder,
|
||||
@ -674,11 +768,19 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add the content to the original object
|
||||
options.attachment.content = parsedBodyParts[0].content;
|
||||
callback(err, err ? undefined : options.attachment);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypts a message and replaces sets the decrypted plaintext as the message's body, html, or attachment, respectively.
|
||||
* The first encrypted body part's ciphertext (in the content property) will be decrypted.
|
||||
*
|
||||
* @param {Object} options.message The message
|
||||
* @param {Function} callback(error, message)
|
||||
*/
|
||||
EmailDAO.prototype.decryptBody = function(options, callback) {
|
||||
var self = this,
|
||||
message = options.message;
|
||||
@ -762,6 +864,12 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encrypted (if necessary) and sends a message with a predefined clear text greeting.
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Function} callback(error) Invoked when the message was sent, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.sendEncrypted = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -782,6 +890,12 @@ define(function(require) {
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a signed message in the plain
|
||||
*
|
||||
* @param {Object} options.email The message to be sent
|
||||
* @param {Function} callback(error) Invoked when the message was sent, or an error occurred
|
||||
*/
|
||||
EmailDAO.prototype.sendPlaintext = function(options, callback) {
|
||||
if (!this._account.online) {
|
||||
callback({
|
||||
@ -797,6 +911,12 @@ define(function(require) {
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
EmailDAO.prototype.encrypt = function(options, callback) {
|
||||
this._pgpbuilder.encrypt(options, callback);
|
||||
};
|
||||
@ -809,6 +929,15 @@ define(function(require) {
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* This handler should be invoked when navigator.onLine === true. It will try to connect a
|
||||
* given instance of the imap client. If the connection attempt was successful, it will
|
||||
* update the locally available folders with the newly received IMAP folder listing.
|
||||
*
|
||||
* @param {Object} options.imapClient The IMAP client used to receive messages
|
||||
* @param {Object} options.pgpMailer The SMTP client used to send messages
|
||||
* @param {Function} callback [description]
|
||||
*/
|
||||
EmailDAO.prototype.onConnect = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -838,7 +967,11 @@ define(function(require) {
|
||||
// attach sync update handler
|
||||
self._imapClient.onSyncUpdate = self._onSyncUpdate.bind(self);
|
||||
|
||||
// fill the imap mailboxCache
|
||||
// fill the imap mailboxCache with information we have locally available:
|
||||
// - highest locally available moseq
|
||||
// - list of locally available uids
|
||||
// - highest locally available uid
|
||||
// - next expected uid
|
||||
var mailboxCache = {};
|
||||
self._account.folders.forEach(function(folder) {
|
||||
if (folder.messages.length === 0) {
|
||||
@ -865,6 +998,7 @@ define(function(require) {
|
||||
});
|
||||
self._imapClient.mailboxCache = mailboxCache;
|
||||
|
||||
// set up the imap client to listen for changes in the inbox
|
||||
var inbox = _.findWhere(self._account.folders, {
|
||||
type: 'Inbox'
|
||||
});
|
||||
@ -881,12 +1015,26 @@ define(function(require) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This handler should be invoked when navigator.onLine === false. It will discard
|
||||
* the imap client and pgp mailer
|
||||
*/
|
||||
EmailDAO.prototype.onDisconnect = function() {
|
||||
this._account.online = false;
|
||||
this._imapClient = undefined;
|
||||
this._pgpMailer = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* The are updates in the IMAP folder of the following type
|
||||
* - 'new': a list of uids that are newly available
|
||||
* - 'deleted': a list of uids that were deleted from IMAP available
|
||||
* - 'messages': a list of messages (uid + flags) that where changes are available
|
||||
*
|
||||
* @param {String} options.type The type of the update
|
||||
* @param {String} options.path The mailbox for which updates are available
|
||||
* @param {Array} options.list Array containing update information. Number (uid) or mail with Object (uid and flags), respectively
|
||||
*/
|
||||
EmailDAO.prototype._onSyncUpdate = function(options) {
|
||||
var self = this;
|
||||
|
||||
@ -939,16 +1087,15 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update unread, answered, modseq to the latest info
|
||||
message.answered = changedMsg.flags.indexOf('\\Answered') > -1;
|
||||
message.unread = changedMsg.flags.indexOf('\\Seen') === -1;
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
message.modseq = changedMsg.modseq;
|
||||
|
||||
self.setFlags({
|
||||
folder: folder,
|
||||
message: message
|
||||
message: message,
|
||||
localOnly: true
|
||||
}, self.onError.bind(self));
|
||||
});
|
||||
}
|
||||
@ -963,14 +1110,18 @@ define(function(require) {
|
||||
|
||||
|
||||
/**
|
||||
* List the folders in the user's IMAP mailbox.
|
||||
* Updates the folder information from memory (if we're offline), or from imap (if we're online),
|
||||
* and adds/removes folders in account.folders, if we added/removed folder in IMAP. If we have an
|
||||
* uninitialized folder that lacks folder.messages, all the locally available messages are loaded
|
||||
* from memory
|
||||
*
|
||||
* @param {Function} callback Invoked when the folders are up to date
|
||||
*/
|
||||
EmailDAO.prototype._initFolders = function(callback) {
|
||||
var self = this,
|
||||
folderDbType = 'folders',
|
||||
folders;
|
||||
folderDbType = 'folders';
|
||||
|
||||
self._account.busy = true;
|
||||
self._account.busy = true; // start the spinner
|
||||
|
||||
if (!self._account.online) {
|
||||
// fetch list from local cache
|
||||
@ -987,15 +1138,13 @@ define(function(require) {
|
||||
} else {
|
||||
// fetch list from imap server
|
||||
self._imapClient.listWellKnownFolders(function(err, wellKnownFolders) {
|
||||
var foldersChanged = false;
|
||||
|
||||
if (err) {
|
||||
done(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// this array is dropped directly into the ui to create the folder list
|
||||
folders = [
|
||||
var folders = [
|
||||
wellKnownFolders.inbox,
|
||||
wellKnownFolders.sent, {
|
||||
type: 'Outbox',
|
||||
@ -1005,7 +1154,9 @@ define(function(require) {
|
||||
wellKnownFolders.trash
|
||||
];
|
||||
|
||||
// are there any new folders?
|
||||
var foldersChanged = false; // indicates if are there any new/removed folders?
|
||||
|
||||
// check for added folders
|
||||
folders.forEach(function(folder) {
|
||||
if (!_.findWhere(self._account.folders, {
|
||||
path: folder.path
|
||||
@ -1016,7 +1167,7 @@ define(function(require) {
|
||||
}
|
||||
});
|
||||
|
||||
// have any folders been deleted?
|
||||
// check for deleted folders
|
||||
self._account.folders.forEach(function(folder) {
|
||||
if (!_.findWhere(folders, {
|
||||
path: folder.path
|
||||
@ -1027,12 +1178,14 @@ define(function(require) {
|
||||
}
|
||||
});
|
||||
|
||||
// if folder have changed, we need to persist them to disk.
|
||||
if (!foldersChanged) {
|
||||
readMessagesFromDisk();
|
||||
return;
|
||||
}
|
||||
|
||||
// persist encrypted list in device storage
|
||||
// NB! persis the array we received from IMAP! do *not* persist self._account.folders with all the messages...
|
||||
self._devicestorage.storeList([folders], folderDbType, function(err) {
|
||||
if (err) {
|
||||
done(err);
|
||||
@ -1045,6 +1198,7 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fill uninitialized folders with the locally available messages
|
||||
function readMessagesFromDisk() {
|
||||
if (!self._account.folders || self._account.folders.length === 0) {
|
||||
done();
|
||||
@ -1060,7 +1214,7 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sync: messages on disk -> scope
|
||||
// sync messages from disk to the folder model
|
||||
self.refreshFolder({
|
||||
folder: folder
|
||||
}, function(err) {
|
||||
@ -1088,7 +1242,12 @@ define(function(require) {
|
||||
//
|
||||
|
||||
/**
|
||||
* Mark imap messages as un-/read or un-/answered
|
||||
* Mark messages as un-/read or un-/answered on IMAP
|
||||
*
|
||||
* @param {Object} options.folder The folder where to find the message
|
||||
* @param {Number} options.uid The uid for which to change the flags
|
||||
* @param {Number} options.unread Un-/Read flag
|
||||
* @param {Number} options.answered Un-/Answered flag
|
||||
*/
|
||||
EmailDAO.prototype._imapMark = function(options, callback) {
|
||||
if (!this._account.online) {
|
||||
@ -1103,6 +1262,14 @@ define(function(require) {
|
||||
this._imapClient.updateFlags(options, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* If we're in the trash folder or no trash folder is available, this deletes a message from IMAP.
|
||||
* Otherwise, it moves a message to the trash folder.
|
||||
*
|
||||
* @param {Object} options.folder The folder where to find the message
|
||||
* @param {Number} options.uid The uid of the message
|
||||
* @param {Function} callback(error) Callback with an error object in case something went wrong.
|
||||
*/
|
||||
EmailDAO.prototype._imapDeleteMessage = function(options, callback) {
|
||||
if (!this._account.online) {
|
||||
callback({
|
||||
@ -1126,6 +1293,7 @@ define(function(require) {
|
||||
return;
|
||||
}
|
||||
|
||||
// move the message to the trash folder
|
||||
this._imapClient.moveMessage({
|
||||
path: options.folder.path,
|
||||
destination: trash.path,
|
||||
@ -1134,7 +1302,8 @@ define(function(require) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an email messsage without the body
|
||||
* Get list messsage headers without the body
|
||||
*
|
||||
* @param {String} options.folder The folder
|
||||
* @param {Number} options.firstUid The lower bound of the uid (inclusive)
|
||||
* @param {Number} options.lastUid The upper bound of the uid range (inclusive)
|
||||
@ -1192,16 +1361,38 @@ define(function(require) {
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* List the locally available items form the indexed db stored under "email_[FOLDER PATH]_[MESSAGE UID]" (if a message was provided),
|
||||
* or "email_[FOLDER PATH]", respectively
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to list the content
|
||||
* @param {Object} options.uid A specific uid to look up locally in the folder
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localListMessages = function(options, callback) {
|
||||
var dbType = 'email_' + options.folder.path + (options.uid ? '_' + options.uid : '');
|
||||
this._devicestorage.listItems(dbType, 0, null, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores a bunch of messages to the indexed db. The messages are stored under "email_[FOLDER PATH]_[MESSAGE UID]"
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to list the content
|
||||
* @param {Array} options.messages The messages to store
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localStoreMessages = function(options, callback) {
|
||||
var dbType = 'email_' + options.folder.path;
|
||||
this._devicestorage.storeList(options.emails, dbType, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores a bunch of messages to the indexed db. The messages are stored under "email_[FOLDER PATH]_[MESSAGE UID]"
|
||||
*
|
||||
* @param {Object} options.folder The folder for which to list the content
|
||||
* @param {Array} options.messages The messages to store
|
||||
* @param {Function} callback(error, list) Invoked with the results of the query, or further information, if an error occurred
|
||||
*/
|
||||
EmailDAO.prototype._localDeleteMessage = function(options, callback) {
|
||||
var path = options.folder.path,
|
||||
uid = options.uid,
|
||||
@ -1225,21 +1416,25 @@ define(function(require) {
|
||||
//
|
||||
//
|
||||
|
||||
/**
|
||||
* Updates a folder's unread count:
|
||||
* - For the outbox, that's the total number of messages,
|
||||
* - For every other folder, it's the number of unread messages
|
||||
*/
|
||||
function updateUnreadCount(folder) {
|
||||
var allMsgs = folder.messages.length,
|
||||
unreadMsgs = _.filter(folder.messages, function(msg) {
|
||||
return msg.unread;
|
||||
}).length;
|
||||
|
||||
// for the outbox, the unread count is determined by ALL the messages
|
||||
// whereas for normal folders, only the unread messages matter
|
||||
folder.count = folder.path === config.outboxMailboxPath ? allMsgs : unreadMsgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that recursively traverses the body parts tree. Looks for bodyParts that match the provided type and aggregates them
|
||||
* @param {[type]} bodyParts The bodyParts array
|
||||
* @param {[type]} type The type to look up
|
||||
*
|
||||
* @param {Array} bodyParts The bodyParts array
|
||||
* @param {String} type The type to look up
|
||||
* @param {undefined} result Leave undefined, only used for recursion
|
||||
*/
|
||||
function filterBodyParts(bodyParts, type, result) {
|
||||
|
@ -1584,6 +1584,7 @@ define(function(require) {
|
||||
setFlagsStub.withArgs({
|
||||
folder: inboxFolder,
|
||||
message: msgs[0],
|
||||
localOnly: true
|
||||
}).yieldsAsync();
|
||||
|
||||
dao.onError = function(err) {
|
||||
|
Loading…
Reference in New Issue
Block a user