Harden sound notification playback

This commit is contained in:
Storm Dragon
2026-06-19 01:49:00 -04:00
parent 2b8bf031fa
commit 8c4dcd1f87
+38 -4
View File
@@ -47,8 +47,13 @@ sub notifier_soundpack {
return 1;
}
# Build sound file path using XDG data directory
my $data_dir = "$ENV{'HOME'}/.local/share/ttyverse";
unless ($sound_pack =~ /^[A-Za-z0-9_.-]+$/ && $class =~ /^[A-Za-z0-9_.-]+$/) {
print $stdout "-- Warning: Invalid sound pack or notification class\n";
return 1;
}
# Use the same XDG data directory as TTYverse and the extension manager.
my $data_dir = $data;
my $sound_file = "$data_dir/sounds/$sound_pack/" . lc($class) . ".ogg";
if (!-f $sound_file) {
@@ -62,9 +67,38 @@ sub notifier_soundpack {
return 1;
}
# Play the sound in background (suppress output)
require Text::ParseWords;
my @soundCommand = Text::ParseWords::shellwords($sound_command);
unless (scalar(@soundCommand)) {
print $stdout "-- Warning: Sound command is empty\n";
return 1;
}
# Double-fork so playback cannot block the client and does not leave a
# child process waiting to be reaped. List-form exec avoids shell parsing.
print $stdout "-- DEBUG: Playing sound: $sound_command \"$sound_file\"\n" if ($verbose);
system("$sound_command \"$sound_file\" >/dev/null 2>&1 &");
my $playerPid = fork();
unless (defined($playerPid)) {
print $stdout "-- Warning: Could not start sound player: $!\n";
return 1;
}
if (!$playerPid) {
# Prevent TTYverse's END handler from shutting down the main client
# when either detached playback process exits.
$in_backticks = 1;
my $playbackPid = fork();
exit 1 unless (defined($playbackPid));
exit 0 if ($playbackPid);
unless ($verbose) {
open(STDOUT, '>', '/dev/null');
}
if (!exec { $soundCommand[0] } @soundCommand, $sound_file) {
print STDERR "TTYverse could not execute sound player '$soundCommand[0]': $!\n";
exit 127;
}
}
waitpid($playerPid, 0);
return 1;
}