/* RustBox UI module: 00-bootstrap.js */
(() => {
"use strict";
const root = document.documentElement;
const configuredBase = root.dataset.basePath || "/";
const BASE = configuredBase === "/" ? "" : configuredBase.replace(/\/$/, "");
const API = `${BASE}/api`;
const ICONS = `${BASE}/assets/icons.svg`;
const state = {
accounts: [],
accountId: localStorage.getItem("rustbox.activeAccount") || null,
folders: [],
folder: "INBOX",
collapsedFolders: new Set(),
page: 0,
perPage: 50,
total: 0,
messages: [],
selected: null,
selectedMessages: new Set(),
selectionMode: false,
searchContext: null,
searchAllResults: null,
currentDetail: null,
specialFolders: { sent: null, drafts: null, trash: null, junk: null, archive: null },
tags: [],
sieveScripts: [],
sieveInfo: null,
sieveEditingRuleId: null,
identities: [],
pgpKeys: [],
pgpPrefs: { wkdEnabled: true, hkpEnabled: false, requireTrustedEncryption: false },
pgpRecipientStatus: [],
authPolicy: { rememberMeEnabled: true, rememberMeDays: 30, sessionTimeoutHours: 24 },
contacts: [],
trustedSenders: new Set(),
contactGroups: [],
contactPhotoUrl: null,
calendarCursor: new Date(),
calendarView: localStorage.getItem("rustbox.calendarView") || "month",
threadExpanded: localStorage.getItem("rustbox.threadExpanded") !== "false",
calendarEvents: [],
savedSearches: [],
responseTemplates: [],
notificationPrefs: { enabled: true, sound: false, folders: ["INBOX"], dnd_enabled: false, dnd_start: "22:00", dnd_end: "07:00" },
mailPrefs: { messages_per_page: 50, mark_read_delay_ms: 0, remote_images: "ask", preferred_body: "auto", thread_mode: "threaded", collapse_quotes: true, show_snippets: true, default_sort: "date_desc", flagged_on_top: false, sync_imap_keywords: false },
currentFolderFlaggedOnTop: false,
markReadTimer: null,
ws: null,
wsRetryTimer: null,
realtimeRefreshTimer: null,
calendarReminderTimer: null,
composeDraftId: null,
composeAttachments: [],
composeDirty: false,
composeNeedsRemoteSync: false,
composeUploading: false,
composeReplyMeta: null,
composeInsertRange: null,
composeSelectedImage: null,
composeSignatureGeneration: 0,
identitySignatureRange: null,
inlineAttachmentIds: new Set(),
inlineImageCleanupTimer: null,
imageEditorBitmap: null,
imageEditorBlob: null,
draftSaveTimer: null,
prefs: {
theme: root.dataset.defaultTheme || "system", interfaceSkin: "default", presetScaleUnlocked: false, density: "compact", preview: "right", scale: "normal", language: "en", composeFormat: "html",
composeAutosaveMs: 3000, defaultPriority: "normal", requestMdnDefault: false, attachmentReminder: true, composeFontFamily: "system", replyPosition: "above", quoteStyle: "standard", forwardMode: "inline", spellcheckEnabled: true,
colorPreset: "sage", accentColor: "#6f9c86", backgroundColor: "#121513", panelColor: "#181c19", textColor: "#edf0ec", fontFamily: "system", fontSize: 13,
rowHeight: 58, folderPaneWidth: 228, messagePaneWidth: 420, borderRadius: 4,
contrast: "normal", showAvatars: true, showAttachmentIcons: true, showFlags: true, reduceMotion: false, dateFormat: "locale", timeFormat: "locale",
iconSize: 18, toolbarDensity: "normal", sidebarItemHeight: 29, readerMaxWidth: 0, composerWidth: 900, selectionColor: "#28352e", unreadFontWeight: 730, unreadBadgeStyle: "dot", compactHeaders: false, showBorders: true, scrollbarDensity: "thin", monochrome: false, folderBackground: "", messageBackground: "", readerBackground: "",
},
translations: {},
quotaWarningLevel: null,
networkOnline: navigator.onLine,
listStateTimer: null,
};
const $ = (selector, parent = document) => parent.querySelector(selector);
const $$ = (selector, parent = document) => [...parent.querySelectorAll(selector)];
const el = (tag, className, text) => {
const node = document.createElement(tag);
if (className) node.className = className;
if (text !== undefined) node.textContent = text;
return node;
};
function svgIcon(name) {
return ``;
}
function escapeHtml(value) {
return String(value ?? "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function stripRustBoxUiLeak(value) {
let text = String(value ?? "");
// Strip only RustBox's own embedded SVG sprite fragments if malformed MIME
// content captured adjacent UI markup. Legitimate SVG/code in mail remains.
text = text.replace(/