#!/bin/bash
#
# File: /usr/local/bin/cpbydate
#
# copy files recursive they modified between to dates from a dir to another dir
#
#    Copyright (C) 2013 Ingo Kaesmann
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program 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.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# Script template: 0.3.0
#
# Exit codes:
# 0 = OK
# 1 = Error in parameters
# 3 = Library old or not found
##############################################################################
# SOURCE FILES

. /usr/local/etc/main-inka-sh.conf			# main config
. $LLIBDIR/lib-inka-std.sh				# functions standard
##############################################################################
# DECLARATION OF VARIABLES

# STRINGS
pkgname=inka-utilities					# package name
lib_inka_std_sh_needed=1.3.6				# standard lib version
#----------------------- end of variables to configure -----------------------
version=$(grep "^VERSION" $PROGREG/$pkgname.inf | cut -f 2)	# version
scriptname=$(basename $0)				# name of script
tempfile=$TEMPDIR/$scriptname.$UID.$$.tmp		# temporary file
infolog="logger -p user.info -t $scriptname --"		# log info messages
errlog="logger -p user.err -t $scriptname -- ERROR:"	# log error messages
debuglog="logger -p user.debug -t $scriptname -- DEBUG:" # log debug messages
debug=no						# debug=yes/no
verbose=""						# verbose=""/-q/-v
opt_found=no						# opt_found=yes/no
opt=""							# option
#------------------------- end of standard variables -------------------------
ls="/bin/ls $LS_OPTIONS"				# ls command

# NUMBERS
err=0							# exit code

##############################################################################
# FUNCTIONS

function show_help ()
{
# Show help
# Uses: cat
# Return codes: standard

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG show_help: $# $@" >&2
	#$debuglog show_help: $# $@
fi

cat <<EOT

Aufruf: $scriptname [OPTION]... DATUM-1 DATUM-2 QUELLE [ZIEL]
Alle Dateien aus QUELLE rekursiv anzeigen, die zwischen DATUM-1 und DATUM-2
modifiziert wurden, bzw. nach ZIEL kopieren

        -s      nur Anzeige der Dateien
-h, --help      Hilfe anzeigen und beenden
 --version      Versionsinformationen anzeigen und beenden
   --debug      Debug-Modus benutzen
        -q      ohne Meldungen

DATUM-1 (DATUM-2) Datum vor (nach) den modifizierten Dateien.
Datum im Format 31.01.2001
QUELLE und ZIEL sind Verzeichnisse. Zielverzeichnis mit absolutem Pfad!

EOT
return
}
#-----------------------------------------------------------------------------
function show_by_date ()
{
# Show files by date
# Parameters: DATE-1 DATE-2 (format: 31.01.2001) DIR-1
# Uses: cat, cd, cut, echo, ls, rm Read_Lines
# Return codes: standard

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG show_by_date: $# $@" >&2
	$debuglog show_by_date: $# $@
fi

local dirname filedate firstchar line day1 month1 year1 day2 month2 year2 fbytes lastline m n sbytes
dirname=""		# directory-name
filedate=""		# m-time of file
firstchar=""		# 1. character of line
line=""			# line of tempfile
day1=${1:0:2}		# day befor date
month1=${1:3:2}		# month befor date
year1=${1:6:4}		# year befor date
day2=${2:0:2}		# day after date
month2=${2:3:2}		# month after date
year2=${2:6:4}		# year after date
fbytes=0		# no of bytes of file
lastline=0		# number of lines of tempfile
m=0			# counter of files
n=0			# counter for loop
sbytes=0		# sumary of bytes

# show files and directories
cd $3
ls -AgGR --time-style=long-iso . > $tempfile		# build list of dirs
lastline=$(cat $tempfile | wc -l)
while [ "$n" -lt "$lastline" ]; do
	let n++
	line=$(Read_Lines $tempfile $n $n)
	firstchar=${line:0:1}
	if [ "$firstchar" == "." ]; then		# line is directory
		dirname=$(echo $line | cut -d ":" -f 1)
		echo "$line"				# show directory
	elif [ "$firstchar" == "-" ]; then		# line is file
		filedate=$(echo $line | cut -d " " -f 4)
		if [ "$filedate" \> "$year1-$month1-$day1" ] && [ "$filedate" \< "$year2-$month2-$day2" ]
			then				# filedate after date-1 and befor date-2
			$ls -AgG $dirname/$(echo $line | cut -d " " -f 6)	# show file
			let m++
			fbytes=$(echo $line | cut -d " " -f 3)
			sbytes=$[$sbytes+$fbytes]
		fi
	fi
done
echo "$m Dateien wurden nach dem $1 und vor dem $2 modifiziert."
echo "Die Datenmenge betraegt $sbytes Bytes."
rm -f $tempfile

return 0
}
#-----------------------------------------------------------------------------
function copy_by_date ()
{
# Copy files by date from dir-1 to dir-2
# Parameters: DATE-1 DATE-2 (date-format: 31.01.2001) DIR-1 DIR-2
# Uses: cat, cd, cp, cut, echo, ls, mkdir, rm, wc, Read_Lines
# Return codes: standard

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG copy_by_date: $# $@" >&2
	$debuglog copy_by_date: $# $@
fi

local dirname filedate filename firstchar line day1 month1 year1 day2 month2 year2 lastline n
dirname=""		# dirname
filedate=""		# m-time of file
filename=""		# filename
firstchar=""		# 1. character of line
line=""			# line of tempfile
day1=${1:0:2}		# day befor date
month1=${1:3:2}		# month befor date
year1=${1:6:4}		# year befor date
day2=${2:0:2}		# day after date
month2=${2:3:2}		# month after date
year2=${2:6:4}		# year after date
lastline=0		# number of lines of tempfile
n=0			# counter


# message
if [ "$verbose" == "-v" ]; then				# show verbose message
	echo "Es wird von $3 nach $4 kopiert:"
elif [ "$verbose" == "" ]; then				# show normal message
	echo "Bitte warten, kopiere Dateien..."
fi

# show files and copy them
cd $3
ls -AgGR --time-style=long-iso . > $tempfile		# build list of dirs
lastline=$(cat $tempfile | wc -l)
while [ "$n" -lt "$lastline" ]; do
	let n++
	line=$(Read_Lines $tempfile $n $n)
	firstchar=${line:0:1}
	if [ "$firstchar" == "." ]; then		# line is directory
		dirname=$(echo $line | cut -d ":" -f 1)
	elif [ "$firstchar" == "-" ]; then		# line is file
		filedate=$(echo $line | cut -d " " -f 4)
		if [ "$filedate" \> "$year1-$month1-$day1" ] && [ "$filedate" \< "$year2-$month2-$day2" ]
			then				# filedate after date-1 and befor date-2
			filename=$(echo $line | cut -d " " -f 6)
			if [ "$verbose" != "-q" ]; then	# show filename
				echo "$dirname/$filename"
			fi
			mkdir -p $4/$dirname		# make directory
			cp -p $dirname/$filename $4/$dirname/$filename	# copy file
		fi
	fi
done

rm -f $tempfile
return 0
}
##############################################################################
# PARSE COMMANDLINE

