#!/bin/bash

# Trash
# - author: Steven A (stevenaaus@yahoo.com)
# - command line trash can (kde compatible)
# - freebsd port available at www.sourceforge.net/projects/filerenameutils

# TRASH is the directory
# EXCLUDE is a regexp of files that are never deleted from TRASH
# - add a dot-slash ( "./" ) to all filenames to make find happy
# - place a backslashed logical "or" ( "|" ) between filenames
# - and dots and or's should be prefixed by a backslash :(

####### start user configuration ###########

### uncomment one of the following
### or copy one into ~/.Trashrc

### KDE ### ( exclude "./.directory" and "." )
TRASH=${HOME}/Desktop/Trash
EXCLUDE="\./\.directory\|\."

### Gnome/other ###
# TRASH=${HOME}/.Trash
# EXCLUDE="\."

######### end user configuration ###########

function Usage () {
	echo 'usage:	Trash [--] FILE(s); trash files
	Trash [-l]        ; list contents of trashcan
	Trash -r FILE(s)  ; recover files
	Trash -e          ; empty trashcan
	Trash -t          ; tree - list using "tree" program'
}

function Error () {
	echo "$NAME: $*"
	exit 1
}

function IsEmpty () {
	[ -z "`find -maxdepth 1 -regex \"$EXCLUDE\" -o -print `" ]
	return $?
}

function Shuffle () {
	# we want to:   mv   $1.~$2~   $1.~(++$2)~
	local FROM="$1.~${2}~"
	local NEXTINDEX=$(($2 + 1))
	local TO="$1.~${NEXTINDEX}~"

	# recursively move it along , then move ourself
	if [ -e "$TO" -o -L "$TO" ] ; then
		Shuffle "$1" $NEXTINDEX
	fi
	mv -- "$FROM" "$TO"
}

########
# main #
########

NAME=`basename "$0"`
TEMP="/tmp/Trash.$$"

# if TRASH is not valid, try reading ".Trashrc"

[ ! -d "$TRASH" ] && source $HOME/.Trashrc &> /dev/null

# exit straight away if TRASH isn't a directory

if [ ! -d "$TRASH" ] ; then
	echo
	echo "$NAME: \"$TRASH\" no such directory."
	echo "Trash does not know where your trash-can is."
	echo "Type \"man Trash\" , or edit $0 directly."
	echo
	exit 1
fi

case "$1" in

	-t) if which tree &>/dev/null ; then
			tree $TRASH
		else
			Error "no program \"tree\" in path."
		fi ;;

	-r) shift
		[ "$1" == "" ] && Error "missing arg(s)"

		# recover a single file to the directory it came from (if applicable)
		# this works by simply cd-ing to "dirname" and then pretending it's 
		# just a normal Trash -r "basename"
		remote_dir=`dirname "$1"`
		if [ $# == 1 -a "$remote_dir" != "."  ] ; then
			cd  $remote_dir 2> /dev/null || \
				Error "Error restoring $1. 'cd $remote_dir' failed."
			set `basename "$1"`
			echo "$NAME: restoring $1 -> $remote_dir"
		fi

		# test the trash for files matching pattern/name $@
		cd $TRASH
		ls -1Qd -- $@ > $TEMP 2>/dev/null
		if [ -z "`cat $TEMP`" ] ; then
			Error "no such file(s) in trash"
		else
			cat $TEMP | xargs mv -i --target-directory="$OLDPWD" -- && echo Untrashed: `xargs <$TEMP`
		fi
		rm $TEMP
		;;

	-l | "")
		cd $TRASH

		IsEmpty && exit 0

		### list contents of trash
		# this does a null terminated "ls" which "xargs -0" can handle
		# listing all files except EXCLUDE ("-o" means or)
		find -maxdepth 1  -regex "$EXCLUDE" -o -printf "%f\000" | xargs -0 ls -d --color --
		# -printf "%f\000" is the same as "-print0" except the prepended "./" is removed
		echo --------------------

		# show summary
		printf "%i  %s,    " `find -regex "$EXCLUDE" -o -print | wc -l` "file(s)"
		du -sh | cut -f 1 ;;

	-e) if [ "$2" == "" ] ; then
			cd $TRASH
			IsEmpty && exit 0
			find -maxdepth 1  -regex "$EXCLUDE" -o -printf "%f\000" \
			| xargs -0 rm -r --
		else
			Error "unexpected arg(s)."
		fi ;;

	--?* | -[^-]* ) Usage ;; # matches "-*" and "--*" but not "--"

	* )	### previously was
		#   mv --backup=numbered --target-directory=$TRASH \
		#   -- "$@" && echo Trashed: "$@"
		# but couldn't backup directories

		[ "$1" == "--" ] && shift

		# if unique mv FILE -> $TRASH/FILE
		# else shuffle FILE -> $TRASH/FILE -> $TRASH/FILE.~1~
		#                   -> .......     -> $TRASH/FILE.~N~

		for j in "$@" ; do

			i=${j%/}    # bash trick to remove trailing slashes

			# test if the file exists (or is a link)
			if [ -e "$i" -o -L "$i" ] ; then

				BASENAME=$(basename "$i")
				DEST=$TRASH/$BASENAME
				INDEX=""
				FILENAME="$DEST"

				if [ -e "$FILENAME" -o -L "$FILENAME" ] ; then
					# handle the first case separately, but after that
					# shuffle along the bastards

					NEXT="$DEST.~1~"

					if  [ -e "$NEXT" -o -L "$NEXT" ] ; then
						cd $TRASH
						Shuffle "$BASENAME" 1
						cd "$OLDPWD"
					fi

					mv -- "$FILENAME" "$NEXT"
				fi

				if mv -- "$i" "$FILENAME" ; then
					echo "Trashed: $i"
				else
					# if not enough permissions will arrive here
					# mv will have already reported an error message
					echo -n ""
				fi
			else
				echo "'$i': no such file"
			fi
		done ;;
esac
