blob: 023a465945ad2202b83aead36b6e74b93066a7a8 [file] [log] [blame]
#!/bin/sh
#---------------------------------------------
# xdg-mime
#
# Utility script to manipulate MIME related information
# on XDG compliant systems.
#
# Refer to the usage() function below for usage.
#
# Copyright 2009-2010, Fathi Boudra <fabo@freedesktop.org>
# Copyright 2009-2010, Rex Dieter <rdieter@fedoraproject.org>
# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
# Copyright 2006, Jeremy White <jwhite@codeweavers.com>
#
# LICENSE:
#
#---------------------------------------------
manualpage()
{
cat << _MANUALPAGE
_MANUALPAGE
}
usage()
{
cat << _USAGE
_USAGE
}
#@xdg-utils-common@
update_mime_database()
{
if [ x"$mode" = x"user" -a -n "$DISPLAY" ] ; then
detectDE
if [ x"$DE" = x"kde" ] ; then
DEBUG 1 "Running kbuildsycoca"
if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
eval 'kbuildsycoca4'$xdg_redirect_output
else
eval 'kbuildsycoca'$xdg_redirect_output
fi
fi
fi
for x in `echo "$PATH:/opt/gnome/bin" | sed 's/:/ /g'`; do
if [ -x $x/update-mime-database ] ; then
DEBUG 1 "Running $x/update-mime-database $1"
eval '$x/update-mime-database $1'$xdg_redirect_output
return
fi
done
}
info_kde()
{
if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
DEBUG 1 "Running kmimetypefinder \"$1\""
kmimetypefinder "$1" 2>/dev/null | head -n 1
else
DEBUG 1 "Running kfile \"$1\""
kfile "$1" 2> /dev/null | head -n 1 | cut -d "(" -f 2 | cut -d ")" -f 1
fi
if [ $? -eq 0 ]; then
exit_success
else
exit_failure_operation_failed
fi
}
info_gnome()
{
if gvfs-info --help 2>/dev/null 1>&2; then
DEBUG 1 "Running gvfs-info \"$1\""
gvfs-info "$1" 2> /dev/null | grep standard::content-type | cut -d' ' -f4
elif gnomevfs-info --help 2>/dev/null 1>&2; then
DEBUG 1 "Running gnomevfs-info \"$1\""
gnomevfs-info --slow-mime "$1" 2> /dev/null | grep "^MIME" | cut -d ":" -f 2 | sed s/"^ "//
else
# according to https://bugs.freedesktop.org/show_bug.cgi?id=33094#c5
# neither gvfs-info or gnomevfs-info are present in a default Ubuntu Natty
# install, so fallback to info_generic
info_generic "$1"
fi
if [ $? -eq 0 ]; then
exit_success
else
exit_failure_operation_failed
fi
}
info_generic()
{
if mimetype --version >/dev/null 2>&1; then
DEBUG 1 "Running mimetype -b \"$1\""
mimetype -b "$1"
else
DEBUG 1 "Running file --mime-type \"$1\""
/usr/bin/file --mime-type "$1" 2> /dev/null | cut -d ":" -f 2 | sed s/"^ "//
fi
if [ $? -eq 0 ]; then
exit_success
else
exit_failure_operation_failed
fi
}
make_default_kde()
{
# $1 is vendor-name.desktop
# $2 is mime/type
#
# On KDE 3, add to $KDE_CONFIG_PATH/profilerc:
# [$2 - 1]
# Application=$1
#
# Remove all [$2 - *] sections, or even better,
# renumber [$2 - *] sections and remove duplicate
#
# On KDE 4, add $2=$1 to $XDG_DATA_APPS/mimeapps.list
#
# Example file:
#
# [Added Associations]
# text/plain=kde4-kate.desktop;kde4-kwrite.desktop;
#
# [Removed Associations]
# text/plain=gnome-gedit.desktop;gnu-emacs.desktop;
vendor="$1"
mimetype="$2"
if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
default_dir=`kde4-config --path xdgdata-apps 2> /dev/null | cut -d ':' -f 1`
default_file="$default_dir/mimeapps.list"
else
default_dir=`kde-config --path config 2> /dev/null | cut -d ':' -f 1`
default_file="$default_dir/profilerc"
fi
if [ -z "$default_dir" ]; then
DEBUG 2 "make_default_kde: No kde runtime detected"
return
fi
DEBUG 2 "make_default_kde $vendor $mimetype"
DEBUG 1 "Updating $default_file"
mkdir -p "$default_dir"
[ -f "$default_file" ] || touch "$default_file"
if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
[ -f "$default_file" ] || touch "$default_file"
awk -v application="$vendor" -v mimetype="$mimetype" '
BEGIN {
prefix=mimetype "="
associations=0
found=0
blanks=0
}
{
suppress=0
if (index($0, "[Added Associations]") == 1) {
associations=1
} else if (index($0, "[") == 1) {
if (associations && !found) {
print prefix application
found=1
}
associations=0
} else if ($0 == "") {
blanks++
suppress=1
} else if (associations && index($0, prefix) == 1) {
value=substr($0, length(prefix) + 1, length)
split(value, apps, ";")
value=application ";"
count=0
for (i in apps) {
count++
}
for (i=0; i < count; i++) {
if (apps[i] != application && apps[i] != "") {
value=value apps[i] ";"
}
}
$0=prefix value
found=1
}
if (!suppress) {
while (blanks > 0) {
print ""
blanks--
}
print $0
}
}
END {
if (!found) {
if (!associations) {
print "[Added Associations]"
}
print prefix application
}
while (blanks > 0) {
print ""
blanks--
}
}
' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file"
eval 'kbuildsycoca4'$xdg_redirect_output
else
awk -v application="$vendor" -v mimetype="$mimetype" '
BEGIN {
header_start="[" mimetype " - "
suppress=0
}
{
if (index($0, header_start) == 1 )
suppress=1
else
if (/^\[/) { suppress=0 }
if (!suppress) {
print $0
}
}
END {
print ""
print "[" mimetype " - 1]"
print "Application=" application
print "AllowAsDefault=true"
print "GenericServiceType=Application"
print "Preference=1"
print "ServiceType=" mimetype
}
' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file"
fi
}
make_default_generic()
{
# $1 is vendor-name.desktop
# $2 is mime/type
# Add $2=$1 to XDG_DATA_HOME/applications/mimeapps.list
xdg_user_dir="$XDG_DATA_HOME"
[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
default_file="$xdg_user_dir/applications/mimeapps.list"
DEBUG 2 "make_default_generic $1 $2"
DEBUG 1 "Updating $default_file"
[ -f "$default_file" ] || touch "$default_file"
awk -v mimetype="$2" -v application="$1" '
BEGIN {
prefix=mimetype "="
indefault=0
added=0
blanks=0
found=0
}
{
suppress=0
if (index($0, "[Default Applications]") == 1) {
indefault=1
found=1
} else if (index($0, "[") == 1) {
if (!added && indefault) {
print prefix application
added=1
}
indefault=0
} else if ($0 == "") {
suppress=1
blanks++
} else if (indefault && !added && index($0, prefix) == 1) {
$0=prefix application
added=1
}
if (!suppress) {
while (blanks > 0) {
print ""
blanks--
}
print $0
}
}
END {
if (!added) {
if (!found) {
print ""
print "[Default Applications]"
}
print prefix application
}
while (blanks > 0) {
print ""
blanks--
}
}
' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file"
}
defapp_generic()
{
MIME="$1"
xdg_user_dir="$XDG_DATA_HOME"
[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
xdg_user_dir="$xdg_user_dir/$xdg_dir_name"
xdg_system_dirs="$XDG_DATA_DIRS"
[ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
for x in `echo "$xdg_user_dir" | sed 's/:/ /g'`; do
mimeapps_list="$x/applications/mimeapps.list"
if [ -f "$mimeapps_list" ] ; then
DEBUG 2 "Checking $mimeapps_list"
trader_result=`awk -v mimetype="$MIME" '
BEGIN {
prefix=mimetype "="
indefault=0
found=0
}
{
if (index($0, "[Default Applications]") == 1) {
indefault=1
} else if (index($0, "[") == 1) {
indefault=0
} else if (!found && indefault && index($0, prefix) == 1) {
print substr($0, length(prefix) +1, length)
found=1
}
}
' $mimeapps_list`
if [ -n "$trader_result" ] ; then
echo $trader_result
exit_success
fi
fi
done
for x in `echo "$xdg_system_dirs" | sed 's/:/ /g'`; do
DEBUG 2 "Checking $x/applications/defaults.list"
trader_result=`grep "$MIME=" $x/applications/defaults.list 2> /dev/null | cut -d '=' -f 2 | cut -d ';' -f 1`
if [ -n "$trader_result" ] ; then
echo $trader_result
exit_success
fi
done
exit_success
}
defapp_kde()
{
MIME="$1"
if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
KTRADER=`which ktraderclient 2> /dev/null`
MIMETYPE="--mimetype"
SERVICETYPE="--servicetype"
else
KTRADER=`which ktradertest 2> /dev/null`
fi
if [ -n "$KTRADER" ] ; then
DEBUG 1 "Running KDE trader query \"$MIME\" mimetype and \"Application\" servicetype"
trader_result=`$KTRADER $MIMETYPE "$MIME" $SERVICETYPE Application 2>/dev/null \
| grep DesktopEntryPath | head -n 1 | cut -d ':' -f 2 | cut -d \' -f 2`
if [ -n "$trader_result" ] ; then
basename "$trader_result"
exit_success
else
exit_failure_operation_failed
fi
else
defapp_generic "$1"
fi
}
[ x"$1" != x"" ] || exit_failure_syntax
mode=
action=
filename=
mimetype=
case $1 in
install)
action=install
;;
uninstall)
action=uninstall
;;
query)
shift
if [ -z "$1" ] ; then
exit_failure_syntax "query type argument missing"
fi
case $1 in
filetype)
action=info
filename="$2"
if [ -z "$filename" ] ; then
exit_failure_syntax "FILE argument missing"
fi
case $filename in
-*)
exit_failure_syntax "unexpected option '$filename'"
;;
esac
check_input_file "$filename"
filename=`readlink -f -- "$filename"`
;;
default)
action=defapp
mimetype="$2"
if [ -z "$mimetype" ] ; then
exit_failure_syntax "mimetype argument missing"
fi
case $mimetype in
-*)
exit_failure_syntax "unexpected option '$mimetype'"
;;
*/*)
# Ok
;;
*)
exit_failure_syntax "mimetype '$mimetype' is not in the form 'minor/major'"
;;
esac
;;
*)
exit_failure_syntax "unknown query type '$1'"
;;
esac
;;
default)
action=makedefault
shift
if [ -z "$1" ] ; then
exit_failure_syntax "application argument missing"
fi
case $1 in
-*)
exit_failure_syntax "unexpected option '$1'"
;;
*.desktop)
filename="$1"
;;
*)
exit_failure_syntax "malformed argument '$1', expected *.desktop"
;;
esac
;;
*)
exit_failure_syntax "unknown command '$1'"
;;
esac
shift
if [ "$action" = "makedefault" ]; then
if [ -z "$1" ] ; then
exit_failure_syntax "mimetype argument missing"
fi
while [ $# -gt 0 ] ; do
case $1 in
-*)
exit_failure_syntax "unexpected option '$1'"
;;
esac
mimetype="$1"
shift
make_default_kde "$filename" "$mimetype"
make_default_generic "$filename" "$mimetype"
done
exit_success
fi
if [ "$action" = "info" ]; then
detectDE
if [ x"$DE" = x"" ]; then
if [ -x /usr/bin/file ]; then
DE=generic
fi
fi
case "$DE" in
kde)
info_kde "$filename"
;;
gnome*)
info_gnome "$filename"
;;
*)
info_generic "$filename"
;;
esac
exit_failure_operation_impossible "no method available for quering MIME type of '$filename'"
fi
if [ "$action" = "defapp" ]; then
detectDE
case "$DE" in
kde)
defapp_kde "$mimetype"
;;
*)
defapp_generic "$mimetype"
;;
esac
exit_failure_operation_impossible "no method available for quering default application for '$mimetype'"
fi
vendor=true
while [ $# -gt 0 ] ; do
parm="$1"
shift
case $parm in
--mode)
if [ -z "$1" ] ; then
exit_failure_syntax "mode argument missing for --mode"
fi
case "$1" in
user)
mode="user"
;;
system)
mode="system"
;;
*)
exit_failure_syntax "unknown mode '$1'"
;;
esac
shift
;;
--novendor)
vendor=false
;;
-*)
exit_failure_syntax "unexpected option '$parm'"
;;
*)
if [ -n "$filename" ] ; then
exit_failure_syntax "unexpected argument '$parm'"
fi
filename="$parm"
check_input_file "$filename"
;;
esac
done
if [ -z "$action" ] ; then
exit_failure_syntax "command argument missing"
fi
if [ -n "$XDG_UTILS_INSTALL_MODE" ] ; then
if [ "$XDG_UTILS_INSTALL_MODE" = "system" ] ; then
mode="system"
elif [ "$XDG_UTILS_INSTALL_MODE" = "user" ] ; then
mode="user"
fi
fi
if [ -z "$mode" ] ; then
if [ `whoami` = "root" ] ; then
mode="system"
else
mode="user"
fi
fi
if [ -z "$filename" ] ; then
exit_failure_syntax "mimetypes-file argument missing"
fi
if [ "$vendor" = "true" -a "$action" = "install" ] ; then
check_vendor_prefix "$filename"
fi
xdg_base_dir=
xdg_dir_name=mime/packages/
xdg_user_dir="$XDG_DATA_HOME"
[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
[ x"$mode" = x"user" ] && xdg_base_dir="$xdg_user_dir/mime"
xdg_user_dir="$xdg_user_dir/$xdg_dir_name"
xdg_system_dirs="$XDG_DATA_DIRS"
[ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
for x in `echo $xdg_system_dirs | sed 's/:/ /g'`; do
if [ -w $x/$xdg_dir_name ] ; then
[ x"$mode" = x"system" ] && xdg_base_dir="$x/mime"
xdg_global_dir="$x/$xdg_dir_name"
break
fi
done
[ -w $xdg_global_dir ] || xdg_global_dir=
DEBUG 3 "xdg_user_dir: $xdg_user_dir"
DEBUG 3 "xdg_global_dir: $xdg_global_dir"
# Find KDE3 mimelnk directory
kde_user_dir=
kde_global_dir=
kde_global_dirs=`kde${KDE_SESSION_VERSION}-config --path mime 2> /dev/null`
DEBUG 3 "kde_global_dirs: $kde_global_dirs"
first=
for x in `echo $kde_global_dirs | sed 's/:/ /g'` ; do
if [ -z "$first" ] ; then
first=false
kde_user_dir="$x"
elif [ -w $x ] ; then
kde_global_dir="$x"
fi
done
DEBUG 3 "kde_user_dir: $kde_user_dir"
DEBUG 3 "kde_global_dir: $kde_global_dir"
# TODO: Gnome legacy support
# See http://forums.fedoraforum.org/showthread.php?t=26875
gnome_user_dir="$HOME/.gnome/apps"
gnome_global_dir=/usr/share/gnome/apps
[ -w $gnome_global_dir ] || gnome_global_dir=
DEBUG 3 "gnome_user_dir: $gnome_user_dir"
DEBUG 3 "gnome_global_dir: $gnome_global_dir"
if [ x"$mode" = x"user" ] ; then
xdg_dir="$xdg_user_dir"
kde_dir="$kde_user_dir"
gnome_dir="$gnome_user_dir"
my_umask=077
else
xdg_dir="$xdg_global_dir"
kde_dir="$kde_global_dir"
gnome_dir="$gnome_global_dir"
my_umask=022
if [ -z "${xdg_dir}${kde_dir}${gnome_dir}" ] ; then
exit_failure_operation_impossible "No writable system mimetype directory found."
fi
fi
# echo "[xdg|$xdg_user_dir|$xdg_global_dir]"
# echo "[kde|$kde_user_dir|$kde_global_dir]"
# echo "[gnome|$gnome_user_dir|$gnome_global_dir]"
# echo "[using|$xdg_dir|$kde_dir|$gnome_dir]"
basefile=`basename "$filename"`
#[ -z $vendor ] || basefile="$vendor-$basefile"
mimetypes=
if [ -n "$kde_dir" ] ; then
DEBUG 2 "KDE3 mimelnk directory found, extracting mimetypes from XML file"
mimetypes=`awk < "$filename" '
# Strip XML comments
BEGIN {
suppress=0
}
{
do
if (suppress) {
if (match($0,/-->/)) {
$0=substr($0,RSTART+RLENGTH)
suppress=0
}
else {
break
}
}
else {
if (match($0,/<!--/)) {
if (RSTART>1) print substr($0,0,RSTART)
$0=substr($0,RSTART+RLENGTH)
suppress=1
}
else {
if ($0) print $0
break
}
}
while(1)
}
' | awk '
# List MIME types listed in <mime-type> tags
BEGIN {
RS="<"
}
/^mime-info/, /^\/mime-info/ {
if (match($0,/^mime-type/)) {
if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) {
print substr($0,RSTART+6,RLENGTH-6)
}
}
}'`
fi
DEBUG 1 "$action mimetype in $xdg_dir"
case $action in
install)
save_umask=`umask`
umask $my_umask
for x in $xdg_dir ; do
mkdir -p $x
eval 'cp $filename $x/$basefile'$xdg_redirect_output
done
if [ -n "$mimetypes" ] ; then
# No quotes around $mimetypes
for x in $mimetypes ; do
DEBUG 1 "Installing $kde_dir/$x.desktop (KDE 3.x support)"
mkdir -p `dirname $kde_dir/$x.desktop`
awk < "$filename" '
# Strip XML comments
BEGIN {
suppress=0
}
{
do
if (suppress) {
if (match($0,/-->/)) {
$0=substr($0,RSTART+RLENGTH)
suppress=0
}
else {
break
}
}
else {
if (match($0,/<!--/)) {
if (RSTART>1) print substr($0,0,RSTART)
$0=substr($0,RSTART+RLENGTH)
suppress=1
}
else {
if ($0) print $0
break
}
}
while(1)
}
' | awk > $kde_dir/$x.desktop '
# Extract mimetype $x from the XML file $filename
# Note that bash requires us to escape a single quote as '"'"'
BEGIN {
the_type=ARGV[1]
the_source=ARGV[2]
ARGC=1
RS="<"
found=0
glob_patterns=""
}
/^mime-info/, /^\/mime-info/ {
if (match($0,/^mime-type/)) {
if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) {
if (substr($0,RSTART+6,RLENGTH-6) == the_type) {
found=1
print "[Desktop Entry]"
print "# Installed by xdg-mime from " the_source
print "Type=MimeType"
print "MimeType=" the_type
the_icon=the_type
sub("/", "-", the_icon)
print "Icon=" the_icon
}
}
}
else if (found) {
if (match($0,/^\/mime-type/)) {
if (glob_patterns)
print "Patterns=" glob_patterns
exit 0
}
if (match($0,/^sub-class-of/)) {
if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) {
print "X-KDE-IsAlso=" substr($0,RSTART+6,RLENGTH-6)
}
else {
print "Error: '"'"'type'"'"' argument missing in " RS $0
exit 1
}
}
if (match($0,/^glob/)) {
if (match($0,/pattern="[^"]*/) || match($0,/pattern='"'"'[^'"'"']*/)) {
glob_patterns = glob_patterns substr($0,RSTART+9,RLENGTH-9) ";"
}
else {
print "Error: '"'"'pattern'"'"' argument missing in " RS $0
exit 1
}
}
if (match($0,/^comment/)) {
if (match($0,/xml:lang="[^"]*/) || match($0,/xml:lang='"'"'[^'"'"']*/)) {
lang=substr($0,RSTART+10,RLENGTH-10)
}
else {
lang=""
}
if (match($0,/>/)) {
comment=substr($0,RSTART+1)
sub("&lt;", "<", comment)
sub("&gt;", ">", comment)
sub("&amp;", "\\&", comment)
if (lang)
print "Comment[" lang "]=" comment
else
print "Comment=" comment
}
}
}
}
END {
if (!found) {
print "Error: Mimetype '"'"'" the_type "'"'"' not found"
exit 1
}
}
' $x $basefile
if [ "$?" = "1" ] ; then
grep -A 10 "^Error:" $kde_dir/$x.desktop >&2
rm $kde_dir/$x.desktop
exit 1
fi
done
fi
umask $save_umask
;;
uninstall)
for x in $xdg_dir ; do
rm -f $x/$basefile
done
# No quotes around $mimetypes
for x in $mimetypes ; do
if grep '^# Installed by xdg-mime' $kde_dir/$x.desktop >/dev/null 2>&1; then
DEBUG 1 "Removing $kde_dir/$x.desktop (KDE 3.x support)"
rm -f $kde_dir/$x.desktop
fi
done
;;
esac
update_mime_database $xdg_base_dir
exit_success