# Read all options with args and all additional args into variables.
# Stop parsing after last parameter.
# Try to do a check on all parameters and version numbers.
# Handle options -h, --show-config and --version directly.
# Exit on error.

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG Parse Commandline: $# $@" >&2
	#$debuglog Parse Commandline: $# $@
fi

# get options and options with arguments
while [ "${1:0:1}" == "-" ]; do				# get all options
	case "$1" in
	  -h|--help)	opt=-h;;			# option -h
	  --version)	opt=--v;; 			# option --version
#	  --show-config) opt=--s;;			# option --show-config
	  --debug)	debug=yes;;			# option --debug
	  -q|--quiet)	verbose=-q;;			# option -q
	  -v|--verbose)	verbose=-v;;			# option -v
#-------------------------- end of standard options --------------------------
	  -s)	opt="$1";;				# option -s
	  *)	if [ "$verbose" != "-q" ]; then
			echo "Fehler - Option $1 falsch!" >&2	# error
		else
			$errlog unknown option $1
		fi
		exit 1;;
	esac
	shift
	opt_found=yes
done

# handle standard options -h, --v, --s
case "$opt" in
  -h)	show_help; exit 0;;					# show help
  --v)	echo "$scriptname (${pkgname}) $version"; exit 0;;	# show version
#  --s)	show_config; exit 0;;					# show config
esac

# check library
Compare_Version $lib_inka_std_sh_needed $Lib_Inka_Std_Sh_Version
ret=$?						# (ret: 0,1,2,9,127)
if [ $ret -eq 1 ]; then				# needed lib-version higher than installed
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Programm benoetigt neuere Version von lib-inka-std.sh!" >&2
	else
		$errlog newer version of lib-inka-std.sh needed
	fi
	exit 3
