#!/bin/sh
##############################################################################
#
# cmirror - Bourne Shell (Configurable Mirror Script) version 1.9 (6/96)
#	by:	Adam Radulovic (adampr@i-link.net,adampr@engin.umich.edu)
#	currently maintained by: Kevin Sartorelli (kevin@topnz.ac.nz)
#
# To explain little the search strings, here is a few examples:
# To search for just "linux" do:
# linux
#
# To search for "linux" and "patch" do:
# linux\|patch
#
# To search for "linux", "patch" and "INDEX" do:
# linux\|patch\|INDEX
#
# Variable Definitions || Read all the definitions carefully, it is the engine
#	 	       -- of this whole script
#
#
# $HOST			: FTP site where you wish to receive new files from.
#			- Must be in the parameter file if used.
# $IN_DIR 		: Mirror directory on localhost to place files.
#			- Must be in the parameter file if used.
# $HOST_FROM_DIR	: Mirror directory on remote $HOST to receive files from.
#			- Must be in the parameter file if used.
# $DIRCOMMAND		: Command to get a directory listing from the
#			- remote host.
#			- Should be "dir" or "ls -l" in most cases.
# $IFL			: Information File Location (warning: do not do ~ ).
# $ENOTICE		: Email address for new files Notice (put 0 to disable).
# $SEARCH		: Enter a substring to search by, remember if you want.
#			- to search for more then one do first\|second , etc..
#			- Leave it blank to mirror all the files from remote
#			- $HOST.
# $RMSRCH		: Enter a substring to search for and exclude from your
#			- mirror site, even though they are located on the  
#			- remote $HOST and found by $SEARCH. If you do not want
#			- anything to be removed, place "/". (This will remove
#			- directories out of the list since cmirror receives
#			- only one directory at a time.)
# $TWO			: Default is 1, but if you log onto a site with
#			- only one file owner identifier set this to 0
#			- (i.e. ftp.funet.fi does this). 
#			- Set to 2 if it is a NetWare site running MurkWorks
#			- (eg tui.lincoln.ac.nz)
# $RM			: Default is 2. If 2 moves file to specified directory
#			- for $OLD. If 1 removes files of the localhost if they
#			- do not appear on the remote host and are not inside
#			- $NORM. If 0, leaves files on localhost.
# $OLD			: If $RM is set to 2, this should have a directory to 
#			- place the old files that were found on localhost and
#			- not on the remote $HOST.
# $NORM			: Enter a subtring to search for in the localhost 
#			- mirroring directory, and keep even though file is
#			- not located on remote $HOST. If you do not want
#			- anything to be saved, place "xxxxxxxx". 
# $MODE			: The mode to change the new files to with chmod.
# $OWNER		: The ownership to change the new files to with chown.
# $NCFTPOPT		: NcFTP options. For ncftp 2.3.0 best options are
#			- "-Lrd0".
#			- I also found it a good idea to set messages off with:
#			-	set remote-msgs off
#			-	set startup-msgs off
#			- Also, set tips off in the .ncftprc file with:
#			-	#unset tips  
#
##############################################################################
#
# Define this to anything if you don't want to use a parameter file, but want
# to define all variables in this script.  This is less portable, but the
# same as per version 1.8
#NO_PARAM="1"
NO_PARAM=""
if [ ! "$NO_PARAM" = "" ] ; then
	$HOST="uiarchive.cso.uiuc.edu"
	$HOST_FROM_DIR="/pub/systems/linux/sunsite/kernel/v1.3"
	$IN_DIR="/home/ftp/pub/Linux/kernel/v1.3"
fi
#
# cmirror variable defaults.  These can be overridden by the parameter file.
#
SEARCH=""
RMSRCH="NcFTP"
TWO="1"
RM="0"
OLD="/var/lib/cmirror/OLD"
NORM="xxxxxxxx"
IFL="/var/lib/cmirror"
ENOTICE="YOUR@EMAIL.ADDRESS.HERE"
DIRCOMMAND="ls -l"
MODE="644"
OWNER="ftp.ftp"

# If defined this will cause extra information to be output to
# the named file in the $IFL directory.
#DEBUG="debug.$$"
DEBUG=""

