7
7
# Refer to the usage() function below for usage.
8
8
#
9
9
# 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>
11
11
# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
12
12
# Copyright 2006, Jeremy White <jwhite@codeweavers.com>
13
13
#
35
35
36
36
manualpage ()
37
37
{
38
- cat << _MANUALPAGE
38
+ cat << ' _MANUALPAGE '
39
39
Name
40
40
41
41
xdg-open -- opens a file or URL in the user's preferred
@@ -58,6 +58,14 @@ Description
58
58
xdg-open is for use inside a desktop session only. It is not
59
59
recommended to use xdg-open as root.
60
60
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
+
61
69
Options
62
70
63
71
--help
@@ -87,6 +95,37 @@ Exit Codes
87
95
4
88
96
The action failed.
89
97
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
+
90
129
See Also
91
130
92
131
xdg-mime(1), xdg-settings(1), MIME applications associations
@@ -108,7 +147,7 @@ _MANUALPAGE
108
147
109
148
usage ()
110
149
{
111
- cat << _USAGE
150
+ cat << ' _USAGE '
112
151
xdg-open -- opens a file or URL in the user's preferred
113
152
application
114
153
@@ -122,22 +161,24 @@ _USAGE
122
161
}
123
162
124
163
# @xdg-utils-common@
125
-
126
164
# ----------------------------------------------------------------------------
127
165
# Common utility functions included in all XDG wrapper scripts
128
166
# ----------------------------------------------------------------------------
129
167
168
+ # shellcheck shell=sh
169
+
130
170
DEBUG ()
131
171
{
132
172
[ -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;
134
174
shift
135
175
echo " $@ " >&2
136
176
}
137
177
138
178
# This handles backslashes but not quote marks.
139
179
first_word ()
140
180
{
181
+ # shellcheck disable=SC2162 # No -r is intended here
141
182
read first rest
142
183
echo " $first "
143
184
}
@@ -147,9 +188,9 @@ first_word()
147
188
binary_to_desktop_file ()
148
189
{
149
190
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 " ) "
153
194
IFS=:
154
195
for dir in $search ; do
155
196
unset IFS
@@ -161,11 +202,11 @@ binary_to_desktop_file()
161
202
grep -q " ^Exec.*$base " " $file " || continue
162
203
# Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop").
163
204
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
167
208
# Fix any double slashes that got added path composition
168
- echo " $file " | sed -e ' s,//*,/,g '
209
+ echo " $file " | tr -s /
169
210
return
170
211
fi
171
212
done
@@ -177,7 +218,7 @@ binary_to_desktop_file()
177
218
desktop_file_to_binary ()
178
219
{
179
220
search=" ${XDG_DATA_HOME:- $HOME / .local/ share} :${XDG_DATA_DIRS:-/ usr/ local/ share:/ usr/ share} "
180
- desktop=" ` basename " $1 " ` "
221
+ desktop=" $( basename " $1 " ) "
181
222
IFS=:
182
223
for dir in $search ; do
183
224
unset IFS
@@ -186,10 +227,10 @@ desktop_file_to_binary()
186
227
if [ " ${desktop#* -} " != " $desktop " ]; then
187
228
vendor=${desktop% -* }
188
229
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 "
193
234
fi
194
235
fi
195
236
if test -z " $file_path " ; then
@@ -203,9 +244,9 @@ desktop_file_to_binary()
203
244
fi
204
245
if [ -r " $file_path " ]; then
205
246
# 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 "
209
250
return
210
251
fi
211
252
done
@@ -214,10 +255,11 @@ desktop_file_to_binary()
214
255
# -------------------------------------------------------------
215
256
# Exit script on successfully completing the desired operation
216
257
258
+ # shellcheck disable=SC2120 # It is okay to call this without arguments
217
259
exit_success ()
218
260
{
219
261
if [ $# -gt 0 ]; then
220
- echo " $@ "
262
+ echo " $* "
221
263
echo
222
264
fi
223
265
@@ -233,7 +275,7 @@ exit_success()
233
275
exit_failure_syntax ()
234
276
{
235
277
if [ $# -gt 0 ]; then
236
- echo " xdg-open: $@ " >&2
278
+ echo " xdg-open: $* " >&2
237
279
echo " Try 'xdg-open --help' for more information." >&2
238
280
else
239
281
usage
@@ -249,7 +291,7 @@ exit_failure_syntax()
249
291
exit_failure_file_missing ()
250
292
{
251
293
if [ $# -gt 0 ]; then
252
- echo " xdg-open: $@ " >&2
294
+ echo " xdg-open: $* " >&2
253
295
fi
254
296
255
297
exit 2
@@ -261,7 +303,7 @@ exit_failure_file_missing()
261
303
exit_failure_operation_impossible ()
262
304
{
263
305
if [ $# -gt 0 ]; then
264
- echo " xdg-open: $@ " >&2
306
+ echo " xdg-open: $* " >&2
265
307
fi
266
308
267
309
exit 3
@@ -273,7 +315,7 @@ exit_failure_operation_impossible()
273
315
exit_failure_operation_failed ()
274
316
{
275
317
if [ $# -gt 0 ]; then
276
- echo " xdg-open: $@ " >&2
318
+ echo " xdg-open: $* " >&2
277
319
fi
278
320
279
321
exit 4
@@ -285,7 +327,7 @@ exit_failure_operation_failed()
285
327
exit_failure_file_permission_read ()
286
328
{
287
329
if [ $# -gt 0 ]; then
288
- echo " xdg-open: $@ " >&2
330
+ echo " xdg-open: $* " >&2
289
331
fi
290
332
291
333
exit 5
@@ -297,7 +339,7 @@ exit_failure_file_permission_read()
297
339
exit_failure_file_permission_write ()
298
340
{
299
341
if [ $# -gt 0 ]; then
300
- echo " xdg-open: $@ " >&2
342
+ echo " xdg-open: $* " >&2
301
343
fi
302
344
303
345
exit 6
@@ -317,7 +359,7 @@ check_vendor_prefix()
317
359
{
318
360
file_label=" $2 "
319
361
[ -n " $file_label " ] || file_label=" filename"
320
- file=` basename " $1 " `
362
+ file=" $( basename " $1 " ) "
321
363
case " $file " in
322
364
[[:alpha:]]* -* )
323
365
return
@@ -340,7 +382,7 @@ check_output_file()
340
382
exit_failure_file_permission_write " no permission to write to file '$1 '"
341
383
fi
342
384
else
343
- DIR=` dirname " $1 " `
385
+ DIR=" $( dirname " $1 " ) "
344
386
if [ ! -w " $DIR " ] || [ ! -x " $DIR " ]; then
345
387
exit_failure_file_permission_write " no permission to create file '$1 '"
346
388
fi
@@ -369,17 +411,22 @@ check_common_commands()
369
411
;;
370
412
371
413
--version)
372
- echo " xdg-open 1.1.3 "
414
+ echo " xdg-open 1.2.1 "
373
415
exit_success
374
416
;;
417
+
418
+ --)
419
+ [ -z " $XDG_UTILS_ENABLE_DOUBLE_HYPEN " ] || break
420
+ ;;
375
421
esac
376
422
done
377
423
}
378
424
379
425
check_common_commands " $@ "
380
426
381
427
[ -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
383
430
# Be silent
384
431
xdg_redirect_output=" > /dev/null 2> /dev/null"
385
432
else
@@ -412,9 +459,8 @@ detectDE()
412
459
KDE)
413
460
DE=kde;
414
461
;;
415
- # Deepin Desktop Environments
416
462
DEEPIN|Deepin|deepin)
417
- DE=dde ;
463
+ DE=deepin ;
418
464
;;
419
465
LXDE)
420
466
DE=lxde;
@@ -434,27 +480,28 @@ detectDE()
434
480
esac
435
481
fi
436
482
437
- if [ x" $DE " = x" " ]; then
483
+ # shellcheck disable=SC2153
484
+ if [ -z " $DE " ]; then
438
485
# 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;
443
490
elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' > /dev/null 2>&1 ; then DE=xfce;
444
491
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;
447
494
fi
448
495
fi
449
496
450
- if [ x " $DE " = x " " ]; then
497
+ if [ -z " $DE " ]; then
451
498
# fallback to checking $DESKTOP_SESSION
452
499
case " $DESKTOP_SESSION " in
453
500
gnome)
454
501
DE=gnome;
455
502
;;
456
503
LXDE|Lubuntu)
457
- DE=lxde;
504
+ DE=lxde;
458
505
;;
459
506
MATE)
460
507
DE=mate;
@@ -465,22 +512,27 @@ detectDE()
465
512
esac
466
513
fi
467
514
468
- if [ x " $DE " = x " " ]; then
515
+ if [ -z " $DE " ]; then
469
516
# fallback to uname output for other platforms
470
- case " $( uname 2> /dev/null) " in
517
+ case " $( uname 2> /dev/null) " in
471
518
CYGWIN* )
472
519
DE=cygwin;
473
520
;;
474
521
Darwin)
475
522
DE=darwin;
476
523
;;
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
+ ;;
477
529
esac
478
530
fi
479
531
480
532
if [ x" $DE " = x" gnome" ]; then
481
533
# gnome-default-applications-properties is only available in GNOME 2.x
482
534
# 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"
484
536
fi
485
537
486
538
if [ -f " $XDG_RUNTIME_DIR /flatpak-info" ]; then
@@ -495,13 +547,13 @@ detectDE()
495
547
496
548
kfmclient_fix_exit_code ()
497
549
{
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 "
505
557
return 0
506
558
}
507
559
@@ -517,9 +569,67 @@ has_display()
517
569
fi
518
570
}
519
571
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
+
520
628
# This handles backslashes but not quote marks.
521
629
last_word ()
522
630
{
631
+ # Backslash handling is intended, not using `first` too
632
+ # shellcheck disable=SC2162,SC2034
523
633
read first rest
524
634
echo " $rest "
525
635
}
@@ -535,7 +645,8 @@ get_key()
535
645
536
646
IFS_=" ${IFS} "
537
647
IFS=" "
538
- while read line
648
+ # No backslash handling here, first_word and last_word do that
649
+ while read -r line
539
650
do
540
651
case " $line " in
541
652
" [Desktop Entry]" )
@@ -556,26 +667,47 @@ get_key()
556
667
IFS=" ${IFS_} "
557
668
}
558
669
670
+ has_url_scheme ()
671
+ {
672
+ echo " $1 " | LC_ALL=C grep -Eq ' ^[[:alpha:]][[:alpha:][:digit:]+\.\-]*:'
673
+ }
674
+
559
675
# Returns true if argument is a file:// URL or path
560
676
is_file_url_or_path ()
561
677
{
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
564
679
return 0
565
680
else
566
681
return 1
567
682
fi
568
683
}
569
684
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
+
570
695
# If argument is a file URL, convert it to a (percent-decoded) path.
571
696
# If not, leave it as it is.
572
697
file_url_to_path ()
573
698
{
574
699
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 " }
576
704
file=${file# file:// }
705
+ if ! echo " $file " | grep -q ' ^/' ; then
706
+ echo " $file "
707
+ return
708
+ fi
577
709
file=${file%%#* }
578
- file=$( echo " $ file" | sed -r ' s/\?.*$// ' )
710
+ file=${ file%% \? * }
579
711
local printf=printf
580
712
if [ -x /usr/bin/printf ]; then
581
713
printf=/usr/bin/printf
@@ -615,7 +747,10 @@ open_kde()
615
747
kde-open " $1 "
616
748
;;
617
749
5)
618
- kde-open${KDE_SESSION_VERSION} " $1 "
750
+ " kde-open${KDE_SESSION_VERSION} " " $1 "
751
+ ;;
752
+ 6)
753
+ kde-open " $1 "
619
754
;;
620
755
esac
621
756
else
@@ -630,7 +765,7 @@ open_kde()
630
765
fi
631
766
}
632
767
633
- open_dde ()
768
+ open_deepin ()
634
769
{
635
770
if dde-open -version > /dev/null 2>&1 ; then
636
771
dde-open " $1 "
@@ -736,11 +871,28 @@ open_enlightenment()
736
871
737
872
open_flatpak ()
738
873
{
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
744
896
745
897
if [ $? -eq 0 ]; then
746
898
exit_success
@@ -752,105 +904,115 @@ open_flatpak()
752
904
# -----------------------------------------
753
905
# Recursively search .desktop file
754
906
907
+ # (application, directory, target file, target_url)
755
908
search_desktop_file ()
756
909
{
757
910
local default=" $1 "
758
911
local dir=" $2 "
759
912
local target=" $3 "
913
+ local target_uri=" $4 "
760
914
761
915
local file=" "
762
916
# look for both vendor-app.desktop, vendor/app.desktop
763
917
if [ -r " $dir /$default " ]; then
764
918
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|-|/|' ) "
767
921
fi
768
922
769
923
if [ -r " $file " ] ; then
770
924
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 " " $@ "
814
978
exit_success
815
979
fi
816
980
fi
817
981
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 "
820
984
done
821
985
}
822
986
823
-
987
+ # (file (or empty), mimetype, optional url)
824
988
open_generic_xdg_mime ()
825
989
{
826
990
filetype=" $2 "
827
- default=` xdg-mime query default " $filetype " `
991
+ default=" $( xdg-mime query default " $filetype " ) "
828
992
if [ -n " $default " ] ; then
829
993
xdg_user_dir=" $XDG_DATA_HOME "
830
994
[ -n " $xdg_user_dir " ] || xdg_user_dir=" $HOME /.local/share"
831
995
832
996
xdg_system_dirs=" $XDG_DATA_DIRS "
833
997
[ -n " $xdg_system_dirs " ] || xdg_system_dirs=/usr/local/share/:/usr/share/
834
998
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 "
838
1006
done
839
1007
fi
840
1008
}
841
1009
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
-
848
1010
open_generic_xdg_x_scheme_handler ()
849
1011
{
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
852
1014
filetype=" x-scheme-handler/$scheme "
853
- open_generic_xdg_mime " $1 " " $filetype "
1015
+ open_generic_xdg_mime " " " $filetype " " $1 "
854
1016
fi
855
1017
}
856
1018
@@ -862,7 +1024,7 @@ has_single_argument()
862
1024
open_envvar ()
863
1025
{
864
1026
local oldifs=" $IFS "
865
- local browser browser_with_arg
1027
+ local browser
866
1028
867
1029
IFS=" :"
868
1030
for browser in $BROWSER ; do
@@ -876,6 +1038,8 @@ open_envvar()
876
1038
# Avoid argument injection.
877
1039
# See https://bugs.freedesktop.org/show_bug.cgi?id=103807
878
1040
# URIs don't have IFS characters spaces anyway.
1041
+ # shellcheck disable=SC2086,SC2091,SC2059
1042
+ # All the scary things here are intentional
879
1043
has_single_argument $1 && $( printf " $browser " " $1 " )
880
1044
else
881
1045
$browser " $1 "
@@ -887,19 +1051,41 @@ open_envvar()
887
1051
done
888
1052
}
889
1053
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
+
890
1073
open_generic ()
891
1074
{
892
1075
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 " ) "
894
1078
895
1079
check_input_file " $file "
896
1080
897
1081
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 "
900
1086
fi
901
1087
902
- if which run-mailcap 2 > /dev/null 1>&2 ; then
1088
+ if command -v run-mailcap > /dev/null; then
903
1089
run-mailcap --action=view " $file "
904
1090
if [ $? -eq 0 ]; then
905
1091
exit_success
@@ -926,7 +1112,7 @@ open_generic()
926
1112
if [ x" $BROWSER " = x" " ]; then
927
1113
BROWSER=www-browser:links2:elinks:links:lynx:w3m
928
1114
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
930
1116
fi
931
1117
fi
932
1118
@@ -940,7 +1126,8 @@ open_lxde()
940
1126
941
1127
# pcmanfm only knows how to handle file:// urls and filepaths, it seems.
942
1128
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 " ) "
944
1131
945
1132
# handle relative paths
946
1133
if ! echo " $file " | grep -q ^/; then
@@ -961,7 +1148,17 @@ open_lxde()
961
1148
962
1149
open_lxqt ()
963
1150
{
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
965
1162
}
966
1163
967
1164
[ x" $1 " != x" " ] || exit_failure_syntax
@@ -997,10 +1194,10 @@ fi
997
1194
998
1195
DEBUG 2 " Selected DE $DE "
999
1196
1000
- # sanitize BROWSER (avoid caling ourselves in particular)
1197
+ # sanitize BROWSER (avoid calling ourselves in particular)
1001
1198
case " ${BROWSER} " in
1002
1199
* :" 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' ) "
1004
1201
;;
1005
1202
" xdg-open" )
1006
1203
BROWSER=
@@ -1012,8 +1209,8 @@ case "$DE" in
1012
1209
open_kde " $url "
1013
1210
;;
1014
1211
1015
- dde )
1016
- open_dde " $url "
1212
+ deepin )
1213
+ open_deepin " $url "
1017
1214
;;
1018
1215
1019
1216
gnome3|cinnamon)
@@ -1056,6 +1253,10 @@ case "$DE" in
1056
1253
open_flatpak " $url "
1057
1254
;;
1058
1255
1256
+ wsl)
1257
+ open_wsl " $url "
1258
+ ;;
1259
+
1059
1260
generic)
1060
1261
open_generic " $url "
1061
1262
;;
0 commit comments