*/ public function mailboxesForUser(string $username): array { $domains = $this->domainsForUser($username); $out = []; foreach ($domains as $domain) { $passwd = $this->virtualRoot . '/' . $domain . '/passwd'; if (!is_file($passwd)) { continue; } $lines = file($passwd, FILE_IGNORE_NEW_LINES) ?: []; foreach ($lines as $line) { $local = trim(strtok($line, ':') ?: ''); if ($local === '' || !preg_match('/^[A-Za-z0-9._+-]+$/', $local)) { continue; } $out[] = ['domain' => $domain, 'mailbox' => $local, 'email' => $local . '@' . $domain]; } } usort($out, static fn (array $a, array $b): int => strcmp($a['email'], $b['email'])); return $out; } /** @return array{owner:string,domain:string,mailbox:string,email:string}|null */ public function resolveRecipient(string $email): ?array { $email = strtolower(trim($email)); if (!preg_match('/^([A-Za-z0-9._+-]+)@([A-Za-z0-9.-]+)$/', $email, $m)) { return null; } $local = $m[1]; $domain = $m[2]; $owners = $this->domainOwners(); $owner = $owners[$domain] ?? null; if ($owner === null) { return null; } $passwd = $this->virtualRoot . '/' . $domain . '/passwd'; if (!is_file($passwd)) { return null; } foreach (file($passwd, FILE_IGNORE_NEW_LINES) ?: [] as $line) { $mailbox = strtolower(trim(strtok($line, ':') ?: '')); if ($mailbox === $local) { return ['owner' => $owner, 'domain' => $domain, 'mailbox' => $local, 'email' => $local . '@' . $domain]; } } return null; } /** @return string[] */ public function domainsForUser(string $username): array { $domains = []; foreach ($this->domainOwners() as $domain => $owner) { if ($owner === $username) { $domains[] = $domain; } } sort($domains); return $domains; } /** @return array */ private function domainOwners(): array { $path = $this->virtualRoot . '/domainowners'; if (!is_file($path)) { return []; } $owners = []; foreach (file($path, FILE_IGNORE_NEW_LINES) ?: [] as $line) { if (!str_contains($line, ':')) { continue; } [$domain, $owner] = array_map('trim', explode(':', $line, 2)); if (!preg_match('/^[A-Za-z0-9.-]+$/', $domain) || !preg_match('/^[A-Za-z0-9._-]+$/', $owner)) { continue; } $owners[strtolower($domain)] = $owner; } return $owners; } }