#!/bin/bash
# GNU Rot[t]log
# Copyright 2001, 2002, 2003, 2004, 2005 Stefano Falsetto <falsetto@gnu.org>
# Copyright 2008, 2009, 2010 David Egan Evans <sinuhe@gnu.org>
#
# This program is free software.  You can redistribute it, or modify it,
# or both, under the terms of the GNU General Public License version 3
# (or any later version) as published by the Free Software Foundation.
#
# 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, see <http://www.gnu.org/licenses>.
#

# Suppress C-c (SIGINT) during TEMPDIR generation
trap '' 2

VERSION="0.72"
MAINDIR="@MAINDIR"
STATDIR="@STATDIR"
BASE_TMP_DIR="/tmp/$(basename $0)"
MAINRC="$MAINDIR/rc"
DELAYED_FILES="$STATDIR/.delayed_logs"
LOCK="@LOCKFILE"
DATE_OFFSET=0
DEF_TABOO_EXT=".new .rpmorig .rpmsave ,v .swp .rpmnew ~"
DEBUG=

# Error codes
E_FILE_NOREAD=1
E_SYNTAX_ERROR=2
E_BAD_LOGPART=3
E_BAD_ENDSCRIPT=4
E_BAD_CREATE=5
E_BAD_ROTATE=6
E_BAD_PARAM=7
E_NO_STOREDIR=8
E_CANT_CREATE=9
E_NO_PAGER=10
E_CANT_UNCOMPRESS=11
E_BAD_SIZE=12
E_BAD_MAXDEPTH=13
E_FILE_NOFIND=14
E_NO_MAIL=15
E_NO_PACK=16
E_NO_PAGER=17
E_NO_STOREDIR=18
E_NO_STORENAME=19
E_NO_TOUSER=20
E_SYMLINK=21
E_BAD_ACTION=22
E_BAD_ENDACTION=23
E_BAD_ENDSCRIPT=24

E_BAD_SYNACTION=35
E_CANT_ROTATE=36
E_BAD_WILDCARD=37
E_BAD_COLL_PERIOD=38
E_BAD_PERIOD=39
E_CANT_COMPRESS=40
E_INVALID_GRP=41
E_INVALID_MODE=42
E_INVALID_OWN=43
E_NOT_IN_DELAY=44
E_BAD_COLLATE_PARAM=45
E_LOCKED=46
E_CANT_READ_OLD_LOGFILE=47
E_INVALID_OFFSET=48
E_BAD_DAY=49
E_BAD_FORCEDAY=50
E_NO_FILE_TO_COLLATE=51
E_NO_RCFILE=52
E_CONF_NOTFOUND=53
E_BAD_MAILOPT=54
E_CANT_WRITE=55
E_NO_CHMOD=56

E_BAD_PERIOD=100
E_INTERNAL=101
E_BAD_RANGE=102
E_BAD_TIME=103
E_BAD_DAY=104
E_BAD_OR=105

# Special values
BREAK_CYCLE=255

# Define functions
#

# See read_and_do
analyze_logpart () {
	# How many bytes must remain?
	qdldl="$1"
	local poschar=$[ ${#qdldl} - 1 ]
	local lastchar=$(echo "${qdldl:$poschar:1}"|tr 'a-z' 'A-Z')

	case "$lastchar" in
	L)
		# sono righe!
		righe=1
		bytes=0
		# elimino la 'L' finale
		qdldl=${qdldl:0:$poschar}
		debecho "analyze_logpart: Will keep last $qdldl rows"
		;;
	B)
		# sono bytes!
		righe=0
		bytes=1
		# elimino la 'B' finale
		qdldl=${qdldl:0:$poschar}
		debecho "analyze_logpart: Will keep last $qdldl bytes"
		;;
	\")
		#echo "E' una regexp!"
		# E' una regexp! (o gi di l...)
		# Elimino il primo e l'ultimo carattere, praticamente gli apici
		cr=${qdldl:1:$poschar-1}
		debecho "analyze_logpart: Here cr=$cr"
		if [ "$cr" = "#1 day" ]
		then
			# TODO: Add use of DATE_OFFSET???
			crit=$(LANG=en date "+%b")
			# Il primo del mese
			crit="$crit  1"
			debecho "analyze_logpart: Searching for $crit"
		else
			crit=$cr
		fi
		debecho "analyze_logpart: Will keep rows beginning from first occurence of $crit"
		bytes=0
		qdldl=0
		;;
	*)
		echo "Bad parameter!"
		debecho "analyze_logpart: bad lastchar=$lastchar"
		return 2
		;;
	esac
	debecho "analyze_logpart: Here bytes=$bytes, qdldl=$qdldl, righe=$righe, crit=$crit"
	return 0
}

# See mail_to_admin
attach_file() {
	if [ ! -z "$mailopt_zip" ]
	then
		echo
		echo "--1yeeQ81UyVL57Vl7"
		echo "Content-Type: application/x-tgz; name=\"$storefile\""
		echo "Content-Transfer-Encoding: base64"
		echo "Content-Disposition: attachment; filename=\"$storefile\""
		echo
		if [ "$1" = "rotate" ]
		then
			mimencode $ROTATE_ATTACH
		elif [ "$1" = "all" ]
		then
			mimencode $ALL_ATTACH
		fi
	else
		echo
		echo "--1yeeQ81UyVL57Vl7"
		echo "Content-Type: text/plain; charset=us-ascii"
		echo "Content-Disposition: attachment; filename=\"$storefile\""
		echo "Content-Transfer-Encoding: 8bit"
		echo
		if [ "$1" = "rotate" ]
		then
			cat $ROTATE_ATTACH
		elif [ "$1" = "all" ]
		then
			cat $ALL_ATTACH
		fi
	fi
}

banner() {
	echo "GNU Rot[t]log $VERSION"
	echo "Copyright 2005 Stefano Falsetto <falsetto@gnu.org>"
	echo "Copyright 2010 David Egan Evans <sinuhe@gnu.org>"
	if [ -z $1 ]
	then
		return
	fi
	echo "License: GPLv3+ <http://gnu.org/licenses/gpl.html>"
	echo "This is free software: you are free to change and redistribute it."
	echo "There is NO WARRANTY, to the extent permitted by law."
	echo
}

# See parse_period
checkitem () {
	if [ $(expr " $1 " : ".* $2 .*") -eq 0 ]
	then
		echo "Error in bound definition. Token: $2"
		USCITA=$E_BAD_RANGE
		exit $USCITA
	fi
}

check_last_rotate () {
	debecho "check_last_rotate: Checking for $3(ly) config file"
	if [ ! -f "$1" ]
	then
		debecho "check_last_rotate: Making new control file: $1"
		echo "0">"$1" 2>/dev/null
		if [ $? -ne 0 ]
		then
			echo "Can't write to $1"
			USCITA=$E_CANT_WRITE
			exit $USCITA
		fi
		chmod 600 "$1" 2>/dev/null
		if [ $? -ne 0 ]
		then
			echo "Can't change permission to file $1"
			USCITA=$E_NO_CHMOD
			exit $USCITA
		fi
	fi
	if [ -e "$1" ]
	then
		chmod 600 "$1"
		last="$(cat "$1")"
		#now="$(date +%s)"
		date_next="$(date --date "$date_refer +1 $3")"   # "+%d/%m/%Y")"
		debecho "check_last_rotate: Old date  : $last"
		debecho "check_last_rotate: New date  : $stamp_now"
		debecho "check_last_rotate: Next date : $date_next"
		DIFFDATA=$[ stamp_now - last ];
		if [ $DIFFDATA -ge $2 ]
		then
			debecho "check_last_rotate: $DIFFDATA >= $2"
			echo "$stamp_now">"$1"
			#echo "$date_next">"$1.next"
			return 1
		fi
	fi
	debecho "check_last_rotate: Rotation not needed: $DIFFDATA < $2"
	return 0
}

# See parse_period
check_mwd () {
	local p=$(echo $token|cut -d"$1" -f1)
	get_control_info date date_file
	get_control_info stamp stamp_file
	if [ $p -lt 1 ]
	then
		echo "$p is not a valid period!"
		USCITA=$E_BAD_PERIOD
		exit $USCITA
	fi
	case $1 in
	w)
		offset="weeks"
		;;
	M)
		offset="months"
		;;
	d)
		offset="days"
		;;
	*)
		echo "Internal Error in check_mwd"
		echo "parameter: $@"
		USCITA=$E_INTERNAL
		exit $USCITA
		;;
	esac
	# First time a log is handled must be rotated anyway
	if [ -z "$stamp_file" ]
	then
		stamp_file=$(date -d "$date_now $p $offset ago" "+%s")
		date_file=$(date -d "$date_now $p $offset ago" "+%m/%d/%Y %H:%M")
		update_stamp
	fi
	local check_p=$(date --date "$date_file $p $offset" "+%s")
	if [ -z "$NOT" ]
	then
		crit="$crit && [ $stamp_now -ge $check_p ]"
	else
		crit="$crit && [ $stamp_now -lt $check_p ]"
	fi
}

