Release Preview 20 shared desktop, Android and Sargo updates
Restore Gaia settings and media workflows, extend native network adapters, and align the APK payload. Generate French/English changelogs and website entries from the simplified JSON source. Validation: shared JS and Tundra unit tests; desktop workflows and persistence; signed APK payload parity; Sargo RAM and installed startup with boot readback. Android runtime qualification is recorded separately.
This commit is contained in:
parent
be2cdce823
commit
1311bed5e9
170 changed files with 19698 additions and 2495 deletions
29
services/mms.mjs
Normal file
29
services/mms.mjs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// JSON transport for Gaia attachments; blobs are encoded at the app boundary.
|
||||
export const MMS_MAX_BYTES = 600 * 1024;
|
||||
export function mmsPayload(message) {
|
||||
if (!message || !Array.isArray(message.receivers) || !message.receivers.length || message.receivers.length>10 ||
|
||||
message.receivers.some(n=>typeof n!=='string' || !/^\+?[0-9]{3,20}$/.test(n))) throw Error('INVALID_NUMBER');
|
||||
const parts=[];
|
||||
if(message.smil) parts.push({id:'smil.xml',type:'application/smil',data:utf8Base64(message.smil)});
|
||||
for(const [i,a] of (message.attachments || []).entries()) {
|
||||
const content=a.content;
|
||||
if(!content?.__vulpesBlobV1 || typeof content.base64!=='string' || !/^[A-Za-z0-9+/]*={0,2}$/.test(content.base64)) throw Error('INVALID_MMS');
|
||||
parts.push({id:a.location || a.id?.replace(/[<>]/g,'') || 'attachment-'+i,type:content.type,data:content.base64});
|
||||
}
|
||||
if(!parts.length || parts.length>20 || parts.reduce((n,p)=>n+Math.floor(p.data.length*3/4),0)>MMS_MAX_BYTES) throw Error('MMS_TOO_LARGE');
|
||||
return {recipients:message.receivers,subject:message.subject || '',parts};
|
||||
}
|
||||
function utf8Base64(text) {const bytes=new TextEncoder().encode(text);let s='';for(const byte of bytes)s+=String.fromCharCode(byte);return btoa(s);}
|
||||
export function receivedMms(row) {
|
||||
let smil='',body='';const attachments=[];
|
||||
for(const part of row.parts || []) {
|
||||
if(['application/smil','text/plain'].includes(part.type)) {
|
||||
const text=new TextDecoder().decode(Uint8Array.from(atob(part.data),c=>c.charCodeAt(0)));
|
||||
if(part.type==='application/smil') {smil=text;continue;}
|
||||
body+=text;
|
||||
}
|
||||
attachments.push({id:part.id,location:part.id,content:{__vulpesBlobV1:true,type:part.type,base64:part.data}});
|
||||
}
|
||||
return {...row,body,smil,attachments,timestamp:row.timestamp || Date.now()};
|
||||
}
|
||||
Loading…
Reference in a new issue