102 lines
3.7 KiB
PHP
102 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Box\Mod\Mailgateway;
|
|
|
|
use FOSSBilling\InformationException;
|
|
|
|
class InboundPolicy
|
|
{
|
|
private const FIELDS = [
|
|
'auto-submitted', 'precedence', 'return-path', 'content-type',
|
|
'x-auto-response-suppress', 'x-autoreply', 'x-autorespond', 'list-id',
|
|
];
|
|
|
|
/** Normalize parsed MIME headers and supported flat header fields. */
|
|
public function headers(array $data): array
|
|
{
|
|
$raw = $data['headers'] ?? [];
|
|
if (!is_array($raw)) {
|
|
throw new InformationException('headers must be an array of header values');
|
|
}
|
|
foreach (self::FIELDS as $field) {
|
|
$flat = str_replace('-', '_', $field);
|
|
if (array_key_exists($flat, $data)) {
|
|
$raw[$field] = array_merge((array) ($raw[$field] ?? []), (array) $data[$flat]);
|
|
}
|
|
}
|
|
$headers = [];
|
|
foreach ($raw as $name => $values) {
|
|
if (!is_string($name)) {
|
|
throw new InformationException('Header names must be strings');
|
|
}
|
|
$name = strtolower(str_replace('_', '-', $name));
|
|
if (!in_array($name, self::FIELDS, true)) {
|
|
continue;
|
|
}
|
|
$values = is_array($values) ? $values : [$values];
|
|
if (count($values) > 20) {
|
|
throw new InformationException('Too many repeated header values');
|
|
}
|
|
foreach ($values as $value) {
|
|
if (!is_string($value) || strlen($value) > 16384) {
|
|
throw new InformationException('Header values must be strings of at most 16384 bytes');
|
|
}
|
|
$value = preg_replace('/\r?\n[ \t]+/', ' ', $value);
|
|
if (preg_match('/[\x00-\x08\x0A-\x1F\x7F]/', $value)) {
|
|
throw new InformationException('Invalid control character in header value');
|
|
}
|
|
$headers[$name][] = strtolower(trim($value));
|
|
}
|
|
}
|
|
ksort($headers);
|
|
|
|
return $headers;
|
|
}
|
|
|
|
public function ignoreReason(array $headers): ?string
|
|
{
|
|
foreach ($headers['auto-submitted'] ?? [] as $value) {
|
|
if (trim(explode(';', $value, 2)[0]) !== 'no') {
|
|
return 'auto_submitted';
|
|
}
|
|
}
|
|
foreach ($headers['return-path'] ?? [] as $value) {
|
|
if (preg_match('/^<\s*>$/D', $value)) {
|
|
return 'null_return_path';
|
|
}
|
|
}
|
|
foreach ($headers['content-type'] ?? [] as $value) {
|
|
if (preg_match('/^multipart\/report\s*(?:;|$)/', $value)
|
|
|| preg_match('/^message\/(?:delivery-status|disposition-notification|global-delivery-status)\s*(?:;|$)/', $value)) {
|
|
return 'delivery_report';
|
|
}
|
|
}
|
|
foreach ($headers['precedence'] ?? [] as $value) {
|
|
if (in_array(trim(explode(';', $value, 2)[0]), ['bulk', 'list', 'junk'], true)) {
|
|
return 'bulk_mail';
|
|
}
|
|
}
|
|
foreach ($headers['list-id'] ?? [] as $value) {
|
|
if ($value !== '') {
|
|
return 'mailing_list';
|
|
}
|
|
}
|
|
foreach ($headers['x-auto-response-suppress'] ?? [] as $value) {
|
|
if (preg_match('/(?:^|[\s,;])(?:all|autoreply|oof|dr|ndr|rn|nrn)(?:$|[\s,;])/', $value)) {
|
|
return 'response_suppressed';
|
|
}
|
|
}
|
|
foreach (['x-autoreply', 'x-autorespond'] as $field) {
|
|
foreach ($headers[$field] ?? [] as $value) {
|
|
if (!in_array($value, ['', 'no', 'false', '0'], true)) {
|
|
return 'legacy_autoresponder';
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|