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.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,192 @@
/**
* 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