Mehrfachauswahl öffnet jetzt EIN Ablagefenster (?messageIds=1,2,3) statt eines Fensters je Nachricht. Der dafür schon vorhandene, bisher unerreichbare Multi-Pfad in dialog.js hatte drei Fehler, die dabei aufgeschlagen wären: - Der Anhang-Haken wurde aus der ERSTEN Mail abgeleitet: hatte die keine Anhänge, fielen die Anhänge aller übrigen Mails still weg. - Die Anhangsliste zeigte die Anhänge von Mail 1 mit wirkungslosen Haken. - Der „bereits abgelegt"-Banner galt nur für Mail 1, sah aber nach einer Aussage über die ganze Auswahl aus. Weiter: - Server-/Zugangsdaten-Wechsel verwirft jetzt auch die serverspezifischen Caches. auth:logout leert zusätzlich ARCHIVED_CACHE; mit scope:"server" fliegen die gecachte Schrankliste sowie defaultCabinetId/dialogByCabinet raus, weil deren GUIDs nur auf dem alten Server existieren. - Retry nach einem Teilfehler lud bereits übertragene Teile erneut hoch und erzeugte Dubletten. Jeder Teil (eml/pdf/Anhang) wird nun je Ziel einmal hochgeladen; dieselbe Mail lässt sich dadurch auch bewusst in ein zweites Archiv ablegen. - ARCHIVED_CACHE wächst nicht mehr unbegrenzt (500 Einträge, ältester fliegt). - HTTP 401/403 liefern statt des nackten Statuscodes eine verständliche Meldung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
187 lines
7.2 KiB
JavaScript
187 lines
7.2 KiB
JavaScript
// Hintergrund-Skript: Button + Kontextmenü, öffnet den Ablage-Dialog.
|
||
// Zusätzlich Auth-Broker: hält den OAuth-Token nur im Speicher dieser TB-Sitzung
|
||
// (siehe auth.js). Das Passwort wird einmalig zum Login durchgereicht, daraus ein
|
||
// Token geholt und sofort verworfen – es wird NIE gespeichert.
|
||
|
||
const DIALOG_URL = "dialog/dialog.html";
|
||
|
||
// Auth-Broker: Dialog-/Optionsfenster fragen hier den Sitzungs-Token an bzw.
|
||
// melden sich mit dem Passwort an. So muss das Passwort nur 1x pro Sitzung getippt
|
||
// werden und liegt nirgends auf der Platte.
|
||
browser.runtime.onMessage.addListener((msg) => {
|
||
if (!msg || !msg.type) return undefined;
|
||
|
||
if (msg.type === "auth:status") {
|
||
return Promise.resolve({ hasToken: Auth.hasValidToken(), token: Auth.currentToken() });
|
||
}
|
||
|
||
if (msg.type === "auth:logon") {
|
||
return (async () => {
|
||
try {
|
||
const settings = await Settings.get();
|
||
if (!settings.serverUrl) throw new Error("Keine DocuWare-Server-URL konfiguriert.");
|
||
Auth.reset();
|
||
const r = await Auth.logon({ ...settings, password: msg.password || "" });
|
||
// Passwort wird hier verworfen – nur der Token bleibt im Speicher.
|
||
return { ok: true, mode: r.mode, token: Auth.currentToken() };
|
||
} catch (e) {
|
||
return { ok: false, error: String((e && e.message) || e) };
|
||
}
|
||
})();
|
||
}
|
||
|
||
// Sitzung verwerfen. Immer: Token + Badge-Cache (der Cache ist serverspezifisch
|
||
// und würde sonst ein ✓ aus der alten Verbindung weiterzeigen).
|
||
// scope:"server" = die Server-URL hat sich geändert -> zusätzlich die gecachte
|
||
// Schrankliste wegwerfen, denn deren GUIDs gehören zum alten Server.
|
||
if (msg.type === "auth:logout") {
|
||
Auth.reset();
|
||
ARCHIVED_CACHE.clear();
|
||
if (msg.scope === "server") {
|
||
return browser.storage.local
|
||
.remove("cabinets")
|
||
.catch(() => {})
|
||
.then(() => ({ ok: true }));
|
||
}
|
||
return Promise.resolve({ ok: true });
|
||
}
|
||
|
||
// Dialog meldet eine erfolgreiche Ablage -> Badge-Cache aktualisieren, damit
|
||
// die Mail beim nächsten Anzeigen sofort als „abgelegt" erscheint.
|
||
if (msg.type === "archive:done") {
|
||
const mid = DocuWare.normalizeMessageId(msg.rfcMessageId);
|
||
if (mid && msg.cabinetId) {
|
||
cacheArchived(`${mid}|${msg.cabinetId}`, { found: true, docId: msg.docId || null });
|
||
}
|
||
return Promise.resolve({ ok: true });
|
||
}
|
||
|
||
return undefined;
|
||
});
|
||
|
||
// --- „Bereits abgelegt"-Badge am Nachrichten-Button ------------------------
|
||
// Beim Anzeigen einer Mail im Standard-Schrank nach der Message-ID suchen und das
|
||
// Ergebnis als Badge (✓) am messageDisplayAction-Button zeigen. Pro Message-ID +
|
||
// Schrank wird das Ergebnis im Speicher gecacht (eine Suche pro Mail).
|
||
|
||
const ARCHIVED_CACHE = new Map(); // "messageId|cabinetId" -> { found, docId }
|
||
const ARCHIVED_CACHE_MAX = 500; // Obergrenze: Thunderbird-Sitzungen laufen wochenlang
|
||
|
||
// Schreibt in den Badge-Cache und hält ihn klein (ältester Eintrag fliegt raus –
|
||
// Map-Iteration ist Einfügereihenfolge).
|
||
function cacheArchived(key, info) {
|
||
if (ARCHIVED_CACHE.size >= ARCHIVED_CACHE_MAX && !ARCHIVED_CACHE.has(key)) {
|
||
ARCHIVED_CACHE.delete(ARCHIVED_CACHE.keys().next().value);
|
||
}
|
||
ARCHIVED_CACHE.set(key, info);
|
||
}
|
||
|
||
async function rfcMessageIdOf(messageId) {
|
||
try {
|
||
const full = await browser.messages.getFull(messageId);
|
||
const h = full && full.headers && full.headers["message-id"];
|
||
if (Array.isArray(h) && h.length) return String(h[0]).trim();
|
||
} catch (_) {}
|
||
return "";
|
||
}
|
||
|
||
function setBadge(tabId, found) {
|
||
try {
|
||
browser.messageDisplayAction.setBadgeText({ tabId, text: found ? "✓" : "" });
|
||
browser.messageDisplayAction.setTitle({
|
||
tabId,
|
||
title: found
|
||
? "Bereits in DocuWare abgelegt – klicken zum Prüfen/Ablegen"
|
||
: "In DocuWare ablegen",
|
||
});
|
||
if (found && browser.messageDisplayAction.setBadgeBackgroundColor) {
|
||
browser.messageDisplayAction.setBadgeBackgroundColor({ tabId, color: "#0e8a8a" });
|
||
}
|
||
} catch (_) {}
|
||
}
|
||
|
||
async function updateArchivedBadge(tab, message) {
|
||
const tabId = tab.id;
|
||
try {
|
||
if (!Auth.hasValidToken()) return setBadge(tabId, false); // ohne Login keine Suche
|
||
const settings = await Settings.get();
|
||
if (!settings.serverUrl || !settings.defaultCabinetId) return setBadge(tabId, false);
|
||
const mid = DocuWare.normalizeMessageId(await rfcMessageIdOf(message.id));
|
||
if (!mid) return setBadge(tabId, false);
|
||
|
||
const key = `${mid}|${settings.defaultCabinetId}`;
|
||
let info = ARCHIVED_CACHE.get(key);
|
||
if (!info) {
|
||
const hit = await DocuWare.findByMessageId(settings, settings.defaultCabinetId, mid).catch(
|
||
() => null
|
||
);
|
||
info = { found: !!hit, docId: hit ? hit.id : null };
|
||
cacheArchived(key, info);
|
||
}
|
||
setBadge(tabId, info.found);
|
||
} catch (_) {
|
||
setBadge(tabId, false);
|
||
}
|
||
}
|
||
|
||
browser.messageDisplay.onMessagesDisplayed.addListener((tab, displayed) => {
|
||
const msgs = Array.isArray(displayed) ? displayed : (displayed && displayed.messages) || [];
|
||
if (msgs.length === 1) updateArchivedBadge(tab, msgs[0]);
|
||
else setBadge(tab.id, false); // bei Mehrfachauswahl keine eindeutige Aussage
|
||
});
|
||
|
||
function openDialog(messageIds) {
|
||
const ids = (Array.isArray(messageIds) ? messageIds : [messageIds])
|
||
.map((id) => parseInt(id, 10))
|
||
.filter((n) => !isNaN(n));
|
||
if (!ids.length) return;
|
||
// EIN Ablagefenster für die gesamte Auswahl – dialog.js arbeitet die Liste
|
||
// nacheinander ab (Fortschritt „Mail 3/20"). Früher wurde pro Nachricht ein
|
||
// eigenes Fenster geöffnet, was bei größerer Auswahl unbrauchbar war.
|
||
const url = browser.runtime.getURL(`${DIALOG_URL}?messageIds=${ids.join(",")}`);
|
||
browser.windows.create({ url, type: "popup", width: 720, height: 820, left: 100, top: 80 });
|
||
}
|
||
|
||
// Button in der geöffneten Nachricht
|
||
browser.messageDisplayAction.onClicked.addListener(async (tab) => {
|
||
const msg = await browser.messageDisplay.getDisplayedMessage(tab.id);
|
||
if (msg) openDialog([msg.id]);
|
||
});
|
||
|
||
// Kontextmenü-Eintrag in der Nachrichtenliste
|
||
browser.menus.create({
|
||
id: "docuware-archive",
|
||
title: "In DocuWare ablegen",
|
||
contexts: ["message_list"],
|
||
});
|
||
|
||
browser.menus.onClicked.addListener((info) => {
|
||
if (info.menuItemId !== "docuware-archive") return;
|
||
const msgs = info.selectedMessages && info.selectedMessages.messages;
|
||
if (msgs && msgs.length > 0) openDialog(msgs.map((m) => m.id));
|
||
});
|
||
|
||
// Tastenkürzel (Strg+Alt+I): angezeigte bzw. alle markierten Nachrichten ablegen.
|
||
browser.commands.onCommand.addListener(async (command) => {
|
||
if (command !== "open-archive-dialog") return;
|
||
const ids = await currentMessageIds();
|
||
if (ids.length) openDialog(ids);
|
||
});
|
||
|
||
// Ermittelt die "aktiven" Nachrichten: erst die im Reader angezeigte, sonst
|
||
// alle im Nachrichtenlisten-Tab markierten.
|
||
async function currentMessageIds() {
|
||
try {
|
||
const [tab] = await browser.tabs.query({ active: true, currentWindow: true });
|
||
if (tab) {
|
||
const shown = await browser.messageDisplay
|
||
.getDisplayedMessage(tab.id)
|
||
.catch(() => null);
|
||
if (shown) return [shown.id];
|
||
}
|
||
const sel = await browser.mailTabs.getSelectedMessages().catch(() => null);
|
||
if (sel && sel.messages && sel.messages.length) return sel.messages.map((m) => m.id);
|
||
} catch (_) {}
|
||
return [];
|
||
}
|