# Copy of ncftp to use, and the parameters to be passed to it.
NCFTPBIN="/var/lib/cmirror/ncftp"
NCFTPOPT="-L"

# Files in our current directory
CRNTFILES="crntfiles.$$"
# Files from remote machine
FILES="files.$$"
# Logs of files being moved
MVACTION="mvaction.$$"
# Logs of files being deleted
RMACTION="rmaction.$$"
# Files to be got
TOGET="toget.$$"
# Temopary file
TEMPFILE="temp.$$"

if [ "$NO_PARAM" = "" ] ; then
# Check for a parameter file given on the command line
	if [ ! $1 ]; then
		echo "No parameter file given, exiting..."
		exit 1;
	fi
# Read in the parameters from the file
	if [ -f $1 ]; then
		. $1
	else
        	echo "Parameter file $1 not found, exiting..."
		exit 1;
	fi
fi

#
##############################################################################
#
# cmirror script
#

# Check for a DNS entry for $HOST, if not found, quit out
NSCHECK=`nslookup \$HOST 2> /dev/null | grep "Non-existent"`
if [ $NSCHECK ] ; then

        echo "No DNS entry for $HOST, exiting..."
        exit 1;

fi

# Moving into directory where mirrored files go
cd $IN_DIR

# Getting file information out of the localhost for the mirrored directory 
ls -l | grep "$SEARCH" | grep -v "$RMSRCH" | grep -v ^d | awk '{printf ("%s %s\n",$5,$9)}' > $IFL/$CRNTFILES

# Getting file information from $HOST in the $HOST_FROM_DIR
if [ "$TWO" = "0" ] ; then

	# If you are logging onto a site (i.e. ftp.funet.fi) with only one (two default)
	# file owner identifier
        echo "$DIRCOMMAND $HOST_FROM_DIR" | $NCFTPBIN $NCFTPOPT $HOST 1> $IFL/$FILES 2> $IFL/$FILES
        TESTME=`cat $IFL/$FILES`
	if [ ! "$DEBUG" = "" ]; then
		echo "Host: $HOST" >>$IFL/$DEBUG
		echo "Directory: $HOST_FROM_DIR" >>$IFL/$DEBUG
		echo "Response: $TESTME" >>$IFL/$DEBUG
	fi
        cat $IFL/$FILES | grep  "$SEARCH" | grep -v "$RMSRCH" | grep -v ^d | awk '{printf ("%s %s\n",$4,$8)}' > $IFL/$TEMPFILE
	mv $IFL/$TEMPFILE $IFL/$FILES

else

	if [ "$TWO" = "2" ] ; then
	        echo "$DIRCOMMAND $HOST_FROM_DIR" | $NCFTPBIN $NCFTPOPT $HOST 1> $IFL/$FILES 2> $IFL/$FILES
	        TESTME=`cat $IFL/$FILES`
		if [ ! "$DEBUG" = "" ]; then
			echo "Host: $HOST" >>$IFL/$DEBUG
			echo "Directory: $HOST_FROM_DIR" >>$IFL/$DEBUG
			echo "Response: $TESTME" >>$IFL/$DEBUG
		fi
	        cat $IFL/$FILES | grep  "$SEARCH" | grep -v "$RMSRCH" | grep -v ^d | awk '{printf ("%s %s\n",$4,$9)}' > $IFL/$TEMPFILE
		mv $IFL/$TEMPFILE $IFL/$FILES

	else

	        echo "$DIRCOMMAND $HOST_FROM_DIR" | $NCFTPBIN $NCFTPOPT $HOST 1> $IFL/$FILES 2> $IFL/$FILES
	        TESTME=`cat $IFL/$FILES`
		if [ ! "$DEBUG" = "" ]; then
			echo "Host: $HOST" >>$IFL/$DEBUG
			echo "Directory: $HOST_FROM_DIR" >>$IFL/$DEBUG
			echo "Response: $TESTME" >>$IFL/$DEBUG
		fi
	        cat $IFL/$FILES | grep  "$SEARCH" | grep -v "$RMSRCH" | grep -v ^d | awk '{printf ("%s %s\n",$5,$9)}' > $IFL/$TEMPFILE
		mv $IFL/$TEMPFILE $IFL/$FILES
	fi
fi

