VulpesOS/gaia/apps/email/js/ext/drafts/draft_rep.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

192 lines
6 KiB
JavaScript
Executable file

/**
* Back-end draft abstraction.
*
* Drafts are saved to folder storage and look almost exactly like received
* messages. The primary difference is that attachments that are in the
* process of being attached are stored in an `attaching` field on the
* `BodyInfo` instance and that they are discarded on load if still present
* (indicating a crash/something like a crash during the save process).
*
**/
define(function(require) {
var mailRep = require('../db/mail_rep');
/**
* Create a new header and body for a draft by extracting any useful state
* from the previous draft's persisted header/body and the revised draft.
*
* @method mergeDraftStates
* @param oldHeader {HeaderInfo}
* @param oldBody {BodyInfo}
* @param newDraftRep {DraftRep}
* @param newDraftInfo {Object}
* @param newDraftInfo.id {Number}
* @param newDraftInfo.suid {SUID}
* @param newDraftInfo.date {Number}
*/
function mergeDraftStates(oldHeader, oldBody,
newDraftRep, newDraftInfo,
universe) {
var identity = universe.getIdentityForSenderIdentityId(newDraftRep.senderId);
// -- convert from compose rep to header/body rep
var newHeader = mailRep.makeHeaderInfo({
id: newDraftInfo.id,
srvid: null, // stays null
suid: newDraftInfo.suid, // filled in by the job
// we currently don't generate a message-id for drafts, but we'll need to
// do this when we start appending to the server.
guid: oldHeader ? oldHeader.guid : null,
author: { name: identity.name, address: identity.address},
to: newDraftRep.to,
cc: newDraftRep.cc,
bcc: newDraftRep.bcc,
replyTo: identity.replyTo,
date: newDraftInfo.date,
flags: [],
hasAttachments: oldBody ? oldBody.attachments.length > 0 : false,
subject: newDraftRep.subject,
snippet: newDraftRep.body.text.substring(0, 100),
});
var newBody = mailRep.makeBodyInfo({
date: newDraftInfo.date,
size: 0,
attachments: oldBody ? oldBody.attachments.concat() : [],
relatedParts: oldBody ? oldBody.relatedParts.concat() : [],
references: newDraftRep.referencesStr,
bodyReps: []
});
newBody.bodyReps.push(mailRep.makeBodyPart({
type: 'plain',
part: null,
sizeEstimate: newDraftRep.body.text.length,
amountDownloaded: newDraftRep.body.text.length,
isDownloaded: true,
_partInfo: {},
content: [0x1, newDraftRep.body.text]
}));
if (newDraftRep.body.html) {
newBody.bodyReps.push(mailRep.makeBodyPart({
type: 'html',
part: null,
sizeEstimate: newDraftRep.body.html.length,
amountDownloaded: newDraftRep.body.html.length,
isDownloaded: true,
_partInfo: {},
content: newDraftRep.body.html
}));
}
return {
header: newHeader,
body: newBody
};
}
function convertHeaderAndBodyToDraftRep(account, header, body) {
var composeBody = {
text: '',
html: null,
};
// Body structure should be guaranteed, but add some checks.
if (body.bodyReps.length >= 1 &&
body.bodyReps[0].type === 'plain' &&
body.bodyReps[0].content.length === 2 &&
body.bodyReps[0].content[0] === 0x1) {
composeBody.text = body.bodyReps[0].content[1];
}
// HTML is optional, but if present, should satisfy our guard
if (body.bodyReps.length == 2 &&
body.bodyReps[1].type === 'html') {
composeBody.html = body.bodyReps[1].content;
}
var attachments = [];
body.attachments.forEach(function(att) {
attachments.push({
name: att.name,
blob: att.file
});
});
var draftRep = {
identity: account.identities[0],
subject: header.subject,
body: composeBody,
to: header.to,
cc: header.cc,
bcc: header.bcc,
referencesStr: body.references,
attachments: attachments
};
}
/**
* Given the HeaderInfo and BodyInfo for a draft, create a new header and body
* suitable for saving to the sent folder for a POP3 account. Specifically:
* - mark the message as read
* - make sure body.attaching does not make it through
* - strip the Blob references so we don't accidentally keep the base64
* encoded attachment parts around forever and clog up the disk.
* - avoid accidental use of the same instances between the drafts folder and
* the sent folder
*
* @param header {HeaderInfo}
* @param body {BodyInfo}
* @param newInfo
* @param newInfo.id
* @param newInfo.suid {SUID}
* @return { header, body }
*/
function cloneDraftMessageForSentFolderWithoutAttachments(header, body,
newInfo) {
// clone the header (drops excess fields)
var newHeader = mailRep.makeHeaderInfo(header);
// clobber the id/suid
newHeader.id = newInfo.id;
newHeader.suid = newInfo.suid;
// Mark the message as read. We are clobbering other flags, but we don't
// currently support a way for them to exist.
newHeader.flags = ['\\Seen'];
// clone the body, dropping excess fields like "attaching".
var newBody = mailRep.makeBodyInfo(body);
// transform attachments
if (newBody.attachments) {
newBody.attachments = newBody.attachments.map(function(oldAtt) {
var newAtt = mailRep.makeAttachmentPart(oldAtt);
// mark the attachment as non-downloadable
newAtt.type = 'application/x-gelam-no-download';
// get rid of the blobs!
newAtt.file = null;
// we will keep around the sizeEstimate so they know how much they sent
// and we keep around encoding/charset/textFormat because we don't care
return newAtt;
});
}
// We currently can't generate related parts, but just in case.
if (newBody.relatedParts) {
newBody.relatedParts = [];
}
// Body parts can be transferred verbatim.
newBody.bodyReps = newBody.bodyReps.map(function(oldRep) {
return mailRep.makeBodyPart(oldRep);
});
return { header: newHeader, body: newBody };
}
return {
mergeDraftStates: mergeDraftStates,
convertHeaderAndBodyToDraftRep: convertHeaderAndBodyToDraftRep,
cloneDraftMessageForSentFolderWithoutAttachments:
cloneDraftMessageForSentFolderWithoutAttachments
};
}); // end define