#! /bin/sh
##
## @PACKAGE@ @VERSION@
## Copyright (c) @COPYYEARS@ by Henry Kilmer and John Heasley
## All rights reserved.
##
## This code is derived from software contributed to and maintained by
## Henry Kilmer, John Heasley, Andrew Partan,
## Pete Whiting, Austin Schutz, and Andrew Fort.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
## 1. Redistributions of source code must retain the above copyright
##    notice, this list of conditions and the following disclaimer.
## 2. Redistributions in binary form must reproduce the above copyright
##    notice, this list of conditions and the following disclaimer in the
##    documentation and/or other materials provided with the distribution.
## 3. Neither the name of RANCID nor the names of its
##    contributors may be used to endorse or promote products derived from
##    this software without specific prior written permission.
##
## THIS SOFTWARE IS PROVIDED BY Henry Kilmer, John Heasley AND CONTRIBUTORS
## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
## POSSIBILITY OF SUCH DAMAGE.
##
## It is the request of the authors, but not a condition of license, that
## parties packaging or redistributing RANCID NOT distribute altered versions
## of the etc/rancid.types.base file nor alter how this file is processed nor
## when in relation to etc/rancid.types.conf.  The goal of this is to help
## suppress our support costs.  If it becomes a problem, this could become a
## condition of license.
# 
#  The expect login scripts were based on Erik Sherk's gwtn, by permission.
# 
#  The original looking glass software was written by Ed Kern, provided by
#  permission and modified beyond recognition.
#
# control_rancid $GROUP
#

# print a usage message to stderr
pr_usage() {
    echo "usage: $0 [-V] [-c commit_msg] [-f group_config_file] [-r device_name] [-m mail rcpt] group" >&2;
}

# command-line options
# -V print version string
# -c <SCM commit message>
# -f <group config file name>
# -m <mail recipients>
# -r <device name>
alt_mailrcpt=0
alt_commitmsg=0
if [ $# -ge 1 ] ; then

    while [ 1 ] ; do
	case $1 in
	-V)
	    echo "@PACKAGE@ @VERSION@"
	    exit 0
	    ;;
	-c)
	    shift
	    # next arg is the commit message
	    alt_commitmsg=1
	    if [ -z "$commitmsg" ] ; then
		commitmsg="$1"
	    else
		commitmsg="$commitmsg,$1"
	    fi
	    shift
	    ;;
	-f)
	    shift
	    # next arg is the alternate config file name
	    ENVFILE="$1"
	    if [ -z $ENVFILE ]; then
		pr_usage
		exit 1
	    fi
	    shift
	    ;;
	-m)
	    shift
	    # next arg is the mail recipient
	    alt_mailrcpt=1
	    if [ -z "$mailrcpt" ] ; then
		mailrcpt="$1"
	    else
		mailrcpt="$mailrcpt,$1"
	    fi
	    shift
	    ;;
	-r)
	    shift
	    # next arg is the device name
	    device="$1"
	    shift
	    ;;
	--)
	    shift; break;
	    ;;
	-h)
	    pr_usage
	    exit 0
	    ;;
	-*)
	    echo "unknown option: $1" >&2
	    pr_usage
	    exit 1
	    ;;
	*)
	    break;
	    ;;
	esac
    done
fi

