#!/bin/zsh
#
# Undertaker, auxiliary command for Tomb
#
# Tomb is a tool to operate file encryption of private and secret data
#
# Undertaker is a tool to retrieve tomb keys from various sources
#
# {{{ Copyleft (C) 2012 Dyne.org foundation
#             2011-2012 Denis Roio <jaromil@dyne.org>
#
# This source  code is free  software; you can redistribute  it and/or
# modify it under the terms of  the GNU Public License as published by
# the Free  Software Foundation; either  version 3 of the  License, or
# (at your option) any later version.
#
# This source code is distributed in  the hope that it will be useful,
# but  WITHOUT ANY  WARRANTY;  without even  the  implied warranty  of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# Please refer to the GNU Public License for more details.
#
# You should have received a copy of the GNU Public License along with
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# }}}

# signal traps (special funcs in Zsh)
TRAPKILL() die "KILL signal caught, undertaker aborting."
TRAPSTOP() die "STOP signal caught, undertaker aborting."

# first of all source the tomb core functions
TOMBBIN=$(dirname $(readlink -f $0))/tomb 
if ! [[ -x $TOMBBIN ]]; then
    print "$fg[red][!]$fg[white] Tomb command not found, operation aborted." >&2; exit 1
fi
source $TOMBBIN ${tomb_opts[@]} source
TOMBEXEC=undertaker

key_found() {
    # $1 is "url"
    if option_is_set --batch; then
        print -n '[m]' >&2
    fi
    print "$fg[white][found] $1" >&2
}



function undertaker_scheme() {
    zparseopts -D -path=print_path

    local scheme
    scheme=$1
    local keypath
    keypath=$2
    case $scheme in


        bluetooth)
            #TODO: support --print-path
            act "access to bluetooth protocol requested"
            which obexftp &> /dev/null
            if [[ $? != 0 ]]; then
                _warning "obexftp not found, needed for bluetooth: operation aborted."
                return 64
            fi
            keytmp=`safe_dir undertaker`
            cd $keytmp
            # fetch key from bluetooth, url format: bluetooth://55:33:44:55:66/file/path
            obexdevpath=${keypath#*//}
            obexdev=${obexdevpath%%/*}
            obexpath=${obexdevpath#*/}
            act "obex device: $obexdev"
            act "obex path: $obexpath"
	    obexftp -b $obexdev -g $obexpath 
	    if [[ $? != 0 ]]; then
		rmdir ${keytmp}
		die "a problem occurred retreiving the key via bluetooth."
	    fi
	# print out the key on stdout
	    if option_is_set --path; then
		echo $obexpath
                # up to the caller to delete the key
		# TODO: --path should have the directory where to put the key
		# as argument, instead of creating keytmp
	    else
		cat `pwd`/$obexpath >&1
                # wipe out the key
		${WIPE[@]} $obexpath
		cd -
		rmdir ${keytmp}
	    fi
	    
        #	tombkey="basename $obexpath"
            ;;

        file)
            if ! [[ -f $keypath ]]; then
                _warning "Invalid path $keypath"
                return 1
            fi
            if option_is_set --path; then
                key_found $scheme://$keypath;
            else
                < $keypath
                r=$?
                if [[ $r != 0 ]]; then return 1; fi
                return 0
            fi
            ;;

        mounted)
            for mountpoint in `cut -f2 /etc/mtab -d ' ' | sort -u`; do
                undertaker_scheme ${print_path[@]} file ${mountpoint}/${keypath}
                ret=$?
                if [[ $ret == 0 ]]; then
                    return 0
                fi
            done
            ;;

        udisks)
            #It implements automounting using udisks; udisks is a (recently)
            #new technology, so we can't rely on it being present
            if ! which udisks &> /dev/null; then
                _warning 'udisks not found'
                exit 64
            fi
            while true; do
                device=`udisks --monitor|egrep '/sd[a-z][0-9]' -o -m1`
                device=/dev$device
                udisks --mount $device
                ###get mountpoint for device
                mountpoint=`egrep "^${device} " /etc/mtab|cut -d ' ' -f2`
                undertaker_scheme ${print_path[@]} file ${mountpoint}/${keypath}
                ret=$?
                udisks --unmount $device
                if [[ $ret == 0 ]]; then
                    return 0
                fi
            done
            ;;

        near)
            ###Given the path to the tomb, search the key near to that
            undertaker_scheme file ${keypath}.key
            ;;



        *)
            if ! which undertaker-$scheme &> /dev/null; then
                _warning "url protocol not recognized: $scheme"
                return 64
            fi
            undertaker-$scheme ${print_path[@]} ${scheme}://$keypath
            return $?
            ;;
    esac
}

function main() {
        typeset -A opts
        zparseopts -M -E -D -Aopts -poll -path -batch
        if ! [ $1 ] ; then
            print "[W] an argument is missing, the undertaker is confused" >&2
            print "usage: undertaker [options] url://host:path/to/tomb.key" >&2
            exit 1;
        fi
        local -a tomb_opts
        if [[ -n ${(k)opts[--batch]} ]]; then
            tomb_opts+='--no-color'
			tomb_opts+='--quiet'
        fi
        local -a under_opts
        if [[ -n ${(k)opts[--path]} ]]; then
            under_opts+='--path'
        fi
        local -A backupopts
        for a in ${(k)opts}; do
            backupopts[$a]=${opts[$a]}
        done
		source tomb ${tomb_opts[@]} source
		TOMBEXEC=undertaker
        for a in ${(k)backupopts}; do
            opts[$a]=${backupopts[$a]}
        done
        check_bin

        _success "Undertaker will look for $1"

        ARG1=${1}
        scheme=${ARG1%://*}
        keypath=${ARG1#*//}

        if [[ -n ${(k)opts[--poll]} ]]; then
            while true; do
                progress poll 0 search
                undertaker_scheme ${under_opts[@]} $scheme $keypath
                r=$?
                if [[ $r == 64 ]]; then
                    exit 64
                fi
                progress poll 100 done
                sleep 3
            done
        else
            undertaker_scheme ${under_opts[@]} $scheme $keypath
        fi
}
main $*

### Conventions and other comments:
# 
# EXIT CODES FOR SCHEME HANDLERS
# 0 is for everything went fine
# 64 is for "not supported/the problem won't be solved by polling". This is for things like: unmet dependencies, not supported at all, etc
# everything else means just "error". Use 1, please. So other codes can be used if needed
#