Fix literal parsing of multiline Unraid notifications
This commit is contained in:
@@ -170,14 +170,48 @@ function disk_health(?string $requested): array {
|
||||
return ['schema_version' => '1.0', 'disk_count' => count($result), 'disks' => $result];
|
||||
}
|
||||
|
||||
/** Read Unraid's flat notification records without INI value interpolation.
|
||||
* INI_SCANNER_RAW rejects multiline quoted descriptions; INI_SCANNER_NORMAL
|
||||
* expands ${...} and coerces bare values. Notification text must stay literal.
|
||||
*/
|
||||
function notification_fields(string $contents): array {
|
||||
$fields = [];
|
||||
$pending = null;
|
||||
$value = '';
|
||||
foreach (preg_split('/\r\n|\n|\r/', $contents) as $line) {
|
||||
if ($pending !== null) {
|
||||
$value .= "\n" . $line;
|
||||
} else {
|
||||
if (trim($line) === '' || preg_match('/^\s*[;#]/', $line)) continue;
|
||||
if (!preg_match('/^([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/', $line, $match)) return [];
|
||||
$pending = $match[1];
|
||||
$value = ltrim($match[2]);
|
||||
if (!str_starts_with($value, '"')) {
|
||||
$fields[$pending] = rtrim($value);
|
||||
$pending = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$end = rtrim($value, " \t");
|
||||
if (strlen($end) >= 2 && str_ends_with($end, '"')) {
|
||||
$fields[$pending] = substr($end, 1, -1);
|
||||
$pending = null;
|
||||
}
|
||||
}
|
||||
// Never return a partial record when a quoted field is truncated.
|
||||
return $pending === null ? $fields : [];
|
||||
}
|
||||
|
||||
function notification_list(int $limit, ?string $importance): array {
|
||||
$limit = max(1, min(50, $limit));
|
||||
$files = array_merge(glob('/tmp/notifications/*.notify') ?: [], glob('/tmp/notifications/archive/*.notify') ?: []);
|
||||
usort($files, fn($a, $b) => filemtime($b) <=> filemtime($a));
|
||||
$items = [];
|
||||
foreach ($files as $file) {
|
||||
$n = parse_ini_file($file, false, INI_SCANNER_RAW);
|
||||
if (!is_array($n)) continue;
|
||||
$contents = @file_get_contents($file);
|
||||
if ($contents === false) continue; // Notifications may be archived/deleted concurrently.
|
||||
$n = notification_fields($contents);
|
||||
if (!$n) continue;
|
||||
$level = trim((string)($n['importance'] ?? 'normal'), '"');
|
||||
if ($importance && $importance !== 'all' && $level !== $importance) continue;
|
||||
$items[] = [
|
||||
|
||||
Reference in New Issue
Block a user