#!/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