"-Zitate, und dass nichts getrennt wird, wenn vor dem Zitat kein eigener Text steht. */ putenv('DESKHUB_TESTING=1'); putenv('DESKHUB_SQLITE_PATH=:memory:'); require_once dirname(__DIR__) . '/includes/bootstrap.php'; require_once dirname(__DIR__) . '/includes/mail_text.php'; $failures = []; $check = function (bool $ok, string $what) use (&$failures): void { if (!$ok) $failures[] = $what; }; // ── Text ───────────────────────────────────────────────────────────────────── [$new, $q] = mail_split_quoted_text("und de nächste Teil von Haus Ledwin\n\nGesendet: Sonntag, 11. Oktober 2026 um 07:42\nVon: Windelgeschichten \nAn: \"Olaf Andresen\" \nBetreff: AW: [#923425] Haus Ledwin Teil 11\n\nHallo Olaf Andresen,\nVielen Dank!"); $check($new === 'und de nächste Teil von Haus Ledwin' && str_starts_with($q, 'Gesendet: Sonntag') && str_contains($q, 'Vielen Dank!'), 'Outlook-Mailkopf (Gesendet vor Von): Verlauf wird abgetrennt: ' . json_encode([$new, substr($q, 0, 30)])); [$new, $q] = mail_split_quoted_text("Danke, passt.\n\nVon: Support \nGesendet: Montag\nAn: Kunde\nBetreff: Re: Frage\n\nAlter Text"); $check($new === 'Danke, passt.' && str_starts_with($q, 'Von: Support'), 'Mailkopf in der üblichen Reihenfolge (Von zuerst)'); [$new, $q] = mail_split_quoted_text("Ja, bitte so machen.\n\nAm 02.11.2026 um 10:15 schrieb Anna Muster :\n> Können Sie das prüfen?\n> Danke"); $check($new === 'Ja, bitte so machen.' && str_starts_with($q, 'Am 02.11.2026') && str_contains($q, '> Können'), '„Am … schrieb …:“ wird abgetrennt'); [$new, $q] = mail_split_quoted_text("Ja.\n\nAm Montag, 2. November 2026 um 10:15 Uhr schrieb Anna Muster\n:\n\nText"); $check($new === 'Ja.' && $q !== '', '„schrieb“ mit Umbruch in der Ankündigungszeile'); [$new, $q] = mail_split_quoted_text("Yes, thanks.\n\nOn Mon, Nov 2, 2026 at 10:15 AM Anna wrote:\n> Please check"); $check($new === 'Yes, thanks.' && str_starts_with($q, 'On Mon'), '„On … wrote:“ wird abgetrennt'); [$new, $q] = mail_split_quoted_text("Antwort\n\n-----Ursprüngliche Nachricht-----\nVon: x\nText"); $check($new === 'Antwort' && str_starts_with($q, '-----Urspr'), '„Ursprüngliche Nachricht“ wird abgetrennt'); [$new, $q] = mail_split_quoted_text("Antwort\n> altes Zitat\n> noch eins"); $check($new === 'Antwort' && str_starts_with($q, '> altes'), '">"-Zeilen ohne Ankündigung werden abgetrennt'); [$new, $q] = mail_split_quoted_text("Von: Support \nGesendet: Montag\nAn: Kunde\nBetreff: Re\n\nText der weitergeleiteten Mail"); $check($q === '' && str_starts_with($new, 'Von: Support'), 'ganz zitierte/weitergeleitete Mail ohne eigenen Text wird nicht getrennt'); [$new, $q] = mail_split_quoted_text("Hallo,\n\nAn Ihrer Adresse hat sich nichts geändert.\nVon uns aus gibt es nichts Neues: bitte melden.\n\nGruß"); $check($q === '' && $new === "Hallo,\n\nAn Ihrer Adresse hat sich nichts geändert.\nVon uns aus gibt es nichts Neues: bitte melden.\n\nGruß", 'normaler Text mit „An“ und „Von“ im Satz bleibt ungetrennt'); [$new, $q] = mail_split_quoted_text("Nur Text ohne Zitat."); $check($q === '' && $new === 'Nur Text ohne Zitat.', 'Text ohne Zitat bleibt unverändert'); [$new, $q] = mail_split_quoted_text("Von: Anna\nIch melde mich morgen.\n\nBis dann"); $check($q === '', 'eine einzelne „Von:“-Zeile ist noch kein Mailkopf'); // ── HTML ───────────────────────────────────────────────────────────────────── $outlook = '

und de nächste Teil von Haus Ledwin


Gesendet: Sonntag, 11. Oktober 2026 um 07:42
Von: Windelgeschichten <einsendungen@windelgeschichten.org>
An: Olaf
Betreff: AW: [#923425] Haus Ledwin Teil 11

Hallo Olaf Andresen,

Vielen Dank!

'; [$new, $q] = mail_split_quoted_html($outlook); $check(str_contains($new, 'und de nächste Teil') && !str_contains($new, 'Gesendet') && str_contains($q, 'Gesendet:') && str_contains($q, 'Vielen Dank!'), 'Outlook-HTML: Linie und Mailkopf trennen den Verlauf ab'); $check(substr_count($new, '') && substr_count($q, ''), 'beide Teile sind in sich ausgeglichen (offene Tags geschlossen)'); $nested = '

Neu


Von: a
Gesendet: b
An: c
Betreff: d

alt

'; [$new, $q] = mail_split_quoted_html($nested); $check(substr_count($new, '') && !str_contains($q, '') || substr_count($q, '= 0, 'verschachtelte Blöcke werden nicht zerrissen'); $check(trim(strip_tags($new)) === 'Neu' && str_contains(strip_tags($q), 'alt'), 'verschachtelt: neuer Teil „Neu“, Verlauf „alt“: ' . json_encode([strip_tags($new), strip_tags($q)])); $border = '

Danke

Von: x
Gesendet: y
An: z
Betreff: w

alter Text

'; [$new, $q] = mail_split_quoted_html($border); $check(trim(strip_tags($new)) === 'Danke' && str_contains(strip_tags($q), 'alter Text'), 'Block mit oberem Rahmen (Outlook klassisch) trennt den Verlauf ab'); [$new, $q] = mail_split_quoted_html('

Hallo


Nur eine Linie, kein Mailkopf

'); $check($q === '', 'Linie ohne Mailkopf trennt nichts'); [$new, $q] = mail_split_quoted_html('
Von: a
Gesendet: b
An: c
'); $check($q === '', 'HTML ganz ohne eigenen Text davor wird nicht getrennt'); [$new, $q] = mail_split_quoted_html('

Ohne Zitat

'); $check($q === '' && $new === '

Ohne Zitat

', 'HTML ohne Zitat bleibt unverändert'); // Eingeklappter Block $w = mail_quote_wrap('

alt

'); $check(str_contains($w, 'email-quote-toggle') && str_contains($w, 'display:none') && str_contains($w, '

alt

'), 'Block ist standardmäßig zugeklappt'); // Sicherheit: Skripte im zitierten Teil bleiben auch nach dem Trennen bereinigt (Eingabe ist bereits bereinigt) [$new, $q] = mail_split_quoted_html(sanitize_staff_html('

Neu


Von: a
Gesendet: b
An: c
')); $check(!str_contains($new . $q, '