1#!/bin/sh 2#--------------------------------------------- 3# xdg-mime 4# 5# Utility script to manipulate MIME related information 6# on XDG compliant systems. 7# 8# Refer to the usage() function below for usage. 9# 10# Copyright 2009-2010, Fathi Boudra <fabo@freedesktop.org> 11# Copyright 2009-2010, Rex Dieter <rdieter@fedoraproject.org> 12# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at> 13# Copyright 2006, Jeremy White <jwhite@codeweavers.com> 14# 15# LICENSE: 16# 17# Permission is hereby granted, free of charge, to any person obtaining a 18# copy of this software and associated documentation files (the "Software"), 19# to deal in the Software without restriction, including without limitation 20# the rights to use, copy, modify, merge, publish, distribute, sublicense, 21# and/or sell copies of the Software, and to permit persons to whom the 22# Software is furnished to do so, subject to the following conditions: 23# 24# The above copyright notice and this permission notice shall be included 25# in all copies or substantial portions of the Software. 26# 27# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 28# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33# OTHER DEALINGS IN THE SOFTWARE. 34# 35#--------------------------------------------- 36 37manualpage() 38{ 39cat << _MANUALPAGE 40Name 41 42xdg-mime - command line tool for querying information about file type handling 43and adding descriptions for new file types 44 45Synopsis 46 47xdg-mime query { filetype | default } ... 48 49xdg-mime default application mimetype(s) 50 51xdg-mime install [--mode mode] [--novendor] mimetypes-file 52 53xdg-mime uninstall [--mode mode] mimetypes-file 54 55xdg-mime { --help | --manual | --version } 56 57Description 58 59The xdg-mime program can be used to query information about file types and to 60add descriptions for new file types. 61 62Commands 63 64query 65 66 Returns information related to file types. 67 68 The query option is for use inside a desktop session only. It is not 69 recommended to use xdg-mime query as root. 70 71 The following queries are supported: 72 73 query filetype FILE: Returns the file type of FILE in the form of a MIME 74 type. 75 76 query default mimetype: Returns the default application that the desktop 77 environment uses for opening files of type mimetype. The default 78 application is identified by its *.desktop file. 79 80default 81 82 Ask the desktop environment to make application the default application for 83 opening files of type mimetype. An application can be made the default for 84 several file types by specifying multiple mimetypes. 85 86 application is the desktop file id of the application and has the form 87 vendor-name.desktop application must already be installed in the desktop 88 menu before it can be made the default handler. The aplication's desktop 89 file must list support for all the MIME types that it wishes to be the 90 default handler for. 91 92 Requests to make an application a default handler may be subject to system 93 policy or approval by the end-user. xdg-mime query can be used to verify 94 whether an application is the actual default handler for a specific file 95 type. 96 97 The default option is for use inside a desktop session only. It is not 98 recommended to use xdg-mime default as root. 99 100install 101 Adds the file type descriptions provided in mimetypes-file to the desktop 102 environment. mimetypes-file must be a XML file that follows the 103 freedesktop.org Shared MIME-info Database specification and that has a 104 mime-info element as its document root. For each new file type one or more 105 icons with name type-subtype must be installed with the xdg-icon-resource 106 command in the mimetypes context. For example the filetype application/ 107 vnd.oasis.opendocument.text requires an icon named 108 application-vnd.oasis.opendocument.text to be installed (unless the file 109 type recommends another icon name). 110uninstall 111 Removes the file type descriptions provided in mimetypes-file and 112 previously added with xdg-mime install from the desktop environment. 113 mimetypes-file must be a XML file that follows the freedesktop.org Shared 114 MIME-info Database specification and that has a mime-info element as its 115 document root. 116 117Options 118 119--mode mode 120 121 mode can be user or system. In user mode the file is (un)installed for the 122 current user only. In system mode the file is (un)installed for all users 123 on the system. Usually only root is allowed to install in system mode. 124 125 The default is to use system mode when called by root and to use user mode 126 when called by a non-root user. 127 128--novendor 129 130 Normally, xdg-mime checks to ensure that the mimetypes-file to be installed 131 has a proper vendor prefix. This option can be used to disable that check. 132 133 A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated 134 with a dash ("-"). Companies and organizations are encouraged to use a word 135 or phrase, preferably the organizations name, for which they hold a 136 trademark as their vendor prefix. The purpose of the vendor prefix is to 137 prevent name conflicts. 138 139--help 140 Show command synopsis. 141--manual 142 Show this manualpage. 143--version 144 Show the xdg-utils version information. 145 146Environment Variables 147 148xdg-mime honours the following environment variables: 149 150XDG_UTILS_DEBUG_LEVEL 151 Setting this environment variable to a non-zero numerical value makes 152 xdg-mime do more verbose reporting on stderr. Setting a higher value 153 increases the verbosity. 154XDG_UTILS_INSTALL_MODE 155 This environment variable can be used by the user or administrator to 156 override the installation mode. Valid values are user and system. 157 158Exit Codes 159 160An exit code of 0 indicates success while a non-zero exit code indicates 161failure. The following failure codes can be returned: 162 1631 164 Error in command line syntax. 1652 166 One of the files passed on the command line did not exist. 1673 168 A required tool could not be found. 1694 170 The action failed. 1715 172 No permission to read one of the files passed on the command line. 173 174See Also 175 176xdg-icon-resource(1), xdg-desktop-menu(1) 177 178Examples 179 180xdg-mime query filetype /tmp/foobar.png 181 182Prints the MIME type of the file /tmp/foobar.png, in this case image/png 183 184xdg-mime query default image/png 185 186Prints the .desktop filename of the application which is registered to open PNG 187files. 188 189xdg-mime install shinythings-shiny.xml 190 191Adds a file type description for "shiny"-files. "shinythings-" is used as the 192vendor prefix. The file type description could look as folows. 193 194shinythings-shiny.xml: 195 196<?xml version="1.0"?> 197<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'> 198 <mime-type type="text/x-shiny"> 199 <comment>Shiny new file type</comment> 200 <glob pattern="*.shiny"/> 201 <glob pattern="*.shi"/> 202 </mime-type> 203</mime-info> 204 205An icon for this new file type must also be installed, for example with: 206 207xdg-icon-resource install --context mimetypes --size 64 shiny-file-icon.png text-x-shiny 208 209_MANUALPAGE 210} 211 212usage() 213{ 214cat << _USAGE 215xdg-mime - command line tool for querying information about file type handling 216and adding descriptions for new file types 217 218Synopsis 219 220xdg-mime query { filetype | default } ... 221 222xdg-mime default application mimetype(s) 223 224xdg-mime install [--mode mode] [--novendor] mimetypes-file 225 226xdg-mime uninstall [--mode mode] mimetypes-file 227 228xdg-mime { --help | --manual | --version } 229 230_USAGE 231} 232 233#@xdg-utils-common@ 234 235#---------------------------------------------------------------------------- 236# Common utility functions included in all XDG wrapper scripts 237#---------------------------------------------------------------------------- 238 239DEBUG() 240{ 241 [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0; 242 [ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0; 243 shift 244 echo "$@" >&2 245} 246 247# This handles backslashes but not quote marks. 248first_word() 249{ 250 read first rest 251 echo "$first" 252} 253 254#------------------------------------------------------------- 255# map a binary to a .desktop file 256binary_to_desktop_file() 257{ 258 search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" 259 binary="`which "$1"`" 260 binary="`readlink -f "$binary"`" 261 base="`basename "$binary"`" 262 IFS=: 263 for dir in $search; do 264 unset IFS 265 [ "$dir" ] || continue 266 [ -d "$dir/applications" -o -d "$dir/applnk" ] || continue 267 for file in "$dir"/applications/*.desktop "$dir"/applications/*/*.desktop "$dir"/applnk/*.desktop "$dir"/applnk/*/*.desktop; do 268 [ -r "$file" ] || continue 269 # Check to make sure it's worth the processing. 270 grep -q "^Exec.*$base" "$file" || continue 271 # Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop"). 272 grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue 273 command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`" 274 command="`which "$command"`" 275 if [ x"`readlink -f "$command"`" = x"$binary" ]; then 276 # Fix any double slashes that got added path composition 277 echo "$file" | sed -e 's,//*,/,g' 278 return 279 fi 280 done 281 done 282} 283 284#------------------------------------------------------------- 285# map a .desktop file to a binary 286## FIXME: handle vendor dir case 287desktop_file_to_binary() 288{ 289 search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" 290 desktop="`basename "$1"`" 291 IFS=: 292 for dir in $search; do 293 unset IFS 294 [ "$dir" -a -d "$dir/applications" ] || continue 295 file="$dir/applications/$desktop" 296 [ -r "$file" ] || continue 297 # Remove any arguments (%F, %f, %U, %u, etc.). 298 command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`" 299 command="`which "$command"`" 300 readlink -f "$command" 301 return 302 done 303} 304 305#------------------------------------------------------------- 306# Exit script on successfully completing the desired operation 307 308exit_success() 309{ 310 if [ $# -gt 0 ]; then 311 echo "$@" 312 echo 313 fi 314 315 exit 0 316} 317 318 319#----------------------------------------- 320# Exit script on malformed arguments, not enough arguments 321# or missing required option. 322# prints usage information 323 324exit_failure_syntax() 325{ 326 if [ $# -gt 0 ]; then 327 echo "xdg-mime: $@" >&2 328 echo "Try 'xdg-mime --help' for more information." >&2 329 else 330 usage 331 echo "Use 'man xdg-mime' or 'xdg-mime --manual' for additional info." 332 fi 333 334 exit 1 335} 336 337#------------------------------------------------------------- 338# Exit script on missing file specified on command line 339 340exit_failure_file_missing() 341{ 342 if [ $# -gt 0 ]; then 343 echo "xdg-mime: $@" >&2 344 fi 345 346 exit 2 347} 348 349#------------------------------------------------------------- 350# Exit script on failure to locate necessary tool applications 351 352exit_failure_operation_impossible() 353{ 354 if [ $# -gt 0 ]; then 355 echo "xdg-mime: $@" >&2 356 fi 357 358 exit 3 359} 360 361#------------------------------------------------------------- 362# Exit script on failure returned by a tool application 363 364exit_failure_operation_failed() 365{ 366 if [ $# -gt 0 ]; then 367 echo "xdg-mime: $@" >&2 368 fi 369 370 exit 4 371} 372 373#------------------------------------------------------------ 374# Exit script on insufficient permission to read a specified file 375 376exit_failure_file_permission_read() 377{ 378 if [ $# -gt 0 ]; then 379 echo "xdg-mime: $@" >&2 380 fi 381 382 exit 5 383} 384 385#------------------------------------------------------------ 386# Exit script on insufficient permission to write a specified file 387 388exit_failure_file_permission_write() 389{ 390 if [ $# -gt 0 ]; then 391 echo "xdg-mime: $@" >&2 392 fi 393 394 exit 6 395} 396 397check_input_file() 398{ 399 if [ ! -e "$1" ]; then 400 exit_failure_file_missing "file '$1' does not exist" 401 fi 402 if [ ! -r "$1" ]; then 403 exit_failure_file_permission_read "no permission to read file '$1'" 404 fi 405} 406 407check_vendor_prefix() 408{ 409 file_label="$2" 410 [ -n "$file_label" ] || file_label="filename" 411 file=`basename "$1"` 412 case "$file" in 413 [a-zA-Z]*-*) 414 return 415 ;; 416 esac 417 418 echo "xdg-mime: $file_label '$file' does not have a proper vendor prefix" >&2 419 echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2 420 echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2 421 echo "Use --novendor to override or 'xdg-mime --manual' for additional info." >&2 422 exit 1 423} 424 425check_output_file() 426{ 427 # if the file exists, check if it is writeable 428 # if it does not exists, check if we are allowed to write on the directory 429 if [ -e "$1" ]; then 430 if [ ! -w "$1" ]; then 431 exit_failure_file_permission_write "no permission to write to file '$1'" 432 fi 433 else 434 DIR=`dirname "$1"` 435 if [ ! -w "$DIR" -o ! -x "$DIR" ]; then 436 exit_failure_file_permission_write "no permission to create file '$1'" 437 fi 438 fi 439} 440 441#---------------------------------------- 442# Checks for shared commands, e.g. --help 443 444check_common_commands() 445{ 446 while [ $# -gt 0 ] ; do 447 parm="$1" 448 shift 449 450 case "$parm" in 451 --help) 452 usage 453 echo "Use 'man xdg-mime' or 'xdg-mime --manual' for additional info." 454 exit_success 455 ;; 456 457 --manual) 458 manualpage 459 exit_success 460 ;; 461 462 --version) 463 echo "xdg-mime 1.1.0 rc1" 464 exit_success 465 ;; 466 esac 467 done 468} 469 470check_common_commands "$@" 471 472[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL; 473if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then 474 # Be silent 475 xdg_redirect_output=" > /dev/null 2> /dev/null" 476else 477 # All output to stderr 478 xdg_redirect_output=" >&2" 479fi 480 481#-------------------------------------- 482# Checks for known desktop environments 483# set variable DE to the desktop environments name, lowercase 484 485detectDE() 486{ 487 # see https://bugs.freedesktop.org/show_bug.cgi?id=34164 488 unset GREP_OPTIONS 489 490 if [ -n "${XDG_CURRENT_DESKTOP}" ]; then 491 case "${XDG_CURRENT_DESKTOP}" in 492 GNOME) 493 DE=gnome; 494 ;; 495 KDE) 496 DE=kde; 497 ;; 498 LXDE) 499 DE=lxde; 500 ;; 501 XFCE) 502 DE=xfce 503 esac 504 fi 505 506 if [ x"$DE" = x"" ]; then 507 # classic fallbacks 508 if [ x"$KDE_FULL_SESSION" = x"true" ]; then DE=kde; 509 elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome; 510 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; 511 elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce; 512 elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce 513 fi 514 fi 515 516 if [ x"$DE" = x"" ]; then 517 # fallback to checking $DESKTOP_SESSION 518 case "$DESKTOP_SESSION" in 519 gnome) 520 DE=gnome; 521 ;; 522 LXDE) 523 DE=lxde; 524 ;; 525 xfce|xfce4) 526 DE=xfce; 527 ;; 528 esac 529 fi 530 531 if [ x"$DE" = x"" ]; then 532 # fallback to uname output for other platforms 533 case "$(uname 2>/dev/null)" in 534 Darwin) 535 DE=darwin; 536 ;; 537 esac 538 fi 539 540 if [ x"$DE" = x"gnome" ]; then 541 # gnome-default-applications-properties is only available in GNOME 2.x 542 # but not in GNOME 3.x 543 which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3" 544 fi 545} 546 547#---------------------------------------------------------------------------- 548# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4 549# It also always returns 1 in KDE 3.4 and earlier 550# Simply return 0 in such case 551 552kfmclient_fix_exit_code() 553{ 554 version=`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'` 555 major=`echo $version | sed 's/KDE.*: \([0-9]\).*/\1/'` 556 minor=`echo $version | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/'` 557 release=`echo $version | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'` 558 test "$major" -gt 3 && return $1 559 test "$minor" -gt 5 && return $1 560 test "$release" -gt 4 && return $1 561 return 0 562} 563 564update_mime_database() 565{ 566 if [ x"$mode" = x"user" -a -n "$DISPLAY" ] ; then 567 detectDE 568 if [ x"$DE" = x"kde" ] ; then 569 DEBUG 1 "Running kbuildsycoca" 570 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 571 eval 'kbuildsycoca4'$xdg_redirect_output 572 else 573 eval 'kbuildsycoca'$xdg_redirect_output 574 fi 575 fi 576 fi 577 for x in `echo "$PATH:/opt/gnome/bin" | sed 's/:/ /g'`; do 578 if [ -x $x/update-mime-database ] ; then 579 DEBUG 1 "Running $x/update-mime-database $1" 580 eval '$x/update-mime-database $1'$xdg_redirect_output 581 return 582 fi 583 done 584} 585 586info_kde() 587{ 588 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 589 DEBUG 1 "Running kmimetypefinder \"$1\"" 590 kmimetypefinder "$1" 2>/dev/null | head -n 1 591 else 592 DEBUG 1 "Running kfile \"$1\"" 593 kfile "$1" 2> /dev/null | head -n 1 | cut -d "(" -f 2 | cut -d ")" -f 1 594 fi 595 596 if [ $? -eq 0 ]; then 597 exit_success 598 else 599 exit_failure_operation_failed 600 fi 601} 602 603info_gnome() 604{ 605 if gvfs-info --help 2>/dev/null 1>&2; then 606 DEBUG 1 "Running gvfs-info \"$1\"" 607 gvfs-info "$1" 2> /dev/null | grep standard::content-type | cut -d' ' -f4 608 elif gnomevfs-info --help 2>/dev/null 1>&2; then 609 DEBUG 1 "Running gnomevfs-info \"$1\"" 610 gnomevfs-info --slow-mime "$1" 2> /dev/null | grep "^MIME" | cut -d ":" -f 2 | sed s/"^ "// 611 else 612 # according to https://bugs.freedesktop.org/show_bug.cgi?id=33094#c5 613 # neither gvfs-info or gnomevfs-info are present in a default Ubuntu Natty 614 # install, so fallback to info_generic 615 info_generic "$1" 616 fi 617 618 if [ $? -eq 0 ]; then 619 exit_success 620 else 621 exit_failure_operation_failed 622 fi 623} 624 625info_generic() 626{ 627 if mimetype --version >/dev/null 2>&1; then 628 DEBUG 1 "Running mimetype -b \"$1\"" 629 mimetype -b "$1" 630 else 631 DEBUG 1 "Running file --mime-type \"$1\"" 632 /usr/bin/file --mime-type "$1" 2> /dev/null | cut -d ":" -f 2 | sed s/"^ "// 633 fi 634 635 if [ $? -eq 0 ]; then 636 exit_success 637 else 638 exit_failure_operation_failed 639 fi 640} 641 642make_default_kde() 643{ 644 # $1 is vendor-name.desktop 645 # $2 is mime/type 646 # 647 # On KDE 3, add to $KDE_CONFIG_PATH/profilerc: 648 # [$2 - 1] 649 # Application=$1 650 # 651 # Remove all [$2 - *] sections, or even better, 652 # renumber [$2 - *] sections and remove duplicate 653 # 654 # On KDE 4, add $2=$1 to $XDG_DATA_APPS/mimeapps.list 655 # 656 # Example file: 657 # 658 # [Added Associations] 659 # text/plain=kde4-kate.desktop;kde4-kwrite.desktop; 660 # 661 # [Removed Associations] 662 # text/plain=gnome-gedit.desktop;gnu-emacs.desktop; 663 vendor="$1" 664 mimetype="$2" 665 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 666 default_dir=`kde4-config --path xdgdata-apps 2> /dev/null | cut -d ':' -f 1` 667 default_file="$default_dir/mimeapps.list" 668 else 669 default_dir=`kde-config --path config 2> /dev/null | cut -d ':' -f 1` 670 default_file="$default_dir/profilerc" 671 fi 672 if [ -z "$default_dir" ]; then 673 DEBUG 2 "make_default_kde: No kde runtime detected" 674 return 675 fi 676 DEBUG 2 "make_default_kde $vendor $mimetype" 677 DEBUG 1 "Updating $default_file" 678 mkdir -p "$default_dir" 679 [ -f "$default_file" ] || touch "$default_file" 680 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 681 [ -f "$default_file" ] || touch "$default_file" 682 awk -v application="$vendor" -v mimetype="$mimetype" ' 683 BEGIN { 684 prefix=mimetype "=" 685 associations=0 686 found=0 687 blanks=0 688 } 689 { 690 suppress=0 691 if (index($0, "[Added Associations]") == 1) { 692 associations=1 693 } else if (index($0, "[") == 1) { 694 if (associations && !found) { 695 print prefix application 696 found=1 697 } 698 associations=0 699 } else if ($0 == "") { 700 blanks++ 701 suppress=1 702 } else if (associations && index($0, prefix) == 1) { 703 value=substr($0, length(prefix) + 1, length) 704 split(value, apps, ";") 705 value=application ";" 706 count=0 707 for (i in apps) { 708 count++ 709 } 710 for (i=0; i < count; i++) { 711 if (apps[i] != application && apps[i] != "") { 712 value=value apps[i] ";" 713 } 714 } 715 $0=prefix value 716 found=1 717 } 718 if (!suppress) { 719 while (blanks > 0) { 720 print "" 721 blanks-- 722 } 723 print $0 724 } 725 } 726 END { 727 if (!found) { 728 if (!associations) { 729 print "[Added Associations]" 730 } 731 print prefix application 732 } 733 while (blanks > 0) { 734 print "" 735 blanks-- 736 } 737 } 738' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file" 739 eval 'kbuildsycoca4'$xdg_redirect_output 740 else 741 awk -v application="$vendor" -v mimetype="$mimetype" ' 742 BEGIN { 743 header_start="[" mimetype " - " 744 suppress=0 745 } 746 { 747 if (index($0, header_start) == 1 ) 748 suppress=1 749 else 750 if (/^\[/) { suppress=0 } 751 752 if (!suppress) { 753 print $0 754 } 755 } 756 END { 757 print "" 758 print "[" mimetype " - 1]" 759 print "Application=" application 760 print "AllowAsDefault=true" 761 print "GenericServiceType=Application" 762 print "Preference=1" 763 print "ServiceType=" mimetype 764 } 765' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file" 766 fi 767} 768 769make_default_generic() 770{ 771 # $1 is vendor-name.desktop 772 # $2 is mime/type 773 # Add $2=$1 to XDG_DATA_HOME/applications/mimeapps.list 774 xdg_user_dir="$XDG_DATA_HOME" 775 [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share" 776 default_file="$xdg_user_dir/applications/mimeapps.list" 777 DEBUG 2 "make_default_generic $1 $2" 778 DEBUG 1 "Updating $default_file" 779 [ -f "$default_file" ] || touch "$default_file" 780 awk -v mimetype="$2" -v application="$1" ' 781 BEGIN { 782 prefix=mimetype "=" 783 indefault=0 784 added=0 785 blanks=0 786 found=0 787 } 788 { 789 suppress=0 790 if (index($0, "[Default Applications]") == 1) { 791 indefault=1 792 found=1 793 } else if (index($0, "[") == 1) { 794 if (!added && indefault) { 795 print prefix application 796 added=1 797 } 798 indefault=0 799 } else if ($0 == "") { 800 suppress=1 801 blanks++ 802 } else if (indefault && !added && index($0, prefix) == 1) { 803 $0=prefix application 804 added=1 805 } 806 if (!suppress) { 807 while (blanks > 0) { 808 print "" 809 blanks-- 810 } 811 print $0 812 } 813 } 814 END { 815 if (!added) { 816 if (!found) { 817 print "" 818 print "[Default Applications]" 819 } 820 print prefix application 821 } 822 while (blanks > 0) { 823 print "" 824 blanks-- 825 } 826 } 827' "$default_file" > "${default_file}.new" && mv "${default_file}.new" "$default_file" 828} 829 830defapp_generic() 831{ 832 MIME="$1" 833 xdg_user_dir="$XDG_DATA_HOME" 834 [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share" 835 xdg_user_dir="$xdg_user_dir/$xdg_dir_name" 836 xdg_system_dirs="$XDG_DATA_DIRS" 837 [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/ 838 839 for x in `echo "$xdg_user_dir" | sed 's/:/ /g'`; do 840 mimeapps_list="$x/applications/mimeapps.list" 841 if [ -f "$mimeapps_list" ] ; then 842 DEBUG 2 "Checking $mimeapps_list" 843 trader_result=`awk -v mimetype="$MIME" ' 844 BEGIN { 845 prefix=mimetype "=" 846 indefault=0 847 found=0 848 } 849 { 850 if (index($0, "[Default Applications]") == 1) { 851 indefault=1 852 } else if (index($0, "[") == 1) { 853 indefault=0 854 } else if (!found && indefault && index($0, prefix) == 1) { 855 print substr($0, length(prefix) +1, length) 856 found=1 857 } 858 } 859' $mimeapps_list` 860 if [ -n "$trader_result" ] ; then 861 echo $trader_result 862 exit_success 863 fi 864 fi 865 done 866 867 for x in `echo "$xdg_system_dirs" | sed 's/:/ /g'`; do 868 DEBUG 2 "Checking $x/applications/defaults.list" 869 trader_result=`grep "$MIME=" $x/applications/defaults.list 2> /dev/null | cut -d '=' -f 2 | cut -d ';' -f 1` 870 if [ -n "$trader_result" ] ; then 871 echo $trader_result 872 exit_success 873 fi 874 done 875 exit_success 876} 877 878defapp_kde() 879{ 880 MIME="$1" 881 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 882 KTRADER=`which ktraderclient 2> /dev/null` 883 MIMETYPE="--mimetype" 884 SERVICETYPE="--servicetype" 885 else 886 KTRADER=`which ktradertest 2> /dev/null` 887 fi 888 if [ -n "$KTRADER" ] ; then 889 DEBUG 1 "Running KDE trader query \"$MIME\" mimetype and \"Application\" servicetype" 890 trader_result=`$KTRADER $MIMETYPE "$MIME" $SERVICETYPE Application 2>/dev/null \ 891 | grep DesktopEntryPath | head -n 1 | cut -d ':' -f 2 | cut -d \' -f 2` 892 if [ -n "$trader_result" ] ; then 893 basename "$trader_result" 894 exit_success 895 else 896 exit_failure_operation_failed 897 fi 898 else 899 defapp_generic "$1" 900 fi 901} 902 903[ x"$1" != x"" ] || exit_failure_syntax 904 905mode= 906action= 907filename= 908mimetype= 909 910case $1 in 911 install) 912 action=install 913 ;; 914 915 uninstall) 916 action=uninstall 917 ;; 918 919 query) 920 shift 921 922 if [ -z "$1" ] ; then 923 exit_failure_syntax "query type argument missing" 924 fi 925 926 case $1 in 927 filetype) 928 action=info 929 930 filename="$2" 931 if [ -z "$filename" ] ; then 932 exit_failure_syntax "FILE argument missing" 933 fi 934 case $filename in 935 -*) 936 exit_failure_syntax "unexpected option '$filename'" 937 ;; 938 esac 939 check_input_file "$filename" 940 filename=`readlink -f -- "$filename"` 941 ;; 942 943 default) 944 action=defapp 945 mimetype="$2" 946 if [ -z "$mimetype" ] ; then 947 exit_failure_syntax "mimetype argument missing" 948 fi 949 case $mimetype in 950 -*) 951 exit_failure_syntax "unexpected option '$mimetype'" 952 ;; 953 954 */*) 955 # Ok 956 ;; 957 958 *) 959 exit_failure_syntax "mimetype '$mimetype' is not in the form 'minor/major'" 960 ;; 961 esac 962 ;; 963 964 *) 965 exit_failure_syntax "unknown query type '$1'" 966 ;; 967 esac 968 ;; 969 970 default) 971 action=makedefault 972 shift 973 974 if [ -z "$1" ] ; then 975 exit_failure_syntax "application argument missing" 976 fi 977 case $1 in 978 -*) 979 exit_failure_syntax "unexpected option '$1'" 980 ;; 981 982 *.desktop) 983 filename="$1" 984 ;; 985 986 *) 987 exit_failure_syntax "malformed argument '$1', expected *.desktop" 988 ;; 989 esac 990 ;; 991 992 *) 993 exit_failure_syntax "unknown command '$1'" 994 ;; 995esac 996 997shift 998 999 1000if [ "$action" = "makedefault" ]; then 1001 if [ -z "$1" ] ; then 1002 exit_failure_syntax "mimetype argument missing" 1003 fi 1004 1005 while [ $# -gt 0 ] ; do 1006 case $1 in 1007 -*) 1008 exit_failure_syntax "unexpected option '$1'" 1009 ;; 1010 esac 1011 mimetype="$1" 1012 shift 1013 1014 make_default_kde "$filename" "$mimetype" 1015 make_default_generic "$filename" "$mimetype" 1016 done 1017 exit_success 1018fi 1019 1020if [ "$action" = "info" ]; then 1021 detectDE 1022 1023 if [ x"$DE" = x"" ]; then 1024 if [ -x /usr/bin/file ]; then 1025 DE=generic 1026 fi 1027 fi 1028 1029 case "$DE" in 1030 kde) 1031 info_kde "$filename" 1032 ;; 1033 1034 gnome*) 1035 info_gnome "$filename" 1036 ;; 1037 1038 *) 1039 info_generic "$filename" 1040 ;; 1041 esac 1042 exit_failure_operation_impossible "no method available for quering MIME type of '$filename'" 1043fi 1044 1045if [ "$action" = "defapp" ]; then 1046 detectDE 1047 1048 case "$DE" in 1049 kde) 1050 defapp_kde "$mimetype" 1051 ;; 1052 1053 *) 1054 defapp_generic "$mimetype" 1055 ;; 1056 esac 1057 exit_failure_operation_impossible "no method available for quering default application for '$mimetype'" 1058fi 1059 1060vendor=true 1061while [ $# -gt 0 ] ; do 1062 parm="$1" 1063 shift 1064 1065 case $parm in 1066 --mode) 1067 if [ -z "$1" ] ; then 1068 exit_failure_syntax "mode argument missing for --mode" 1069 fi 1070 case "$1" in 1071 user) 1072 mode="user" 1073 ;; 1074 1075 system) 1076 mode="system" 1077 ;; 1078 1079 *) 1080 exit_failure_syntax "unknown mode '$1'" 1081 ;; 1082 esac 1083 shift 1084 ;; 1085 1086 --novendor) 1087 vendor=false 1088 ;; 1089 1090 -*) 1091 exit_failure_syntax "unexpected option '$parm'" 1092 ;; 1093 1094 *) 1095 if [ -n "$filename" ] ; then 1096 exit_failure_syntax "unexpected argument '$parm'" 1097 fi 1098 1099 filename="$parm" 1100 check_input_file "$filename" 1101 ;; 1102 esac 1103done 1104 1105if [ -z "$action" ] ; then 1106 exit_failure_syntax "command argument missing" 1107fi 1108 1109if [ -n "$XDG_UTILS_INSTALL_MODE" ] ; then 1110 if [ "$XDG_UTILS_INSTALL_MODE" = "system" ] ; then 1111 mode="system" 1112 elif [ "$XDG_UTILS_INSTALL_MODE" = "user" ] ; then 1113 mode="user" 1114 fi 1115fi 1116 1117if [ -z "$mode" ] ; then 1118 if [ `whoami` = "root" ] ; then 1119 mode="system" 1120 else 1121 mode="user" 1122 fi 1123fi 1124 1125if [ -z "$filename" ] ; then 1126 exit_failure_syntax "mimetypes-file argument missing" 1127fi 1128 1129if [ "$vendor" = "true" -a "$action" = "install" ] ; then 1130 check_vendor_prefix "$filename" 1131fi 1132 1133xdg_base_dir= 1134xdg_dir_name=mime/packages/ 1135 1136xdg_user_dir="$XDG_DATA_HOME" 1137[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share" 1138[ x"$mode" = x"user" ] && xdg_base_dir="$xdg_user_dir/mime" 1139xdg_user_dir="$xdg_user_dir/$xdg_dir_name" 1140 1141xdg_system_dirs="$XDG_DATA_DIRS" 1142[ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/ 1143for x in `echo $xdg_system_dirs | sed 's/:/ /g'`; do 1144 if [ -w $x/$xdg_dir_name ] ; then 1145 [ x"$mode" = x"system" ] && xdg_base_dir="$x/mime" 1146 xdg_global_dir="$x/$xdg_dir_name" 1147 break 1148 fi 1149done 1150[ -w $xdg_global_dir ] || xdg_global_dir= 1151DEBUG 3 "xdg_user_dir: $xdg_user_dir" 1152DEBUG 3 "xdg_global_dir: $xdg_global_dir" 1153 1154# Find KDE3 mimelnk directory 1155kde_user_dir= 1156kde_global_dir= 1157kde_global_dirs=`kde${KDE_SESSION_VERSION}-config --path mime 2> /dev/null` 1158DEBUG 3 "kde_global_dirs: $kde_global_dirs" 1159first= 1160for x in `echo $kde_global_dirs | sed 's/:/ /g'` ; do 1161 if [ -z "$first" ] ; then 1162 first=false 1163 kde_user_dir="$x" 1164 elif [ -w $x ] ; then 1165 kde_global_dir="$x" 1166 fi 1167done 1168DEBUG 3 "kde_user_dir: $kde_user_dir" 1169DEBUG 3 "kde_global_dir: $kde_global_dir" 1170 1171# TODO: Gnome legacy support 1172# See http://forums.fedoraforum.org/showthread.php?t=26875 1173gnome_user_dir="$HOME/.gnome/apps" 1174gnome_global_dir=/usr/share/gnome/apps 1175[ -w $gnome_global_dir ] || gnome_global_dir= 1176DEBUG 3 "gnome_user_dir: $gnome_user_dir" 1177DEBUG 3 "gnome_global_dir: $gnome_global_dir" 1178 1179if [ x"$mode" = x"user" ] ; then 1180 xdg_dir="$xdg_user_dir" 1181 kde_dir="$kde_user_dir" 1182 gnome_dir="$gnome_user_dir" 1183 my_umask=077 1184else 1185 xdg_dir="$xdg_global_dir" 1186 kde_dir="$kde_global_dir" 1187 gnome_dir="$gnome_global_dir" 1188 my_umask=022 1189 if [ -z "${xdg_dir}${kde_dir}${gnome_dir}" ] ; then 1190 exit_failure_operation_impossible "No writable system mimetype directory found." 1191 fi 1192fi 1193 1194# echo "[xdg|$xdg_user_dir|$xdg_global_dir]" 1195# echo "[kde|$kde_user_dir|$kde_global_dir]" 1196# echo "[gnome|$gnome_user_dir|$gnome_global_dir]" 1197# echo "[using|$xdg_dir|$kde_dir|$gnome_dir]" 1198 1199basefile=`basename "$filename"` 1200#[ -z $vendor ] || basefile="$vendor-$basefile" 1201 1202mimetypes= 1203if [ -n "$kde_dir" ] ; then 1204 DEBUG 2 "KDE3 mimelnk directory found, extracting mimetypes from XML file" 1205 1206 mimetypes=`awk < "$filename" ' 1207# Strip XML comments 1208BEGIN { 1209 suppress=0 1210} 1211{ 1212 do 1213 if (suppress) { 1214 if (match($0,/-->/)) { 1215 $0=substr($0,RSTART+RLENGTH) 1216 suppress=0 1217 } 1218 else { 1219 break 1220 } 1221 } 1222 else { 1223 if (match($0,/<!--/)) { 1224 if (RSTART>1) print substr($0,0,RSTART) 1225 $0=substr($0,RSTART+RLENGTH) 1226 suppress=1 1227 } 1228 else { 1229 if ($0) print $0 1230 break 1231 } 1232 } 1233 while(1) 1234} 1235' | awk ' 1236# List MIME types listed in <mime-type> tags 1237BEGIN { 1238 RS="<" 1239} 1240/^mime-info/, /^\/mime-info/ { 1241 if (match($0,/^mime-type/)) { 1242 if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) { 1243 print substr($0,RSTART+6,RLENGTH-6) 1244 } 1245 } 1246}'` 1247fi 1248 1249DEBUG 1 "$action mimetype in $xdg_dir" 1250 1251case $action in 1252 install) 1253 save_umask=`umask` 1254 umask $my_umask 1255 1256 for x in $xdg_dir ; do 1257 mkdir -p $x 1258 eval 'cp $filename $x/$basefile'$xdg_redirect_output 1259 done 1260 1261 if [ -n "$mimetypes" ] ; then 1262 # No quotes around $mimetypes 1263 for x in $mimetypes ; do 1264 DEBUG 1 "Installing $kde_dir/$x.desktop (KDE 3.x support)" 1265 mkdir -p `dirname $kde_dir/$x.desktop` 1266 awk < "$filename" ' 1267# Strip XML comments 1268BEGIN { 1269 suppress=0 1270} 1271{ 1272 do 1273 if (suppress) { 1274 if (match($0,/-->/)) { 1275 $0=substr($0,RSTART+RLENGTH) 1276 suppress=0 1277 } 1278 else { 1279 break 1280 } 1281 } 1282 else { 1283 if (match($0,/<!--/)) { 1284 if (RSTART>1) print substr($0,0,RSTART) 1285 $0=substr($0,RSTART+RLENGTH) 1286 suppress=1 1287 } 1288 else { 1289 if ($0) print $0 1290 break 1291 } 1292 } 1293 while(1) 1294} 1295' | awk > $kde_dir/$x.desktop ' 1296# Extract mimetype $x from the XML file $filename 1297# Note that bash requires us to escape a single quote as '"'"' 1298BEGIN { 1299 the_type=ARGV[1] 1300 the_source=ARGV[2] 1301 ARGC=1 1302 RS="<" 1303 found=0 1304 glob_patterns="" 1305} 1306/^mime-info/, /^\/mime-info/ { 1307 if (match($0,/^mime-type/)) { 1308 if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) { 1309 if (substr($0,RSTART+6,RLENGTH-6) == the_type) { 1310 found=1 1311 print "[Desktop Entry]" 1312 print "# Installed by xdg-mime from " the_source 1313 print "Type=MimeType" 1314 print "MimeType=" the_type 1315 the_icon=the_type 1316 sub("/", "-", the_icon) 1317 print "Icon=" the_icon 1318 } 1319 } 1320 } 1321 else if (found) { 1322 if (match($0,/^\/mime-type/)) { 1323 if (glob_patterns) 1324 print "Patterns=" glob_patterns 1325 exit 0 1326 } 1327 1328 if (match($0,/^sub-class-of/)) { 1329 if (match($0,/type="[^"]*/) || match($0,/type='"'"'[^'"'"']*/)) { 1330 print "X-KDE-IsAlso=" substr($0,RSTART+6,RLENGTH-6) 1331 } 1332 else { 1333 print "Error: '"'"'type'"'"' argument missing in " RS $0 1334 exit 1 1335 } 1336 } 1337 if (match($0,/^glob/)) { 1338 if (match($0,/pattern="[^"]*/) || match($0,/pattern='"'"'[^'"'"']*/)) { 1339 glob_patterns = glob_patterns substr($0,RSTART+9,RLENGTH-9) ";" 1340 } 1341 else { 1342 print "Error: '"'"'pattern'"'"' argument missing in " RS $0 1343 exit 1 1344 } 1345 } 1346 if (match($0,/^comment/)) { 1347 if (match($0,/xml:lang="[^"]*/) || match($0,/xml:lang='"'"'[^'"'"']*/)) { 1348 lang=substr($0,RSTART+10,RLENGTH-10) 1349 } 1350 else { 1351 lang="" 1352 } 1353 if (match($0,/>/)) { 1354 comment=substr($0,RSTART+1) 1355 sub("<", "<", comment) 1356 sub(">", ">", comment) 1357 sub("&", "\\&", comment) 1358 if (lang) 1359 print "Comment[" lang "]=" comment 1360 else 1361 print "Comment=" comment 1362 } 1363 } 1364 } 1365} 1366END { 1367 if (!found) { 1368 print "Error: Mimetype '"'"'" the_type "'"'"' not found" 1369 exit 1 1370 } 1371} 1372' $x $basefile 1373 if [ "$?" = "1" ] ; then 1374 grep -A 10 "^Error:" $kde_dir/$x.desktop >&2 1375 rm $kde_dir/$x.desktop 1376 exit 1 1377 fi 1378 done 1379 fi 1380 1381 umask $save_umask 1382 ;; 1383 1384 uninstall) 1385 for x in $xdg_dir ; do 1386 rm -f $x/$basefile 1387 done 1388 1389 # No quotes around $mimetypes 1390 for x in $mimetypes ; do 1391 if grep '^# Installed by xdg-mime' $kde_dir/$x.desktop >/dev/null 2>&1; then 1392 DEBUG 1 "Removing $kde_dir/$x.desktop (KDE 3.x support)" 1393 rm -f $kde_dir/$x.desktop 1394 fi 1395 done 1396 ;; 1397esac 1398 1399update_mime_database $xdg_base_dir 1400 1401exit_success 1402 1403