# See read_and_do
check_perms () {
	local tmpown
	local tmpgrp
	debecho "check_perms: Checking permissions..."
	if [ "$1" != "" ]
	then
		debecho "check_perms: Checking for mode $1..."
		if [ ${#1} -gt 4 ]
		then
			echo "Error analyzing $4 parameter"
			echo "Invalid mode: too long!"
			USCITA=$E_INVALID_MODE
			exit $USCITA
		fi
		if [ $(expr match "$1" "[01234567]*") -ne ${#1} ]
		then
			echo "Error analyzing $4 parameter"
			echo "Invalid mode!"
			USCITA=$E_INVALID_MODE
			exit $USCITA
		fi
	fi
	if [ "$2" != "" ]
	then
		debecho "check_perms: Checking for owner $2..."
		tmpvar=$(grep "^$2:" /etc/passwd 2>/dev/null|cut -d':' -f1)
		if [ -z "$tmpvar" ]
		then
			echo "Error analyzing $4 parameter"
			echo "Invalid owner! It doesn't exists in /etc/passwd."
			USCITA=$E_INVALID_OWN
			exit $USCITA
		fi
	fi
	tmpvar=
	if [ "$3" != "" ]
	then
		debecho "check_perms: Checking for group $3..."
		tmpvar=$(grep "^$3:" /etc/group 2>/dev/null)
		if [ -z "$tmpvar" ]
		then
			echo "Error analyzing $4 parameter"
			echo "Invalid group! It doesn't exists in /etc/group."
			USCITA=$E_INVALID_GRP
			exit $USCITA
		fi
	fi
}

# See Main
checkrc () {
	while [ $# -ne 0 ]
	do
		echo "==========================================================================="
		if [ "$1" = "main" ]
		then
			echo "Check for main configuration file done."
		elif [ ! -e $MAINDIR/$1 ]
		then
			echo "WARNING: $1 file doesn't exist!"
		else
			echo "Checking $1 configuration file..."
			quale=$1
			DISABLE_SCRIPT=1
			read_and_do /bin/true
			echo "Done."
		fi
		shift
	done
}

# See prepare_rotate
collate_logfiles () {
	local logname="$(basename $1)"
	local arch_file="$2"
	(
		source $TMPROTTCOLLECT.$logname
		expand_metavar "$COLLECT_LOG" "$COLLECT_ARCDIR"
		pcdpc="$expanded_metavars"

		# trick: special metavar-expansion
		COLLECT_ARCFIL="${COLLECT_ARCFIL//\@NEXT_EXT/*}"
		COLLECT_ARCFIL="${COLLECT_ARCFIL//\@FILENAME/@BASENAME.*}"
		expand_metavar "$pcdpc" "$COLLECT_ARCFIL"
		storefile="$pcdpc/$expanded_metavars"
		storefile=${storefile//\/\//\/}

		FILES=$(ls -1tr $storefile 2>/dev/null)
		if [ -z "$FILES" ]
		then
			if [ $nomissingok -eq 0 ]
			then
				debecho "collate_logfiles: No file to collate!"
				return
			else
				echo "Can't find file to collate!"
				USCITA=$E_NO_FILE_TO_COLLATE
				exit $USCITA
			fi
		fi

		#NFILES=$(echo "$FILES"|wc -l)
		#>$arch_file
		TOBEPACK="$(grep "^$1=.*" $DELAYED_FILES 2>/dev/null|cut -d'=' -f2-)"
		if [ -z "$TOBEPACK" ]
		then
			if [ ! -z "$COLLECT_DELAY" ]
			then
				echo "Delayed logfile is not in control file"
				USCITA=$E_NOT_IN_DELAY
				exit $USCITA
			else
				TOBEPACK=" "
			fi
		fi
		count=1

		case $COLLATE in
		tar)
			#Shipped in 0.30alpha. It works
			#debecho "Performing TARCOLLATE"
			#arch_file="$arch_file.tar.$extension"
			#tar c --use-compress-program $packer -f "$arch_file" $FILES
			#------------------------------
			debecho "collate_logfiles: Performing TARCOLLATE"
			MAKETREE=
			for f in $FILES
			do
				if [ -z "$MAKETREE" ]
				then
					MAKETREE="$TEMPDIR/tarcollect/$(dirname "$f")"
					debecho "collate_logfiles: Make tree=$MAKETREE"
					copy_tree $(dirname "$f") "$TEMPDIR/tarcollect/"
					#mkdir -p $MAKETREE
				fi
				if [ -z "$COLLECT_NOCOMPRESS" ]
				then
					cp -pf "$f" $MAKETREE
					debecho "collate_logfiles: Copied $f in $MAKETREE"
					continue
				fi
				#if [ ! -z "$COLLECT_DELAY" ] && \
				#   [ ! -z $(grep "^.*=$f" $DELAYED_FILES 2>/dev/null) ]
				#then
				if [ ! -z "$COLLECT_DELAY" ] && [ "$TOBEPACK" = "$f" ]
				then
					debecho "collate_logfiles: Compressing $f in $MAKETREE/$(basename "$f")"
					$packer $compress "$f" > $MAKETREE/$(basename "$f")
					eval "count_${COLLECT_QUALE}=$[ count_${COLLECT_QUALE} + 1 ]"
				else
					cp -pf "$f" $MAKETREE
					debecho "collate_logfiles: Copied $f in $MAKETREE"
					eval "count_${COLLECT_QUALE}=$[ count_${COLLECT_QUALE} + 1 ]"
				fi
			done
			arch_file="$arch_file.tar.$extension"
			OLD_PWD="$PWD"
			cd "$TEMPDIR/tarcollect"
			cd ${packdir:1} 2>/dev/null
			debecho "collate_logfiles: Now PWD=$PWD"
			#tar c --use-compress-program $packer -f "$arch_file" *
			# It's more portable:
			tar cf - *|$packer >"$arch_file"
			eval "count_$quale=$[ count_$quale + 1 ]"
			cd $OLD_PWD
			debecho "collate_logfiles: After tar and cd, PWD=$PWD"
			;;
		*)
			debecho "collate_logfiles: Performing COLLATE"
			for f in $FILES
			do
				#if [ ! -z "$COLLECT_DELAY" ] && \
				#   [ ! -z $(grep "^.*=$f" $DELAYED_FILES 2>/dev/null) ]
				#then
				if [ ! -z "$COLLECT_DELAY" ] && [ "$TOBEPACK" = "$f" ]
				then
					cat "$f" >>$TMP_ARCH_FILE
				elif [ -z "$COLLECT_NOCOMPRESS" ]
				then
					cp -p "$f" $TEMP_TARCOLL.$count.$extension
					$unpacker $uncompress "$TEMP_TARCOLL.$count.$extension" >>$TMP_ARCH_FILE
					eval "count_${COLLECT_QUALE}=$[ count_${COLLECT_QUALE} + 1 ]"
				else
					cat "$f" >>$TMP_ARCH_FILE
					eval "count_${COLLECT_QUALE}=$[ count_${COLLECT_QUALE} + 1 ]"
				fi
				count=$[ count + 1 ]
			done
			debecho "collate_logfiles: Compressing collection file..."
			$packer $compress "$TMP_ARCH_FILE">"$arch_file.$extension"
			if [ $? -ne 0 ]
			then
				echo "Error in compress collected files!"
				return $E_CANT_COMPRESS
			fi
			eval "count_$quale=$[ count_$quale + 1 ]"
			;;
		esac
		rm -f $TMPROTTCOLLECT.$logname
	)
}

# See read_and_do
collect_log_info () {
	local p=$2
	local find="$1"

	for find in ${pcldr[@]}
	do
		debecho "collect_log_info: Searching for matching logfile in ${pcldr[@]}"
		if [ "$find" = "$1" ]
		then
			debecho "collect_log_info: Found matching logfile $find"
			if [ -z "$ROTATE" ] || [ $ROTATE -ne $p ]
			then
				echo "Invalid rotate period for collate link."
				return $E_BAD_PERIOD
			fi
			local tmpf="$TMPROTTCOLLECT.$(basename $find)"
			make_storefile "$find"
			echo "COLLECT_LOG=$find" 				 >$tmpf
			echo "COLLECT_ARCDIR=$pcdpc" 			>>$tmpf
			if [ ! -z "$param_storefile" ]
			then
				echo "COLLECT_ARCFIL=$param_storefile" 		>>$tmpf
			else
				echo "COLLECT_ARCFIL=@BASENAME.@NEXT_EXT"	>>$tmpf
			fi
			echo "COLLECT_DELAY=$DELAY" 			>>$tmpf
			echo "COLLECT_NOCOMPRESS=$NOCOMPRESS" 		>>$tmpf
			echo "COLLECT_PERIOD=$p" 				>>$tmpf
			echo "COLLECT_QUALE=$3"				>>$tmpf
		fi
		return $BREAK_CYCLE
	done
}

cp_mod_own () {
	if [ -z "$follow_symlinks" ]
	then
		local lsdir=$(ls -ld "$1"|tr -s ' ')
	else
		local lsdir=$(ls -Ld "$1"|tr -s ' ')
	fi

	local perms=$(echo "$lsdir"|cut -d' ' -f1)
	local own=$(echo "$lsdir"|cut -d' ' -f3)
	local grp=$(echo "$lsdir"|cut -d' ' -f4)
	local count=0
	local SMODE=0
	local MODE=0
	local sub=
	local num=
	local NEWMODE=

	if [ -z "$own" ]
	then
		echo "Can't extract owner from filename!"
		USCITA=$E_FILE_NOREAD
		exit $USCITA
	fi

	if [ -z "$grp" ]
	then
		echo "Can't extract group from filename!"
		USCITA=$E_FILE_NOREAD
		exit $USCITA
	fi
	SMODE=0
	for num in 1 4 7
	do
		sub=${perms:$num:3}
		debecho "cp_mod_own: Group $grp=$sub"
		MODE=0
		sub=${sub//-/}
		debecho "cp_mod_own: Group $grp purged=$sub"
		count=0
		while [ $count -lt ${#sub} ]
		do
			debecho "cp_mod_own: Parsing ${sub:$count:1}"
			case "${sub:$count:1}" in
			r)
				MODE=$[ MODE + 4 ]
				;;
			w)
				MODE=$[ MODE + 2 ]
				;;
			x)
				MODE=$[ MODE + 1 ]
				;;
			s|S)
				if [ $num -eq 1 ]
				then
					SMODE=$[ SMODE + 4 ]
				else
					SMODE=$[ SMODE + 2 ]
				fi
				if [ "${sub:$count:1}" = "s" ]
				then
					MODE=$[ MODE + 1 ]
				fi
				;;
			t|T)
				SMODE=$[ SMODE + 1 ]
				if [ "${sub:$count:1}" = "t" ]
				then
					MODE=$[ MODE + 1 ]
				fi
				;;
			esac
			count=$[ count + 1 ]
		done
	NEWMODE="${NEWMODE}${MODE}"
	done

	NEWMODE="${SMODE}${NEWMODE}"
	debecho "cp_mod_own: Now new mode is: $NEWMODE"

	if [ ! -z "$2" ]
	then
		chown $own "$2" 2>/dev/null
		if [ $? -ne 0 ]
		then
			echo "Can't change owner for $2"
			USCITA=$E_INVALID_OWNER
			exit $USCITA
		fi
		chgrp $grp "$2" 2>/dev/null
		if [ $? -ne 0 ]
		then
			echo "Can't change group for $2"
			USCITA=$E_INVALID_GROUP
			exit $USCITA
		fi
		chmod $NEWMODE "$2" 2>/dev/null
		if [ $? -ne 0 ]
		then
			echo "Can't change permissions for $2"
			USCITA=$E_INVALID_MODE
			exit $USCITA
		fi
	else
		CHMOD="$NEWMODE"
		CHOWN="$own"
		CHGRP="$grp"
	fi
}

# See collate_logfiles
copy_tree () {
	local destd="$2"
	local lenb=0       # ${#2}
	local newd=

	# Remove all // in destd dir
	destd=${destd//\/\//\/}
	lenb=${#destd}

	if [ ${destd:$lenb-1} = "/" ]
	then
		lenb=$[ lenb - 1 ]
	fi

	mkdir -p "$destd/$1"
	dirs="$(find $destd -type d|tail +2)"
	debecho "copy_tree: dirs=$dirs"
	for d in $dirs
	do
		newd="${d:$lenb}"
		if [ -z "$newd" ]
		then
			continue
		fi
		cp_mod_own "$newd" "$d"
	done
}

debecho () {
	if [ ! -z "$DEBUG" ]
	then
		echo "$1" >&2
	fi
}

# See prepare_rotate
do_rotate() {
	local TRY_SIZE
	local dbl_qdl
	local partqdl

	debecho "Processing file $1"
	>$TMPERRMSG
	if [ ! -z "$notifempty" ] && [ "$size_b" -eq 0 ]
	then
		debecho "do_rotate: Archive/rotation not necessary"
		return 1
	fi

	# If $1 logfile must be handled with logpart, it must be
	# tailed from beginning (if needed)
	if [ ! -z "$bytes" ]
	then
		debecho "do_rotate: Check for first time a logpart log is handled"
		get_control_info size TRY_SIZE
		if [ -z "$TRY_SIZE" ]
		then
			debecho "do_rotate: This is the first time this log is handled"
			# Non  il posto giusto. Deve andare dopo: update_stamp
		else
			debecho "do_rotate: Second (or more) time this log is handled"
			debecho "do_rotate: cutting data (from beginning) already stored"
			# if I can, i will cut log from beginning
			dbl_qdl=[ $qdldl * 2 ]
			get_control_info partial partqdl
			# Sanity checks
			if [ $size_b -lt $TRY_SIZE ]
			then
				# errore: il file non pu essere di dimensioni inferiori alle
				# precedenti. Pu solo crescere
				echo "Size of logfile is inconsistent"
				USCITA=$E_BAD_SIZE
				exit $USCITA
			elif [ $size_b -lt $dbl_qdl ]
			then
				if [ ! -z "$notifempty" ]
				then
					# considero il file come vuoto
					debecho "do_rotate: logpart+notifempty sizeb<2*qdldl = do nothing"
					debecho "do_rotate: updating control file"
					update_stamp $size_b
					return 1
				fi
				if [ $bytes -ne 0 ]
				then
					debecho "do_rotate: tailing bytes from beginning"
					tail --bytes=+$partqdl $1 >$2
					size_b=$(ls -l "$1"|tr -s ' '|cut -d' ' -f5)
					update_stamp $size_b
				else
					# lascio righe o una regexp
					debecho "do_rotate: tailing rows from beginning"
					tail +$partqdl $1 >$2
					size_b=$(ls -l "$1"|tr -s ' '|cut -d' ' -f5)
					update_stamp $size_b
				fi 
			fi # end of sanity checks
		fi # end of if -z TRY_SIZE
	fi
	if [ ! -z "$DELAY" ]
	then
		IS_OLD=$(grep "$1" $DELAYED_FILES 2>/dev/null)
		if [ ! -z "$IS_OLD" ]
		then
			debecho "do_rotate: Compressing previously archived logfile"
			old_rotated=$(echo "$IS_OLD"|cut -d'=' -f2-)
			# sanity check
			if [ ! -r "$old_rotated" ]
			then
				if [ ! -z "$remove_missing" ]
				then
					(
					echo "Archived log is not readable."
					echo "Erasing from control files."
					) >>$TMPERRMSG
					remove_from_ctrlfile "$1"
					return 2
				 else
					echo "Archived log is not readable."
					USCITA=$E_CANT_READ_OLD_LOGFILE
					exit $USCITA
				fi
			fi
			debecho "do_rotate: executing cp -p $old_rotated $tmpfil"
			cp -p "$old_rotated" $tmpfil
			debecho "do_rotate: $packer $compress "$tmpfil" >"$old_rotated" 2>$TMPERR"
			$packer $compress "$tmpfil" >"$old_rotated" 2>$TMPERR
			if [ $? -ne 0 ]
			then
				(
					echo "Error in:"
					echo "$packer $compress \"$tmpfil\" \>\"$old_rotated\""
					echo
					cat $TMPERR
				) >> $TMPERRMSG
				return 2
			fi
			touch -r $tmpfil "$old_rotated"
			remove_from_ctrlfile "$1"
		fi
		debecho "do_rotate: Updating delayed files archive"
		echo "$1=$2" >>$DELAYED_FILES
		cp -p "$1" "$2"
		remove_maxage "$maxage"
	else
		# Comprime il file direttamente se non c' delaycompress
		debecho "do_rotate: Compressing logfile"
		$packer $compress "$1" >"$2" 2>$TMPERR
		remove_maxage "$maxage"
		if [ $? -ne 0 ]
		then
			(
			echo "Error in:"
			echo "$packer $compress \"$1\" \>\"$2\""
			echo
			cat $TMPERR
			) >> $TMPERRMSG
			return 2
		fi
	fi

	if [ -z "$bytes" ] && [ -z "$crit" ]
	then
		if [ -z "$NOCREATE" ]
		then
			debecho "do_rotate: creating new logfile"
			if [ ! -z "$create_logrotate" ]
			then
				cp_mod_own "$1"
			fi
			>$1
			if [ ! -z "$CHOWN" ]
			then
				debecho "do_rotate: Changing own and perms to logfile"
				chown $CHOWN $1
				chgrp $CHGRP $1
				chmod $CHMOD $1
			fi
		fi
		return
	fi

	debecho "do_rotate: Begin new logfile creation (using logpart)"
	cp -pf "$1" $tmpfil
	quanti=$(wc -l $tmpfil|tr -s ' '|cut -d' ' -f-2)

	# TODO: TAGLIARE DA SOTTO SE NECESSARIO, MA
	# TODO: SOPRATTUTTO AGGIORNARE CORRETTAMENTE IL FILE DI STAMP
	if [ -z "$bytes" ] || [ $bytes -eq 0 ]
	then
		# Leave last lines (if needed)
		if [ -z "$qdldl" ] || [ $qdldl -eq 0 ]
		then
			debecho "do_rotate: Keep logfile part beginning from regexp $crit"
			qdl=$(grep -n "$crit" $tmpfil|head -n 1|cut -d':' -f1)
			if [ -z "$qdl" ]
			then
				debecho "do_rotate: Couldn't find regexp in logfile"
				qdl=0
			fi
			qdldl=$[ quanti - qdl + 1 ]
		fi
		if [ $quanti -le $qdldl ]
		then
			debecho "do_rotate: Logfile tail is not necessary"
			return 1
		else
			debecho "do_rotate: Keep last $bytes lines of logfile"
			tail -n $qdldl $tmpfil > "$1"
			REALLY_FREED=$qdldl
			size_b=$(ls -l "$1"|tr -s ' '|cut -d' ' -f5)
			update_stamp $size_b
			return 1
		fi
	else
		# Leave last bytes (if needed)
		if [ $quanti -lt $qdldl ]
		then
			debecho "do_rotate: Logfile tail is not necessary"
			return
		else
			debecho "do_rotate: Keep last $bytes bytes of logfile"
			tail --bytes=$qdldl $tmpfil > "$1"
			size_b=$(ls -l "$1"|tr -s ' '|cut -d' ' -f5)
			update_stamp $size_b
		fi
	fi
}

# See read_and_do
expand_filenames () {
	# Filename expansion
	local index=0
	local addr=0
	debecho "expand_filenames: Begin filename expansion for $1"
	if [ $(expr index "$filenames" ",") -ne 0 ]
	then
		OLDIFS="$IFS"
		IFS=","
		for f in $filenames
		do
			is_quoted "$f"
			debecho "expand_filenames: Checking for wildcard in $f"
			is_wildcard "$f"
			if [ $? -eq 0 ]
			then
				debecho "expand_filenames: Normal fill of pcldr (commas)"
				is_readable "$f" "$1"
				if [ $? -eq 1 ]
				then
					run_lastaction
					continue
				fi
				pcldr[$index]="$f"
				index=$[ index + 1 ]
			else
				IFS="$OLDIFS"
				debecho "expand_filenames: Wildcard filling (commas)"
				for f in $wild_filenames
				do
					is_quoted "$f"
					is_taboo "$f"
					if [ $? -ne 1 ]
					then
						is_readable "$f" "$1"
						pcldr[$index]="$f"
						debecho "expand_filenames: Inserted file: ${pcldr[$index]}"
						index=$[ index + 1 ]
					fi 
				done
			fi
		done
		IFS="$OLDIFS"
	else
		is_quoted "$filenames"
		is_wildcard "$f"
		if [ $? -eq 0 ]
		then
			is_readable "$f" "$1"
			if [ $? -eq 1 ]
			then
				run_lastaction
				#continue
			fi
			debecho "expand_filenames: Normal fill of pcldr"
			pcldr[0]="$f"
		else
			for ff in $wild_filenames
			do
				is_quoted "$ff"
				is_readable "$ff" "$1"
				pcldr[$index]="$ff"
				debecho "expand_filenames: Wildcard filling"
				index=$[ index + 1 ]
			done
		fi
	fi
  
	# To know at what file must be run postrotate script
	if [ ! -z "$sharedscr" ]
	then
		addr=${#pcldr[@]}
		addr=$[ addr - 1 ]
		sharedscr="${pcldr[$addr]}"
		debecho "expand_filenames: Will run postrotate script after handling $sharedscr"
	fi
	debecho "expand_filenames: End of filename expansion"
}

expand_metavar() {
	# If used two parameters:
	# First parameter $1 is logfile to be rotated/archived (with path)
	# Second parameter is string to expand
	# All metavariables can be expanded
	#debecho "In expand_metavar:"
	local tmpstr=
	local tmpfname=

	debecho "expand_metavar: Filling date-related meta-variables with offset"
	year=$(date +%Y --date "$date_refer" --date "$DATE_OFFSET days")
	month=$(date +%m --date "$date_refer" --date "$DATE_OFFSET days")
	day=$(date +%d --date "$date_refer" --date "$DATE_OFFSET days")
	if [ $(echo "$SunMon"|tr A-Z a-z) = "sun" ]
	then
		week=$(date +%U --date "$date_refer" --date "$DATE_OFFSET days") # @WEEK (sun)
	else
		week=$(date +%W --date "$date_refer" --date "$DATE_OFFSET days") # @WEEK (mon)
	fi

	if [ "$variables_expanded" != "$1" ]
	then
		bname=$(basename "$1") # @BASENAME
		bdir=$(dirname "$1") # @DIRNAME

		if [ -z "$NO_EXTENSION" ]
		then
			comp_ext="$extension" # @COMP_EXT
		else
			comp_ext=""
		fi
		make_tmpdir meta_tmp_dir # @TEMPDIR
	else
		debecho "expand_metavar: META-VARIABLES already expanded for this logfile."
	fi

	# Substitute meta-variables with values:
	debecho "1=$1"
	debecho "2=$2"
	tmpstr="$2"
	debecho "expand_metavar: tmpstr before modify: $tmpstr"
	tmpstr=${tmpstr//\@BASENAME/$bname}
	tmpstr=${tmpstr//\@DIRNAME/$bdir}

	[ -z "$year_based" ] && tmpfname=${tmpstr//\@YEAR/????} || tmpfname=${tmpstr//\@YEAR/$year}
	[ -z "$month_based" ] && tmpfname=${tmpfname//\@MONTH/??} || tmpfname=${tmpfname//\@MONTH/$month}
	[ -z "$week_based" ] && tmpfname=${tmpfname//\@WEEK/??} || tmpfname=${tmpfname//\@WEEK/$week}
	[ -z "$day_based" ] && tmpfname=${tmpfname//\@DAY/??} || tmpfname=${tmpfname//\@DAY/$day}
	debecho "expand_metavar: now tmpfname=$tmpfname"

	tmpstr=${tmpstr//\@YEAR/$year}
	tmpstr=${tmpstr//\@MONTH/$month}
	tmpstr=${tmpstr//\@DAY/$day}

	# TODO: prima di espandere questa cerco in DELAYED_FILES
	# Babel Fish says: TODO: before expanding this I try in DELAYED_FILES
	tmpstr=${tmpstr//\@COMP_EXT/$comp_ext}
	tmpstr=${tmpstr//\@TEMPDIR/$meta_tmp_dir}
	tmpstr=${tmpstr//\@WEEK/$week}

	case "$tmpstr" in
	*\@[1-9]*)
		make_metapos "$log"
		n=10
		while [ $n -le ${#meta_pos[@]} ]
		do
			j=$[ n - 1 ]
			mp=${meta_pos[j]}
			tmpstr=${tmpstr//\@$n/$mp}
			n=$[ n + 1 ]
		done
		n=1
		while [ $n -le ${#meta_pos[@]} ] && [ $n -le 9 ]
		do
			j=$[ n - 1 ]
			mp=${meta_pos[j]}
			tmpstr=${tmpstr//\@$n/$mp}
			n=$[ n + 1 ]
		done
		;;
	esac

	# Only if path and filename is already expanded may these two
	# metavariables be sustituted.
	if [ $(expr index "$pcdpc" "\@") -eq 0 ]
	then
		case "$tmpstr" in
		*\@DEF_DIR*)
			def_path="$pcdpc"
			tmpstr=${tmpstr//\@DEF_DIR/$pcdpc}
			;;
		esac
		case "$tmpstr" in
		*\@NEXT_EXT*|*\@FILENAME*)
			tmpfname=${tmpfname//\@NEXT_EXT/*}
			tmpfname=${tmpfname//\@FILENAME/$bname.*}
			lastnum "$pcdpc/$tmpfname" 1
			next_ext=$?
			tmpstr=${tmpstr//\@NEXT_EXT/$next_ext}
			filename="$bname.$next_ext"
			tmpstr=${tmpstr//\@FILENAME/$filename}
			;;
		esac
	fi

	variables_expanded="$1"
	debecho "expand_metavar: tmpstr after all modifies: $tmpstr"
	expanded_metavars="$tmpstr"
}

# See Main
fill_timevar () {
	debecho "fill_timevar: filling time-related variables"
	local string_date=$(LANG=en date -d "$1" \
	                  "+%s %m %d %Y %H %M %a %b %A %B"| tr A-Z a-z)
	set -- $string_date
	stamp_now=$1
	today=$3
	date_now="$2/$3/$4 $5:$6"
	now_hour=$5
	now_min=$6
	name_today=$7
	name_month=$8
	long_name_today=$9
	long_name_month=${10}
	ldom=$(cal |tail -n 2|head -n 1|rev|cut -d' ' -f1|rev)
}

# See summarize_loginfo
findlog () {
	local log=
	local q=
	case $quale in
	monthly)
		q=month
		ADD=2592000
		;;
	daily)
		q=day
		ADD=86400
		;;
	weekly)
		q=week
		ADD=604800
		;;
	custom)
		#TODO: Show correct information if logfile is in custom
		q=custom
		#ADD=$PERIOD
		;;
	esac
	debecho "findlog: q=$q +++ ADD=$ADD"
	debecho "findlog: Here pcldr=${pcldr[@]}"
	for log in ${pcldr[@]}
	do
		if [ "$(basename $log)" = "$1" ]
		then
			echo
			echo "Summary of logfile: $(basename $log)"
			echo
			echo "Full path : $log"
			echo "Store dir : $pcdpc"
			#local now=$(date +%s)
			if [ ! -z "$ADD" ]
			then
				debecho "findlog: Here ADD=$ADD, stamp_now=$stamp_now"
				local last=$(cat "$STATDIR/.last$q" 2>/dev/null)
				# Sanity check!
				if [ $last -lt $ADD ]
				then
					local daydone=0
					local datedone=$(date "+%a %x")
					local daytodo=$[ ADD / 86400 ]
					local datetodo=$(date --date "++$daytodo days" "+%a %x")
				else
					local next=$[ last + ADD ]
					local secsdone=$[ stamp_now - last ]
					local secstodo=$[ next - stamp_now ]
					local daydone=$[ secsdone / 86400 ]
					local daytodo=$[ secstodo / 86400 + 1 ]
					local datedone=$( date --date "$daydone days ago" "+%a %x")
					local datetodo=$( date --date "++$daytodo days" "+%a %x")
				fi
			else
				#local datedone=$(cat "$STATDIR/.${log//\//_}.rtt"|grep "^date:"|cut -d':' -f2-)
				#local secsdone=$(cat "$STATDIR/.${log//\//_}.rtt"|grep "^stamp:"|cut -d':' -f2)
				local datedone=
				local secsdone=
				get_control_info date datedone
				get_control_info stamp secsdone
				secsdone=$[ stamp_now - secsdone ]
				local daydone=$[ secsdone / 86400 ]
				local datetodo="$PERIOD"
				local daytodo=
			fi
			if [ ! -z "$daytodo" ] && [ "$daytodo" -lt 0 ]
			then
				[ -z "$ROTATE" ] && cosa="archive" || cosa="rotate"
				printf "\n           WARNING: This file must be ${cosa}d as soon as possible!\n\n"
			fi
			echo "Interval  : $quale"
			[ ! -z "$NOCOMPRESS" ] && local textnot="yes" || local textnot="no"
			echo "Compress  : $textnot"
			[ ! -z "$notifempty" ] && textnot="yes" || textnot="no"
			echo "If empty  : $textnot"
			[ ! -z "$rotate" ] && textnot="$ROTATE" || textnot="no"
			echo "Rotate    : $textnot"
			[ $nomissingok -eq 0 ] && textnot="yes" || textnot="no"
			echo "Missingok : $textnot"
			[ ! -z "$createdir" ] \
			&& textnot="mode: $dir_perm, own.grp: $dir_own.$dir_grp" \
			|| textnot="no"
			echo "Createdir : $textnot"
			[ ! -z "$nomail" ] && textnot="no" || textnot="yes"
			echo "Mail admin: $textnot"
			[ -z "$ADD" ] && echo "Period    : $PERIOD"
			echo
			if [ ! -z "$ADD" ]
			then
				printf "Days since last rotation : %2d (%s)\n" $daydone "$datedone"
				printf "Days until next rotation  : %2d (%s)\n" $daytodo "$datetodo"
			else
				printf "Days since last rotation : %2d (%s)\n" $daydone "$datedone"
			fi
			if [ ! -z "$DELAY" ]
			then
				echo
				notcomp=$(grep "$1" $DELAYED_FILES 2>/dev/null|cut -d'=' -f2-)
				echo "Not compressed log: $notcomp"
			fi
			echo
			return $BREAK_CYCLE
		fi
	done
}

get_control_info () {
	local NameOfCtrlFile="$STATDIR/.${log//\//_}.rtt"
	case "$1" in
	date|stamp|size|partial)
		eval "$2=\"$(cat $NameOfCtrlFile 2>/dev/null|grep \
		"^$1:"| cut -d':' -f2-)\""
		;;
	*)
		echo "Internal error in get_control_info call"
		echo "parameters: $@"
		USCITA=$E_INTERNAL
		exit $USCITA
	esac
}

# See mail_to_admin
header_mail() {
	echo "From: $fromuser"
	echo "To: $touser"
	if [ -z "$1" ]
	then
		echo "Subject: GNU Rot[t]log $quale maintenance"
	elif [ "$1" = "err" ]
	then
		echo "Subject: GNU Rot[t]log $quale maintenance: ERROR report"
	elif [ "$1" = "stat" ]
	then
		echo "Subject: GNU Rot[t]log $quale maintenance: statistical report"
	elif [ "$1" = "over" ]
	then
		echo "Subject: GNU Rot[t]log $quale maintenance: overwriting logfile"
		echo "Mime-Version: 1.0"
		echo "Content-Type: multipart/mixed; boundary=\"1yeeQ81UyVL57Vl7\""
		echo "Content-Disposition: inline"
		echo "Content-Transfer-Encoding: 8bit"
		echo "Content-Length: $size_b"
		echo 
		echo 
		echo "--1yeeQ81UyVL57Vl7"
		echo "Content-Type: text/plain; charset=us-ascii"
		echo "Content-Disposition: inline"
	elif [ "$1" = "all" ]
	then
		echo "Subject: GNU Rot[t]log $quale maintenance: attaching handled logfile"
		echo "Mime-Version: 1.0"
		echo "Content-Type: multipart/mixed; boundary=\"1yeeQ81UyVL57Vl7\""
		echo "Content-Disposition: inline"
		echo "Content-Transfer-Encoding: 8bit"
		echo "Content-Length: $size_b"
		echo 
		echo 
		echo "--1yeeQ81UyVL57Vl7"
		echo "Content-Type: text/plain; charset=us-ascii"
		echo "Content-Disposition: inline"
	fi
	echo
}

# See expand_filenames
is_readable() {
	debecho "is_readable: Checking for $1"
	if [ ! -r "$1" ]
	then
		debecho "is_readable: nomissingok=$nomissingok"
		if [ "$nomissingok" -ne 0 ] && [ "$2" != "log" ]
		then
			debecho "Missing? OK!"
			return 1
		else
			echo "ERROR: Couldn't read $2 file!"
			echo "Filename: $1"
			USCITA=$E_FILE_NOREAD
			exit $USCITA
		fi
	fi
	if [ -L "$1" ] && [ $follow_symlinks -eq 0 ]
	then
		echo "Can't follow symbolic links!"
		echo "Filename: $1"
		USCITA=$E_SYMLINK
		exit $USCITA
	fi
}

# See expand_filenames
is_taboo() {
	local taboo
	local tt
	local extf
	for taboo in $TABOO_EXT
	do
		debecho "Checking if $1 ends with taboo extension $taboo"
		#if [ $(basename "$1" $taboo) != "$1" ]
		#then
		# Speed up:
		if [ "${1%$taboo}" != "$1" ]
		then
			debecho "File $1 has a taboo extension!"
			return 1
		fi
	done
	return 0
}

# See expand_filenames
is_quoted() {
	if [ $(expr index "$1" "\"" ) -eq 0 ]
	then
		f=${1// /}
	else
		f=${1//\"/}
	fi
}

# See expand_filenames
is_wildcard() {
	local filna="$1"

	filna=${filna//\\\\[/}
	filna=${filna//\\\\]/}
	filna=${filna//\\\\{/}
	filna=${filna//\\\}/}
	filna=${filna//\\\\?/}
	filna=${filna//\\\\\\*}

	case "$filna" in
	*\]*|*\[*|*\{*|*\}*|*\?*)
		echo "Only * wildcard can be used!"
		USCITA=$E_BAD_WILDCARD
		exit $USCITA
		;;
	esac

	if [ $(expr index "$filna" "\*" ) -eq 0 ]
	then
		debecho "is_wildcard: No wildcard in this filename"
		return 0
	else
		if [ $follow_symlinks -eq 0 ]
		then
			wild_filenames=$(find $filna -maxdepth $MAXDEPTH -type f 2>/dev/null)
		else
			wild_filenames=$(find $filna -maxdepth $MAXDEPTH -type f -o -type l 2>/dev/null)
		fi
		debecho "is_wildcard: Found * in filename. Follows found files:"
		debecho "is_wildcard: $wild_filenames"
		return 1
	fi
}

# See make_storefile and expand_metavar
lastnum () {
	[ -z "$2" ] && local add=0 || local add=$2
	local crit=$1
	debecho "lastnum: Adding number: $add"
	debecho "lastnum: Counting how many files respect $1 criteria"
	local ext_file=$(ls -1v $1 2>/dev/null|wc -l)
	debecho "lastnum: In storedir there are $ext_file files respecting criteria"
 
	#if [ $ext_file -eq 0 ]
	#then
	#	local lastnum=$add # was 1
	#	#[ -z "$START_ROTATE" ] && ext_file=$add \
	#	#|| ext_file=$START_ROTATE
	#	[ -z "$START_ROTATE" ] && lastnum=$add || lastnum=$START_ROTATE
	#else
	#	local lastnum=$[ ext_file + add ]
	#fi   

	if [ -z "$START_ROTATE" ]
	then
		local lastnum=$[ ext_file + add ]
	else
		local lastnum=$[ ext_file + add + $START_ROTATE - 1 ]
	fi

	rotate_overwrite=

	if [ ! -z "$ROTATE" ] && [ ! -z "$log_rotate" ]
	then
		rotate_logrotate "$crit"
		rotate_overwrite=1
		lastnum=$START_ROTATE	#1
		debecho "lastnum: Now log_rotate lastnum is $lastnum"
	elif [ ! -z "$ROTATE" ] && [ $lastnum -gt "$ROTATE" ]
	then
		debecho "lastnum: Rotate Numbering"
		startp=$(expr index "$crit" \*)
		if [ $startp -ne "${#crit}" ]
		then
			#startp=$[ startp + 1 ]
			endchar=${1:startp:1}
			if [ ! -z "$maxage" ]
			then
				#Can't use find!
				#find -mtime +$maxage $1 >$TMP_ROTTMAXAGE
				ls -1t $1 >$TMP_ROTTMAXAGE 2>/dev/null
			fi
			if [ ! -z "$DELAY" ]
			then
				lastnum=$(ls -1t $1|tail -n 2|head -n 1|cut -b $startp-)
			else
				lastnum=$(ls -1t $1|tail -n 1|cut -b $startp-)
			fi
			if [ ! -z "$endchar" ]
			then
				lastnum=${lastnum//$endchar*/}
			fi
			if [ "$lastnum" = "" ]
			then
				lastnum=$START_ROTATE	#1
			fi
		else
			lastnum=$(ls -1t $1 |tail -n 1|rev|cut -d'.' -f1|rev)
		fi
		rotate_overwrite=1
		debecho "lastnum: Now rotate number is $lastnum"
	fi
	debecho "lastnum: returning $lastnum"
	return $lastnum
}

# See mail_to_admin
mail_err() {
cat <<EOF
Details of $quale log rotation NOT performed

File to $1           : $log
Name of ${1}d file   : $storefile

$( cat $TMPERRMSG )

EOF
}

# See mail_to_admin
mail_norm() {
	echo "Details of $quale log rotation performed:"
	echo 
	echo 
	local lenpack=${#packdir}
	echo "File to $1         : $log"
	if [ $(expr "$storefile" : "$packdir*") -eq $lenpack ]
	then
		echo "Main store dir         : $packdir"
		local short_storefile=${storefile:lenpack+1}
	else
		local short_storefile="$storefile"
	fi
	echo "File ${1}d in        : $short_storefile"
	if [ ! -z "$qdldl" ]
	then
		echo "Old filesize          : $size_b"
		echo "New filesize          : $size_a"
	fi
	echo "Log $2 begin on  : $date_begin"
	echo "Completed on           : $date_end"
	if [ ! -z "$DELAY"  -a "$quale" != "custom" ]
	then
		echo "Will be compressed on   : $date_next (approximatively)" 
	fi
	echo
	if [ "$quale" != "custom" ]
	then
		echo "Next rotation will be performed approximatively on $date_next." 
	fi
	if [ -e $ROTATE_ATTACH ] && [ ! -z "$mailopt_over" ]
	then
		echo "Attaching overwrited logfile."
	fi
	if [ -e $ALL_ATTACH ] && [ ! -z "$mailopt_all" ]
	then
		echo "Attaching handled logfile."
	fi
}

# See mail_to_admin
mail_stat() {
	source $TMP_STATFILE
	local end_refer=$(date "+%m/%d/%Y %H:%M:%S")
	local date_end=$(date -d "$end_refer" "+%s")
	local diff_s=$[ date_end - stamp_now ]
	local diff_h=$(expr $diff_s / 3600)
	local start_d=$(date -d "$date_refer" "+%d/%m/%Y %H:%M:%S")
	local end_d=$(date -d "$end_refer" "+%d/%m/%Y %H:%M:%S")
	if [ $diff_h -ne 0 ]
	then
		local diff_rest=$(expr $diff_s % 3600)
		local diff_m=$(expr $diff_rest / 60)
		local diff_s=$(expr $diff_rest % 60)
	else
		local diff_m=$(expr $diff_s / 60)
		local diff_s=$(expr $diff_s % 60)
	fi
	local diff_time=$(printf "%02d:%02d:%02d" "$diff_h" "$diff_m" "$diff_s")
	local totalf=0
	local bytes_freed=0
	for f in custom daily weekly monthly
	do
		eval totalf=$[ totalf + count_$f ]
		eval bytes_freed=$[ bytes_freed + freed_$f ]
	done
cat <<EOF
GNU Rot[t]log Statistics Report

Disk-related statistics:
=======================

Total custom rotated logfiles               : $count_custom
Total daily rotated logfiles                : $count_daily
Total weekly rotated logfiles               : $count_weekly
Total monthly rotated logfiles              : $count_monthly
------------------------------------------------------------
   Total number of logs handled             : $totalf

Total bytes freed handling custom logfiles  : $freed_custom
Total bytes freed handling daily logfiles   : $freed_daily
Total bytes freed handling weekly logfiles  : $freed_weekly
Total bytes freed handling monthly logfiles : $freed_monthly
------------------------------------------------------------
   Total bytes freed                        : $bytes_freed

Time-related statistics:
=======================

Start time                                  : $start_d
End time                                    : $end_d
------------------------------------------------------------
Total execution time                        : $diff_time

EOF
}

mail_to_admin() {
	(
		trap 'debecho "mail_to_admin: Erasing temporary files"; rm -f $MAILMSG $ROTATE_ATTACH $ALL_ATTACH' 0

		if [ "$1" = "stat" ]
		then
			debecho "mail_to_admin: making stat mail"
			header_mail stat	 >$MAILMSG
			mail_stat   	>>$MAILMSG
			signature   	>>$MAILMSG
			cat $MAILMSG|$mail
			debecho "mail_to_admin: Sent stats mail from $fromuser to $touser"
			return
		fi
		if [ ! -z "$qdldl" ]
		then
			local size_a=$(ls -l "$storefile" 2>/dev/null|tr -s ' '|cut -d' ' -f5)
		else
			local size_a=0
		fi
		if [ $RET_DO_ROTATE -eq 0 ]
		then
			local diffbytes=$[ size_b - size_a ]
		else
			[ -z "$REALLY_FREED" ] && local diffbytes=0 \
			|| diffbytes=$REALLY_FREED
		fi
		if [ ! -z $bytes_freed ]
		then 
			bytes_freed=$[  bytes_freed + diffbytes ]
		else
			bytes_freed=diffbytes
		fi
		eval freed_$quale=$[ freed_$quale + diffbytes ]
		update_stats $quale freed
		if [ ! -z "$ROTATE" ]
		then
			local cosa="rotate"
			local cosing="rotating"
		else
			local cosa="archive"
			local cosing="archiving"
		fi
		if [ -s "$TMPERRMSG" ] && [ ! -z $mailopt_err ]
		then
			header_mail err 	>$MAILMSG
			mail_err $cosa	>>$MAILMSG
			signature		>>$MAILMSG
			cat $MAILMSG|$mail
			return
		fi
		if [ ! -s "$TMPERRMSG" ]
		then
			debecho "mail_to_admin: here ROTATE_ATTACH=$ROTATE_ATTACH"
			debecho "mail_to_admin: here mailopt_over=$mailopt_over"
			if [ -e $ROTATE_ATTACH ] && [ ! -z "$mailopt_over" ]
			then
				debecho "mail_to_admin: Making attach e-mail message (over)"
				header_mail over		>$MAILMSG
				mail_norm	$cosa $cosing	>>$MAILMSG
				signature			>>$MAILMSG
				attach_file rotate	>>$MAILMSG
			elif [ -e $ALL_ATTACH ] && [ ! -z "$mailopt_all" ]
			then
				debecho "mail_to_admin: Making attach e-mail message (all)"
				header_mail all           >$MAILMSG
				mail_norm $cosa $cosing   >>$MAILMSG
				signature                 >>$MAILMSG
				attach_file all           >>$MAILMSG
			else
				debecho "mail_to_admin: Making standard e-mail message"
				header_mail		>$MAILMSG
				mail_norm	$cosa $cosing	>>$MAILMSG
				signature			>>$MAILMSG
			fi
			cat $MAILMSG|$mail
			debecho "mail_to_admin: Sent mail from $fromuser to $touser"
			return
		fi
	)
}

# See expand_metavar
make_metapos() {
	local path="$1"
	local startt=0
	local endt=0
	local countt=0
	local pos=0
	while [ $startt -lt ${#path} ]
	do
		if [ "${path:startt:1}" = "/" ]
		then
			startt=$[ startt + 1 ]
		fi
		endt=$startt
		while [ $endt -lt ${#path} ] && [ "${path:endt:1}" != "/" ]
		do
			endt=$[ endt + 1 ]
			countt=$[ countt + 1 ]
		done
		endt=$[ endt -  1 ]
		meta_pos[$pos]="${path:startt:countt}"
		pos=$[ pos + 1 ]
		startt=$[ endt + 1 ]
		countt=0
	done
}

# See expand_metavar and Main
make_tmpdir () {
	# Following code was taken from (with changes):
	# checkinstall v1.4.1 (c) Felipe Eduardo Sanchez Diaz Duran

	# Find a safe TEMPDIR
	[ ! -d $BASE_TMP_DIR ] && mkdir -p $BASE_TMP_DIR

	local tmpd=${BASE_TMP_DIR}/`awk 'BEGIN { srand(); for (i=1;i<21;i++) { a=95; while (a > 90 && a < 97) { a=65+int(50*rand())}; printf("%c", a) } }'`
	[ -e "$tmpd" ] && rm -rf "$tmpd"
	if [ -e "$tmpd" ]
	then
		echo
		echo "Aborting: A temporary directory exists already."
		echo
		exit 1
	fi

	mkdir $tmpd
	chmod 1700 $tmpd
	RETURN=$?

	if [ $RETURN -gt 0 ]
	then
		echo
		echo "Failed to create ${BASE_TMP_DIR}!"
		echo
		exit  $RETURN
	fi

	# Ignore these signals, but not critical.
	trap '' 1 2 5 6

	if [ -z "$1" ]
	then
		TEMPDIR="$tmpd"
		tmpfil=$TEMPDIR/rotttempfile.$$
		NEWtmpFILE=$TEMPDIR/rottnewtmpfile.$$
		PURGED_FILE=$TEMPDIR/rottpurgedfile.$$
		IFINCLUDE_FILE=$TEMPDIR/rottifincludefile.$$
		TMPERR=$TEMPDIR/rotttemperr.$$
		TMPERRMSG=$TEMPDIR/rotttempmsg.$$
		MAILMSG=$TEMPDIR/rotttempmsg.$$
		ROTATE_ATTACH=$TEMPDIR/rottateattach.$$
		ALL_ATTACH=$TEMPDIR/rotallattach.$$
		HANDLED=$TEMPDIR/rotthandled.$$
		TMPROTTCOLLECT=$TEMPDIR/rottmpcollect.$$
		TEMP_TARCOLL=$TEMPDIR/rotttarcol.$$
		TMP_ARCH_FILE=$TEMPDIR/rotttmparchfile.$$
		TMP_STATFILE=$TEMPDIR/rotttmpstatfile.$$
		NEW_TMP_STATFILE=$TEMPDIR/rottnewtmpstatfile.$$
		TMP_PERIOD_RC=$TEMPDIR/rotttmpperiodrc.$$
		TMP_ROTTMAXAGE=$TEMPDIR/rottmaxage.$$
	else
		eval "$1=\"$tmpd\""
	fi
}

make_storefile () {
	if [ ! -z "$param_storefile" ]
	then
		debecho "make_storefile: Before expand_metavar:"
		debecho "make_storefile: storefile=$storefile"
		debecho "make_storefile: param_storefile=$param_storefile"
		expand_metavar "$log" "$param_storefile"
		storefile="$pcdpc/$expanded_metavars"
		debecho "make_storefile: After all expand_metavar:"
		debecho "make_storefile: storefile=$storefile"
	else
		debecho "make_storefile: No storefile directive used."
		debecho "make_storefile: Composing storefile: $pcdpc / basename $1"
		storefile="$pcdpc/$(basename $1)"
		lastnum "$storefile*" 1
		numero=$?
		storefile="$storefile.$numero"
		debecho "make_storefile: Here storefile=$storefile"
	fi
}

# See prepare_rotate
parse_period () {
 local exit_t=
 local OLDIFS="$IFS"
 local list_elem_lday="monday tuesday wednesday thursday friday \
                       saturday sunday"
 local list_elem_lmonth="january february march april may june july august \
                         september october november december"
 local list_elem_sday="mon tue wed thu fri sat sun"
 local list_elem_smonth="jan feb mar apr may jun jul aug sep oct nov dec"

 local crit=
 local pieces="$1"

 while [ 0 ]
 do
  local IFS=","
  local num_cond=1
  for opt in $pieces
  do
   num_cond=$[ num_cond + 1 ]
   [ -z "$opt" -o "$opt" = "," ] && continue 
   local ltoken=0
   local token=
   local rest=
   local first=
   local NOT=
   opt=$(echo $opt|tr -s ' ')
   [ "${opt:0:1}" = " " ] && opt=${opt:1}
   IFS="$OLDIFS"
   for token in $opt
   do
    debecho "parse_period: Here token=$token"
    ltoken=$[ ltoken + ${#token} + 1 ] # +1 per lo spazio tra i tokens
    rest=${opt:ltoken}
    if [ "${token:0:1}" = '!' ]; then
     debecho "parse_period: Operator NOT"
     NOT='!'
     token=${token:1}
     #rest=${opt:ltoken+1}
    fi
    case "$token" in
     *+*)
      debecho "parse_period: Expanding inline OR operator"
      lastchar=$[ ${#token} - 1 ]
      if [ "${token:$[ ${#token} - 1 ]:1}" = '+' ]; then
       echo "Error in OR definition"
       exit $E_BAD_OR
      fi
      op=$(echo "$token"|cut -d'+' -f1)
      if [ -z "$op" ]; then
       echo "Error in OR definition"
       USCITA=$E_BAD_OR
       exit $USCITA
      fi
      case "$op" in
       monday|tuesday|wednesday|thursday|friday|\
       saturday|sunday)
        local list_elem=$list_elem_lday
        ;;
       january|february|march|april|may|june|july|\
       august|september|october|november|december)
        local list_elem=$list_elem_lmonth
        ;;
       mon|tue|wed|thu|fri|sat|sun)
        local list_elem=$list_elem_sday
        ;;
       jan|feb|mar|apr|may|jun|jul|aug|sep|oct|\
       nov|dec)
        local list_elem=$list_elem_smonth
        ;;
       *)
        echo "Error in inline OR definition!"
        USCITA=$E_BAD_OR
        exit $USCITA
        ;;
      esac
      allop=${token//+/ }
      for lop in $allop
      do
       checkitem "$list_elem" "$lop"
       if [ -z "$NOT" ]; then
        exit_t="$exit_t, $first $lop $rest"
       else
        exit_t="$exit_t $NOT$lop"
       fi
      done
      [ ! -z "$NOT" ] && exit_t="$first $exit_t $rest"
      ;; # end case on *+*
     *-*) 
      debecho "parse_period: Expanding range: $token"
      local checkminus=$(echo "$token"|cut -d'-' -f3-)
      if [ ! -z "$checkminus" ]; then
       echo "Error in range definition!"
       USCITA=$E_BAD_RANGE
       exit $USCITA
      fi
      case $token in
       *monday*|*tuesday*|*wednesday*|*thursday*|*friday*|\
       *saturday*|*sunday*)
        local default_begin="monday"
        local default_end="sunday"
        local list_elem=$list_elem_lday
        ;;
       *january*|*february*|*march*|*april*|*may*|*june*|*july*|\
       *august*|*september*|*october*|*november*|*december*)
        local default_begin="january"
        local default_end="december"
        local list_elem=$list_elem_lmonth
        ;;
       *mon*|*tue*|*wed*|*thu*|*fri*|*sat*|*sun*)
        local default_begin="mon"
        local default_end="sun"
        local list_elem=$list_elem_sday
        ;;
       *jan*|*feb*|*mar*|*apr*|*may*|*jun*|*jul*|*aug*|*sep*|*oct*|\
       *nov*|*dec*)
        local default_begin="jan"
        local default_end="dec"
        local list_elem=$list_elem_smonth
        ;;
       *)
        echo "Error in range definition!"
        USCITA=$E_BAD_RANGE
        exit $USCITA
       ;;
      esac
      begin_t=$(echo "$token"|cut -d'-' -f1)
      end_t=$(echo "$token"|cut -d'-' -f2)
      # If it is a range, begin before -xxx)
      if [ -z "$begin_t" ]; then
       local begin_t="$default_begin"
      fi
      # If it is a range, end after xxx-
      if [ -z "$end_t" ]; then
       local end_t="$default_end"
      else
       case "$end_t" in
        monday|tuesday|wednesday|thursday|friday|saturday|sunday)
         checkitem "$list_elem_lday" "$begin_t"
         ;;
        january|february|march|april|may|june|july|august|\
        september|october|november|december)
         checkitem "$list_elem_lmonth" "$begin_t"
         ;;
        mon|tue|wed|thu|fri|sat|sun)
         checkitem "$list_elem_sday" "$begin_t"
         ;;
        jan|feb|mar|apr|may|jun|jul|aug|sep|oct|\
        nov|dec)
         checkitem "$list_elem_smonth" "$begin_t"
         ;;
        *)
         echo "Error on end range!"
         USCITA=$E_BAD_RANGE
         exit $USCITA
         ;;
       esac
      fi
      # Expanding range xxx-yyy
      local append=
      local exit_t=
      for i in $list_elem
      do
       [ $i = "$begin_t" ] && append=1
       if [ ! -z "$append" ]; then
        if [ -z "$NOT" ]; then
         exit_t="$exit_t, $first $i $rest"
        else
         exit_t="$exit_t $NOT$i"
        fi
       fi
       [ $i = "$end_t" ] && append=
      done
      [ ! -z "$NOT" ] && exit_t="$first $exit_t $rest"
      ;; # End case on *-*
    esac
    if [ ! -z "$exit_t" ]; then
     debecho "parse_period: using num_cond=$num_cond in pieces=$pieces"
     local addpieces=$(echo "$pieces"|cut -d',' -f$num_cond-)
     if [ -z "$addpieces" ] || [ "$pieces" = "$addpieces" ]; then
      pieces="$exit_t"
     else
      pieces="$exit_t,$addpieces"
     fi
     dont_exit=1
     num_cond=1
     break 2
    fi
    if [ $(expr "$opt" : ".*-.*") -gt $ltoken ] || \
       [ $(expr "$opt" : ".*+.*") -gt $ltoken ]; then
     debecho "parse_period: Non yet filling criteria. Waiting for following iteration"
    else
     debecho "parse_period: checking token=$token"
     case $token in
      # Add HHh and MMm ???
      0)
       debecho "parse_period: --> Always"
       crit="$crit && [ 1 ]"
       ;;
      [[:digit:]][[:digit:]]:[[:digit:]][[:digit:]])
       debecho "parse_period: --> HH:MM"
       local ch="$(echo $token|cut -d':' -f1)"
       local cm="$(echo $token|cut -d':' -f2)"
       if [ $ch -gt 23 ] || [ $cm -gt 59 ]; then
        echo "Bad time definition!"
        USCITA=$E_BAD_TIME
        exit $USCITA
       fi
       #Use timestamp??
       crit="$crit && [ \"$ch:$cm\" $NOT= \"$now_hour:$now_min\" ]"
       ;;
      mon|tue|wed|thu|fri|sat|sun)
       debecho "parse_period: --> abbreviated weekday"
       local wday="$token"
       crit="$crit && [ $wday $NOT= $name_today ]"
       ;;
      monday|tuesday|wednesday|thursday|friday|saturday|sunday)
       debecho "parse_period: --> long weekday"
       local wday="$token"
       crit="$crit && [ $wday $NOT= $long_name_today ]"
       ;;
      jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)
       debecho "parse_period: --> abbreviated monthname"
       local wmonth="$token"
       crit="$crit && [ $wmonth $NOT= $name_month ]"
       ;;
      january|ferbruary|march|april|may|june|july|august|september|\
      october|november|december)
       debecho "parse_period: --> long monthname"
       local wmonth="$token"
       crit="$crit && [ $wmonth $NOT= $long_name_month ]"
       ;;
      [[:digit:]]d|[[:digit:]][[:digit:]]d)
       debecho "parse_period: --> days period"
       check_mwd "d"
       ;;
      [[:digit:]]w|[[:digit:]][[:digit:]]w)
       debecho "parse_period: --> weeks period"
       check_mwd "w"
       ;;
      [[:digit:]]M|[[:digit:]][[:digit:]]M)
       debecho "parse_period: --> month period"
       check_mwd "M"
       ;;
      [[:digit:]]|[[:digit:]][[:digit:]])
       debecho "parse_period: --> Exact day"
       if [ $token -gt 31 ]; then
        echo "There is no month long $token days!"
        USCITA=$E_BAD_DAY
        exit $USCITA
       fi
       if [ $token -gt $ldom ]; then
        debecho "parse_period: Adjusting to last day of month"
        token=$ldom
       fi
       if [ -z "$NOT" ]; then
        crit="$crit && [ $today -eq $token ]"
       else
        crit="$crit && [ $today -ne $token ]"
       fi
       ;;
      *)
       echo "Error in period definition. Token: $token"
       USCITA=$E_BAD_PERIOD
       exit $USCITA
       ;;
     esac
    fi
    if [ -z "$first" ]; then
     first="$NOT$token"
    else
     first="$first $NOT$token"
    fi
    NOT=
   done
   crit=${crit:4}
   debecho "parse_period: evaluating:"
   debecho "parse_period: $crit"
   eval "if $crit; then update_stamp; return 1; else crit=; fi"
  done
  if [ -z $dont_exit ]; then
   break
  else
   dont_exit=
   exit_t=
  fi
  IFS="$OLDIFS"
 done
 return 0
}

# See read_and_do
prepare_rotate () {
 local orig_pcdpc="$pcdpc"
 for log in ${pcldr[@]}; do
  # If logfile has been already rotated/archived
  yet=$(grep "$log" $HANDLED 2>/dev/null)
 if [ ! -z "$yet" ]; then
  debecho "prepare_rotate: Logfile has already been rotated/archived"
  debecho "prepare_rotate: logfile=$log"
  debecho "prepare_rotate: yet=$yet"
  continue
 fi

 if [ ! -z "$PERIOD" ]; then
  parse_period "$PERIOD"
  if [ $? -eq 1 ]; then
   debecho "prepare_rotate: period VERIFIED"
  else
   debecho "prepare_rotate: period not verified"
   continue
  fi
 fi
        
 size_b=$(ls -l "$log" 2>/dev/null|tr -s ' '|cut -d' ' -f5)
 if [ -z "$size_b" ]; then
  size_b=0
 fi
 if [ ! -z "$MAXSIZE" ] && [ $size_b -le $MAXSIZE ]; then
  debecho "prepare_rotate: Filesize of logfile is less than MAXSIZE"
  debecho "prepare_rotate: logfile=$log"
  debecho "prepare_rotate: filesize=$size_b"
  debecho "prepare_rotate: MAXSIZE=$MAXSIZE"
  continue
 fi
 debecho "prepare_rotate: Restoring value of pcdpc..."
 pcdpc="$orig_pcdpc"
 debecho "prepare_rotate: Before expand_metavar pcdpc=$pcdpc"
 expand_metavar "$log" "$pcdpc"
 pcdpc="$expanded_metavars"
 debecho "prepare_rotate: After expand_metavar pcdpc=$pcdpc"
 if [ ! -d "$pcdpc" ] && [ ! -z "$createdir" ]; then
  debecho "prepare_rotate: Trying to make $pcdpc..."
  mkdir -p "$pcdpc" 2>/dev/null
  chown $dir_own "$pcdpc"
  chgrp $dir_grp "$pcdpc"
  chmod $dir_perm "$pcdpc"
 fi
 if [ ! -d "$pcdpc" ]; then
  echo "Directory to store compressed log doesn't exist!"
  echo "Log=$log"
  echo "Dir=$pcdpc"
  USCITA=$E_NO_STOREDIR
  exit $USCITA
 fi

 make_storefile "$log"

 # ddd//bbb --> ddd/bbb
 storefile=${storefile//\/\//\/}

 if [ ! -z "$CHATTR" ]; then
  chattr -a "$log"
 fi

 # Eseguiamo lo script prima di ruotare
 debecho "prepare_rotate: Executing prerotate script"
 if [ -r "$TEMPDIR/prerotate.$$" ] && [ -z "$DISABLE_SCRIPT" ]; then
  # Here must be expanded metavars
  while read l
  do
   expand_metavar "$log" "$l"
   echo "$expanded_metavars"
  done <$TEMPDIR/prerotate.$$ >$TEMPDIR/meta-prerotate.$$
  debecho "prepare_rotate: Output of meta-prerotate.$$:"
  debecho "$(cat $TEMPDIR/meta-prerotate.$$)"
  . $TEMPDIR/meta-prerotate.$$
 fi

 if [ ! -z "$rotate_overwrite" ] && [ ! -z "$mailopt_over" ]; then
  if [ ! -z "$NOCOMPRESS" ]; then
   if [ ! -z "$mailopt_zip" ]; then
    $packer $compress "$storefile" >$ROTATE_ATTACH
   else
    cp -f $storefile $ROTATE_ATTACH
   fi
  else
   if [ -z "$mailopt_zip" ]; then
    $unpacker $uncompress "$storefile" >$ROTATE_ATTACH
   else
    cp -f $storefile $ROTATE_ATTACH
   fi
  fi
 fi

 # Ruotiamo il log
 debecho "prepare_rotate: Rotating log"
 date_begin=$(date)
 if [ -z "$COLLATE" ]; then
  do_rotate "$log" "$storefile"
  RET_DO_ROTATE=$?
  if [ $RET_DO_ROTATE -eq 0 ]; then 
   eval "count_$quale=$[ count_$quale + 1 ]" # for statistical informations
  fi
 else
  collate_logfiles "$log" "$storefile"
 fi
    
 if [ ! -z "$mailopt_all" ]; then
  if [ ! -z "$NOCOMPRESS" ]; then
   if [ -z "$mailopt_zip" ]; then
    cp -f $storefile $ALL_ATTACH
   else
    $packer $compress "$storefile" >$ALL_ATTACH
   fi
  else
   if [ -z "$mailopt_zip" ]; then
    $unpacker $uncompress "$storefile" >$ALL_ATTACH
   else
    cp -f $storefile $ALL_ATTACH
   fi
  fi
 fi

 # Eseguiamo lo script dopo la rotazione
 if [ ! -z "$sharedscr" ]; then
  if [ "$sharedscr" = "$log" ]; then
   runpost=1
  else
   runpost=0
  fi
 else
  runpost=1
 fi

 if [ $runpost -eq 1 ]; then
  debecho "prepare_rotate: Executing postrotate script"
  if [ -r "$TEMPDIR/postrotate.$$" ] && [ -z "$DISABLE_SCRIPT" ]; then
   # Here must be expanded metavars
   while read l
   do
    expand_metavar "$log" "$l"
    echo "$expanded_metavars"
   done <$TEMPDIR/postrotate.$$ >$TEMPDIR/meta-postrotate.$$
   . $TEMPDIR/meta-postrotate.$$
  fi
 fi

 if [ ! -z "$CHATTR" ]; then
  chattr +a "$log"
 fi

 date_end=$(date)
 if [ -z "$nomail" ]; then
  debecho "prepare_rotate: mailing to $touser action report"
  mail_to_admin
 else
  debecho "prepare_rotate: DON'T mail to $touser"
 fi
  debecho "prepare_rotate: adding $log in $HANDLED"
  echo "$log" >>$HANDLED
 done
 rm -f $TEMPDIR/meta-prerotate.$$
 rm -f $TEMPDIR/prerotate.$$
 rm -f $TEMPDIR/meta-postrotate.$$
 rm -f $TEMPDIR/postrotate.$$
 if [ $meta_tmp_dir != "" ] # or if [ -d $meta_tmp_dir ]
  then
  rm -Rf $meta_tmp_dir
 fi
}

read_and_do() {
 if [ -z "$1" ]; then
  cmd_exec=( prepare_rotate )
 else
  cmd_exec=( $@ )
 fi
 debecho "read and do: will execute ${cmd_exec[@]}"
 sed -e '/^[[:space:]]*#.*/d' -e ' /^$/d' "$MAINDIR/$quale" >$PURGED_FILE
 (
  setup_vars
  debecho "read and do: Here looking for include directive..."
  cp -p $PURGED_FILE $IFINCLUDE_FILE
  local filenames=
  while read ifinclude
  do
   if [ "${ifinclude// */}" = "include" ]; then
    debecho "read and do: found $ifinclude"
    ifinclude=${ifinclude//* /}
    if [ ! -z "$filenames" ]; then
     filenames="$filenames,\"$ifinclude\""
    else
     filenames="$ifinclude"
    fi
    debecho "read and do: Now filenames=$filenames"
   else
    debecho "read and do: Row not matching: $ifinclude"
    break
   fi
  done <$IFINCLUDE_FILE
  if [ ! -z "$filenames" ]; then
   sed -e '/^include*/d' "$IFINCLUDE_FILE" >$PURGED_FILE
   expand_filenames $filenames
   debecho "read and do: After expansion pcldr=${pcldr[@]}"
   for i in ${pcldr[@]}
   do
    debecho "read and do: including $i file..."
    if [ ! -r "$i" ]; then
     echo "Can't read $i include file!"
     USCITA=$E_CONF_NOTFOUND
     exit $USCITA
    fi
    sed -e '/^[[:space:]]*#.*/d' -e ' /^$/d' "$i" >>$PURGED_FILE
   done
  fi
 )
 EXIT_SUBS=$?
 if [ $EXIT_SUBS -ne 0 ]; then
  exit $EXIT_SUBS
 fi
 > $HANDLED
 while read LINEA
 do
  debecho "read and do: Reading $LINEA from $PURGED_FILE"
  local tmp=${LINEA// /}
  unset pcldr
  setup_vars
  if [ "${tmp:${#tmp}-1}" != "{" ]; then
   debecho "read and do: Probably common period variable"
   debecho "read and do: Making new file to be read"
   cat -s $PURGED_FILE|sed -e '/{/q'|grep -v '{' >$TMP_PERIOD_RC
   if [ ! -f $TMP_PERIOD_RC ]; then
    echo "Undefined error in file $MAINDIR/$quale"
    USCITA=$E_SYNTAX_ERROR
    exit $USCITA
   fi
   debecho "read and do: calling read_rcopts"
   read_rcopts $TMP_PERIOD_RC write
   debecho "read and do: excluding global options lines"
   while [ "${LINEA/{/}" = "$LINEA" ]
   do
    read LINEA
   done
   #if [ ]; then
   #  echo "Syntax error in file $MAINDIR/$quale"
   #  USCITA=$E_SYNTAX_ERROR
   #  exit $USCITA
   #fi
  fi
  # If there are multiple files to rotate with same rules
  filenames="${LINEA/{*/}"
  debecho "read and do: Parsing options for logfiles"
  read LINEA
  (
   if [ -f $TMP_PERIOD_RC ]; then
    source $TMP_PERIOD_RC
   fi
   while [ "$LINEA" != "}" ]
   do
    # After the first line (containing '{') the syntax is: <keyword> <value>
    set -- $LINEA
    debecho "read and do: Analyzing parameters of '$LINEA'"
    while [ $# -gt 0 ]
    do
     case "$1" in
      forceday|period)
       shift
       if [ "$quale" != "custom" ]; then
        echo "parameter 'period' can be used only in custom configuration file!"
        USCITA=$E_BAD_FORCEDAY
        exit $USCITA
       fi
       # Here I can put syntax checking, but no actions must
       # be performed before expanded filenames.
       PERIOD="$@"
       PERIOD=$(echo "$PERIOD"|tr -s ' ')
       if [ -z "$PERIOD" ]; then
        echo "No period to be forced!"
        USCITA=$E_BAD_DAY
        exit $USCITA
       fi
       shift $#
       ;;
      collate|tarcollate)
       COLLATE="${1:0:3}"
       ;;
      dateoffset)
       shift
       # Days to add or subtract in date-related meta-variables
       if [ ! -z "$1" ]; then
        case "${1:0:1}" in
         +|-)
          DATE_OFFSET="$1"
          ;;
         *)
          DATE_OFFSET="-$1"
         ;;
        esac
       else
        echo "No valid offset"
        USCITA=$E_INVALID_OFFSET
        exit $USCITA
       fi
       ;;
      firstaction)
       if [ ! -z "$ACTION" ]; then
        IGNORE_ACTION=1
       fi
       if [ -z "$2" ]; then
        ACTION_EXIT=0
       else
        ACTION_EXIT=$2
       fi
       read ACTION
       read LINEA
       if [ "$LINEA" != "endaction" ]; then
        echo "Actions must be only one command line!"
        USCITA=$E_BAD_SYNACTION
        exit $USCITA
       fi
       if [ -z "$IGNORE_ACTION" ] && [ -z "$DISABLE_SCRIPT" ]; then
        $ACTION 2>$TMPERR
        if [ $? -ne $ACTION_EXIT ]; then
         echo "Error while executing $1"
         echo "stderr from $LINEA:"
         cat $TMPERR
         USCITA=$E_BAD_ACTION
        fi
       fi
       ;;
      lastaction)
       if [ -z "$2" ]; then
        LASTACTION_EXIT=0
       else
        LASTACTION_EXIT=$2
       fi
       read LASTACTION
       read LINEA
       if [ "$LINEA" != "endaction" ]; then
        echo "Actions must be only one command line!"
        USCITA=$E_BAD_SYNACTION
        exit $USCITA
       fi
       ;;
      endaction)
       echo -n "This keyword must be used after a firstaction/lastaction"
       echo " definition!"
       USCITA=$E_BAD_ENDACTION
       exit $USCITA
       ;;
      storedir)
       if [ ${2:0:1} != "/" ]; then
        pcdpc="$packdir/$2"
       else
        pcdpc="$2"
       fi
       shift
       debecho "read and do: storedir parameter pcdpc=$pcdpc"
       ;;
      nostoredir)
       pcdpc="@DIRNAME"
       ;;
      storefile)
       if [ -z $2 ]; then
        echo "No store file specified!"
        USCITA=$E_NO_STORENAME
        exit $USCITA
       fi
       shift
       local params=$@
       param_storefile="$params"
       debecho "read and do: storefile parameter: param_storefile=$param_storefile"
       ;;
      dateext)
       param_storefile="@BASENAME.@NEXT_EXT-@YEAR@MONTH@DAY"
      ;;
      logpart)
       shift
       # Due to a (probably) buggy 2.03.0(1) bash
       local params=$@
       debecho "read and do: params=$params"
       analyze_logpart "$params"
       if [ $? -eq 0 ]; then
        shift
       else
        echo "Error in logpart parameter!"
       USCITA=$E_BAD_LOGPART
        exit $USCITA
       fi
       debecho "read and do: logpart parameter: parsing OK"
       LOGPART=1
       shift $#
       ;;
      nocompress)
       NOCOMPRESS=1
       debecho "read and do: using nocompress feature"
       ;;
      compress)
       NOCOMPRESS=
       debecho "read and do: using compress to overwrite nocompress"
       ;;
      postrotate|prerotate)
       SCRIPTFILE=$TEMPDIR/$1.$$
       debecho "read and do: Writing $SCRIPTFILE"
       > $SCRIPTFILE
       chmod 700 $SCRIPTFILE
       read LINEA
       while [ "$LINEA" != "endscript" ]
       do
        debecho "read and do: >>> $LINEA"
        echo "$LINEA" >>$SCRIPTFILE
        read LINEA
       done
       debecho "read and do: End $SCRIPTFILE"
       ;;
      endscript)
       echo -n "This keyword must be used after a postrotate/prerotate"
       echo " definition!"
       USCITA=$E_BAD_ENDSCRIPT
       exit $USCITA
       ;;
      touser)
       touser="$2"
       debecho "read and do: touser parameter: touser=$touser"
       shift
       ;;
      create)
      shift
      case $# in
       0)
        CHMOD=$fil_perm
        CHOWN=$fil_own
        CHGRP=$fil_grp
        ;;
       1)
        CHMOD="$1"
        CHOWN=$fil_own
        CHGRP=$fil_grp
        shift
        ;;
       2)
        CHMOD="$1"
        CHOWN="$2"
        CHGRP=$fil_grp
        shift 2
        ;;
       3)
        CHMOD="$1"
        CHOWN="$2"
        CHGRP="$3"
        shift 3
        ;;
       *)
        echo "Error in create parameter!"
        USCITA=$E_BAD_CREATE
        exit $USCITA
        ;;
      esac
      debecho "read and do: create parameter: $CHMOD,$CHOWN,$CHGRP"
      check_perms "$CHMOD" "$CHOWN" "$CHGRP" create
      ;;
     delaycompress)
      DELAY=1
      debecho "read and do: delaycompress parameter: DELAY=$DELAY"
      ;;
     nodelaycompress)
      DELAY=
      debecho "read and do: nodelaycompress parameter"
      ;;
     ifempty)
      notifempty=
      debecho "read and do: ifempty"
      ;;
     notifempty)
      notifempty=1
      debecho "read and do: notifempty"
      ;;
     rotate)
      if [ -z "$2" ] || [ "$2" -lt 0 ] 2>/dev/null; then
       echo "Bad rotate parameter"
       USCITA=$E_BAD_ROTATE
       exit $USCITA
      fi
      ROTATE=$2
      debecho "read and do: rotate parameter: ROTATE=$ROTATE"
      shift
      ;;
     log_rotate)
      log_rotate=1
      ;;
     create_logrotate)
      create_logrotate=1
      ;;
     size)
      if [ -z "$2" ]; then
       echo "no size parameter!"
       USCITA=$E_BAD_SIZE
       exit $USCITA
      fi
      # Remove last char
      lensize=${#2}
      lastchar=${2:$lensize-1}
      #lensize=$[ lensize - 1 ]
      case $lastchar in
       k|K)
        MULT=1024
        ;;
       m|M)
        MULT=1000000
        ;;
       ""|b|B)
        MULT=1
        ;;
       *)
        debecho "read and do: bad size identifier: assuming bytes"
        MULT=1
        lensize=$[ lensize + 1 ]
        #USCITA=$E_BAD_SIZE
        #exit $USCITA
       esac
       MAXSIZE=${2:0:$lensize-1}
       if [ $MAXSIZE -lt 0 ]; then
        echo "bad size parameter: Must be a valid number"
        USCITA=$E_BAD_SIZE
        exit $USCITA
       fi
       MAXSIZE=$[ MAXSIZE * MULT ]
       debecho "read and do: size parameter: MAXSIZE=$MAXSIZE"
       shift
       ;;
      nocreate)
       NOCREATE=1
       ;;
      createdir)
       if [ ! -z "$2" ]; then
        dir_perm=$2
        shift
       fi
       if [ ! -z "$2" ]; then
        dir_own=$2
        shift
       fi
       if [ ! -z "$2" ]; then
        dir_grp=$2
        shift
       fi
       check_perms "$dir_perm" "$dir_own" "$dir_grp" createdir
       createdir=1
       ;;
      append-only)
       CHATTR=1
       ;;
      maxdepth)
       if [ -z "$2" ] || [ "$2" -lt 0 ] >/dev/null; then
        echo "Invalid maxdepth!"
        USCITA=$E_BAD_MAXDEPTH
        exit $USCITA
       fi
       shift
       MAXDEPTH=$1
       ;;
      missingok)
       #missingok=1
       nomissingok=0
       ;;
      nomissingok)
       #missingok=0
       nomissingok=1
       ;;
      nosharedscripts)
       sharedscr=
       ;;
      sharedscripts)
       sharedscr=1
       ;;
      mailopt)
       local check_opt="$2"
       local loop_opt=
       check_opt=${check_opt//,/ }
       check_opt=$(echo "$check_opt"|tr -s ' ')
       [ "${check_opt:0:1}" = " " ] && check_opt=${check_opt:1}
       for loop_opt in $check_opt; do
        case "$loop_opt" in
         all|a) 
          mailopt=1
          mailopt_all=1
          ;;
         # RE-add mailopt stat to allow statistical messages
         # about only one file
         maillast|overwrite|over)
          mailopt=2
          mailopt_over=1
          ;;
         zip|ziplast)
          mailopt=4
          mailopt_zip=1
          ;;
         error|err)
          mailopt=3
          mailopt_err=1
          ;;
         none|nomail)
          nomail=1
          ;;
         *)
          echo "Bad mailopt parameter!"
          USCITA=$E_BAD_MAILOPT
          exit $USCITA
          ;;
        esac
       done
       shift
       ;;
      maxage)
       shift
       if [ -z "$1" ]; then
        maxage=365
       else
        maxage=$1
        shift
       fi
       debecho "read_and_do: maxage=$maxage"
       #TODO: Add a check??
       ;;
      nomail)
       nomail=1
       ;;
      tabooext)
       TABOO_EXT="$DEF_TABOO_EXT"
       shift
       # parse list of taboo extensions
       tt=$(echo $1)
       tt=${tt//\"/}
       if [ ! -z "$tt" ]; then
        debecho "read_and_do: tabooext is ${tt:0:1}"
        if [ ${tt:0:1} = "+" ]; then
         debecho "read_and_do: Adding new patterns to TABOO_EXT"
         TABOO_EXT="$TABOO_EXT $(echo ${tt:1})"
         shift
         TABOO_EXT="$TABOO_EXT $@"
        else
         debecho "read_and_do: Substituting default pattern with user defined"
         TABOO_EXT=$(echo $@)
        fi
       fi
       debecho "read_and_do: new extension list is: $TABOO_EXT"
       shift $#
       ;;
      start)
       shift
       if [ -z "$1" ]; then
        START_ROTATE=$def_start
       else
        START_ROTATE=$1
        shift
       fi
       debecho "read_and_do: start=$START_ROTATE"
       ;;
      year_based|month_based|week_based|day_based)
       eval "$1"=1
       ;;
      *)
       echo "Bad parameter!"
       debecho "read and do: Bad parameter: $1"
       USCITA=$E_BAD_PARAM
       exit $USCITA
       ;;
     esac
     shift
    done # sui campi della riga
    read LINEA
   done # sulle righe != }

   # SANITY CHECKS
   if [ -z "$param_storefile" ] && [ ! -z "$default_storefile" ]; then
    param_storefile="$default_storefile" 
   fi
   if [ ! -z "$FORCE_DAY" ]; then
    # exit from subshell?
    debecho "read and do: Sanity check: exit from subshell due to FORCE_DAY=$FORCE_DAY"
    exit
   fi
   debecho "read and do: Ignoring nocompress if using delaycompress"
   if [ ! -z "$NOCOMPRESS" ] && [ -z "$DELAY" ]; then
    packer="cat"
    compress=
   fi
   if [ -z "$pcdpc" ]; then
    pcdpc="$packdir"
   fi
   if [ ! -z "$LOGPART" ] && [ ! -z "$CHOWN" ]; then
    echo "create option can't be used with logpart!"
    USCITA=$E_CANT_CREATE
    exit $USCITA
   fi
   # Meta-variables about time can't be used in storefile if used to rotate too
   # In reality:
   # day  da evitare sempre
   # week  da evitare in monthly e weekly
   # month  da evitare in monthly
   # year volendo si pu anche non evitare...
   #if [ ! -z "$ROTATE" ]; then
   #  #local check="$param_storefile"
   #  local check=
   #  local check_orig=
   #  for check in "$param_storefile" "$pcdpc"; do
   #    check_orig=$check
   #    case "$quale" in
   #      daily)
   #        local META_TIME="DAY"
   #           ;;
   #      weekly)
   #        local META_TIME="DAY WEEK"
   #           ;;
   #      monthly)
   #        local META_TIME="DAY WEEK MONTH"
   #           ;;
   #      *)
   #        local META_TIME="DAY MONTH YEAR WEEK"
   #           ;;
   #    esac
   #    #local META_TIME="DAY MONTH YEAR WEEK"
   #    for c in $META_TIME; do
   #      check=${check//\@$c/}
   #    done
   #    if [ "$check" != "$check_orig" ]; then
   #      META_TIME="@${META_TIME// / @}"
   #      echo "$META_TIME meta-variables can't be used with rotate parameter"
   #      echo "in $quale config file!" 
   #      USCITA=$E_CANT_ROTATE
   #      exit $USCITA
   #    fi
   #  done
   #fi
   if [ ! -z "$COLLATE" ]; then
    if [ "$COLLATE" = "tar" ]; then
     caction="tarcollate"
    else
     caction="collate"
    fi
    #This option is compatible only with following options:
    #  - [no]storedir
    #  - storefile
    #  - createdir
    #  - firstaction/lastaction
    #  - prerotate/postrotate
    #  - nocompress
    #  - touser
    #  - nomail
    checkparam="LOGPART CHMOD DELAY ROTATE MAXSIZE NOCREATE CHATTR MAXDEPTH"
    for check in $checkparam
    do
     if [ ! -z "$(eval echo "\$$check")" ] && [ "$(eval echo "\$$check")" -ne 0 ]; then
      echo "$caction is not compatible with $check parameter"
      USCITA=$E_BAD_COLLATE_PARAM
      exit $USCITA
     fi
    done
   fi
   if [ "$quale" = "custom" ] && [ -z "$PERIOD" ]; then
    echo "Each logfile entry in custom config file needs period parameter!"
    USCITA=$E_BAD_PERIOD
    exit $USCITA
   fi
   # End of sanity check
   debecho "read_and_do: expanding filenames $filenames"
   expand_filenames $filenames
  (
   if [ -z "$COLLATE" ]; then
    exit 0
   fi
   case $quale in
    monthly)
     quale=weekly
     coll_period=4
     ;;
    weekly)
     quale=daily
     coll_period=7
     ;;
    *)
     echo "$1 can't be used in period different than monthly or weekly"
     USCITA=$E_BAD_COLL_PERIOD
     exit $USCITA
     ;;
   esac
   debecho "read and do: Saving original value of purged_file variable"
   orig_PURGED_FILE="$PURGED_FILE"
   PURGED_FILE="$PURGED_FILE.collect"
   # in un futuro passer pcldr[@] invece di pcldr[0]
   # cos far pi in fretta a cercare i log da collegare
   # se modfico anche collect_log_info
   debecho "read and do: Calling collect_log_info with log=${pcldr[0]} and coll_period=$coll_period"
   COLLATE=
   read_and_do collect_log_info "${pcldr[0]}" $coll_period $quale
   debecho "read and do: Restoring original purged_file variable value..."
   PURGED_FILE="$orig_PURGED_FILE"
  )
  RET_VAL=$?
  if [ $RET_VAL -ne 0 ]; then
   exit $RET_VAL
  fi
  # call function specified in "$1" with all other parameters
  ${cmd_exec[@]}
  EXIT_CODE=$?
  run_lastaction
  if [ $EXIT_CODE -ne 0 ]; then
   exit $EXIT_CODE
  fi
  debecho "pread_and_do: Making stat temp file if necessary"
  if [ ! -z "$mailstats" ]; then
   update_stats $quale count
   #update_stats $quale freed
  fi
 )
 USCITA=$?
 debecho "read and do: Exit from subshell with errorcode: $USCITA"
 if [ $USCITA -ne 0 ] && [ $USCITA -ne $BREAK_CYCLE ]; then
  echo "There is an error in read cycle for configuration file $quale"
  exit $USCITA
 elif [ $USCITA -eq $BREAK_CYCLE ]; then
  return
 fi
 #unset pcldr
 done <$PURGED_FILE
 rm -f $TMP_PERIOD_RC # TODO: move to a setup routine????
}

