1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-12 04:05:13 -05:00
mail/src/js/bo/outbox.js

315 lines
10 KiB
JavaScript
Raw Normal View History

define(function(require) {
'use strict';
var _ = require('underscore'),
str = require('js/app-config').string,
config = require('js/app-config').config,
InvitationDAO = require('js/dao/invitation-dao'),
dbType = 'email_OUTBOX';
2013-11-21 04:57:22 -05:00
/**
2013-11-21 05:37:18 -05:00
* High level business object that orchestrates the local outbox.
* The local outbox takes care of the emails before they are being sent.
2013-11-21 04:57:22 -05:00
* It also checks periodically if there are any mails in the local device storage to be sent.
*/
2013-12-02 09:48:59 -05:00
var OutboxBO = function(emailDao, keychain, devicestorage, invitationDao) {
/** @private */
2013-12-02 09:48:59 -05:00
this._emailDao = emailDao;
/** @private */
this._keychain = keychain;
/** @private */
this._devicestorage = devicestorage;
/** @private */
2013-12-02 09:48:59 -05:00
this._invitationDao = invitationDao;
/**
* Semaphore-esque flag to avoid 'concurrent' calls to _processOutbox when the timeout fires, but a call is still in process.
* @private */
this._outboxBusy = false;
/**
* Pending, unsent emails stored in the outbox. Updated on each call to _processOutbox
* @public */
this.pendingEmails = [];
};
OutboxBO.prototype.init = function() {
var outboxFolder = _.findWhere(this._emailDao._account.folders, {
type: 'Outbox'
});
outboxFolder.messages = this.pendingEmails;
};
2013-11-21 04:57:22 -05:00
/**
* This function activates the periodic checking of the local device storage for pending mails.
* @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails.
*/
OutboxBO.prototype.startChecking = function(callback) {
// start periodic checking of outbox
this._intervalId = setInterval(this._processOutbox.bind(this, callback), config.checkOutboxInterval);
};
2013-11-21 04:57:22 -05:00
/**
* Outbox stops the periodic checking of the local device storage for pending mails.
*/
OutboxBO.prototype.stopChecking = function() {
if (!this._intervalId) {
return;
}
clearInterval(this._intervalId);
delete this._intervalId;
};
/**
* Private Api which is called whenever a message has been sent
* The public callback "onSent" can be set by the caller to get notified.
*/
OutboxBO.prototype._onSent = function(message) {
if (typeof this.onSent === 'function') {
this.onSent(message);
}
};
2013-11-21 04:57:22 -05:00
/**
* Checks the local device storage for pending mails.
* @param {Function} callback(error, pendingMailsCount) Callback that informs you about the count of pending mails.
*/
OutboxBO.prototype._processOutbox = function(callback) {
var self = this,
emails;
2013-11-21 05:37:18 -05:00
// if a _processOutbox call is still in progress when a new timeout kicks
// in, since sending mails might take time, ignore it. otherwise, mails
// could get sent multiple times
if (self._outboxBusy) {
return;
}
checkStorage();
function checkStorage() {
self._outboxBusy = true;
// get last item from outbox
2014-02-06 05:55:24 -05:00
self._emailDao.listForOutbox(function(err, pending) {
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
// update outbox folder count
emails = pending;
// fill all the pending mails into the pending mails array
self.pendingEmails.length = 0; //fastest way to empty an array
pending.forEach(function(i) {
self.pendingEmails.push(i);
});
2014-01-20 05:03:01 -05:00
// we're not online, don't even bother sending mails
if (!self._emailDao._account.online) {
self._outboxBusy = false;
callback(null, self.pendingEmails.length);
return;
}
// sending pending mails
processMails();
});
}
2013-11-21 05:37:18 -05:00
// process the next pending mail
function processMails() {
if (emails.length === 0) {
2013-11-21 05:37:18 -05:00
// in the navigation controller, this updates the folder count
self._outboxBusy = false;
callback(null, self.pendingEmails.length);
return;
}
2013-11-21 05:37:18 -05:00
// in the navigation controller, this updates the folder count
callback(null, self.pendingEmails.length);
var email = emails.shift();
checkReceivers(email);
}
2013-11-21 05:37:18 -05:00
// check whether there are unregistered receivers, i.e. receivers without a public key
function checkReceivers(email) {
var unregisteredUsers, receiverChecked;
unregisteredUsers = [];
receiverChecked = _.after(email.to.length, function() {
2013-11-21 05:37:18 -05:00
// invite unregistered users if necessary
if (unregisteredUsers.length > 0) {
invite(unregisteredUsers);
return;
}
sendEncrypted(email);
});
2013-11-21 05:37:18 -05:00
// find out if there are unregistered users
email.to.forEach(function(recipient) {
self._keychain.getReceiverPublicKey(recipient.address, function(err, key) {
if (err) {
2013-11-21 05:37:18 -05:00
self._outboxBusy = false;
callback(err);
return;
}
if (!key) {
unregisteredUsers.push(recipient);
}
receiverChecked();
});
});
}
2013-11-21 05:37:18 -05:00
// invite the unregistered receivers, if necessary
function invite(addresses) {
2013-12-02 09:48:59 -05:00
var sender = self._emailDao._account.emailAddress;
var invitationFinished = _.after(addresses.length, function() {
// after all of the invitations are checked and sent (if necessary),
processMails();
});
2013-11-21 05:37:18 -05:00
// check which of the adresses has pending invitations
addresses.forEach(function(recipient) {
var recipientAddress = recipient.address;
2013-11-21 05:37:18 -05:00
2013-12-02 09:48:59 -05:00
self._invitationDao.check({
recipient: recipientAddress,
sender: sender
}, function(err, status) {
2013-11-21 05:37:18 -05:00
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
if (status === InvitationDAO.INVITE_PENDING) {
// the recipient is already invited, we're done here.
invitationFinished();
return;
}
2013-11-21 05:37:18 -05:00
// the recipient is not yet invited, so let's do that
2013-12-02 09:48:59 -05:00
self._invitationDao.invite({
recipient: recipientAddress,
sender: sender
}, function(err, status) {
if (err) {
2013-11-21 05:37:18 -05:00
self._outboxBusy = false;
callback(err);
return;
}
if (status !== InvitationDAO.INVITE_SUCCESS) {
2013-11-21 05:37:18 -05:00
self._outboxBusy = false;
callback({
errMsg: 'could not successfully invite ' + recipientAddress
});
return;
}
sendInvitationMail(recipient, sender);
});
});
});
2013-11-21 05:37:18 -05:00
// send an invitation to the unregistered user, aka the recipient
function sendInvitationMail(recipient, sender) {
var invitationMail = {
from: [sender],
to: [recipient],
subject: str.invitationSubject,
body: 'Hi,\n\n' + str.invitationMessage + '\n\n'
};
// send invitation mail
self._emailDao.sendPlaintext({
email: invitationMail
}, function(err) {
if (err) {
2013-11-21 05:37:18 -05:00
self._outboxBusy = false;
if (err.code === 42) {
// offline try again later
callback();
} else {
callback(err);
}
2013-11-21 05:37:18 -05:00
return;
}
// fire sent notification
self._onSent(invitationMail);
invitationFinished();
});
}
}
function sendEncrypted(email) {
2013-12-04 09:36:20 -05:00
self._emailDao.sendEncrypted({
email: email
}, function(err) {
if (err) {
self._outboxBusy = false;
if (err.code === 42) {
// offline try again later
callback();
} else {
callback(err);
}
return;
}
// the email has been sent, remove from pending mails
removeFromPendingMails(email);
// fire sent notification
self._onSent(email);
removeFromStorage(email.id);
});
}
// update the member so that the outbox can visualize
function removeFromPendingMails(email) {
var i = self.pendingEmails.indexOf(email);
self.pendingEmails.splice(i, 1);
}
function removeFromStorage(id) {
if (!id) {
self._outboxBusy = false;
callback({
errMsg: 'Cannot remove email from storage without a valid id!'
});
return;
}
// delete email from local storage
var key = dbType + '_' + id;
self._devicestorage.removeList(key, function(err) {
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
processMails();
});
}
};
return OutboxBO;
});