Fix: Mailbox Stats über Dovecot mit config/mailpool.php

main v1.0.55
boban 2025-10-26 18:41:54 +01:00
parent a943b42fec
commit c11d330c38
2 changed files with 100 additions and 32 deletions

View File

@ -15,42 +15,117 @@ class SpamAvCollectCommand extends Command
{
$this->info('Collecting Spam/AV metrics…');
// Rspamd counters (kein Root nötig)
$out = trim(@shell_exec('rspamc counters 2>/dev/null') ?? '');
$ham = preg_match('/\bham\s*:\s*(\d+)/i', $out, $m1) ? (int)$m1[1] : 0;
$spam = preg_match('/\bspam\s*:\s*(\d+)/i', $out, $m2) ? (int)$m2[1] : 0;
$reject = preg_match('/\breject\s*:\s*(\d+)/i', $out, $m3) ? (int)$m3[1] : 0;
$rpC = '/usr/bin/rspamc';
$rpA = '/usr/bin/rspamadm';
// ClamAV Version + Signatur-Datum robust ohne Datei-Zugriff
$clamLine = trim((string) @shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null'));
$clamVer = $clamLine !== '' ? $clamLine : '';
// --- RSPAMD: erst 'stat' (sicher), sonst 'counters' als Fallback ---
$ham = $spam = $reject = 0;
// Aus clamd/clamscan-Output das Datum am Ende herausziehen (Format: ".../Sun Oct 26 09:42:43 2025")
$stat = trim(@shell_exec("$rpC -h 127.0.0.1:11334 stat 2>/dev/null") ?? '');
if ($stat !== '') {
$ham = preg_match('/Messages treated as ham:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0;
$spam = preg_match('/Messages treated as spam:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0;
$reject = preg_match('/Messages with action reject:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0;
} else {
$cnt = trim(@shell_exec("$rpC -h 127.0.0.1:11334 counters 2>/dev/null") ?? '');
$ham = preg_match('/\bham\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0;
$spam = preg_match('/\bspam\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0;
$reject = preg_match('/\breject\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0;
}
// Rspamd Version
$rspamdVer = trim(@shell_exec("$rpA --version 2>/dev/null") ?? '');
if ($rspamdVer === '') {
$rspamdVer = trim(@shell_exec("dpkg-query -W -f='\${Version}\n' rspamd 2>/dev/null") ?? '');
}
// --- CLAMAV: Versionzeile inkl. Signaturdatum ausgeben ---
$clamLine = trim(@shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null') ?? '') ?: '';
$clamVer = $clamLine;
// Versuch, Datum aus der Versionzeile zu ziehen (kein Zugriff auf freshclam.log nötig)
$sigUpdated = null;
if ($clamLine && preg_match('#/([^/]+\d{4})$#', $clamLine, $m)) {
// $m[1] ist z.B. "Sun Oct 26 09:42:43 2025"
$sigUpdated = $m[1];
if (preg_match('#/([^/]+ [0-9]{2} [0-9:]{8} [0-9]{4})$#', $clamLine, $m)) {
$sigUpdated = $m[1]; // z.B. "Sun Oct 26 09:42:43 2025"
} else {
// Fallback: journalctl (falls Gruppe adm)
$jl = trim(@shell_exec('journalctl -u freshclam -n 50 --no-pager 2>/dev/null | grep -i "Database updated" | tail -n1') ?? '');
if ($jl) $sigUpdated = $jl;
}
$data = [
'ts' => time(),
'ham' => $ham,
'spam' => $spam,
'reject' => $reject,
'rspamdVer' => trim((string) @shell_exec('rspamadm version 2>/dev/null')) ?: '',
'clamVer' => $clamVer,
'ts' => time(),
'ham' => $ham,
'spam' => $spam,
'reject' => $reject,
'rspamdVer' => $rspamdVer ?: '',
'clamVer' => $clamVer,
'sigUpdated' => $sigUpdated,
];
// Persistieren (DB→Redis) + kurzer UI-Cache
Setting::set('spamav.metrics', $data);
Cache::put('dash.spamav', $data, 60);
$this->info(sprintf(
'ham=%d spam=%d reject=%d | rspamd=%s | clam=%s',
$data['ham'], $data['spam'], $data['reject'], $data['rspamdVer'], $data['clamVer']
$ham, $spam, $reject, $data['rspamdVer'], $clamVer
));
return self::SUCCESS;
}
}
//
//namespace App\Console\Commands;
//
//use Illuminate\Console\Command;
//use Illuminate\Support\Facades\Cache;
//use App\Models\Setting;
//
//class SpamAvCollectCommand extends Command
//{
// protected $signature = 'spamav:collect';
// protected $description = 'Collect Rspamd/ClamAV metrics and persist to Settings (DB→Redis)';
//
// public function handle(): int
// {
// $this->info('Collecting Spam/AV metrics…');
//
// // Rspamd counters (kein Root nötig)
// $out = trim(@shell_exec('rspamc counters 2>/dev/null') ?? '');
// $ham = preg_match('/\bham\s*:\s*(\d+)/i', $out, $m1) ? (int)$m1[1] : 0;
// $spam = preg_match('/\bspam\s*:\s*(\d+)/i', $out, $m2) ? (int)$m2[1] : 0;
// $reject = preg_match('/\breject\s*:\s*(\d+)/i', $out, $m3) ? (int)$m3[1] : 0;
//
// // ClamAV Version + Signatur-Datum robust ohne Datei-Zugriff
// $clamLine = trim((string) @shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null'));
// $clamVer = $clamLine !== '' ? $clamLine : '';
//
// // Aus clamd/clamscan-Output das Datum am Ende herausziehen (Format: ".../Sun Oct 26 09:42:43 2025")
// $sigUpdated = null;
// if ($clamLine && preg_match('#/([^/]+\d{4})$#', $clamLine, $m)) {
// // $m[1] ist z.B. "Sun Oct 26 09:42:43 2025"
// $sigUpdated = $m[1];
// }
//
// $data = [
// 'ts' => time(),
// 'ham' => $ham,
// 'spam' => $spam,
// 'reject' => $reject,
// 'rspamdVer' => trim((string) @shell_exec('rspamadm version 2>/dev/null')) ?: '',
// 'clamVer' => $clamVer,
// 'sigUpdated' => $sigUpdated,
// ];
//
// // Persistieren (DB→Redis) + kurzer UI-Cache
// Setting::set('spamav.metrics', $data);
// Cache::put('dash.spamav', $data, 60);
//
// $this->info(sprintf(
// 'ham=%d spam=%d reject=%d | rspamd=%s | clam=%s',
// $data['ham'], $data['spam'], $data['reject'], $data['rspamdVer'], $data['clamVer']
// ));
//
// return self::SUCCESS;
// }
//}

View File

@ -52,11 +52,11 @@ class SpamAvCard extends Component
}
// 3) Auf Properties mappen
$this->ham = (int)($data['ham'] ?? 0);
$this->spam = (int)($data['spam'] ?? 0);
$this->reject = (int)($data['reject'] ?? 0);
$this->rspamdVer = (string)($data['rspamdVer'] ?? '');
$this->clamVer = (string)($data['clamVer'] ?? '');
$this->ham = (int)($data['ham'] ?? 0);
$this->spam = (int)($data['spam'] ?? 0);
$this->reject = (int)($data['reject'] ?? 0);
$this->rspamdVer = (string)($data['rspamdVer'] ?? ''); // <- wichtig
$this->clamVer = (string)($data['clamVer'] ?? '');
$this->sigUpdated = $data['sigUpdated'] ?? null;
}
@ -77,13 +77,6 @@ class SpamAvCard extends Component
$sigUpdated = $m[1];
}
//// Fallback: Versuch über journalctl (falls adm-Rechte vorhanden)
// if (!$sigUpdated) {
// $jl = trim(shell_exec('journalctl -u freshclam -n 50 --no-pager 2>/dev/null | grep -i "Database updated" | tail -n1') ?? '');
// if ($jl) $sigUpdated = $jl;
// }
return [
'ts' => time(),
'ham' => $ham,