# Must specify a group on which to run rancid
if [ $# -lt 1 ] ; then
    echo 'must specify group'; exit 1
else
    GROUP=$1
fi
TMP=${TMPDIR:=/tmp}/rancid.$GROUP.$$
if [ -z "$ENVFILE" ] ; then
    ENVFILE="@sysconfdir@/rancid.conf"
fi
if [ -f "$ENVFILE" ] ; then
    . $ENVFILE
fi
trap 'rm -fr $TMP;' 1 2 15
DIR=$BASEDIR/$GROUP

# disable noclobber
unset noclobber > /dev/null 2>&1

# SENDMAIL location
SENDMAIL=${SENDMAIL:=sendmail};
# default MAILHEADERS
set | grep MAILHEADERS= > /dev/null 2>&1
if [ $? -ne 0 ] ; then
    MAILHEADERS="Precedence: bulk\nAuto-submitted: auto-generated\nX-Auto-Response-Suppress: All"; export MAILHEADERS
fi

# Bail if we do not have the necessary info to run
if [ ! -d $DIR ] ; then
    adminmailrcpt=${adminmailrcpt:-"@ADMINMAILPLUS@${GROUP}${MAILDOMAIN}"};
    echo "$DIR does not exist."
    echo "Run bin/rancid-cvs $GROUP to make all of the needed directories."
    (
	echo "To: $adminmailrcpt"
	echo "Subject: no $GROUP directory"
	echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
	echo ""
	echo "$DIR does not exist."
	echo "Run bin/rancid-cvs $GROUP to make all of the needed directories."
    ) | $SENDMAIL -t $MAILOPTS
    exit 1
fi
cd $DIR
if [ -f "rancid.conf" ] ; then
    . ./rancid.conf
fi

# RCS system
RCSSYS=${RCSSYS:=cvs};
if [ $RCSSYS != "cvs" -a $RCSSYS != "svn" -a $RCSSYS != "git" ] ; then
    echo "$RCSSYS is not a valid value for RCSSYS. See rancid.conf(5)." >&2
    exit 1
fi

# the recipient(s) of diffs & mail options
mailrcpt=${mailrcpt:-"@MAILPLUS@${GROUP}${MAILDOMAIN}"}; export mailrcpt
adminmailrcpt=${adminmailrcpt:-"@ADMINMAILPLUS@${GROUP}${MAILDOMAIN}"};
export adminmailrcpt
if [ -z "$commitmsg" ] ; then
    commitmsg="updates"
    if [ $alt_mailrcpt -eq 1 ] ; then
	commitmsg="$commitmsg - courtesy of $mailrcpt"
    fi
    export commitmsg
fi

# Number of things par should run in parallel.
PAR_COUNT=${PAR_COUNT:-5}
# Number of times failed collections should be retried.  Minimum 0.
MAX_ROUNDS=${MAX_ROUNDS:-4}
if [ $MAX_ROUNDS -lt 0 ] ; then
    echo "Error: MAX_ROUNDS must be at least 0 or greater." >&2
    MAX_ROUNDS=1
fi

# Check for missing configs dir.
if [ ! -d $DIR/configs ] ; then
    mkdir $DIR/configs
    if [ $? -ne 0 ] ; then
	echo "Error: could not create missing configs directory" >&2
	exit
    fi
    case $RCSSYS in
    cvs | svn)
	$RCSSYS add configs
	;;
    esac
fi

# create a .cvsignore/.gitignore
case $RCSSYS in
git )
    if [ ! -f .gitignore ] ; then
	touch .gitignore
	git add .gitignore
    else
	git ls-files .gitignore --error-unmatch > /dev/null 2>&1
	if [ $? -ne 0 ] ; then
	    git add .gitignore
	fi
    fi
    rm -rf .gitignore
    cat > .gitignore <<EOF
/routers.all
/routers.down
/routers.single
/routers.up
/runcount
.old
*.new
*.raw
EOF
    if [ -f .gitignore.locale ] ; then
	cat .gitignore.locale >> .gitignore
    fi
    ;;
cvs | svn )
    if [ ! -f .cvsignore ] ; then
	touch .cvsignore
	$RCSSYS add .cvsignore
    fi
    rm -rf .cvsignore
    cat >.cvsignore <<EOF
.cvsignore
routers.all
routers.down
routers.single
routers.up
runcount
EOF
    if [ -f .cvsignore.locale ] ; then
	cat .cvsignore.locale >> .cvsignore
    fi
    if [ ! -f configs/.cvsignore ] ; then
	touch configs/.cvsignore
	$RCSSYS add configs/.cvsignore
    fi
    rm -rf configs/.cvsignore
    cat > configs/.cvsignore <<EOF2
.old
*.new
*.raw
EOF2
    if [ -f configs/.cvsignore.locale ] ; then
	cat configs/.cvsignore.locale >> configs/.cvsignore
    fi
    if [ $RCSSYS = svn ] ; then
	svn propset svn:ignore -F .cvsignore .
	svn propset svn:ignore -F configs/.cvsignore configs
	svn update .
	svn commit -m 'set svn:ignores' .
    fi
    ;;
esac