# See Main
read_custom() {
	quale="custom"
	if [ ! -e $MAINDIR/$quale ]
	then
		debecho "read_custom: Config file '$quale' does not exist"
		return
	fi
	debecho "read_custom: This file will always be read"
	read_and_do
	if [ "$config_file" = "custom" ]
	then
		[ -e "$TMP_STATFILE" ] && mail_to_admin stat
		exit 0
	fi
}

# See Main
read_daily() {
	quale="daily"
	if [ ! -e $MAINDIR/$quale ]
	then
		debecho "read_daily: Config file '$quale' does not exist"
		return
	fi
	check_last_rotate "$STATDIR/.lastday" 86400 day
	if [ $? -eq 1 ]
	then
		debecho "read_daily: Rotating daily logfiles"
		read_and_do
	fi
	if [ "$config_file" = "day" ]
	then
		[ -e "$TMP_STATFILE" ] && mail_to_admin stat
		exit 0
	fi
}

# See show_log
read_log () {
	local old_pcdpc="$pcdpc"
	for log in ${pcldr[@]}
	do
		pcdpc="$old_pcdpc"
		expand_metavar "$log" "$pcdpc"
		pcdpc="$expanded_metavars"
		if [ $1 -eq 1 ]
		then
			if [ "${2:0:1}" != "/" ]
			then
				storefile="$packdir/$2"
			else
				storefile="$2"
			fi
		else
		storefile="$pcdpc/$2"
		fi
		debecho "read_log: Here storefile=$storefile"
		if [ -r "$storefile" ]
		then
			debecho "read_log: Found $storefile"
			debecho "read_log: NOCOMPRESS=$NOCOMPRESS; DELAY=$DELAY;"
			[ ! -z "$DELAY" ] && local c=$(grep "$storefile" $DELAYED_FILES 2>/dev/null)
			if [ ! -z "$NOCOMPRESS" ] || [ ! -z "$c" ]
			then
				unpacker=cat
				uncompress=
				extension="txt"
			fi
			cp -f "$storefile" $NEWtmpFILE.$extension
			if [ ! -r "$NEWtmpFILE.$extension" ]
			then
				echo "Can't read temporary logfile!"
				USCITA=$E_FILE_NOREAD
				exit $USCITA
			fi
			debecho "read_log: $unpacker $uncompress $NEWtmpFILE.$extension | $PAGER"
			$unpacker $uncompress "$NEWtmpFILE.$extension" | $PAGER
			echo "$NEWtmpFILE" >"$NEWtmpFILE.$extension"
			return $BREAK_CYCLE
		fi
	done
}

