#!/bin/sh -e
#
# Update Sendmail databases for Debian
#
# Copyright (c) 1999, Richard Nelson <cowboy@debian.org>.
# Time-stamp: <1999/05/19 10:00:00 cowboy>
#
# Notes (to all):
#   * assumes makemap dbtype /etc/mail/database < /etc/mail/database
#
# Notes (to self):
#   * changes made herein *must* be reflected in parsemc,updatedb,debian.m4
#   * multiple db options not supported
#   * userdb can also have multiple databases and then a forward!
#   * need sendmail stop/start
#
set -e 

# List of db features
db_features="access_db bitdomain domaintable genericstable \
	     mailertable uucpdomain virtusertable use_ct_file use_cw_file";
export db_features;
# kluge for userdb, cr,ct,and cw files support
db_files="confCR_FILE confUSERDB_SPEC ALIAS_FILE";
db_files="sendmail.mc $db_features $db_files";
export db_files;

# control amount of output
verbosity=0;

# flag used to ensure only one newaliases command is run
newaliases_run=0;

# flag used to indicate a dataset has been moved, may need another update
changed=0;

# max return code
max_rc=0;
missing_rqd=0;
missing_opt=0;
m4_errors=0;

#-------------------------------------------------------------
# Initial update of sendmail.mc/databases
#-------------------------------------------------------------
initial () {
	if [ $verbosity -gt 1 ]; then
		echo "initial()";
		fi;

	# Make sure not using text mailertable (it doesn't work)
	if (grep -q "^[[:space:]]*FEATURE(mailertable, \`text /etc/mail/mailertable')dnl" /etc/mail/sendmail.mc); then
	sed "s?FEATURE(mailertable, \`text /etc/mail/mailertable')dnl?FEATURE(mailertable)dnl?g" \
		/etc/mail/sendmail.mc > /etc/mail/sendmail.mc.new
	chown root.mail /etc/mail/sendmail.mc.new
	chmod 0664 /etc/mail/sendmail.mc.new
	mv /etc/mail/sendmail.mc.new /etc/mail/sendmail.mc
	fi;

	# Make sure the data file is current using the version of
	# parsemc that corresponds to this version of updatedb
	$(dirname $0)/parsemc || true
	}

#-------------------------------------------------------------
# Handle found databases
#-------------------------------------------------------------
is_found () {
	if [ $verbosity -gt 1 ]; then
		echo "is_found()";
		fi;
	process=1;

	case "$dbfeat" in
	ALIAS_FILE)
		if [ ! -f /etc/aliases -a -f /etc/mail/aliases ]; then
			echo "Linking /etc/aliases to /etc/mail/aliases"
			ln -sf mail/aliases /etc/aliases
			fi
		;;
	esac
	}

