Skip to content

Commit c702c66

Browse files
authoredMar 8, 2024··
Linux: Update xdg-open to 1.2.1 (#338)
1 parent ee13d93 commit c702c66

File tree

1 file changed

+338
-137
lines changed

1 file changed

+338
-137
lines changed
 

‎xdg-open

+338-137
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# Refer to the usage() function below for usage.
88
#
99
# Copyright 2009-2010, Fathi Boudra <fabo@freedesktop.org>
10-
# Copyright 2009-2010, Rex Dieter <rdieter@fedoraproject.org>
10+
# Copyright 2009-2016, Rex Dieter <rdieter@fedoraproject.org>
1111
# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
1212
# Copyright 2006, Jeremy White <jwhite@codeweavers.com>
1313
#
@@ -35,7 +35,7 @@
3535

3636
manualpage()
3737
{
38-
cat << _MANUALPAGE
38+
cat << '_MANUALPAGE'
3939
Name
4040
4141
xdg-open -- opens a file or URL in the user's preferred
@@ -58,6 +58,14 @@ Description
5858
xdg-open is for use inside a desktop session only. It is not
5959
recommended to use xdg-open as root.
6060
61+
As xdg-open can not handle arguments that begin with a "-" it
62+
is recommended to pass filepaths in one of the following ways:
63+
* Pass absolute paths, i.e. by using realpath as a
64+
preprocessor.
65+
* Prefix known relative filepaths with a "./". For example
66+
using sed -E 's|^[^/]|./\0|'.
67+
* Pass a file URL.
68+
6169
Options
6270
6371
--help
@@ -87,6 +95,37 @@ Exit Codes
8795
4
8896
The action failed.
8997
98+
In case of success the process launched from the .desktop file
99+
will not be forked off and therefore may result in xdg-open
100+
running for a very long time. This behaviour intentionally
101+
differs from most desktop specific openers to allow terminal
102+
based applications to run using the same terminal xdg-open was
103+
called from.
104+
105+
Reporting Issues
106+
107+
Please keep in mind xdg-open inherits most of the flaws of its
108+
configuration and the underlying opener.
109+
110+
In case the command xdg-mime query default "$(xdg-mime query
111+
filetype path/to/troublesome_file)" names the program
112+
responsible for any unexpected behaviour you can fix that by
113+
setting a different handler. (If the program is broken let the
114+
developers know)
115+
116+
Also see the security note on xdg-mime(1) for the default
117+
subcommand.
118+
119+
If a flaw is reproducible using the desktop specific opener
120+
(and isn't a configuration issue): Please report to whoever is
121+
responsible for that first (reporting to xdg-utils is better
122+
than not reporting at all, but since the xdg-utils are
123+
maintained in very little spare time a fix will take much
124+
longer)
125+
126+
In case an issue specific to xdg-open please report it to
127+
https://gitlab.freedesktop.org/xdg/xdg-utils/-/issues .
128+
90129
See Also
91130
92131
xdg-mime(1), xdg-settings(1), MIME applications associations
@@ -108,7 +147,7 @@ _MANUALPAGE
108147

109148
usage()
110149
{
111-
cat << _USAGE
150+
cat << '_USAGE'
112151
xdg-open -- opens a file or URL in the user's preferred
113152
application
114153
@@ -122,22 +161,24 @@ _USAGE
122161
}
123162

124163
#@xdg-utils-common@
125-
126164
#----------------------------------------------------------------------------
127165
# Common utility functions included in all XDG wrapper scripts
128166
#----------------------------------------------------------------------------
129167

168+
#shellcheck shell=sh
169+
130170
DEBUG()
131171
{
132172
[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0;
133-
[ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0;
173+
[ "${XDG_UTILS_DEBUG_LEVEL}" -lt "$1" ] && return 0;
134174
shift
135175
echo "$@" >&2
136176
}
137177

138178
# This handles backslashes but not quote marks.
139179
first_word()
140180
{
181+
# shellcheck disable=SC2162 # No -r is intended here
141182
read first rest
142183
echo "$first"
143184
}
@@ -147,9 +188,9 @@ first_word()
147188
binary_to_desktop_file()
148189
{
149190
search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
150-
binary="`which "$1"`"
151-
binary="`readlink -f "$binary"`"
152-
base="`basename "$binary"`"
191+
binary="$(command -v "$1")"
192+
binary="$(xdg_realpath "$binary")"
193+
base="$(basename "$binary")"
153194
IFS=:
154195
for dir in $search; do
155196
unset IFS
@@ -161,11 +202,11 @@ binary_to_desktop_file()
161202
grep -q "^Exec.*$base" "$file" || continue
162203
# Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop").
163204
grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue
164-
command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`"
165-
command="`which "$command"`"
166-
if [ x"`readlink -f "$command"`" = x"$binary" ]; then
205+
command="$(grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word)"
206+
command="$(command -v "$command")"
207+
if [ x"$(xdg_realpath "$command")" = x"$binary" ]; then
167208
# Fix any double slashes that got added path composition
168-
echo "$file" | sed -e 's,//*,/,g'
209+
echo "$file" | tr -s /
169210
return
170211
fi
171212
done
@@ -177,7 +218,7 @@ binary_to_desktop_file()
177218
desktop_file_to_binary()
178219
{
179220
search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
180-
desktop="`basename "$1"`"
221+
desktop="$(basename "$1")"
181222
IFS=:
182223
for dir in $search; do
183224
unset IFS
@@ -186,10 +227,10 @@ desktop_file_to_binary()
186227
if [ "${desktop#*-}" != "$desktop" ]; then
187228
vendor=${desktop%-*}
188229
app=${desktop#*-}
189-
if [ -r $dir/applications/$vendor/$app ]; then
190-
file_path=$dir/applications/$vendor/$app
191-
elif [ -r $dir/applnk/$vendor/$app ]; then
192-
file_path=$dir/applnk/$vendor/$app
230+
if [ -r "$dir/applications/$vendor/$app" ]; then
231+
file_path="$dir/applications/$vendor/$app"
232+
elif [ -r "$dir/applnk/$vendor/$app" ]; then
233+
file_path="$dir/applnk/$vendor/$app"
193234
fi
194235
fi
195236
if test -z "$file_path" ; then
@@ -203,9 +244,9 @@ desktop_file_to_binary()
203244
fi
204245
if [ -r "$file_path" ]; then
205246
# Remove any arguments (%F, %f, %U, %u, etc.).
206-
command="`grep -E "^Exec(\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word`"
207-
command="`which "$command"`"
208-
readlink -f "$command"
247+
command="$(grep -E "^Exec(\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word)"
248+
command="$(command -v "$command")"
249+
xdg_realpath "$command"
209250
return
210251
fi
211252
done
@@ -214,10 +255,11 @@ desktop_file_to_binary()
214255
#-------------------------------------------------------------
215256
# Exit script on successfully completing the desired operation
216257

258+
# shellcheck disable=SC2120 # It is okay to call this without arguments
217259
exit_success()
218260
{
219261
if [ $# -gt 0 ]; then
220-
echo "$@"
262+
echo "$*"
221263
echo
222264
fi
223265

@@ -233,7 +275,7 @@ exit_success()
233275
exit_failure_syntax()
234276
{
235277
if [ $# -gt 0 ]; then
236-
echo "xdg-open: $@" >&2
278+
echo "xdg-open: $*" >&2
237279
echo "Try 'xdg-open --help' for more information." >&2
238280
else
239281
usage
@@ -249,7 +291,7 @@ exit_failure_syntax()
249291
exit_failure_file_missing()
250292
{
251293
if [ $# -gt 0 ]; then
252-
echo "xdg-open: $@" >&2
294+
echo "xdg-open: $*" >&2
253295
fi
254296

255297
exit 2
@@ -261,7 +303,7 @@ exit_failure_file_missing()
261303
exit_failure_operation_impossible()
262304
{
263305
if [ $# -gt 0 ]; then
264-
echo "xdg-open: $@" >&2
306+
echo "xdg-open: $*" >&2
265307
fi
266308

267309
exit 3
@@ -273,7 +315,7 @@ exit_failure_operation_impossible()
273315
exit_failure_operation_failed()
274316
{
275317
if [ $# -gt 0 ]; then
276-
echo "xdg-open: $@" >&2
318+
echo "xdg-open: $*" >&2
277319
fi
278320

279321
exit 4
@@ -285,7 +327,7 @@ exit_failure_operation_failed()
285327
exit_failure_file_permission_read()
286328
{
287329
if [ $# -gt 0 ]; then
288-
echo "xdg-open: $@" >&2
330+
echo "xdg-open: $*" >&2
289331
fi
290332

291333
exit 5
@@ -297,7 +339,7 @@ exit_failure_file_permission_read()
297339
exit_failure_file_permission_write()
298340
{
299341
if [ $# -gt 0 ]; then
300-
echo "xdg-open: $@" >&2
342+
echo "xdg-open: $*" >&2
301343
fi
302344

303345
exit 6
@@ -317,7 +359,7 @@ check_vendor_prefix()
317359
{
318360
file_label="$2"
319361
[ -n "$file_label" ] || file_label="filename"
320-
file=`basename "$1"`
362+
file="$(basename "$1")"
321363
case "$file" in
322364
[[:alpha:]]*-*)
323365
return
@@ -340,7 +382,7 @@ check_output_file()
340382
exit_failure_file_permission_write "no permission to write to file '$1'"
341383
fi
342384
else
343-
DIR=`dirname "$1"`
385+
DIR="$(dirname "$1")"
344386
if [ ! -w "$DIR" ] || [ ! -x "$DIR" ]; then
345387
exit_failure_file_permission_write "no permission to create file '$1'"
346388
fi
@@ -369,17 +411,22 @@ check_common_commands()
369411
;;
370412

371413
--version)
372-
echo "xdg-open 1.1.3"
414+
echo "xdg-open 1.2.1"
373415
exit_success
374416
;;
417+
418+
--)
419+
[ -z "$XDG_UTILS_ENABLE_DOUBLE_HYPEN" ] || break
420+
;;
375421
esac
376422
done
377423
}
378424

379425
check_common_commands "$@"
380426

381427
[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL;
382-
if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then
428+
# shellcheck disable=SC2034
429+
if [ "${XDG_UTILS_DEBUG_LEVEL-0}" -lt 1 ]; then
383430
# Be silent
384431
xdg_redirect_output=" > /dev/null 2> /dev/null"
385432
else
@@ -412,9 +459,8 @@ detectDE()
412459
KDE)
413460
DE=kde;
414461
;;
415-
# Deepin Desktop Environments
416462
DEEPIN|Deepin|deepin)
417-
DE=dde;
463+
DE=deepin;
418464
;;
419465
LXDE)
420466
DE=lxde;
@@ -434,27 +480,28 @@ detectDE()
434480
esac
435481
fi
436482

437-
if [ x"$DE" = x"" ]; then
483+
# shellcheck disable=SC2153
484+
if [ -z "$DE" ]; then
438485
# classic fallbacks
439-
if [ x"$KDE_FULL_SESSION" != x"" ]; then DE=kde;
440-
elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
441-
elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then DE=mate;
442-
elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then DE=gnome;
486+
if [ -n "$KDE_FULL_SESSION" ]; then DE=kde;
487+
elif [ -n "$GNOME_DESKTOP_SESSION_ID" ]; then DE=gnome;
488+
elif [ -n "$MATE_DESKTOP_SESSION_ID" ]; then DE=mate;
489+
elif dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1 ; then DE=gnome;
443490
elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
444491
elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce
445-
elif echo $DESKTOP | grep -q '^Enlightenment'; then DE=enlightenment;
446-
elif [ x"$LXQT_SESSION_CONFIG" != x"" ]; then DE=lxqt;
492+
elif echo "$DESKTOP" | grep -q '^Enlightenment'; then DE=enlightenment;
493+
elif [ -n "$LXQT_SESSION_CONFIG" ]; then DE=lxqt;
447494
fi
448495
fi
449496

450-
if [ x"$DE" = x"" ]; then
497+
if [ -z "$DE" ]; then
451498
# fallback to checking $DESKTOP_SESSION
452499
case "$DESKTOP_SESSION" in
453500
gnome)
454501
DE=gnome;
455502
;;
456503
LXDE|Lubuntu)
457-
DE=lxde;
504+
DE=lxde;
458505
;;
459506
MATE)
460507
DE=mate;
@@ -465,22 +512,27 @@ detectDE()
465512
esac
466513
fi
467514

468-
if [ x"$DE" = x"" ]; then
515+
if [ -z "$DE" ]; then
469516
# fallback to uname output for other platforms
470-
case "$(uname 2>/dev/null)" in
517+
case "$(uname 2>/dev/null)" in
471518
CYGWIN*)
472519
DE=cygwin;
473520
;;
474521
Darwin)
475522
DE=darwin;
476523
;;
524+
Linux)
525+
grep -q microsoft /proc/version > /dev/null 2>&1 && \
526+
command -v explorer.exe > /dev/null 2>&1 && \
527+
DE=wsl;
528+
;;
477529
esac
478530
fi
479531

480532
if [ x"$DE" = x"gnome" ]; then
481533
# gnome-default-applications-properties is only available in GNOME 2.x
482534
# but not in GNOME 3.x
483-
which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3"
535+
command -v gnome-default-applications-properties > /dev/null || DE="gnome3"
484536
fi
485537

486538
if [ -f "$XDG_RUNTIME_DIR/flatpak-info" ]; then
@@ -495,13 +547,13 @@ detectDE()
495547

496548
kfmclient_fix_exit_code()
497549
{
498-
version=`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'`
499-
major=`echo $version | sed 's/KDE.*: \([0-9]\).*/\1/'`
500-
minor=`echo $version | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/'`
501-
release=`echo $version | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'`
502-
test "$major" -gt 3 && return $1
503-
test "$minor" -gt 5 && return $1
504-
test "$release" -gt 4 && return $1
550+
version="$(LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE')"
551+
major="$(echo "$version" | sed 's/KDE.*: \([0-9]\).*/\1/')"
552+
minor="$(echo "$version" | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/')"
553+
release="$(echo "$version" | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/')"
554+
test "$major" -gt 3 && return "$1"
555+
test "$minor" -gt 5 && return "$1"
556+
test "$release" -gt 4 && return "$1"
505557
return 0
506558
}
507559

@@ -517,9 +569,67 @@ has_display()
517569
fi
518570
}
519571

572+
#----------------------------------------------------------------------------
573+
# Prefixes a path with a "./" if it starts with a "-".
574+
# This is useful for programs to not confuse paths with options.
575+
576+
unoption_path()
577+
{
578+
case "$1" in
579+
-*)
580+
printf "./%s" "$1" ;;
581+
*)
582+
printf "%s" "$1" ;;
583+
esac
584+
}
585+
586+
#----------------------------------------------------------------------------
587+
# Performs a symlink and relative path resolving for a single argument.
588+
# This will always fail if the given file does not exist!
589+
590+
xdg_realpath()
591+
{
592+
# allow caching and external configuration
593+
if [ -z "$XDG_UTILS_REALPATH_BACKEND" ] ; then
594+
if command -v realpath >/dev/null 2>/dev/null ; then
595+
lines="$(realpath -- / 2>&1)"
596+
if [ $? = 0 ] && [ "$lines" = "/" ] ; then
597+
XDG_UTILS_REALPATH_BACKEND="realpath"
598+
else
599+
# The realpath took the -- literally, probably the busybox implementation
600+
XDG_UTILS_REALPATH_BACKEND="busybox-realpath"
601+
fi
602+
unset lines
603+
elif command -v readlink >/dev/null 2>/dev/null ; then
604+
XDG_UTILS_REALPATH_BACKEND="readlink"
605+
else
606+
exit_failure_operation_failed "No usable realpath backend found. Have a realpath binary or a readlink -f that canonicalizes paths."
607+
fi
608+
fi
609+
# Always fail if the file doesn't exist (busybox realpath does that for example)
610+
[ -e "$1" ] || return 1
611+
case "$XDG_UTILS_REALPATH_BACKEND" in
612+
realpath)
613+
realpath -- "$1"
614+
;;
615+
busybox-realpath)
616+
# busybox style realpath implementations have options too
617+
realpath "$(unoption_path "$1")"
618+
;;
619+
readlink)
620+
readlink -f "$(unoption_path "$1")"
621+
;;
622+
*)
623+
exit_failure_operation_impossible "Realpath backend '$XDG_UTILS_REALPATH_BACKEND' not recognized."
624+
;;
625+
esac
626+
}
627+
520628
# This handles backslashes but not quote marks.
521629
last_word()
522630
{
631+
# Backslash handling is intended, not using `first` too
632+
# shellcheck disable=SC2162,SC2034
523633
read first rest
524634
echo "$rest"
525635
}
@@ -535,7 +645,8 @@ get_key()
535645

536646
IFS_="${IFS}"
537647
IFS=""
538-
while read line
648+
# No backslash handling here, first_word and last_word do that
649+
while read -r line
539650
do
540651
case "$line" in
541652
"[Desktop Entry]")
@@ -556,26 +667,47 @@ get_key()
556667
IFS="${IFS_}"
557668
}
558669

