Fix i3-dmenu-desktop quoting (#5162)

Commit 70f23caa9a introduced new issues.

Instead of distinguishing " and \, as that commit attempted,
let’s instead keep the level of escaping by escaping each backslash,
just like each double quote.

I tested this with:

    # recommended way to quote $ and " in quoted arguments, not ambiguous
    Exec=/tmp/logargs "hello \\$PWD \\"and\\" more"

    # permitted way to quote $ and " in quoted arguments, but ambiguous
    Exec=/tmp/logargs "hello \$PWD \"and\" more"

    # permitted way to quote arguments, slightly unusual to quote first arg
    Exec="/tmp/logargs" hey

    # a complicated shell expression, not ambiguous
    Exec=sh -c "if [ -n \\"\\$*\\" ]; then exec /tmp/logargs --alternate-editor= --display=\\"\\$DISPLAY\\" \\"\\$@\\"; else exec /tmp/logargs --alternate-editor= --create-frame; fi" placeholder %F

related to https://github.com/i3/i3/issues/4697 (electrum, original)
related to https://github.com/i3/i3/issues/5152 (phpstorm, breakage)
related to https://github.com/i3/i3/issues/5156 (emacsclient, breakage)
This commit is contained in:
Michael Stapelberg
2022-09-28 18:29:26 +02:00
committed by Michael Stapelberg
parent 3f58d51ec6
commit decc37eba1
2 changed files with 141 additions and 4 deletions

View File

@@ -413,7 +413,7 @@ my $exec = $app->{Exec};
my $location = $app->{_Location};
# Quote as described by “The Exec key”:
# https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
# https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s07.html
sub quote {
my ($str) = @_;
$str =~ s/("|`|\$|\\)/\\$1/g;
@@ -425,6 +425,17 @@ $choice = quote($choice);
$location = quote($location);
$name = quote($name);
# https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s07.html:
#
# Note that the general escape rule for values of type string states that the
# backslash character can be escaped as ("\\") as well and that this escape rule
# is applied before the quoting rule. As such, to unambiguously represent a
# literal backslash character in a quoted argument in a desktop entry file
# requires the use of four successive backslash characters ("\\\\"). Likewise, a
# literal dollar sign in a quoted argument in a desktop entry file is
# unambiguously represented with ("\\$").
$exec =~ s/\\\\/\\/g;
# Remove deprecated field codes, as the spec dictates.
$exec =~ s/%[dDnNvm]//g;
@@ -481,9 +492,10 @@ EOT
# starts with a double quote ("), everything is parsed as-is until the next
# double quote which is NOT preceded by a backslash (\).
#
# Therefore, we escape all double quotes (") by replacing them with \"
$exec =~ s/\\"/\\\\\\"/g;
$exec =~ s/([^\\])"/$1\\"/g;
# Therefore, we escape all double quotes (") by replacing them with \".
# To not change the meaning of any double quote, backslashes need to be
# escaped as well.
$exec =~ s/(["\\])/\\$1/g;
if (exists($app->{StartupNotify}) && !$app->{StartupNotify}) {
$nosn = '--no-startup-id';