#-------------------------------------------------------------
# Handle missing databases:
#    moving  /etc/xxx to /etc/mail/xxx
#    rename  /etc/mail/xxx to /etc/mail/yyy
#-------------------------------------------------------------
is_not_found () {
	if [ $verbosity -gt 1 ]; then
		echo "is_not_found()";
		fi;
	process=0;

	case "$dbfeat" in
	use_cw_file)
		if [ -f /etc/local-host-names ]; then
			if [ ! -L /etc/local-host-names ]; then
			   echo "Moving /etc/local-host-names to /etc/mail/."
			   mv /etc/local-host-names /etc/mail/
			   process=1;
			else
			   echo "/etc/local-host-names is a link," \
				"move it to /etc/mail/local-host-names"
			   missing_rqd=`expr $missing_rqd + 1`;
			   fi;
		elif [ -f /etc/mail/sendmail.cw ]; then
			echo "Renaming sendmail.cw to local-host-names."
			mv /etc/mail/sendmail.cw /etc/mail/local-host-names
			process=1;
		elif [ -f /etc/sendmail.cw ]; then
			if [ ! -L /etc/sendmail.cw ]; then
				echo "Moving /etc/sendmail.cw to /etc/mail/"
				mv /etc/sendmail.cw /etc/mail/local-host-names
				process=1;
			else
				echo "/etc/sendmail.cw is a link," \
					"move it to /etc/mail/local-host-names"
				missing_rqd=`expr $missing_rqd + 1`;
				fi
		elif [ "$dbopts" = "-o" ]; then
			echo "Informational: $dbfeat source" \
				"file not found: $dbname"
			missing_opt=`expr $missing_opt + 1`;
		else
			echo "Error: $dbfeat source file not found: $dbname"
			missing_rqd=`expr $missing_rqd + 1`;
			fi
		;;
	use_ct_file)
		if [ -f /etc/trusted-users ]; then
			if [ ! -L /etc/trusted-users ]; then
			   echo "Moving /etc/trusted-users to /etc/mail/."
			   mv /etc/trusted-users /etc/mail/
			   process=1;
			else
			   echo "/etc/trusted-users is a link," \
				"move it to /etc/mail/trusted-users"
			   missing_rqd=`expr $missing_rqd + 1`;
			   fi;
		elif [ -f /etc/mail/sendmail.ct ]; then
			echo "Renaming sendmail.ct to trusted-users."
			mv /etc/mail/sendmail.ct /etc/mail/trusted-users
			process=1;
		elif [ -f /etc/sendmail.ct ]; then
			if [ ! -L /etc/sendmail.ct ]; then
				echo "Moving /etc/sendmail.ct to /etc/mail/"
				mv /etc/sendmail.ct /etc/mail/trusted-users
				process=1;
			else
				echo "/etc/sendmail.ct is a link," \
                                        "move it to /etc/mail/trusted-users"
				missing_rqd=`expr $missing_rqd + 1`;
				fi
		elif [ "$dbopts" = "-o" ]; then
			echo "Informational: $dbfeat source" \
				"file not found: $dbname"
			missing_opt=`expr $missing_opt + 1`;
		else
			echo "Error: $dbfeat source file not found: $dbname"
			 missing_rqd=`expr $missing_rqd + 1`;
		fi
		;;
	ALIAS_FILE)
		if [ -f /etc/$dbsname ]; then
			if [ ! -L /etc/$dbsname ]; then
			  echo "Moving /etc/aliases to /etc/mail/aliases "
		  	  echo "and linking /etc/aliases to /etc/mail/aliases"
			  echo "This preserves current function/abilities"
			  mv -f /etc/$dbsname     /etc/mail/
			  ln -sf mail/aliases /etc/aliases
			  #ln -sf /etc/mail/aliases /etc/aliases
			  if [ -f /etc/$dbsname.db ]; then
				  mv -f /etc/$dbsname.db  /etc/mail/
				  fi
			  if [ -f /etc/$dbsname.pag ]; then
				  mv -f /etc/$dbsname.pag /etc/mail/
				  fi
			  if [ -f /etc/$dbsname.dir ]; then
				  mv -f /etc/$dbsname.dir /etc/mail/
				  fi
			  process=1;
			  changed=1;
			else
			  echo "/etc/$dbsname is a link, move it to $dbname"
			  missing_rqd=`expr $missing_rqd + 1`;
			  fi;
		elif [ "$dbopts" = "-o" ]; then
			echo "Informational: $dbfeat source" \
				"file not found: $dbname"
			missing_opt=`expr $missing_opt + 1`;
		else
			echo "Error: $dbfeat source file not found: $dbname"
			missing_rqd=`expr $missing_rqd + 1`;
			fi;
		;;
	m4)
		 if [ -f /etc/$dbsname ]; then
			if [ ! -L /etc/$dbsname ]; then
			  echo "Moving /etc/sendmail.{mc,cf} to /etc/mail/";
			  mv -f /etc/sendmail.mc  /etc/mail/
			  if [ -f /etc/sendmail.cf ]; then
				  mv -f /etc/sendmail.cf  /etc/mail/
				  fi
			  process=1;
			else
			  echo "/etc/$dbsname is a link, move it to $dbname"
			  missing_rqd=`expr $missing_rqd + 1`;
			  fi;
		elif [ "$dbopts" = "-o" ]; then
			echo "Informational: $dbfeat source" \
				"file not found: $dbname"
			missing_opt=`expr $missing_opt + 1`;
		else
			echo "Error: $dbfeat source file not found: $dbname"
			missing_rqd=`expr $missing_rqd + 1`;
			fi;
		;;
	*)
		if [ -f /etc/$dbsname ]; then
			if [ ! -L /etc/$dbsname ]; then
			  echo "Moving /etc/$dbsname{,.*} to $dbname";
			  mv -f /etc/$dbsname     /etc/mail/ 
			  if [ -f /etc/$dbsname.db ]; then
				  mv -f /etc/$dbsname.db  /etc/mail/
				  fi
			  if [ -f /etc/$dbsname.pag ]; then
				  mv -f /etc/$dbsname.pag /etc/mail/
				  fi
			  if [ -f /etc/$dbsname.dir ]; then
				  mv -f /etc/$dbsname.dir /etc/mail/
				  fi
			  process=1;
			else
			  echo "/etc/$dbsname is a link, move it to $dbname"
			  missing_rqd=`expr $missing_rqd + 1`;
			  fi;
		elif [ "$dbopts" = "-o" ]; then
			echo "Informational: $dbfeat source" \
				"file not found: $dbname"
			missing_opt=`expr $missing_opt + 1`;
		else
			echo "Error: $dbfeat source file not found: $dbname"
			missing_rqd=`expr $missing_rqd + 1`;
			fi;
		;;
	esac
	}