# if there is a rancid.conf, check if it needs to be added to the RCS
if [ -f rancid.conf ] ; then
    case $RCSSYS in
    cvs )
	cvs log -rHEAD rancid.conf > /dev/null 2>&1
	if [ $? -eq 0 ] ; then LN=1; else LN=0; fi
	;;
    svn )
	LN=`(svn ls rancid.conf | wc -l) 2>/dev/null`
	;;
    git )
	git ls-files rancid.conf --error-unmatch > /dev/null 2>&1
	if [ $? -eq 0 ] ; then LN=1; else LN=0; fi
        ;;
    esac
    if [ $LN -eq 0 ] ; then
	$RCSSYS add rancid.conf
    fi
fi

# do RCS update of router.db in case anyone has fiddled.
case $RCSSYS in
git )
    # git doesnt make this easy.  XXX
    #git fetch > $TMP 2>&1
    #git checkout FETCH_HEAD -- router.db
    #grep "^C" $TMP > /dev/null	# XXX right for git?
    touch $TMP
    ;;
cvs | svn )
    $RCSSYS update router.db > $TMP 2>&1
    grep "^C" $TMP > /dev/null
    if [ $? -eq 0 ] ; then
	echo "There were $RCSSYS conflicts during update."
	echo ""
	cat $TMP
	rm -f $TMP
	exit 1
    fi
    ;;
esac
rm -f $TMP

if [ ! -f $DIR/router.db ] ; then
    echo "$DIR/router.db does not exist."
    (
	echo "To: $adminmailrcpt"
	echo "Subject: no $GROUP/router.db file"
	echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
	echo ""
	echo "$DIR/router.db does not exist."
    ) | $SENDMAIL -t $MAILOPTS
    exit 1;
fi

# IQ test
@PERLV@ -F\; -ane '{if ($F[0] !~ /^\s*#/ && $F[0] !~ /^\s*$/ && $#F < 2 && $F[0] =~ /:/) {print "WARNING: Have you forgotten to update the FS in router.db?\n"; exit;}}' router.db

# generate the list of all, up, & down routers
cd $DIR
trap 'rm -fr routers.db routers.all.new routers.down.new routers.up.new \
	routers.mail routers.added routers.deleted $TMP;' 1 2 15
@PERLV@ -ne '{s/^\s*//; s/\s*$//; s/\s*;\s*/;/g; next if (/^(#|;|$)/);
    @F = split /\;/;
    $F[2] =~ s/\s*\$//;
    $F[0] =~ tr@A-Z@a-z@;
    if (defined($A{$F[0]})) {
      printf STDERR "WARNING: %s appears in routers.db multiple times\n", $F[0];
      next;
    } $A{$F[0]} = "$F[1];$F[2]";}
    END { foreach $k (sort((keys(%A)))) {print "$k;$A{$k}\n";} }' \
    router.db > routers.db
cut -d\; -f1,2 routers.db > routers.all.new
if [ ! -f routers.all ] ; then touch routers.all; fi
@DIFF_CMD@ routers.all routers.all.new > /dev/null 2>&1; RALL=$?
@PERLV@ -F\; -ane '{$F[2] =~ s/\s*\$//; ($F[0] =~ tr@A-Z@a-z@, print $_)
    if ($F[2] !~ /^up$/i);}' routers.db > routers.down.new
if [ ! -f routers.down ] ; then touch routers.down; fi
@DIFF_CMD@ routers.down routers.down.new > /dev/null 2>&1; RDOWN=$?
@PERLV@ -F\; -ane '{$F[2] =~ s/\s*\$//; ($F[0] =~ tr@A-Z@a-z@,
    print "$F[0];$F[1]\n") if ($F[2] =~ /^up$/i);}' routers.db > routers.up.new
if [ ! -f routers.up ] ; then touch routers.up; fi
@DIFF_CMD@ routers.up routers.up.new > /dev/null 2>&1; RUP=$?