# See Main
read_monthly() {
	quale="monthly"
	if [ ! -e $MAINDIR/$quale ]
	then
		debecho "read_monthly: Config file '$quale' does not exist"
		return
	fi
	# Comparision time is 28, 29, 30 or 31 days depending on previous month
	local days=
	local comptime=
	for days in 31 30 29 28
	do
		comptime=$(cal $(date --date "$date_refer -1 month" "+%m %Y")|grep $days)
		if [ ! -z "$comptime" ]
		then
			comptime=$[ days * 86400 ]
			break
		fi
	done
	check_last_rotate "$STATDIR/.lastmonth" $comptime month
	if [ $? -eq 1 ]
	then
		debecho "read_monthly: Rotating monthly logfiles"
		read_and_do
	fi
	if [ "$config_file" = "month" ]
	then
		[ -e "$TMP_STATFILE" ] && mail_to_admin stat
		exit 0
	fi
}

# See read_and_do and Main
read_rcopts() {
 local tmp_param
 local RC_VARS="packer compress unpacker uncompress extension pager packdir fromuser touser notifempty mail nomail maxdepth follow_symlink nomissingok missingok nocompress ifempty notifempty nocreate createdir dir_perm dir_own dir_grp fil_own fil_grp fil_perm remove_missing default_storefile SunMon mailstats create_logrotate log_rotate nostoredir sharescripts nosharedscripts tabooext maxage"
 local i=

 if [ -z "$1" ]; then
  echo "Internal error in read_rcopts!!"
  USCITA=$E_INTERNAL
  exit $USCITA
 fi

 debecho "read_rcopts: Reading $1 configuration file"
 if [ ! -f $1 ]; then
  echo "Couldn't read main rc file!"
  USCITA=$E_NO_RCFILE
  exit $USCITA
 fi

 for i in $RC_VARS
 do
  tmp_param=$(awk "/^[[:space:]]*$i/ { print }" < $1)
  #tmp_param=$(awk "/^[[:space:]]*$i\>/ { print }" < $1)
  if [ -z "$tmp_param" ]; then
   continue
  fi
  if [ $(expr "$tmp_param" : ".*=.*") -eq 0 ]; then
   debecho "read_rcopts: tmp_param=$tmp_param (=1)"
   eval $tmp_param=1
  else
   debecho "read_rcopts: tmp_param=$tmp_param"
   # Check for spaced atipical option (i.e. tabooext)
   if [ "${tmp_param//\"/}" = "$tmp_param" ] && \
    [ "${tmp_param// /}" != "$tmp_param" ]; then
    tmp_param=${tmp_param/=/=\"}
    tmp_param="$tmp_param\""
   fi
   eval $tmp_param
  fi
 done

 # Sanity checks
 if [ -z "$2" ]; then
  if [ -z "$packer" ] || [ -z "$compress" ]; then
   echo "WARNING: defaults to nocompress"
   echo "To compress a logfile you must fill correctly"
   echo "packer and compress options!"
   NOCOMPRESS=1
  fi
  if [ -z "$unpacker" ] || [ -z "$uncompress" ]; then
   echo "WARNING: -l feature is disabled"
   echo "To use it you must fill correctly:"
   echo "unpacker and decompress variables"
   NO_SHOWLOG=1
  fi
  if [ -z "$extension" ]; then
   echo "WARNING: Can't use @COMP_EXT metavariable"
   echo "To use it, the extension option must have a value."
   NO_EXTENSION=1
  fi
  if [ -z "$pager" ] && [ -z "$PAGER" ]; then
   echo "WARNING: No default pager"
   echo "This means that -l will be used only with the -p option"
   echo "To avoid this behaviour you must correctly fill pager variable"
  fi
  if [ -z "$touser" ]; then
   echo "Must specify destination address for e-mail messages"
   USCITA=$E_NO_TOUSER
   exit $USCITA
  fi
  if [ -z "$mail" ]; then
   echo "Must specify mailer program with parameters in mail variable"
   USCITA=$E_NO_MAIL
   exit $USCITA
  fi
  if [ ! -z "$tabooext" ]; then
   TABOO_EXT="$DEF_TABOO_EXT"
   tt=$(echo $tabooext)
   if [ ${tt:0:1} = "+" ]; then
    debecho "read_rcopts: Adding new patterns to TABOO_EXT"
    TABOO_EXT="$TABOO_EXT $(echo ${tt:1})"
   else
    debecho "read_rcopts: Substituting default pattern with user defined"
    TABOO_EXT=$(echo $tt)
   fi
   tabooext="$TABOO_EXT"
  fi
 setup_vars "set"
 else
  > $TMP_PERIOD_RC
  for i in $RC_VARS; do
   if [ ! -z "$(eval echo \$$i)" ]; then
    echo "$i=\"$(eval echo \$$i)\"" >>$TMP_PERIOD_RC
   fi
  done
 fi
}

# See Main
read_weekly() {
	quale="weekly"
	if [ ! -e $MAINDIR/$quale ]
	then
		debecho "read_weekly: Config file '$quale' does not exist"
		return
	fi
	check_last_rotate "$STATDIR/.lastweek" 604800 week
	if [ $? -eq 1 ]
	then
		debecho "read_weekly: Rotating weekly logfiles"
		read_and_do
	fi
	if [ "$config_file" = "week" ]
	then
		[ -e "$TMP_STATFILE" ] && mail_to_admin stat
		exit 0
	fi
}

# See do_rotate
remove_from_ctrlfile () {
	# Protect each '/' with '\' : ddd/fff --> ddd\/fff
	local ESCAPED=${1//\//\\/}
	sed -e "/^$ESCAPED/d" $DELAYED_FILES >$NEWtmpFILE
	cat $NEWtmpFILE >$DELAYED_FILES
}

# See do_rotate
remove_maxage() {
	if [ ! -s $TMP_ROTTMAXAGE ]
	then
		return
	fi

	local checktime
	local diffsec
	local diffdays  

	while read ff
	do
		checktime=$(date -r "$ff" +%s)
		diffsec=$[ stamp_now - checktime ]
		if [ $diffsec -lt 0 ]
		then
			echo "Old logfile newer than new logfile??"
			return
		fi
		diffdays=$[ diffsec / 86400 ]
		if [ $diffdays -gt $maxage ]
		then
			rm -f "$ff"
		else
			return 0
		fi
	done <$TMP_ROTTMAXAGE
  
	# TODO: Is this the correct place?
	rm -f $TMP_ROTTMAXAGE
}

# (See lastnum)
rotate_logrotate() {
	# Pull down rotated files
	local num_files=$(ls -1v $1 2>/dev/null|wc -w)
	local last_file=""
	local last_file2=""
	local i=1
	local startp=""
	local end_fn=""
	local start_fn=""
	local check=$(expr index "$1" \?)

	# TODO: Make this error not so critical?
	if [ $check -ne 0 ]
	then
		echo "ERROR: Time-related metavariables can't be used without *_force options"
		USCITA=$E_LOGROTATE_NO_TIMEVAR
		exit $USCITA
	fi

	if [ $num_files -eq 0 ]
	then
		return $START_ROTATE
	fi

	if [ $num_files -eq $[ ROTATE - START_ROTATE + 1 ] ]
	then 
		debecho "rotate_logrotate: A loop ends"
		num_files=$[ num_files - 1 ]
		ext_file=$ROTATE
	else
		ext_file=$[ num_files + START_ROTATE ]
	fi
	startp=$(expr index "$1" \*)
	if [ $startp -ne 0 ]
	then
		end_fn="${1:startp}"
		startp=$[ startp - 1 ]
		start_fn="${1:0:startp}"
	else
		echo "ERROR: Internal error in rotate_logrotate!"
		USCITA=$E_INTERNAL
		exit $USCITA
	fi

	for((i=1;i<=num_files;i++)) {
		last_file=${start_fn}${ext_file}${end_fn}
		ext_file=$[ ext_file - 1 ]
		last_file2=${start_fn}${ext_file}${end_fn}
		mv -f $last_file2 $last_file
	}
	return $START_ROTATE
}

run_lastaction () {
	debecho "run_lastaction: Here LASTACTION=$LASTACTION"
	if [ ! -z "$LASTACTION" ] && [ -z "$DISABLE_SCRIPT" ]
	then
		$LASTACTION 2>$TMPERR
		if [ $? -ne $LASTACTION_EXIT ]
		then
			echo "Error while executing $1"
			echo "stderr from $LINEA:"
			cat $TMPERR
			USCITA=$E_BAD_ACTION
		fi
	fi
}

# See read_{and_do,rcopts}
setup_vars () {
	if [ "$1" = "set" ]
	then
		def_maxdepth=${MAXDEPTH-0}
		def_mail=$mail
		def_dir_own=${dir_own-root}
		def_dir_grp=${dir_grp-root}
		def_dir_perm=${dir_perm-0640}
		def_fil_own=${fil_own-root}
		def_fil_grp=${fil_grp-root}
		def_fil_perm=${fil_perm-0640}
		def_pager=$pager
		def_follow_symlinks=${follow_symlinks-0}
		def_missingok=${missingok-1}
		def_nomissingok=${nomissingok-0}
		def_SunMon=${SunMon-sun}
		def_mailstats=${mailstats-}
		def_packer=${packer-gzip}
		def_compress=${compress-\-9c}
		def_extension=${extension-gz}
		def_nostoredir=${nostoredir-}
		def_log_rotate=${log_rotate-}
		def_create_logrotate=${create_logrotate-}
		def_sharedscr=${sharedscripts-}
		def_nosharedscr=${nosharedscripts-}
		def_tabooext="${tabooext-$DEF_TABOO_EXT}"
		def_maxage=${maxage-}
		def_start=${START_ROTATE-1}
		def_year_based=${year_based-1}
		def_month_based=${month_based-}
		def_week_based=${week_based-}
		def_day_based=${day_based-}
		if [ ! -z "$def_mailstats" ]
		then
			(
				echo "count_custom=0"
				echo "count_daily=0"
				echo "count_weekly=0"
				echo "count_monthly=0"
				echo "freed_custom=0"
				echo "freed_daily=0"
				echo "freed_weekly=0"
				echo "freed_monthly=0"
			)>$TMP_STATFILE
		fi
		return
	fi

	MAXDEPTH=$def_maxdepth
	mail=$def_mail
	dir_own=$def_dir_own
	dir_grp=$def_dir_grp
	dir_perm=$def_dir_perm
	fil_own=$def_fil_own
	fil_grp=$def_fil_grp
	fil_perm=$def_fil_perm
	pager=$def_pager
	follow_symlinks=$def_follow_symlinks
	missingok=$def_missingok
	nomissingok=$def_nomissingok
	SunMon=$def_SunMon
	mailstats="$def_mailstats"
	log_rotate=$def_log_rotate
	create_logrotate=$def_create_logrotate
	def_maxage=$def_maxage
	START_ROTATE=$def_start
	year_based=$def_year_based
	month_based=$def_month_based
	week_based=$def_week_based
	day_based=$def_day_based

	if [ ! -z $def_nosharedscr ]
	then
		sharedscr=
	else
		sharedscr=$def_sharedscr
	fi
	tabooext="$def_tabooext"

	# nostoredir fill pcdpc variable
	[ -z "$def_nostoredir" ] || pcdpc="@DIRNAME"

	# TODO: add mailopt_* ??
}

show_defaults () {
	local VARS="VERSION MAINDIR MAINRC STATDIR DELAYED_FILES DATE_OFFSET \
	            BASE_TMP_DIR DEBUG mail pager follow_symlinks dir_own \
	            dir_grp dir_perm fil_own fil_grp fil_perm tabooext"
	local V=
	banner
	echo
	echo "Default values for important variables:"
	echo
	for V in $VARS
	do
		echo -n "$V="
		eval echo \$$V
	done
	#Alternative, but less flexible.
	#set|grep "^def_.*="|cut -b 5-
}

# See Main
show_log () {
 debecho "show_log: input pager: pager=$pager -- PAGER=$PAGER"
 if [ ! -z "$pager" ]; then
  PAGER="$pager"
 fi
 if [ -z "$PAGER" ]; then
  PAGER=$(which less)
  if [ -z "$PAGER" ]; then
   PAGER=$(which more)
  fi
  if [ -z "$PAGER" ]; then
   echo "Can't find a pager! Use pager variable in main rc file or "
   echo "PAGER environnement variable"
   USCITA=$E_NO_PAGER
   exit $USCITA
  fi
  if [ ! -x "$PAGER" ]; then
   echo "Can't exec pager $PAGER!"
   USCITA=$E_NO_PAGER
   exit $USCITA
  fi
 fi
 debecho "show_log: Using pager $PAGER"
 if [ -z "$unpacker" ] || [ -z "$uncompress" ]; then
  echo "Bad configuration: use unpacker and uncompress variables in mail rc file"
  USCITA=$E_CANT_UNCOMPRESS
  exit $USCITA
 fi
 if [ $(expr "$1" : ".*\/.*") -ne 0 ]; then
  rpath=1
 else
  rpath=0
 fi
 debecho "show_log: Here rpath=$rpath"
 for quale in custom daily weekly monthly; do
  if [ -e $MAINDIR/$quale ]; then
   debecho "show_log: Searching in $quale conffile"
   read_and_do read_log "$rpath" "$1"
   if [ "$(cat "$NEWtmpFILE.$extension" 2>/dev/null)" = "$NEWtmpFILE" ]; then
    USCITA=$BREAK_CYCLE
    break
   fi
  fi
 done
 if [ $USCITA -ne $BREAK_CYCLE ]; then
  echo "Can't find $1"
  USCITA=$E_FILE_NOFIND
  exit $USCITA
 fi
}

# See mail_to_admin
signature() {
cat <<EOF

-- 
GNU Rot[t]log $VERSION
    <http://www.gnu.org/software/rottlog>
EOF
}

# See Main
summarize_loginfo () {
	# Cycle between daily, weekly, monthly, and custom
	# quando trovo il file in uno di questi tre visualizzo le info ed esco
	for quale in custom daily weekly monthly
	do
		if [ -e $MAINDIR/$quale ]
		then
			debecho "summarize_loginfo: Searching in $quale conffile"
			read_and_do findlog "$1"
		fi
	done
}

# See Main
usage () {
	echo
	echo "Usage: rottlog [-dlv] [--help] [-p CMD] [-s FILE] [--version]"
	echo "               [--checkrc all|custom|daily|weekly|monthly]"
	echo "       rottlog {-f} [custom|daily|weekly|monthly]"
	echo
	echo "Report bugs to: <bug-rottlog@gnu.org>"
	echo "Rot[t]log on the web: <http://www.gnu.org/software/rottlog/>"
	echo "User questions may be asked on IRC: #sgos on irc.freenode.net"
	echo "General help using GNU software: <http://www.gnu.org/gethelp/>"
	echo
}

update_stamp() {
	local NameOfCtrlFile="$STATDIR/.${log//\//_}.rtt"
	debecho "update_stamp: Updating $NameOfCtrlFile file"
	echo "stamp:$stamp_now"  >$NameOfCtrlFile
	echo "date:$date_now"   >>$NameOfCtrlFile
	echo "size:$size_b"     >>$NameOfCtrlFile
	if [ ! -z "$1" ]
	then
		echo "partial:$1"  >>$NameOfCtrlFile
	fi
	if [ ! -f "$NameOfCtrlFile" ]
	then
		debecho "update_stamp: Can't write control file!"
		debecho "update_stamp: Disk full or permission denied!"
	fi
}

# See read_and_do and mail_to_admin
update_stats() {
	(
		local newc=$(eval echo \$${2}_${1})
		if [ -s $TMP_STATFILE ]
		then
			source $TMP_STATFILE
			local newc=$[ newc + $(eval echo \$${2}_${1}) ]
			sed -e "s/^$2_$1=.*/$2_$1=$newc/" \
			       $TMP_STATFILE >$NEW_TMP_STATFILE
			cp -f $NEW_TMP_STATFILE $TMP_STATFILE
		fi
	)
}

# MAIN
#
trap 'rm -rf $TEMPDIR $LOCK; exit $USCITA' 0
debecho "MAIN: Filling time base variable."
date_refer=$(date "+%m/%d/%Y %H:%M:%S")
# Prevent multiple executions of this program at the same time:
if [ -e $LOCK ]
then
	echo "Can't run multiple instances of Rot[t]log."
	USCITA=$E_LOCKED
	exit $USCITA
else
	echo "$$" >$LOCK
	chmod 0400 $LOCK
fi
if [ $# -eq 1 ]
then
	case "$1" in
	# This should be a separate script.
	--checkrc)
		shift
		if [ -z "$1" ]
		then
			echo "Invalid syntax!"
		fi
		while [ $# -ne 0 ]
		do
			case "$1" in
			weekly)
				rctocheck="$rctocheck weekly"
				;;
			monthly)
				rctocheck="$rctocheck monthly"
				;;
			daily)
				rctocheck="$rctocheck daily"
				;;
			custom)
				rctocheck="$rctocheck custom"
				;;
			all)
				rctocheck="weekly monthly daily custom"
				;;
			main)
				# already checked!
				rctocheck="$rctocheck main"
				;;
			*)
				echo "Invalid option to checkrc: $1"
				USCITA=$E_BAD_PARAM; exit $USCITA
				;;
			esac
			shift
		done
		checkrc $rctocheck
		;;
	--help)
		usage
		exit 0
		;;
	--version)
		banner 1
		exit 0
		;;
	esac
