#!/bin/bash
# $Header: /cvs/WebShield/wsrc/files/mgmt/spam-functions,v 1.14 2004/08/03 14:25:09 bwhittak Exp $
#
# Copyright (C) 2004 Networks Associates Technology Inc. All rights reserved.
#
# functions for handling SpamAssassin

if [[ ${SPAMRPMDIR+x}${SPAMJAIL+x}${SPAMRPMEXTRA+x} == xxx ]]; then :
elif [[ -f $NETAWSS/.profile.vars ]]; then
    . $NETAWSS/.profile.vars
else
    . /var/NAIENV/.profile.vars
fi

shopt -s extglob
shopt -s nullglob

[[ :$PATH: == *:/sbin:* ]] || PATH=$PATH:/sbin
[[ :$PATH: == *:/usr/sbin:* ]] || PATH=$PATH:/usr/sbin

Die()
{
    code=$?
    echo "${*:-Dying with exit status $code}" >&2
    [[ $code != 0 ]] && exit $code
    exit 1
}

GetLatest()
{
    set -- $SPAMRPMDIR/[0-9]*/*.rpm
    [[ $# -gt 0 ]] || Die "No SpamAssassin RPM found!"
    shift $(($# -1))
    echo "${1%/*.rpm}"
}

RPMver()
{
    set -- $SPAMRPMDIR/[0-9]*/$1-version
    [[ $# -gt 0 ]] || Die "No SpamAssassin $1 version found!"
    eval cat \"\$$#\"
}

ImportSigs()
{
    local known=$SPAMRPMDIR/sigs/.known_ids
    local list cmd
    if [[ $known -nt /var/lib/rpm/Packages ]]; then
	list=$(<$known)
    else
	list=$(rpm -qa gpg-pubkey) cmd="rpm -qa gpg-pubkey >$known"
    fi
    local f
    for f in $SPAMRPMDIR/sigs/*.id; do
	[[ $list == *$(<$f)* ]] && continue
	f=${f%.id}.asc
	[[ -s $f ]] && rpm --import $f
    done
    [[ -n $cmd ]] && echo "$cmd" | wsmount
}

InstallSpamDir()
{	# copy engine from $1 and rules from $2 to be current spam RPM directory
	# stamp with $3
	# moving others out of the way
    local nver=3	# will be $SPAMRPMDIR/$nver.$stamp
    local engdir=$1
    local datdir=$2
    local stamp=$3
    # keep original $SPAMRPMDIR/0 and $nver others - $SPAMRPMDIR/[1-$nver].*
    local d
    set -- $SPAMRPMDIR/[1-9]*
    while [[ $# -ge $nver ]]; do
	d=$1; shift
	[[ -d $d ]] && rm -rf $d
    done
    # do the copy
    (
	for t in $SPAMRPMDIR/T.*; do
	    rm -rf $(find $t -prune -ctime +0 -print)
	done
	target=$SPAMRPMDIR/T.$stamp
	[[ ! -e $target ]] || exit
	trap "rm -rf $target" EXIT
	mkdir -p "$target" || exit
	for f in $(<"$engdir/engine-list") engine-list engine-version; do
	    ln "$engdir/$f" "$target" 2>/dev/null ||
		cp -a "$engdir/$f" "$target" || exit
	done
	for f in $(<"$datdir/rules-list") rules-list rules-version; do
	    ln "$datdir/$f" "$target" 2>/dev/null ||
		cp -a "$datdir/$f" "$target" || exit
	done
	n=0
	# rename the new series of directories
	for d in "$@" "$target"; do
	    t=$SPAMRPMDIR/$((++n))${d#$SPAMRPMDIR/?}
	    [[ -d $t ]] || mv "$d" "$t" || exit
	done
    )
    return
}

DestroySpamJail()
{
    local jail=$1
    [[ -d $jail ]] || return 0
    [[ ! ${jail}/spamassassin -ef /wk/spamassassin ]] ||
	umount ${jail}/spamassassin || return 1
    [[ !  $jail/dev -ef /var/dev ]] || umount $jail/dev || return 1
    rm -rf $jail
}

MakeSpamJail()
{
    local jail=${SPAMJAIL:=/var/spamjail}
    case $1 in
	(-j) jail=$2; shift 2;;
    esac
    if [[ $# -lt 1 ]]; then
	latest_rpms=$(GetLatest) || return
	set -- $latest_rpms/*.rpm $SPAMRPMEXTRA/*.rpm
    fi

    ImportSigs

    local com=$(type -p sh bash host ping
		echo /usr/lib/libnss*.so /lib/libnss*.so /bin/pwd
		rpm -ql expat | perl -lne 'print if -f')
    local lib='
    /usr/lib/libexpat.so.0
    /lib/libc.so.6
    /lib/libnsl.so.1
    /lib/libtermcap.so.2
    /lib/libcrypt.so.1
    /lib/libnss_files.so.1
    /usr/lib/libgdbm.so.2
    /lib/libresolv.so.2
    /lib/libnss_files.so.2
    /lib/libm.so.6
    /lib/libdl.so.2
    /lib/ld-linux.so.2
    '
    local etc='
    /etc/hosts
    /etc/resolv.conf
    /etc/protocols
    /etc/nsswitch.conf
    /etc/passwd
    /etc/group
    /usr/lib/locale/locale-archive
    '
    local spam='
    /config/wsxmlconf/spamconfig
    /etc/mail/spamassassin
    /etc/sysconfig/spamassassin
    '

    DestroySpamJail $jail || return 1
    mkdir $jail && tar -zxf $SPAMRPMDIR/spamjail.tgz -C $jail || Die
    find $com $lib $etc -depth -print0 |
	perl -n0e 'while (($f{join " ",(lstat)[0,1]} ||= print) , -l _){
			$s = readlink() . "\0";
			if ($s !~ /^\//) { s=^(.*\/)?.*$=$1$s= }
			else { $_ = $s }
		    }' |
	cpio -pdm0 $jail
    mkdir -p /wk/spamassassin/parameters > /dev/null 2>&1
    touch /wk/spamassassin/parameters/default.prefs
    chmod -R 777 /wk/spamassassin
    mount --bind /wk/spamassassin ${jail}/spamassassin
    mount --bind /var/dev $jail/dev
    rpm --root $jail -iv "$@" || return 1
    find $spam -depth -print0 | cpio -pdmu0 $jail
    local f stamp=$jail/.rpmtime	# date of most recent RPM in jail
    for f do [[ $f -nt $stamp ]] && touch -r "$f" "$stamp"; done
    chmod -R a+rX $jail
}

MakeRulesInfo()
{
    local jail=${SPAMJAIL:=/var/spamjail}
    case $1 in
	(-j) jail=$2; shift 2;;
    esac
    local stamp=$jail/.rpmtime	# date of most recent RPM in jail
    # set up for generating rule_info.xml files
    local maxtries=3	# times to retry spamrules
    local opt=$(OPTIONS='-x -local'
		. /etc/sysconfig/spamassassin; echo "$OPTIONS" |
		    sed 's/-d\>//; s/--daemonize\>//')
    local port=1783	# first guess at a port to use
    # for each language
    local d p lang busy rxml try
    for d in ${*:-$NETAWSS/ui/menu/*/}; do
	d=${d%/} lang=${d##*/} rxml=$XMLCONFDIR/eservices/$lang/rules_info.xml
	[[ $rxml -nt $stamp ]] && grep -qsw "$lang" "$rxml" && continue
	[[ -d ${rxml%/*} ]] || mkdir -p ${rxml%/*}
	# find the ports already busy
	busy=$'\n'$(netstat -ltn | sed -n 's/^tcp[^:]*:\([0-9]*\).*/\1/p')$'\n'
	# pick a free port
	while [[ $'\n'$busy$'\n' == *$'\n'$port$'\n'* ]]; do ((++port)); done
	(
	    trap 'kill -0 $p 2>/dev/null && kill $p' EXIT
	    LANGUAGE=$lang LANG=$lang LC_ALL=$lang \
		chroot "$jail" mcafee-spamd $opt -p $port -m 1&
	    p=$!
	    sleep 5	# pause for the server to get ready
	    try=0
	    while kill -0 $p && (( try++ < maxtries )); do
		if /opt/NETAeSCM/eplugin/spamrules \
			-sdk /usr/lib \
			-lang $lang \
			-conf localhost:$port \
			>$rxml-new
		then
		    mv $rxml-new $rxml
		    break
		else
		    rm -f $rxml-new
		    echo retry $try $lang
		fi
	    done
	    kill $p
	    wait
	)
    done
}

TestSpamRPMs()
{
    local jail=/tmp/spamtest.$$
    local opt='-x --local'
    [[ -f /etc/sysconfig/spamassassin ]] &&
	opt=$(OPTIONS=$opt; . /etc/sysconfig/spamassassin; echo "$OPTIONS")
    MakeSpamJail -j "$jail" "$@" 2>/dev/null &&
	LC_ALL=C chroot "$jail" /usr/bin/mcafee-spamd --lint $opt
    local ret=$?
    DestroySpamJail $jail
    return $ret
}

XMLele()
{
    perl -we '
	$e = shift;
	if (! @ARGV) { print "<$e/>\n"; exit; }
	print "<$e>\n";
	for (@ARGV) {
	    s{([^\w !*,..:;=?/\()\-+[\]\{\}])}{"&#".ord($1).";"}xsge;
	    print "$_\n";
	}
	print "</$e>\n";
    ' "$@";
}
XMLdie()
{
    code=$?
    [[ $code != 0 ]] || code=1
    [[ $# -gt 0 ]] || set -- "Command failed with exit status $code}"
    XMLele Error "$@"
    printf '%s\n' "$@" | logger -t "${0##*/}[$$]"
    exit $code
}