elif [ $ret -eq 9 ] || [ $ret -eq 127 ]; then	# other error (version or lib missing)
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Versionspruefung von lib-inka-std.sh nicht moeglich!"
	else
		$errlog check of version of lib-inka-std.sh impossible
	fi
	exit 3
else						# check ok, reset $ret
	ret=0
fi

# check version of config files			# set config var!
#Compare_Version $conf_file_needed $Program_Conf
#Compare_Version $conf_file_needed $Program_Rc
ret=$?						# (ret: 0,1,2,9)
if [ $ret -eq 1 ]; then				# needed config-version higher than installed
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - $scriptname benoetigt neuere Version der Konfig-datei!" >&2
	else
		$errlog newer version of conf file needed
	fi
	exit 2
elif [ $ret -eq 9 ]; then			# other error (version of conffile missing)
	if [ "$verbose" != "-q" ]; then
		echo "Fehler - Versionspruefung der Konfig-datei von $scriptname nicht moeglich!"
	else
		$errlog check of version of conf file impossible
	fi
	exit 2
else						# check ok, reset $ret
	ret=0
fi

# check arguments after options
case "$opt" in
  -s|"")							# check dates
		if [ "${1:0:2}" \< "01" ] || [ "${2:0:2}" \< "01" ] ||
		[ "${1:0:2}" \> "31" ] || [ "${2:0:2}" \> "31" ] ||
		[ "${1:3:2}" \< "01" ] || [ "${2:3:2}" \< "01" ] ||
		[ "${1:3:2}" \> "12" ] || [ "${2:3:2}" \> "12" ] ||
		[ "${1:6:4}" \< "1900" ] || [ "${2:6:4}" \< "1900" ] ||
		[ "${1:6:4}" \> "2300" ] || [ "${2:6:4}" \> "2300" ] ||
		[ "${1:2:1}" != "." ] || [ "${2:2:1}" != "." ] ||
		[ "${1:5:1}" != "." ] || [ "${2:5:1}" != "." ] ||
		[ "${1:10:1}" != "" ] || [ "${2:10:1}" != "" ]; then
			if [ "$verbose" != "-q" ]; then		# date wrong
				echo "Fehler - Datum fehlt oder falsch angegeben!" >&2
			else
				$errlog date missing or wrong
			fi
			exit 1
# check opt is -s and it gives 3 pars, or opt is nothing and it gives 4 pars
		elif	( [ "$opt" == "-s" ] && [ "$#" != "3" ] ) ||
			( [ "$opt" == "" ] && [ "$#" != "4" ] ); then
				if [ "$verbose" != "-q" ]; then	# parcount wrong
					echo "Fehler - Parameteranzahl falsch!" >&2
				else
					$errlog parameter ount
				fi
				exit 1
# check it gives 3 pars and par3 is dir, or it gives 4 pars and par3 and par4 are dirs
		elif	( [ "$#" == "3" ] && ! [ -d "$3" ] ) ||
			( [ "$#" == "4" ] && ! ( [ -d "$3" ] || ! [ -d "$4" ] ) ); then
				if [ "$verbose" != "-q" ]; then	# no directory
					echo "Fehler - Kein Verzeichnis!" >&2
				else
					$errlog no directory
				fi
				exit 1
		else					# parameter ok
			arg1="$1"			# DATE-1
			arg2="$2"			# DATE-2
			arg3="$3"			# DIR-1
			arg4="$4"			# DIR-1
			shift 4
		fi;;

  *)	if [ "$#" -ne 0 ]; then				# error in param count
		if [ "$verbose" != "-q" ]; then
			echo "Fehler - Parameteranzahl falsch!" >&2
		else
			$errlog parameter count
		fi
		exit 1
	fi;;
esac
##############################################################################
# MAINPROGRAM

if [ "$debug" == "yes" ]; then				# debug
	echo "DEBUG Main: $# $@" >&2
	#$debuglog Main: $# $@
fi

# Check what to do (initial options and args are removed from cmdline)
case "$opt" in
  -s)							# opt -s
	show_by_date $arg1 $arg2 $arg3
	err=$?;;
  "")							# no opt given
	copy_by_date $arg1 $arg2 $arg3 $arg4
	err=$?;;
esac

exit $err