#-------------------------------------------------------------
# Handle empty databases
#-------------------------------------------------------------
is_empty () {
	if [ $verbosity -gt 1 ]; then
		echo "is_empty()";
		fi;
	if [ $process -eq 1 ]; then
		if [ "$dbtype" != "-" ]; then
			rm -f $dbname.db
			rm -f $dbname.pag
			rm -f $dbname.dir
			fi
		case "$dbfeat" in
		*)
			echo "Informational: $dbfeat file empty: $dbname"
			if [ "$dbopts" = "-o" ]; then
				process=0;
				fi;
			;;
		esac
		fi
	}

#-------------------------------------------------------------
# Handle no data (exists, but is only comments) databases
#-------------------------------------------------------------
is_comments () {
	if [ $verbosity -gt 1 ]; then
		echo "is_comments()";
		fi;
	if [ $process -eq 1 ]; then
		if [ "$dbtype" != "-" ]; then
			rm -f $dbname.db
			rm -f $dbname.pag
			rm -f $dbname.dir
			fi
		case "$dbfeat" in
		*)
			echo "Informational: $dbfeat no data: $dbname"
			if [ "$dbopts" = "-o" ]; then
				process=0;
				fi;
			;;
		esac
		fi
	}

#-------------------------------------------------------------
# Handle normal databases (exists, has data)
#-------------------------------------------------------------
is_normal () {
	if [ $verbosity -gt 1 ]; then
		echo "is_normal()";
		fi;
	if [ $process -eq 1 -a $max_rc -eq 0 ]; then
		if [ "$dbtype" != "-" ]; then
			case "$dbtype" in
			btree)
				makemap -d $dbtype $dbname.db < $dbname
				chown root.mail $dbname.db
				chmod 0664 $dbname.db
				;;
			dbm | btree | hash)
				makemap $dbtype $dbname.db < $dbname
				chown root.mail $dbname.db
				chmod 0664 $dbname.db
				;;
			text)
				true;
				;;
			newaliases)
				if [ $newaliases_run -eq 0 -o \
				     $changed -eq 1 ]; then
					newaliases_run=1
					newaliases
					fi
				chown root.mail $dbname.db
				chmod 0664 $dbname.db
				;;
			m4)
				echo "Generating /etc/mail/sendmail.cf ..."
				m4 \
				   /usr/share/sendmail/sendmail.cf/m4/cf.m4 \
				   /etc/mail/sendmail.mc \
				   > /etc/mail/sendmail.cf.new \
				   2> /etc/mail/sendmail.cf.errors
				chown root.mail /etc/mail/sendmail.cf.new
				chmod 0644 /etc/mail/sendmail.cf.new
				if [ ! -s /etc/mail/sendmail.cf.errors ]; then
					rm /etc/mail/sendmail.cf.errors;
				else
					cat /etc/mail/sendmail.cf.errors;
					echo " ";
					m4_errors=1;
					fi;
				# Can't tell if the errors are fatal or not ;-{
				mv -f /etc/mail/sendmail.cf.new \
					/etc/mail/sendmail.cf
				;;
			*)
				echo "$dbtype map not done herein"
				;;
			esac
			fi;
		fi;
	}