# Making sure FTP did not exit with an error
TESTING=`echo "$TESTME" | grep "Login failed.\|User anonymous access denied.\|Not connected.\|No route to host\|Network is"`
if [ "$TESTING" ] ; then

	if [ "$ENOTICE" = "0" ] ; then
		echo "Error starting FTP with $HOST::$TESTING"
	else
		echo "Error starting FTP with $HOST:$HOST_FROM_DIR::$TESTING" | mail -s "Error starting FTP to $HOST" $ENOTICE

	fi
	if [ "$DEBUG" = "" ] ; then
		rm -f $IFL/$CRNTFILES $IFL/$FILES $IFL/$MVACTION $IFL/$TOGET
	fi
	exit 1;

fi

# Checks if there is a need to receive files
LATEST=`diff \$IFL/$CRNTFILES \$IFL/$FILES | awk '{print \$3}' | sort | uniq`

# If there are files that need to be updated/received, takes proper actions
if [ "$LATEST" = "" ] ; then

	echo "No updates, exiting..."
	if [ "$DEBUG" = "" ] ; then
		rm -f $IFL/$CRNTFILES $IFL/$FILES $IFL/$MVACTION $IFL/$TOGET
	fi
	exit 1;

else
# Giving the list of files that need updating
        echo Updating Files $LATEST

        # Removes files that are located on localhost and not on the remote host        
	if [ "$RM" = "1" ] ; then

                for i in $LATEST
                do
                        rm $i 2> $IFL/$RMACTION
                done

        # Moves files into the $OLD directory if files are located on localhost
        # and not on remote $HOST
        elif [ "$RM" = "2" ] ; then

                for i in $LATEST
                do
                        mv $i $OLD 2> $IFL/$MVACTION
                done

        fi

	# Get a new localhost directory listing
        ls -l | grep "$SEARCH" | grep -v "$RMSRCH" | grep -v ^d | awk '{printf ("%s %s\n",$5,$9)}' > $IFL/$CRNTFILES

	# Proper new files list created considering $RM
	if [ "$RM" = "0" ] ; then
	        GETTING=`diff \$IFL/$CRNTFILES \$IFL/$FILES | grep -v "< " | awk '{print \$3}' | sort | uniq | grep -v "\$NORM" `
	else
                GETTING=`diff \$IFL/$CRNTFILES \$IFL/$FILES | awk '{print \$3}' | sort | uniq | grep -v "\$NORM" `
	fi
       
	# In case no new files needed to be received and only old were moved
	if [ "$GETTING" = "" ] ; then
        	echo "No new files, exiting..."
		if [ "$DEBUG" = "" ] ; then
			rm -f $IFL/$CRNTFILES $IFL/$FILES $IFL/$MVACTION $IFL/$TOGET $IFL/$RMACTION
		fi
        	exit 1;
	fi 
	
	if [ "$ENOTICE" = "0" ] ; then
                echo "--New files from $HOST--"
        elif [ "$GETTING" ] ; then
                echo "Receiving new files from $HOST - Directory $HOST_FROM_DIR :: $GETTING ::" | mail -s "FTP from $HOST:$HOST_FROM_DIR" $ENOTICE
	fi

	rm -f $IFL/$TOGET
	for i in $GETTING
	do
		echo "get $HOST_FROM_DIR/$i" >>$IFL/$TOGET
	done
        # Record the ftp message in case there was a problem
        FTPMSG=`cat $IFL/$TOGET | $NCFTPBIN $NCFTPOPT $HOST | grep "Login failed."`

        # If there was a problem, mail it
	if [ "$FTPMSG" ] ; then
		if [ "$ENOTICE" = "0" ] ; then
			echo "Failed mirror!!"
		else
			cat $IFL/$TOGET | mail -s "Failed mirror!!" $ENOTICE
		fi
        else
		for i in $GETTING
		do
	 	       	chmod $MODE $i 2> /dev/null
	          	chown $OWNER $i 2> /dev/null
		done
        fi
	if [ "$DEBUG" = "" ] ; then
		rm -f $IFL/$CRNTFILES $IFL/$FILES $IFL/$MVACTION $IFL/$TOGET $IFL/$RMACTION
	fi
fi

#
# end cmirror script
##############################################################################
#
#EOF
#
