fetchQueue(); $this->selected = $val ? array_column($messages, 'id') : []; } public function flush(): void { @shell_exec('sudo postqueue -f >/dev/null 2>&1 &'); $this->dispatch('toast', type: 'info', title: 'Queue-Flush gestartet'); } public function deleteSelected(): void { $count = count($this->selected); foreach ($this->selected as $id) { @shell_exec('sudo postsuper -d ' . escapeshellarg($id) . ' 2>&1'); } $this->selected = []; $this->selectAll = false; $this->dispatch('toast', type: 'success', title: "{$count} Nachricht(en) gelöscht"); } public function deleteAll(): void { @shell_exec('sudo postsuper -d ALL 2>&1'); $this->selected = []; $this->selectAll = false; $this->dispatch('toast', type: 'warning', title: 'Alle Queue-Nachrichten gelöscht'); } public function openMessage(string $queueId): void { $this->dispatch('openModal', component: 'ui.nx.mail.modal.queue-message-modal', arguments: ['queueId' => $queueId] ); } public function render() { $all = $this->fetchQueue(); $counts = [ 'all' => count($all), 'active' => count(array_filter($all, fn($m) => $m['queue'] === 'active')), 'deferred' => count(array_filter($all, fn($m) => $m['queue'] === 'deferred')), 'hold' => count(array_filter($all, fn($m) => $m['queue'] === 'hold')), ]; $messages = $all; if ($this->filter !== 'all') { $messages = array_values(array_filter($messages, fn($m) => $m['queue'] === $this->filter)); } if ($this->search !== '') { $s = strtolower($this->search); $messages = array_values(array_filter($messages, fn($m) => str_contains(strtolower($m['sender'] ?? ''), $s) || str_contains(strtolower($m['recipient'] ?? ''), $s) || str_contains(strtolower($m['id'] ?? ''), $s) )); } return view('livewire.ui.nx.mail.queue-list', compact('messages', 'counts')); } // ── helpers ────────────────────────────────────────────────────────────── public function fetchQueue(): array { $out = trim(@shell_exec('postqueue -j 2>/dev/null') ?? ''); if ($out !== '') { return $this->parseJson($out); } return $this->parseText(trim(@shell_exec('postqueue -p 2>/dev/null') ?? '')); } private function parseJson(string $out): array { $rows = []; foreach (explode("\n", $out) as $line) { $line = trim($line); if ($line === '') continue; $m = json_decode($line, true); if (!is_array($m)) continue; $recipients = $m['recipients'] ?? []; $rcptList = array_column($recipients, 'address'); $reason = $recipients[0]['delay_reason'] ?? ''; $rows[] = [ 'id' => $m['queue_id'] ?? '', 'queue' => $m['queue_name'] ?? 'deferred', 'sender' => $m['sender'] ?? '', 'recipient' => implode(', ', $rcptList), 'size' => (int)($m['message_size'] ?? 0), 'arrival' => (int)($m['arrival_time'] ?? 0), 'reason' => $this->trimReason($reason), ]; } return $rows; } private function parseText(string $out): array { $rows = []; $current = null; foreach (explode("\n", $out) as $line) { if (preg_match('/^([A-F0-9]{9,})\*?\s+(\d+)\s+\S+\s+\S+\s+\d+\s+\d{1,2}:\d{2}:\d{2}\s+(.*)/i', $line, $m)) { if ($current) $rows[] = $current; $current = [ 'id' => $m[1], 'queue' => 'active', 'sender' => trim($m[3]), 'recipient' => '', 'size' => (int)$m[2], 'arrival' => 0, 'reason' => '', ]; } elseif ($current && preg_match('/^\s+([\w.+%-]+@[\w.-]+)/', $line, $m)) { $current['recipient'] = $m[1]; } elseif ($current && preg_match('/^\s+\((.+)\)/', $line, $m)) { $current['reason'] = $this->trimReason($m[1]); $current['queue'] = 'deferred'; } } if ($current) $rows[] = $current; return $rows; } private function trimReason(string $r): string { $r = preg_replace('/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s+/', '', trim($r)); return mb_strlen($r) > 100 ? mb_substr($r, 0, 100) . '…' : $r; } }