where('is_active', true) ->whereNotNull('email') ->where('email', 'like', '%@%'); if ($email = trim((string)$this->option('user'))) { $q->where('email', $email); } $users = $q->get(); if ($users->isEmpty()) { $this->warn('Keine passenden Mailboxen gefunden.'); return self::SUCCESS; } foreach ($users as $u) { $email = trim($u->email); if (!preg_match('/^[^@\s]+@[^@\s]+\.[^@\s]+$/', $email)) { // ungültig → überspringen continue; } [$local, $domain] = explode('@', $email, 2); $maildir = "/var/mail/vhosts/{$domain}/{$local}"; // 1) Größe (rekursiv, ohne `du`) $usedBytes = 0; if (is_dir($maildir)) { $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($maildir, \FilesystemIterator::SKIP_DOTS) ); foreach ($it as $file) { if ($file->isFile()) { $usedBytes += $file->getSize(); } } } // 2) Nachrichtenzahl – bevorzugt via doveadm (sudo -u vmail), Fallback: Dateien zählen $messageCount = $this->messageCountViaDoveadm($email); if ($messageCount === null) { $messageCount = $this->messageCountViaFilesystem($maildir); } Setting::set("mailbox.{$email}", [ 'used_bytes' => $usedBytes, 'message_count' => $messageCount, 'updated_at' => now()->toDateTimeString(), ]); $this->line(sprintf( "%-35s %7.1f MiB %5d msgs", $email, $usedBytes / 1024 / 1024, $messageCount )); } $this->info('Mailbox-Statistiken aktualisiert.'); return self::SUCCESS; } /** * Holt die Anzahl der Nachrichten in INBOX über doveadm als vmail (sudo). * Gibt int bei Erfolg, oder null bei Fehlern zurück. */ private function messageCountViaDoveadm(string $email): ?int { // bevorzugtes Format: tabellarisch → "INBOX\t123" $cmd = sprintf( "sudo -n -u vmail /usr/bin/doveadm -f tab mailbox status -u %s messages INBOX 2>/dev/null", escapeshellarg($email) ); $out = trim((string) shell_exec($cmd)); if ($out === '') { // Fallback auf normales Format: "messages=123" $cmd2 = sprintf( "sudo -n -u vmail /usr/bin/doveadm mailbox status -u %s messages INBOX 2>/dev/null", escapeshellarg($email) ); $out = trim((string) shell_exec($cmd2)); } if ($out === '') { return null; } // Match "INBOX123" oder "messages=123" if (preg_match('/\t(\d+)\s*$/', $out, $m) || preg_match('/messages=(\d+)/', $out, $m)) { return (int) $m[1]; } return null; } /** * Fallback: Zählt Dateien in cur/ + new/ (Maildir). */ private function messageCountViaFilesystem(string $maildir): int { $count = 0; foreach (['cur', 'new'] as $sub) { $dir = "{$maildir}/{$sub}"; if (is_dir($dir) && is_readable($dir)) { $dh = opendir($dir); if ($dh) { while (($fn = readdir($dh)) !== false) { if ($fn !== '.' && $fn !== '..' && $fn[0] !== '.') { $count++; } } closedir($dh); } } } return $count; } }