if [ $RALL -ne 0 -o $RDOWN -ne 0 -o $RUP -ne 0 ] ; then
    (
	if [ $RUP -ne 0 ] ; then
	    if [ ! -s routers.up ] ; then
		echo Routers changed to up:
		sed -e 's/^/        /' routers.up.new
		echo
	    else
		WCUP=`comm -13 routers.up routers.up.new | wc -l | \
			sed -e 's/^ *\([^ ]*\)/\1/'`
		if [ $WCUP -gt 0 ] ; then
		    echo Routers changed to up:
		    comm -13 routers.up routers.up.new | sed -e 's/^/        /'
		    echo
		fi
	    fi
	fi
	if [ $RDOWN -ne 0 ] ; then
	    if [ ! -s routers.down ] ; then
		echo Routers changed to down:
		sed -e 's/^/        /' routers.down.new
		echo
	    else
		WCDOWN=`comm -13 routers.down routers.down.new | wc -l | \
			sed -e 's/^ *\([^ ]*\)/\1/'`
		if [ $WCDOWN -eq 1 ] ; then
		    echo Routers changed to down:
		    comm -13 routers.down routers.down.new | \
			sed -e 's/^/        /'
		    echo
		fi
	    fi
	fi
	if [ $RALL -eq 1 ] ; then
	    comm -13 routers.all routers.all.new | sed -e 's/^/        /' \
		> routers.added
	    comm -23 routers.all routers.all.new | sed -e 's/^/        /' \
		> routers.deleted

	    WCADDED=`wc -l routers.added | sed -e 's/^ *\([^ ]*\) .*$/\1/'`
	    WCDELETED=`wc -l routers.deleted | sed -e 's/^ *\([^ ]*\) .*$/\1/'`

	    if [ $WCADDED -gt 0 ] ; then
		echo Added routers:
		cat routers.added
		echo
	    fi
	    if [ $WCDELETED -gt 0 ] ; then
		echo Deleted routers:
		cat routers.deleted
		echo
	    fi

	    rm -f routers.added routers.deleted
	fi
    ) > routers.mail

    if [ -s routers.mail ] ; then
	(
	  echo "To: $adminmailrcpt"
	  echo "Subject: changes in $GROUP routers"
	  echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
	  echo ""
	  cat routers.mail
	) | $SENDMAIL -t $MAILOPTS
    fi
    rm -f routers.mail

    cd $DIR/configs

    # Add new routers to the CVS structure.
    for router in `comm -13 $DIR/routers.up $DIR/routers.up.new`
    do
	OFS=$IFS
	IFS=';'
	set $router
	IFS=$OFS
	router=$1

	touch $router
	case $RCSSYS in
	cvs )
	    cvs add -ko $router
	    ;;
	svn | git )
	    $RCSSYS add $router
	    ;;
	esac
	$RCSSYS commit -m 'new router' $router
	echo "Added $router"
    done
    echo
    cd $DIR

fi
mv -f routers.all.new routers.all
if [ $? -ne 0 ] ; then
    echo "Error: could not rename routers.all.new" >&2
fi
mv -f routers.down.new routers.down
if [ $? -ne 0 ] ; then
    echo "Error: could not rename routers.down.new" >&2
fi
mv -f routers.up.new routers.up
if [ $? -ne 0 ] ; then
    echo "Error: could not rename routers.up.new" >&2
fi
rm -f routers.db
trap 'rm -fr $TMP;' 1 2 15

cd $DIR/configs
# check for 'up' routers missing in RCS.  no idea how this happens to some folks
for router in `cut -d\; -f1 ../routers.up` ; do
    case $RCSSYS in
    cvs )
	cvs status $router | grep -i 'status: unknown' > /dev/null 2>&1
	if [ $? -eq 0 ] ; then
	    touch $router
	    cvs add -ko $router
	    cvs commit -m 'new router' $router
	    echo "$RCSSYS added missing router $router"
	fi
	;;
    svn )
	if [ ! -f $router ] ; then
	    touch $router
	fi
	svn status $router | grep '^?' > /dev/null 2>&1
	if [ $? -eq 0 ] ; then
	    svn add $router
	    svn commit -m 'new router' $router
	    echo "$RCSSYS added missing router $router"
	fi
        ;;
    git )
	if [ ! -f $router ] ; then
	    touch $router
	fi
	git status --porcelain $router | grep '^?' > /dev/null 2>&1
	if [ $? -eq 0 ] ; then
	    git add $router
	    git commit -m 'new router' $router
	    echo "$RCSSYS added missing router $router"
	fi
        ;;
    esac
done
echo
# delete configs from RCS for routers not listed in routers.up.
for router in `find . \( -name \*.new -prune -o -name CVS -prune -o -name .svn -prune -o -name .cvsignore -prune -o -name .gitignore -prune -o -name .old -prune \) -o -type f -print | sed -e 's/^.\///'` ; do
    grep -i "^$router\;" ../router.db > /dev/null 2>&1
    if [ $? -eq 1 ] ; then
	rm -f $router
	case $RCSSYS in
	cvs | svn )
	    $RCSSYS delete $router
	    $RCSSYS commit -m "deleted router $router" $router
	    ;;
	git )
	    git rm $router
	    git commit -m "deleted router $router" $router
	    ;;
	esac
	echo "Deleted $router"
    fi