670+
has_url_scheme()
671+
{
672+
echo "$1" | LC_ALL=C grep -Eq '^[[:alpha:]][[:alpha:][:digit:]+\.\-]*:'
673+
}
674+
559675
# Returns true if argument is a file:// URL or path
560676
is_file_url_or_path()
561677
{
562-
if echo "$1" | grep -q '^file://' \
563-
|| ! echo "$1" | egrep -q '^[[:alpha:]+\.\-]+:'; then
678+
if echo "$1" | grep -q '^file://' || ! has_url_scheme "$1" ; then
564679
return 0
565680
else
566681
return 1
567682
fi
568683
}
569684

685+
get_hostname() {
686+
if [ -z "$HOSTNAME" ]; then
687+
if command -v hostname > /dev/null; then
688+
HOSTNAME=$(hostname)
689+
else
690+
HOSTNAME=$(uname -n)
691+
fi
692+
fi
693+
}
694+
570695
# If argument is a file URL, convert it to a (percent-decoded) path.
571696
# If not, leave it as it is.
572697
file_url_to_path()
573698
{
574699
local file="$1"
575-
if echo "$file" | grep -q '^file:///'; then
700+
get_hostname
701+
if echo "$file" | grep -q '^file://'; then
702+
file=${file#file://localhost}
703+
file=${file#file://"$HOSTNAME"}
576704
file=${file#file://}
705+
if ! echo "$file" | grep -q '^/'; then
706+
echo "$file"
707+
return
708+
fi
577709
file=${file%%#*}
578-
file=$(echo "$file" | sed -r 's/\?.*$//')
710+
file=${file%%\?*}
579711
local printf=printf
580712
if [ -x /usr/bin/printf ]; then
581713
printf=/usr/bin/printf
@@ -615,7 +747,10 @@ open_kde()
615747
kde-open "$1"
616748
;;
617749
5)
618-
kde-open${KDE_SESSION_VERSION} "$1"
750+
"kde-open${KDE_SESSION_VERSION}" "$1"
751+
;;
752+
6)
753+
kde-open "$1"
619754
;;
620755
esac
621756
else
@@ -630,7 +765,7 @@ open_kde()
630765
fi
631766
}
632767

633-
open_dde()
768+
open_deepin()
634769
{
635770
if dde-open -version >/dev/null 2>&1; then
636771
dde-open "$1"
@@ -736,11 +871,28 @@ open_enlightenment()
736871

737872
open_flatpak()
738873
{
739-
gdbus call --session \
740-
--dest org.freedesktop.portal.Desktop \
741-
--object-path /org/freedesktop/portal/desktop \
742-
--method org.freedesktop.portal.OpenURI.OpenURI \
743-
"" "$1" {}
874+
if is_file_url_or_path "$1"; then
875+
local file
876+
file="$(file_url_to_path "$1")"
877+
878+
check_input_file "$file"
879+
880+
gdbus call --session \
881+
--dest org.freedesktop.portal.Desktop \
882+
--object-path /org/freedesktop/portal/desktop \
883+
--method org.freedesktop.portal.OpenURI.OpenFile \
884+
--timeout 5 \
885+
"" "3" {} 3< "$file"
886+
else
887+
# $1 contains an URI
888+
889+
gdbus call --session \
890+
--dest org.freedesktop.portal.Desktop \
891+
--object-path /org/freedesktop/portal/desktop \
892+
--method org.freedesktop.portal.OpenURI.OpenURI \
893+
--timeout 5 \
894+
"" "$1" {}
895+
fi
744896

745897
if [ $? -eq 0 ]; then
746898
exit_success
@@ -752,105 +904,115 @@ open_flatpak()
752904
#-----------------------------------------
753905
# Recursively search .desktop file
754906

907+
#(application, directory, target file, target_url)
755908
search_desktop_file()
756909
{
757910
local default="$1"
758911
local dir="$2"
759912
local target="$3"
913+
local target_uri="$4"
760914

761915
local file=""
762916
# look for both vendor-app.desktop, vendor/app.desktop
763917
if [ -r "$dir/$default" ]; then
764918
file="$dir/$default"
765-
elif [ -r "$dir/`echo $default | sed -e 's|-|/|'`" ]; then
766-
file="$dir/`echo $default | sed -e 's|-|/|'`"
919+
elif [ -r "$dir/$(echo "$default" | sed -e 's|-|/|')" ]; then
920+
file="$dir/$(echo "$default" | sed -e 's|-|/|')"
767921
fi
768922

769923
if [ -r "$file" ] ; then
770924
command="$(get_key "${file}" "Exec" | first_word)"
771-
command_exec=`which $command 2>/dev/null`
772-
icon="$(get_key "${file}" "Icon")"
773-
# FIXME: Actually LC_MESSAGES should be used as described in
774-
# http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html
775-
localised_name="$(get_key "${file}" "Name")"
776-
set -- $(get_key "${file}" "Exec" | last_word)
777-
# We need to replace any occurrence of "%f", "%F" and
778-
# the like by the target file. We examine each
779-
# argument and append the modified argument to the
780-
# end then shift.
781-
local args=$#
782-
local replaced=0
783-
while [ $args -gt 0 ]; do
784-
case $1 in
785-
%[c])
786-
replaced=1
787-
arg="${localised_name}"
788-
shift
789-
set -- "$@" "$arg"
790-
;;
791-
%[fFuU])
792-
replaced=1
793-
arg="$target"
794-
shift
795-
set -- "$@" "$arg"
796-
;;
797-
%[i])
798-
replaced=1
799-
shift
800-
set -- "$@" "--icon" "$icon"
801-
;;
802-
*)
803-
arg="$1"
804-
shift
805-
set -- "$@" "$arg"
806-
;;
807-
esac
808-
args=$(( $args - 1 ))
809-
done
810-
[ $replaced -eq 1 ] || set -- "$@" "$target"
811-
"$command_exec" "$@"
812-
813-
if [ $? -eq 0 ]; then
925+
if command -v "$command" >/dev/null; then
926+
icon="$(get_key "${file}" "Icon")"
927+
# FIXME: Actually LC_MESSAGES should be used as described in
928+
# http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html
929+
localised_name="$(get_key "${file}" "Name")"
930+
#shellcheck disable=SC2046 # Splitting is intentional here
931+
set -- $(get_key "${file}" "Exec" | last_word)
932+
# We need to replace any occurrence of "%f", "%F" and
933+
# the like by the target file. We examine each
934+
# argument and append the modified argument to the
935+
# end then shift.
936+
local args=$#
937+
local replaced=0
938+
while [ $args -gt 0 ]; do
939+
case $1 in
940+
%[c])
941+
replaced=1
942+
arg="${localised_name}"
943+
shift
944+
set -- "$@" "$arg"
945+
;;
946+
%[fF])
947+
# if there is only a target_url return,
948+
# this application can't handle it.
949+
[ -n "$target" ] || return
950+
replaced=1
951+
arg="$target"
952+
shift
953+
set -- "$@" "$arg"
954+
;;
955+
%[uU])
956+
replaced=1
957+
# When an URI is requested use it,
958+
# otherwise fall back to the filepath.
959+
arg="${target_uri:-$target}"
960+
shift
961+
set -- "$@" "$arg"
962+
;;
963+
%[i])
964+
replaced=1
965+
shift
966+
set -- "$@" "--icon" "$icon"
967+
;;
968+
*)
969+
arg="$1"
970+
shift
971+
set -- "$@" "$arg"
972+
;;
973+
esac
974+
args=$(( args - 1 ))
975+
done
976+
[ $replaced -eq 1 ] || set -- "$@" "${target:-$target_uri}"
977+
env "$command" "$@"
814978
exit_success
815979
fi
816980
fi
817981