#-------------------------------------------------------------
# Handle completion
#-------------------------------------------------------------
final () {
	if [ $verbosity -gt 1 ]; then
		echo "final()";
		fi;
	}


# status report if not for single database
if [ -z "$1" ]; then
	echo "Checking sendmail.cf and databases."
	fi; 

initial

for file in $db_files; do \
	line=$(egrep -e "^[[:space:]]*$file" /etc/mail/databases || true);
	while ([ "$line" != "" ]); do
		str=$(echo "$line" | cut -d "
" -f 1)
		line=$(echo "$line" | cut -d "
" -f 2)

		# Strip line back into four pieces: feature, type, opts, name
		dbfeat=$(echo "$str" | cut -d ":" -f 1)
		dbtype=$(echo "$str" | cut -d ":" -f 2)
		dbopts=$(echo "$str" | cut -d ":" -f 3)
		dbname=$(echo "$str" | cut -d ":" -f 4)
		dbregx=$(echo "$str" | cut -d ":" -f 5)
		if [ $(dirname "$dbname") = "/etc/mail" ]; then
			dbsname=$(basename "$dbname")
		elif [ $(dirname "$dbname") = "/etc/" ]; then
			dbsname=$(basename "$dbname")
		else
			dbsname="$dbname"
			fi;
		if [ "$dbopts" = "-" ]; then
			dbopts="";
			fi;
		if [ "$dbregx" = "-" ]; then
			dbregx="";
			fi;

		# Check to see if we're doing one, or all
		if [ ! -z "$1" ]; then
			if [ "$1" = "$dbfeat" -o \
			     "$1" = "$dbname"  -o \
			     "$1" = "$dbsname" ]; then
				true;
			else
				continue;
				fi;
			fi;

		changed=0;
		if [ $verbosity -gt 0 ]; then
			echo "Processing $dbname...";
			fi;


		# Check for database existance
		if [  -f "$dbname" ]; then
			is_found
		else
			is_not_found
			fi;

		# Check for something in database
		if [ ! -s "$dbname" ]; then
			is_empty
			fi;

		# Check for real data (not just comments)
		if [ $process -eq 1 ]; then
			if ! egrep -q -e "^[[:space:]]*[^$\#]" $dbname; then
				is_comments
				fi;
			fi;

		# Finally, assume a normal file...
		is_normal
		
		done;
	done;

final

# Final notices...
if [ $missing_opt -ne 0 ]; then
	echo " "
	echo "Informational: $missing_opt optional database(s) sources"
	echo "               were not found, please investigate."
	fi;
if [ $missing_rqd -ne 0 ]; then
	echo " "
	echo "Error: $missing_rqd required database(s) sources"
	echo "       were not found, correct this before starting sendmail!"
	if [ $max_rc -lt 2 ]; then
		max_rc=2;
		fi;
	fi;
if [ $missing_opt -ne 0 -o $missing_rqd -ne 0 ]; then
	echo " "
	echo "$0 assumes that databases, and their source datasets"
	echo "have the same base name (not counting the .db).  If this is not"
	echo "true, $0 can not rebuild your databases to make sure"
	echo "they will work with the newer sendmail.  You will have to do this"
	echo "yourself - before starting sendmail."
	echo " "
	fi;
if [ $m4_errors -ne 0 ]; then
	echo " "
	echo "Warning: These messages were issued while creating sendmail.cf"
	echo "         make sure they are benign before starting sendmail!"
	echo " "
	cat /etc/mail/sendmail.cf.errors;
	echo " "
	if [ $max_rc -lt 2 ]; then
		max_rc=2;
		fi;
	fi;
exit $max_rc