done
cd $DIR

# no routers, empty list or all 'down'
if [ ! -s routers.up ] ; then
    # commit router.db, etc
    message="updates of group $GROUP"
    case $RCSSYS in
    cvs | svn )
	$RCSSYS commit -m "$message"
	;;
    git )
	git add router.db
	git commit -am "$message"
	git push
	;;
    esac
    exit;
fi

# if a device (-r) was specified, see if that device is in this group
if [ "X$device" != "X" ] ; then
    trap 'rm -fr $TMP $DIR/routers.single;' 1 2 15
    devlistfile="$DIR/routers.single"
    grep -i "^$device\;" routers.up > $devlistfile
    if [ $? -eq 1 ] ; then
	exit;
    fi
else
    devlistfile="$DIR/routers.up"
fi

# Now we can actually try to get the configs
cd $DIR/configs

# The number of processes running at any given time can be
# tailored to the specific installation.
echo ""
echo "Trying to get all of the configs."
par -q -n $PAR_COUNT -c 'rancid-fe "{}"' $devlistfile

# This section will generate a list of missed routers
# and try to grab them again.  It will run through
# $pass times.
pass=$MAX_ROUNDS
round=1
if [ -f $DIR/routers.up.missed ] ; then
    rm -f $DIR/routers.up.missed
fi
while [ $round -le $pass ]
do
    for router in `cat $devlistfile`
    do
	OFS=$IFS
	IFS=';'
	set $router
	IFS=$OFS
	router=$1; mfg=$2

	if [ ! -s $router.new ]
	then
	    echo "$router;$mfg" >> $DIR/routers.up.missed
	    rm -f $router.new
	fi
    done

    if [ -f $DIR/routers.up.missed ] ; then
	echo "====================================="
	echo "Getting missed routers: round $round."
	par -q -n $PAR_COUNT -c 'rancid-fe "{}"' $DIR/routers.up.missed
	rm -f $DIR/routers.up.missed
	round=`expr $round + 1`
    else
	echo "All routers successfully completed."
	round=`expr $pass + 1`
    fi
done
echo

# Make sure that no empty/truncated configs are accepted.  The remainder are
# renamed from device_name.new -> device_name.
for router in `cat $devlistfile | cut -d\; -f1`
do
    if [ ! -s $router.new ] ; then
	rm -f $router.new
    else
	notcomment=`egrep -v "^[-*\!\;#]|\/\*" $router.new | wc -l`
	if [ $notcomment -gt 10 ]; then
	    lines=1;
	else
	    lines=0;
	fi

	if [ ! $lines ] ; then
	    rm -f $router.new
	else
	    mv -f $router.new $router
	    if [ $? -ne 0 ] ; then
		echo "Error: could not rename $router.new to $router" >&2
		rm -f $router.new
	    fi
	fi
    fi
done

# This has been different for different machines...
# Diff the directory and then checkin.
trap 'rm -fr $TMP $TMP.diff $DIR/routers.single;' 1 2 15
cd $DIR
if [ "X$DIFFSCRIPT" = "X" ]; then
    case $RCSSYS in
    cvs )
	cvs -f @DIFF_CMD@ -ko | sed -e '/^RCS file: /d' -e '/^--- /d' \
	-e '/^+++ /d' -e 's/^\([-+ ]\)/\1 /' >$TMP.diff
	;;
    svn | git )
	$RCSSYS diff | sed -e '/^+++ /d' -e 's/^\([-+ ]\)/\1 /' >$TMP.diff
	;;
    esac
else
    case $RCSSYS in
    cvs )
	cvs -f @DIFF_CMD@ -ko | (eval $DIFFSCRIPT) 2>&1 >$TMP.diff
	;;
    svn | git )
	$RCSSYS diff | (eval $DIFFSCRIPT) 2>&1 >$TMP.diff
	;;
    esac
fi

if [ $alt_mailrcpt -eq 1 ] ; then
    subject="router config diffs - courtesy of $mailrcpt"
