redirect(route('ui.webmail.login')); return; } // Restore staged attachments from session, drop any whose files were cleaned up $staged = session('compose_attachments', []); $this->stagedAttachments = array_values( array_filter($staged, fn($a) => Storage::exists($a['path'])) ); $user = MailUser::where('email', session('webmail_email'))->first(); $prefs = $user?->webmail_prefs ?? []; $sig = (string) ($user?->signature ?? ''); if ($this->draftUid > 0) { $this->loadDraft(); return; } // Signatur laden — wird NICHT in den Body injiziert, sondern separat angezeigt if ($sig) { $this->signatureIsHtml = (bool) preg_match('/<[a-zA-Z][^>]*>/', $sig); $applyNew = ($prefs['signature_new'] ?? true); $applyReply = ($prefs['signature_reply'] ?? false); if ($this->replyUid > 0 && $applyReply) { $this->signatureRaw = $sig; } elseif ($this->replyUid === 0 && $applyNew) { $this->signatureRaw = $sig; } } if ($this->replyUid > 0) { $this->loadReply(); return; } } // Called by Livewire when $attachments changes (after upload completes) public function updatedAttachments(): void { $dir = 'webmail-tmp/' . session()->getId(); foreach ($this->attachments as $file) { $filename = uniqid('att_') . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $file->getClientOriginalName()); $path = $file->storeAs($dir, $filename, 'local'); $this->stagedAttachments[] = [ 'name' => $file->getClientOriginalName(), 'size' => $file->getSize(), 'mime' => $file->getMimeType() ?: 'application/octet-stream', 'path' => $path, ]; } $this->attachments = []; session(['compose_attachments' => $this->stagedAttachments]); } private function loadDraft(): void { $this->isDraft = true; try { $imap = app(ImapService::class); $client = $imap->client(session('webmail_email'), session('webmail_password')); $orig = $imap->getMessage($client, $this->draftFolder, $this->draftUid); $client->disconnect(); $this->to = $orig['to'] ?? ''; $this->subject = $orig['subject'] ?? ''; $this->body = $orig['text'] ?? strip_tags($orig['html'] ?? ''); } catch (\Throwable) {} } private function loadReply(): void { $this->isReply = true; try { $imap = app(ImapService::class); $client = $imap->client(session('webmail_email'), session('webmail_password')); $orig = $imap->getMessage($client, $this->replyFolder, $this->replyUid); $client->disconnect(); $this->to = $orig['from'] ?? ''; $sub = $orig['subject'] ?? ''; $this->subject = str_starts_with(strtolower($sub), 're:') ? $sub : 'Re: ' . $sub; $date = $orig['date'] ? \Carbon\Carbon::parse($orig['date'])->format('d.m.Y \u\m H:i \U\h\r') : ''; $fromName = $orig['from_name'] ?: ($orig['from'] ?? ''); $fromAddr = $orig['from'] ?? ''; $this->replyMeta = "Am {$date} schrieb {$fromName} <{$fromAddr}>:"; $quoteText = $orig['text'] ?: strip_tags($orig['html'] ?? ''); $quoted = implode("\n", array_map( fn($l) => '> ' . $l, explode("\n", rtrim($quoteText)) )); $this->body = "\n\n\n" . $this->replyMeta . "\n" . $quoted; } catch (\Throwable) {} } public function back(): void { $hasContent = trim($this->to) || trim($this->subject) || trim(preg_replace('/^[\s>]+$/m', '', $this->body)); if ($hasContent) { $this->saveCurrentDraft(true); } $this->clearStagedAttachments(); $this->redirect(route('ui.webmail.inbox')); } public function send(): void { $this->validate([ 'to' => 'required|email', 'subject' => 'required|string|max:255', 'body' => 'required|string', ]); try { $imap = app(ImapService::class); if ($this->signatureIsHtml && $this->signatureRaw) { $htmlBody = '
' . htmlspecialchars($this->body) . '
' . '
' . $this->signatureRaw . '
'; $imap->sendMessage( session('webmail_email'), session('webmail_password'), $this->to, $this->subject, $htmlBody, $this->stagedAttachments, true, ); } else { $plainBody = $this->body; if ($this->signatureRaw) { $plainBody .= "\n\n" . $this->normalizeSignature($this->signatureRaw); } $imap->sendMessage( session('webmail_email'), session('webmail_password'), $this->to, $this->subject, $plainBody, $this->stagedAttachments, ); } if ($this->draftUid > 0) { try { $client = $imap->client(session('webmail_email'), session('webmail_password')); $imap->deleteMessage($client, $this->draftFolder, $this->draftUid); $client->disconnect(); } catch (\Throwable) {} } $this->clearStagedAttachments(); $this->sent = true; $this->to = ''; $this->subject = ''; $this->body = ''; $this->isReply = false; $this->isDraft = false; $this->dispatch('toast', type: 'done', badge: 'Webmail', title: 'Gesendet', text: 'Nachricht wurde erfolgreich gesendet.', duration: 4000); } catch (\Throwable $e) { $this->addError('to', 'Senden fehlgeschlagen: ' . $e->getMessage()); } } public function removeAttachment(int $index): void { if (isset($this->stagedAttachments[$index])) { Storage::delete($this->stagedAttachments[$index]['path']); } array_splice($this->stagedAttachments, $index, 1); session(['compose_attachments' => $this->stagedAttachments]); } private function normalizeSignature(string $sig): string { $trimmed = ltrim($sig, "\r\n"); // Prüfen ob der User bereits "-- " als Trenner eingetragen hat if (str_starts_with($trimmed, '-- ') || str_starts_with($trimmed, "--\n") || str_starts_with($trimmed, "--\r\n")) { return $trimmed; } return "-- \n" . $trimmed; } private function clearStagedAttachments(): void { foreach ($this->stagedAttachments as $att) { Storage::delete($att['path']); } $this->stagedAttachments = []; session()->forget('compose_attachments'); } private function saveCurrentDraft(bool $notify = false): void { try { $imap = app(ImapService::class); $client = $imap->client(session('webmail_email'), session('webmail_password')); if ($this->draftUid > 0) { $imap->deleteMessage($client, $this->draftFolder, $this->draftUid); } $imap->saveDraft($client, session('webmail_email'), $this->to, $this->subject, $this->body); $client->disconnect(); if ($notify) { $this->dispatch('toast', type: 'done', badge: 'Webmail', title: 'Entwurf gespeichert', text: 'Nachricht in Entwürfe gespeichert.', duration: 3000); } } catch (\Throwable $e) { \Illuminate\Support\Facades\Log::warning('Draft save failed', ['error' => $e->getMessage()]); } } public function autoSave(): void { if ($this->sent) return; $hasContent = trim($this->to) || trim($this->subject) || trim(preg_replace('/^[\s>]+$/m', '', $this->body)); if (! $hasContent) return; $this->saveCurrentDraft(false); } public function render() { return view('livewire.ui.webmail.compose'); } }