#!/usr/bin/perl -w
#
# update-qmail
# John Simpson <jms1@jms1.net> 2005-06-24
#
# rebuilds qmail control files when/if needed. this command should be
# called from some other script (like a "qmail-updater" service) whenever
# a change is made in the appropriate files.
#
# 2006-04-11 jms1 - adding "auth.cdb" file.
#
# 2006-04-12 jms1 - adding "force" support.
#
# 2007-01-25 jms1 - adding the logic to call a "push" program, in case data
#   needs to be sent to other servers. thanks to Chad Berg for reminding me
#   that this wasn't in there yet.
#
# 2007-06-18 jms1 - mkvalidrcptto now supports a "-c" option which will build
#   the validrcptto.cdb file by itself, including the "diff" logic. changing
#   this script to use that.
#
# 2008-05-06 jms1 - mkauth also supports a "-c" option. i meant to add it
#   to this script at the time, but real life intruded... adding it now,
#   while setting up the script on a client's machine.
#
###############################################################################
#
# Copyright (C) 2005,2006,2007,2008 John Simpson.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2, 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# or visit http://www.gnu.org/licenses/gpl.txt
#
###############################################################################

require 5.003 ;
use strict ;

###############################################################################
#
# configuration

my $vq  = "/var/qmail"  ;
my $vqc = "$vq/control" ;
my $vqu = "$vq/users"   ;

my $smtpd_user		= "qmaild" ; # userid that qmail-smtpd runs as

my $mkvalidrcptto	= "/usr/local/bin/mkvalidrcptto" ;
my $mkauth		= "/usr/local/bin/mkauth" ;

my $push_cmd		= "" ;

###############################################################################
#
# global variables

my ( @pw , $smtp_uid , $smtp_gid , @s ) ;

my $force		= 0 ;
my $restart		= 0 ;
my $do_push		= 0 ;

###############################################################################

sub mtime($)
{
	my @s = stat ( $_[0] ) ;
	return ( ( $#s > -1 ) ? $s[9] : -1 ) ;
}

###############################################################################
###############################################################################
###############################################################################

print "Starting\n" ;

if ( ( $ARGV[0] || "" ) eq "force" )
{
	print "Running in FORCE mode\n" ;
	$force = 1 ;
	$do_push = 1 ;
}

@pw = getpwnam ( $smtpd_user ) ;
$smtp_uid = ( $pw[2] || die "Can\'t find uid for \"$smtpd_user\"\n" ) ;
$smtp_gid = ( $pw[3] || die "Can\'t find gid for \"$smtpd_user\"\n" ) ;

umask 022 ;

########################################
# work-around for vpopmail bug (vdeldomain sometimes leaves
# the "rcpthosts" file with bad permissions)

@s = stat ( "$vqc/rcpthosts" ) ;
if ( $#s < 0 )
{
	print "Creating non-existent $vqc/rcpthosts\n" ;
	open ( O , ">$vqc/rcpthosts" ) ;
	close O ;
	$do_push = 1 ;
}

if ( ( ( $s[2] || 0 ) & 0777 ) != 0644 )
{
	print "chmod 0644 $vqc/rcpthosts\n" ;
	chmod ( 0644 , "$vqc/rcpthosts" ) ;
}

########################################
# build vqu/cdb from vqu/assign

print "Checking users/assign and users/cdb\n" ;

if ( -f "$vqu/assign" )
{
	if ( $force || ( mtime ( "$vqu/assign" ) > mtime ( "$vqu/cdb" ) ) )
	{
		print "  Running qmail-newu\n" ;
		system "$vq/bin/qmail-newu" ;
	}
}
elsif ( -f "$vqu/cdb" )
{
	print "  Deleting $vqu/cdb"
		. " since $vqu/assign does not exist\n" ;
	unlink "$vqu/cdb" ;
}

########################################
# build vqc/morercpthosts.cdb from vqc/morercpthosts

print "Checking morercpthosts and morercpthosts.cdb\n" ;

if ( -f "$vqc/morercpthosts" )
{
	if ( $force || ( mtime ( "$vqc/morercpthosts" ) >
		mtime ( "$vqc/morercpthosts.cdb" ) ) )
	{
		print "  Running qmail-newmrh\n" ;
		system "$vq/bin/qmail-newmrh" ;
		$do_push = 1 ;
	}
}
elsif ( -f "$vqc/morercpthosts.cdb" )
{
	print "  Deleting morercpthosts.cdb"
		. " since morercpthosts does not exist\n" ;
	unlink "$vqc/morercpthosts.cdb" ;
	$do_push = 1 ;
}

########################################
# if virtualdomains or locals has changed,
#   we will need to send a HUP to qmail-send

$restart = 0 ;

print "Checking virtualdomains\n" ;

if ( -f "$vqc/virtualdomains" )
{
	if ( $force || ( mtime ( "$vqc/virtualdomains" ) >
		mtime ( "$vqc/virtualdomains.last" ) ) )
	{
		print "  virtualdomains has changed\n" ;
		unlink "$vqc/virtualdomains.last" ;
		open ( O , ">$vqc/virtualdomains.last" ) ;
		close O ;
		$restart = 1 ;
		$do_push = 1 ;
	}
}

print "Checking locals\n" ;

if ( -f "$vqc/locals" )
{
	if ( $force || ( mtime ( "$vqc/locals" ) >
		mtime ( "$vqc/locals.last" ) ) )
	{
		print "  locals has changed\n" ;
		unlink "$vqc/locals.last" ;
		open ( O , ">$vqc/locals.last" ) ;
		close O ;
		$restart = 1 ;
		$do_push = 1 ;
	}
}

if ( $restart )
{
	print "Sending HUP to qmail-send\n" ;
	system "killall -HUP qmail-send" ;
}

########################################
# build validrcptto.cdb if needed

print "Checking validrcptto.cdb\n" ;

if ( -f "$vqc/validrcptto.cdb" )
{
	umask 027 ;

	print "  Running $mkvalidrcptto\n" ;

	my $ot = mtime ( "$vqc/validrcptto.cdb" ) ;
	system "$mkvalidrcptto -c $vqc/validrcptto.cdb" ;
	my $nt = mtime ( "$vqc/validrcptto.cdb" ) ;

	if ( $nt != $ot )
	{
		print "    Change detected\n" ;
		$do_push = 1 ;
	}
	else
	{
		print "    No change detected\n" ;
	}
}

########################################
# build auth.cdb if needed

print "Checking auth.txt and auth.cdb\n" ;

if ( -f "$vqc/auth.cdb" )
{
	umask 027 ;

	print "  Running $mkauth\n" ;

	my $ot = mtime ( "$vqc/auth.cdb" ) ;
	system "$mkauth -c $vqc/auth.cdb" ;
	my $nt = mtime ( "$vqc/auth.cdb" ) ;

	if ( $nt != $ot )
	{
		print "    Change detected\n" ;
		$do_push = 1 ;
	}
	else
	{
		print "    No change detected\n" ;
	}
}

########################################
# handle push (if needed)

if ( $do_push && $push_cmd && -e $push_cmd )
{
	print "Calling program to push data to external servers\n" ;
	print "/-----\n" ;
	open ( I , "$push_cmd |" )
		or die "Cannot run \"$push_cmd\": $!\n" ;
	map { print "| $_" } <I> ;
	close I ;
	print "\\-----\n" ;
}

########################################
# outta here

print "Done\n" ;
exit 0 ;