else
    subject="router config diffs"
fi
if [ $RCSSYS = git ] ; then
    $RCSSYS commit -am "$commitmsg"
else
    $RCSSYS commit -m "$commitmsg"
fi
if [ "X$device" != "X" ] ; then
    subject="$GROUP/$device $subject"
else
    subject="$GROUP $subject"
fi

# working-directory maintenance & cleanup every 100 runs
if [ -f "runcount" ] ; then
    read RUNCOUNT < ./runcount
    RUNCOUNT=`expr $RUNCOUNT + 1`
else
    RUNCOUNT=1
fi
case $RCSSYS in
svn )
    svn cleanup
    ;;
git )
    git push
    if [ $RUNCOUNT -gt 100 ] ; then
	git gc --quiet
	RUNCOUNT=0
    fi
    ;;
esac
rm -f ./runcount
echo $RUNCOUNT > ./runcount

# Mail out the diffs (if there are any).
if [ -s $TMP.diff ] ; then
    MAXSZ=${MAILSPLIT:=0}
    if [ $MAXSZ -ne 0 ] ; then
	BLOCKSIZE=1024; export BLOCKSIZE
	tmpk=`perl -e "my(@S) = stat(\"$TMP.diff\"); print int(\\$S[7] / 1024);"`
	unset BLOCKSIZE
	if [ $tmpk -lt $MAXSZ ] ; then
	    MAXSZ=0
	fi
    fi
    if [ $MAXSZ -eq 0 ] ; then
	(
	  echo "To: $mailrcpt"
	  echo "Subject: $subject"
	  echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
	  echo ""
	  if [ $alt_commitmsg -eq 1 ] ; then
		echo "Commit message: $commitmsg"
		echo ""
	  fi
	  cat $TMP.diff
	) | $SENDMAIL -t $MAILOPTS
    else
	CDIR=`pwd`
	SDIR=${TMPDIR:=/tmp}/rancid.$GROUP.$$.mail
	error=`mkdir $SDIR`
	if [ $? -ne 0 ] ; then
	    echo "Could not create $SDIR directory" >&2
	    echo $error >&2
	else
	    cd $SDIR
	    split -b${MAXSZ}k $TMP.diff
	    nfiles=`ls | wc -l | sed -e 's/^ *//' |cut -d' ' -f1`
	    n=0
	    dt=`perl -e 'print time();'`
	    for file in `ls`; do
		n=`expr $n + 1`
		MSGID="<$dt.RANCID$GROUP$$${nfiles}${n}@`hostname`>"
		(
		echo "To: $mailrcpt"
		echo "Subject: $n of ${nfiles}: $subject"
		echo "Message-Id: $MSGID"
		if [ $n -gt 1 ] ; then
		    echo "References: $LASTIDS"
		fi
		echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
		echo ""
		if [ $alt_commitmsg -eq 1 ] ; then
		    echo "Commit message: $commitmsg"
		    echo ""
		fi
		cat $file
		) | $SENDMAIL -t $MAILOPTS
		LASTIDS="$LASTIDS $MSGID"
		if [ $n -lt $nfiles ]; then
		    # this just tries to make the msgs order right in MUAs
		    sleep 1
		fi
	    done
	    cd $CDIR
	    rm -rf $SDIR
	fi
    fi
fi

# If any machines have not been reached within the last $OLDTIME
# hours, mail out a list of them.
cd $DIR/configs
rm -f $DIR/routers.failed
if [ "X$OLDTIME" = "X" ] ; then
    OLDTIME=24
fi
@PERLV@ -F\; -ane "{\$t = (stat(\$F[0]))[9]; print \`ls -ld \$F[0]\`
	if (time() - \$t >= $OLDTIME*60*60);}" $devlistfile | sort -u > $DIR/routers.failed
if [ -s $DIR/routers.failed ] ; then
	(
	  echo "To: $adminmailrcpt"
	  echo "Subject: config fetcher problems - $GROUP"
	  echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}'
	  echo ""
	  echo "The following routers have not been successfully contacted for"
	  echo "more than $OLDTIME hours."

	  cat $DIR/routers.failed
	) | $SENDMAIL -t $MAILOPTS
fi

# Cleanup
rm -f $TMP.diff $DIR/routers.single $DIR/routers.failed
trap '' 1 2 15