fi
make_tmpdir
read_rcopts "$MAINRC"
fill_timevar "$date_refer"
if [ $# -ne 0 ]
then
	while getopts "dflpsv" OPTS
	do
		case "$OPTS" in
		d)
			show_defaults
			;;
		f)
			if [ -z "$2" ]
			then
				config_file="day month week custom"
			else
				case "$2" in
				daily)
					config_file="day"
					;;
				monthly)
					config_file="month"
					;;
				weekly)
					config_file="week"
					;;
				custom)
					config_file="custom"
					;;
				esac
			fi
			debecho "MAIN: Deleting time control files $config_file"
			(
				for i in $config_file
				do
					debecho "MAIN: Deleting $STATDIR/.last${i}"
					rm -f "$STATDIR/.last${i}"
				done
			)
			#DONTEXIT=1
			# This was changed from --force:
			[ "$1" = "-f" ] && config_file="none"
			shift
			;;
		l)
			if [ -z "$NO_SHOWLOG" ]
			then
				show_log "$2"
			fi
			shift
			exit 0
			;;
		s)
			summarize_loginfo "$2"
			shift
			exit 0
			;;
		p)
			if [ -z "$NO_SHOWLOG" ]
			then
				if [ -z "$2" ]
				then
					echo "Must specify pager!"
					USCITA=$E_NO_PAGER
					exit $USCITA
				fi
				pager="$2"
				debecho "MAIN: Pager will be: $pager"
			fi
			shift
			;;
		v)
			DEBUG=1
			;;
		*)
			usage
			;;
		esac
		shift
	done
	#[ -z "$DONTEXIT" ] && exit 0
fi
read_custom
read_daily
read_weekly
read_monthly
[ -e "$TMP_STATFILE" ] && mail_to_admin stat