818-
for d in $dir/*/; do
819-
[ -d "$d" ] && search_desktop_file "$default" "$d" "$target"
982+
for d in "$dir/"*/; do
983+
[ -d "$d" ] && search_desktop_file "$default" "$d" "$target" "$target_uri"
820984
done
821985
}
822986

823-
987+
# (file (or empty), mimetype, optional url)
824988
open_generic_xdg_mime()
825989
{
826990
filetype="$2"
827-
default=`xdg-mime query default "$filetype"`
991+
default="$(xdg-mime query default "$filetype")"
828992
if [ -n "$default" ] ; then
829993
xdg_user_dir="$XDG_DATA_HOME"
830994
[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
831995

832996
xdg_system_dirs="$XDG_DATA_DIRS"
833997
[ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
834998

835-
DEBUG 3 "$xdg_user_dir:$xdg_system_dirs"
836-
for x in `echo "$xdg_user_dir:$xdg_system_dirs" | sed 's/:/ /g'`; do
837-
search_desktop_file "$default" "$x/applications/" "$1"
999+
search_dirs="$xdg_user_dir:$xdg_system_dirs"
1000+
DEBUG 3 "$search_dirs"
1001+
old_ifs="$IFS"
1002+
IFS=:
1003+
for x in $search_dirs ; do
1004+
IFS="$old_ifs"
1005+
search_desktop_file "$default" "$x/applications/" "$1" "$3"
8381006
done
8391007
fi
8401008
}
8411009

842-
open_generic_xdg_file_mime()
843-
{
844-
filetype=`xdg-mime query filetype "$1" | sed "s/;.*//"`
845-
open_generic_xdg_mime "$1" "$filetype"
846-
}
847-
8481010
open_generic_xdg_x_scheme_handler()
8491011
{
850-
scheme="`echo $1 | sed -n 's/\(^[[:alnum:]+\.-]*\):.*$/\1/p'`"
851-
if [ -n $scheme ]; then
1012+
scheme="$(echo "$1" | LC_ALL=C sed -n 's/\(^[[:alpha:]][[:alnum:]+\.-]*\):.*$/\1/p')"
1013+
if [ -n "$scheme" ]; then
8521014
filetype="x-scheme-handler/$scheme"
853-
open_generic_xdg_mime "$1" "$filetype"
1015+
open_generic_xdg_mime "" "$filetype" "$1"
8541016
fi
8551017
}
8561018

@@ -862,7 +1024,7 @@ has_single_argument()
8621024
open_envvar()
8631025
{
8641026
local oldifs="$IFS"
865-
local browser browser_with_arg
1027+
local browser
8661028

8671029
IFS=":"
8681030
for browser in $BROWSER; do
@@ -876,6 +1038,8 @@ open_envvar()
8761038
# Avoid argument injection.
8771039
# See https://bugs.freedesktop.org/show_bug.cgi?id=103807
8781040
# URIs don't have IFS characters spaces anyway.
1041+
# shellcheck disable=SC2086,SC2091,SC2059
1042+
# All the scary things here are intentional
8791043
has_single_argument $1 && $(printf "$browser" "$1")
8801044
else
8811045
$browser "$1"
@@ -887,19 +1051,41 @@ open_envvar()
8871051
done
8881052
}
8891053

1054+
open_wsl()
1055+
{
1056+
local win_path
1057+
if is_file_url_or_path "$1" ; then
1058+
win_path="$(file_url_to_path "$1")"
1059+
win_path="$(wslpath -aw "$win_path")"
1060+
[ $? -eq 0 ] || exit_failure_operation_failed
1061+
explorer.exe "${win_path}"
1062+
else
1063+
rundll32.exe url.dll,FileProtocolHandler "$1"
1064+
fi
1065+
1066+
if [ $? -eq 0 ]; then
1067+
exit_success
1068+
else
1069+
exit_failure_operation_failed
1070+
fi
1071+
}
1072+
8901073
open_generic()
8911074
{
8921075
if is_file_url_or_path "$1"; then
893-
local file="$(file_url_to_path "$1")"
1076+
local file
1077+
file="$(file_url_to_path "$1")"
8941078

8951079
check_input_file "$file"
8961080

8971081
if has_display; then
898-
filetype=`xdg-mime query filetype "$file" | sed "s/;.*//"`
899-
open_generic_xdg_mime "$file" "$filetype"
1082+
filetype="$(xdg-mime query filetype "$file" | sed "s/;.*//")"
1083+
# passing a path a url is okay too,
1084+
# see desktop file specification for '%u'
1085+
open_generic_xdg_mime "$file" "$filetype" "$1"
9001086
fi
9011087

902-
if which run-mailcap 2>/dev/null 1>&2; then
1088+
if command -v run-mailcap >/dev/null; then
9031089
run-mailcap --action=view "$file"
9041090
if [ $? -eq 0 ]; then
9051091
exit_success
@@ -926,7 +1112,7 @@ open_generic()
9261112
if [ x"$BROWSER" = x"" ]; then
9271113
BROWSER=www-browser:links2:elinks:links:lynx:w3m
9281114
if has_display; then
929-
BROWSER=x-www-browser:firefox:iceweasel:seamonkey:mozilla:epiphany:konqueror:chromium:chromium-browser:google-chrome:microsoft-edge:$BROWSER
1115+
BROWSER=x-www-browser:firefox:iceweasel:seamonkey:mozilla:epiphany:konqueror:chromium:chromium-browser:google-chrome:$BROWSER
9301116
fi
9311117
fi
9321118

@@ -940,7 +1126,8 @@ open_lxde()
9401126

9411127
# pcmanfm only knows how to handle file:// urls and filepaths, it seems.
9421128
if pcmanfm --help >/dev/null 2>&1 && is_file_url_or_path "$1"; then
943-
local file="$(file_url_to_path "$1")"
1129+
local file
1130+
file="$(file_url_to_path "$1")"
9441131

9451132
# handle relative paths
9461133
if ! echo "$file" | grep -q ^/; then
@@ -961,7 +1148,17 @@ open_lxde()
9611148

9621149
open_lxqt()
9631150
{
964-
open_generic "$1"
1151+
if qtxdg-mat open --help 2>/dev/null 1>&2; then
1152+
qtxdg-mat open "$1"
1153+
else
1154+
exit_failure_operation_impossible "no method available for opening '$1'"
1155+
fi
1156+
1157+
if [ $? -eq 0 ]; then
1158+
exit_success
1159+
else
1160+
exit_failure_operation_failed
1161+
fi
9651162
}
9661163

9671164
[ x"$1" != x"" ] || exit_failure_syntax
@@ -997,10 +1194,10 @@ fi
9971194

9981195
DEBUG 2 "Selected DE $DE"
9991196

1000-
# sanitize BROWSER (avoid caling ourselves in particular)
1197+
# sanitize BROWSER (avoid calling ourselves in particular)
10011198
case "${BROWSER}" in
10021199
*:"xdg-open"|"xdg-open":*)
1003-
BROWSER=$(echo $BROWSER | sed -e 's|:xdg-open||g' -e 's|xdg-open:||g')
1200+
BROWSER="$(echo "$BROWSER" | sed -e 's|:xdg-open||g' -e 's|xdg-open:||g')"
10041201
;;
10051202
"xdg-open")
10061203
BROWSER=
@@ -1012,8 +1209,8 @@ case "$DE" in
10121209
open_kde "$url"
10131210
;;
10141211

1015-
dde)
1016-
open_dde "$url"
1212+
deepin)
1213+
open_deepin "$url"
10171214
;;
10181215

10191216
gnome3|cinnamon)
@@ -1056,6 +1253,10 @@ case "$DE" in
10561253
open_flatpak "$url"
10571254
;;
10581255

1256+
wsl)
1257+
open_wsl "$url"
1258+
;;
1259+
10591260
generic)
10601261
open_generic "$url"
10611262
;;

0 commit comments

Comments
 (0)
Please sign in to comment.