feat: implement vacation responder functionality with UI integration and localization
This commit is contained in:
+45
-1
@@ -40,9 +40,53 @@ function isValidRule(rule: unknown): rule is FilterRule {
|
||||
return r.conditions.every(isValidCondition) && r.actions.every(isValidAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect Stalwart-generated vacation-only scripts (no metadata).
|
||||
* These contain `vacation` command but no other filter logic we need to preserve.
|
||||
*/
|
||||
function detectVacationOnlyScript(content: string): ParseResult | null {
|
||||
// Must contain a vacation command
|
||||
if (!/\bvacation\b/.test(content)) return null;
|
||||
|
||||
// Strip requires, comments, and whitespace to see if only vacation remains
|
||||
const stripped = content
|
||||
.replace(/^\s*require\s+\[[^\]]*\]\s*;/gm, '')
|
||||
.replace(/#[^\n]*/g, '')
|
||||
.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.trim();
|
||||
|
||||
// After stripping, the only meaningful statement should be a vacation command.
|
||||
// Check there are no if/elsif/else blocks (i.e., no filter rules).
|
||||
if (/\b(?:if|elsif|else)\b/.test(stripped)) return null;
|
||||
|
||||
// Extract subject if present
|
||||
const subjectMatch = stripped.match(/:subject\s+"((?:[^"\\]|\\.)*)"/);
|
||||
const subject = subjectMatch ? subjectMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\') : '';
|
||||
|
||||
// Extract the body text (last quoted string in the vacation command)
|
||||
// Stalwart uses MIME format; extract the plain text after the MIME headers
|
||||
const mimeBodyMatch = stripped.match(/Content-Transfer-Encoding:[^\n]*\n\n([\s\S]*?)"\s*;\s*$/);
|
||||
const simpleBodyMatch = stripped.match(/vacation[^;]*"((?:[^"\\]|\\.)*)"\s*;\s*$/);
|
||||
let textBody = '';
|
||||
if (mimeBodyMatch) {
|
||||
textBody = mimeBodyMatch[1].trim();
|
||||
} else if (simpleBodyMatch) {
|
||||
textBody = simpleBodyMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
return {
|
||||
rules: [],
|
||||
isOpaque: false,
|
||||
vacation: { isEnabled: true, subject, textBody },
|
||||
};
|
||||
}
|
||||
|
||||
export function parseScript(content: string): ParseResult {
|
||||
const beginIdx = content.indexOf(METADATA_BEGIN);
|
||||
if (beginIdx === -1) return OPAQUE;
|
||||
if (beginIdx === -1) {
|
||||
// No metadata — check if it's a Stalwart vacation-only script
|
||||
return detectVacationOnlyScript(content) || OPAQUE;
|
||||
}
|
||||
|
||||
const endIdx = content.indexOf(METADATA_END, beginIdx);
|
||||
if (endIdx === -1) return OPAQUE;
|
||||
|
||||
Reference in New Issue
Block a user