#!/usr/bin/env bash # # Mutt mailcap helper -- this program creates a hard link to the file # to be viewed prior to starting the viewer in the background. This # allows mutt to delete the temporary file without disturbing the # viewer. # # Syntax: mailcap_bg filename prog [args] # mailcap_test filename prog (determines if mailcap_bg can run) # # Copyright 2003 Aron Griffis # released under the GNU General Public License version 2 PS4="${0##*/}+ " exec 1>>~/mailcap_bg.log 2>&1 set -x # Setup global variables. need_wait=no fname=${1} ; shift prog=${1} ; shift declare -a args=("${@}") # Test only if called as mailcap_test if [[ $0 == *_test ]]; then # Note regarding mailcap %s usage in test= section: This will only # resolve to a value when there is a filename specified in the # attachment, for example # # Content-Type: application/x-msdownload; name="pack276.exe" # # Otherwise it will be blank. That is the reason for the # following rearrangement of variables. There is some further # explanation and discussion in .mailcap if [[ -z "$prog" ]]; then prog=$fname fname= fi # make sure the requested program exists type -P "$prog" &>/dev/null || exit 1 # need a local display for browsers, # and a (local or remote) display for everything else case "$prog" in *[Mm]oz*|*galeon*|run_browser) [[ $DISPLAY == :* ]] || exit 1 ;; display) [[ -n $DISPLAY ]] || exit 1 # Doesn't seem to work for some png files :-( # identify "${fname}" &>/dev/null || exit $? ;; *) [[ -n $DISPLAY ]] || exit 1 ;; esac # no other restrictions of which we're aware at this point exit 0 fi # Link the file so that mutt can delete the original. # Using a temp dir instead of a temp file preserves the original # extension. Note that fname should always be an absolute path. # # Mutt appears to zero out the file from the disk prior to deleting # it. That results in the hard link being zero'd before the browser # gets a chance to access it. For that reason we have to mv rather # than ln. tname=$(mktemp -d "${fname%/*}/mailcap_bg.XXXXXX") \ && mv -f "${fname}" "${tname}/${fname##*/}" \ && tname="${tname}/${fname##*/}" if [[ $? != 0 ]]; then # Can't background, unfortunately need_wait=yes tname=${fname} fi # Run the viewer in the background ( # replace @s if it exists in the viewer string if [[ "${args[*]}" == *@s* ]]; then args=("${args[@]//@s/$tname}") # Alternative method follows; do them one at a time #for ((i = 0; i < ${#args[@]}; i = i+1)); do # args[i] = "${args[i]//%s/$tname}" #done else args=("${args[@]}" "${tname}") fi # run the program "$prog" "${args[@]}" # delete the temp file when it's no longer in use. # this is important for mozilla, for example, which can return # immediately once it has signalled a running instance. # An hour is pretty arbitrary and arguably too low and high. if [[ $tname != $fname ]]; then while true; do sleep $((60*60)) # 1 hour [[ -f $tname ]] || break # no longer exists fuser "$tname" &>/dev/null && continue # still in use rm -f "$tname" rmdir "${tname%/*}" # tname is a file in a temporary directory break done & fi ) & # Only wait if we have to (couldn't hard link)... this could lead to # problems because of the 30-second pause [[ $need_wait == yes ]] && wait