#!/bin/sh
# $Id: smtpcnf.sh,v 1.33 2007/02/14 03:39:33 ca Exp $
# Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers.
#	All rights reserved.
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
#
# test program running the full system with a configuration file:
# qmgr, smar, smtpc, smtps
# using smtps and smtpc from statethreads/examples as source/sink
# this program tests some failure modes, e.g., temporary/permanent
# errors from the sink.
#
# This is a fairly versatile test program that can be used by other
# scripts.  It also accepts filenames that contain the expected content
# of DEFEDB such that a caller can pass its own data.
#
test -s stop && exit 1

# source directory of this (and other) shell script
SD=`dirname $0`
if test "${SD}" = "."
then
   SD=../chkmts
fi
#
EDBOUT=edb.out
EDBROUT=edbr.out
EDBOK=edbr.ok
EDBOKIN=""
# default settings
TAS=1
THREADS=1
RCPTS=1
TOTAL=1
TR=1
TRQS=1
TTAS=-1
MULTIPLE=1
INIT=true
RMDEFEDB=true
RMIBDB=true
RCPTADDR=""
SENDER="a@b.c"
# see common.sh!
CONF="-f smx.conf"

# additional SMAR options
AROPTS=""
# after this amount of time the SMTP sink will accept all mails
OKDELAY=""
SINK=smtps2
# other options to pass to SMTP sink
SINKOPTS=""
SINKPORT=""
WAIT4SINK=false
# other options to pass to smtpc2 (sender/source)
SRCOPTS=""
SOURCE=""
# time to sleep after running test before terminating programs
SLEEP=4
# debug flags
D="-d 7"
LGLVL=""
SNDUSR1=false
LMTPSINK=""
LMTPSINKOPTS=""
LMTPRCPTS=""
# server options
SRVOPTS=${MTA_SERVER_OPTIONS}
# milter
PMILTER=false
PMILTOPTS=""
PMILTPRG=../libpmilter/t-pmilter-0
STOPMTS=true
SMTPCDELAY=0

# version of output files
V=0

# works only with ksh on OSF/1: how to test for it?
while getopts 13:A:a:B:C:c:Dd:E:e:F:f:i:Ik:LMm:n:O:o:P:p:Q:R:rS:s:T:t:v:V:W:wX:x:Y:y:Z:z FLAG
do
  case "${FLAG}" in
    1) SNDUSR1=true;;
    3)
       # remove the socket
       rm -f ${OPTARG};
       LMTP="-L ${OPTARG}"
       LMTPSINK="unix:${OPTARG}";;
    A) TOTAL="${OPTARG}";;
    a) AROPTS="${AROPTS} ${OPTARG}";;
    B) LMTPSINKOPTS="${OPTARG}";;
    c) SRCOPTS="${SRCOPTS} ${OPTARG}";;
    C) COPTS="${OPTARG}";;
    d) D="-d ${OPTARG}";;
    D) INIT=false;;
    E) TR="${OPTARG}";;
    e) LMTPRCPTS="${OPTARG}";;
    f) CONF="-f ${OPTARG}";;
    F) SRCPORT="${OPTARG}";;
    i) DELAY_TRY="${OPTARG}";;
    I) RMIBDB=false;;
    k) SINKPORT="${OPTARG}";;
    L) SINKOPTS="${SINKOPTS} -L unix:lmtpsock";;
    m) MULTIPLE="${OPTARG}";;
    M) RMDEFEDB=false;;
    n) RCPTS="${OPTARG}";;
    o) OKDELAY="-o ${OPTARG}";;
    O)
	# expected results for t-edbr (DEFEDB)
       EDBOKIN="${OPTARG}"
       ;;
    p) PMILTPRG="${OPTARG}";;
    P)
       PMILTOPTS="${PMILTOPTS} ${OPTARG}"
       PMILTER=true
       ;;
    Q) QOPTS="${OPTARG}";;
    R) RCPTADDR="${RCPTADDR} -R${OPTARG}";;
    r)
       SINK="smtps3"
       SMTPDIR="smtpdir/"
       SINKOPTS="-C ${SMTPDIR} ${SINKOPTS}"
       export SMTPDIR
       ;;
    s) SLEEP="${OPTARG}";;
    S) SENDER="${OPTARG}";;
    T) TAS="${OPTARG}";;
    t) THREADS="${OPTARG}";;
    v) LGLVL="-v ${OPTARG}";;
    V) SRVOPTS="${OPTARG}";;
    w) WAIT4SINK=true;;
    W) SMTPCDELAY="${OPTARG}";;
    x) TTAS="${OPTARG}";;
    X) TRQS="${OPTARG}";;
    Y) SINKOPTS="${SINKOPTS} ${OPTARG}";;
    Z) SOURCE="${OPTARG}";;
    z) STOPMTS=false;;
    ?)
       echo "$0: unknown option ${FLAG}"
       echo "$0: options:"
       echo "-1         send USR1 signal to all MTS components before shutdown"
       echo "-3 socket  also start LMTP sink (smtps3) listening on socket"
       echo "-A n       expected number of mails sent by source"
       echo "-a opts    use opts for smar"
       echo "-B opts    use opts for smtps3 (requires -3 socket)"
       echo "-C opts    additional SMTP client options"
       echo "-c opts    additional options for source (sender) program"
       echo "-d n       debug level"
       echo "-D         do not initialize test environment"
       echo "-E n       expected number of recipients in sink"
       echo "-e n       expected number of recipients in LMTP sink"
       echo "-f conf    use conf as configuration file [$CONF]"
       echo "-I         do not remove IBDB"
       echo "-i n       initial delay for retries in QMGR scheduler"
       echo "-k port    use port for sink"
       echo "-m n       send n messages in separate sessions"
       echo "-M         do not remove defedb"
       #echo "-n n      n transactions are expected"
       echo "-o n       after n seconds accept all mails in SMTP sink"
       echo "-O file    file contains expected results from t-edbr-0"
       echo "-P opts    run pmilter test program with opts"
       echo "-p prg     use pmilter test program prg instead of ${PMILTPRG}"
       echo "-Q opts    options for QMGR"
       echo "-R address recipient address"
       echo "-r         use SMTP sink smtps3"
       echo "-s n       sleep n seconds before terminating system"
       echo "-S address sender address"
       #echo "-T n      n transactions"
       #echo "-t n      n threads"
       echo "-v n       set loglevel to n"
       echo "-V opts    additional SMTP server options"
       echo "-w         wait for sink to terminate (requires extra sink options: -Y)"
       echo "-W n       wait n seconds before starting smtpc"
       echo "-X n       n requests are expected in sink"
       echo "-Y opts    options for SMTP sink"
       echo "-Z source  source (sender) program"
       echo "-z         Do not stop MTS after test"
       exit 1
       ;;
  esac
done
shift `expr ${OPTIND} - 1`

if ${WAIT4SINK}
then
  if test X"${SINKOPTS}" != "X"
  then
    :
  else
    echo "$0: cannot wait for sink without extra sink options"
    exit 2
  fi
fi

#
# setup/initialize system
. ${SD}/mta-setup.sh
#

# set SRCPORT if not done yet; this must be done after mta-setup
if test "X"${SRCPORT} = X
then
  SRCPORT=${SRVPORT}
fi

# set  if not done yet; this must be done after mta-setup
if test "X"${SINKPORT} = X
then
  SINKPORT=${SNKPORT}
fi

killit()
{
if test -s ${PIDS}
then
  # stop MTA components
  for i in `cat ${PIDS}`
  do
    kill ${i}
  done
fi
# ----------------
# thanks kids for not following the POSIX standard...
if test X"`uname`" = "XLinux"
then
  killall qmgr smar
  if ${PMILTER}
  then
    killall ${PMILTPRG}
  fi
fi
if test X"${SRVPID}" != "X"
then
  kill -TERM ${SRVPID}
fi
if test X"${LMTPPID}" != "X"
then
  kill -TERM ${LMTPPID}
fi
exit 1
}

SRVPID=""
LMTPPID=""
# store the PIDs for the started programs
rm -f ${PIDS}
trap killit 2 15

SRCPRG=${STE}/smtpc
if test X"${SOURCE}" != "X"
then
  SRCPRG=${STE}/${SOURCE}
fi

if ${PMILTER}
then
  if test -x ${PMILTPRG}
  then
    ${PMILTPRG} ${PMILTOPTS} > m${V}.log 2>&1 &
    PMID=$!
    echo ${PMID} >> ${PIDS}
    if ${STOPMTS}
    then
      :
    else
      echo ${PMID} >> ${PMIDS}
    fi
  else
    echo "$0: ${PMILTPRG} not found"
    exit 1
  fi
fi

# start SMTP sink
${STE}/${SINK} ${PIPELINING} ${SINKOPTS} ${OKDELAY} -i -l . -b ${H}:${SINKPORT} > ${SRVL} 2>&1 &
status=$?
SRVPID=$!
if test "x${status}" != "x0"
then
  echo "$0: FAIL: cannot start server ${status}"
  exit ${status}
fi
sleep 1

# start LMTP sink
if test X"${LMTPSINK}" != "X" -a X"${LMTPDIR}" != "X"
then
${STE}/smtps3 ${PIPELINING} -C ${LMTPDIR} ${LMTPSINKOPTS} -L ${LMTPSINK} > ${LMTPL} 2>&1 &
status=$?
LMTPPID=$!
if test "x${status}" != "x0"
then
  echo "$0: FAIL: cannot start LMTP sink ${status}"
  exit ${status}
fi
sleep 1
fi

# path to programs
P=..
# file to override settings
# test -f options && . ./options

# go for it
${P}/smar/smar ${CONF} ${D} ${LGLVL} ${AROPTS} > a${V}.log 2>&1 &
echo $! >> ${PIDS}
#${CHKD}/qmgr-running.sh "${SMARSOCK}" || killit
${P}/qmgr/qmgr ${CONF} ${D} ${LGLVL} ${QOPTS} > q${V}.log 2>&1 &
echo $! >> ${PIDS}
QMGRPID=$!
# wait a bit for startup such that the sockets are created
#export SMTPCSOCK
#${CHKD}/qmgr-running.sh || killit
if test ${SMTPCDELAY} -eq 0
then
${P}/smtpc/smtpc ${CONF} ${LGLVL} ${COPTS} ${LMTP} ${D} > c${V}.log 2>&1 &
echo $! >> ${PIDS}
fi
${P}/smtps/smtps ${CONF} ${LGLVL} ${SRVOPTS} ${D} > s${V}.log 2>&1 &
echo $! >> ${PIDS}

# check that the MTA is running
export SRVPORT P
${CHKD}/mta-running.sh || killit

if test X"${MTA_SOURCE}" != X
then
${MTA_SOURCE}
else
if test X"${RCPTADDR}" != X
then
  if ${SRCPRG} ${SRCOPTS} -r ${H}:${SRCPORT} -f "${SENDER}" ${RCPTADDR} -n "${RCPTS}" -T "${TAS}" -t "${THREADS}" > ${CLTL} 2>&1
  then
    :
  else
    cat ${CLTL}
    ERRS=`expr ${ERRS} + 1 `
  fi
elif test X"${SRCOPTS}" != X
then
  if ${SRCPRG} ${SRCOPTS} -r ${H}:${SRCPORT} > ${CLTL} 2>&1
  then
    :
  else
    cat ${CLTL}
    ERRS=`expr ${ERRS} + 1 `
  fi
fi
# MTA_SOURCE 
fi

if test ${SMTPCDELAY} -gt 0
then
sleep ${SMTPCDELAY}
${SNDUSR1} && kill -USR1 ${QMGRPID}
${P}/smtpc/smtpc ${CONF} ${LGLVL} ${COPTS} ${LMTP} ${D} > c${V}.log 2>&1 &
echo $! >> ${PIDS}
fi

if ${WAIT4SINK}
then
  if kill -0 ${SRVPID}
  then
    wait ${SRVPID}
  else
    echo "kill -0 sink failed: $?"
  fi
else
  sleep ${SLEEP}
fi

if ${SNDUSR1}
then
  for i in `cat ${PIDS}`
  do
    if test ${WAIT4SINK} = "false" -o ${i} -ne ${SRVPID}
    then
      kill -USR1 ${i}
    fi
  done
fi

# ----------------
# stop MTA components
if ${STOPMTS}
then
for i in `cat ${PIDS}`
do
  if test ${WAIT4SINK} = "false" -o ${i} -ne ${SRVPID}
  then
    kill ${i}
  fi
done
# ----------------
# thanks kids for not following the POSIX standard...
if test X"`uname`" = "XLinux"
then
  killall qmgr smar
  if ${PMILTER}
  then
    killall ${PMILTPRG}
  fi
fi
fi

if ${WAIT4SINK}
then
  :
else
  # send SMTP server a signal to dump its state
  if kill -USR1 ${SRVPID}
  then
    :
  else
    echo "kill -USR1 sink failed: $?"
    exit 1
  fi
  sleep 2
fi

# send LMTP server a signal to dump its state
if test X"${LMTPPID}" != "X"
then
  if kill -USR1 ${LMTPPID}
  then
    :
  else
    echo "kill -USR1 failed: $?"
    exit 1
  fi
  sleep 2
fi

# check state of SMTP server (sink)
if ${WAIT4SINK}
then
  if ${GREP} "8 threads on ${H}:${P}" ${SRVL} > /dev/null
  then
    :
  else
    echo "$0: sink did not start properly?"
    ERRS=`expr ${ERRS} + 1 `
  fi
else
  if ${GREP} "^Address *${H}:${P}" ${SRVL} > /dev/null
  then
    :
  else
    echo "$0: failed to listen on ${H}:${P}"
    ERRS=`expr ${ERRS} + 1 `
  fi
  if ${GREP} "^Thread.* 8/" ${SRVL} > /dev/null
  then
    :
  else
    echo "$0: failed to start threads"
    ERRS=`expr ${ERRS} + 1 `
  fi
fi

# the number of requests can vary based on the scheduler...
RQS=`${GREP} "^Requests served *" ${SRVL} | head -n1 | sed -e 's/^Requests served *//'`
if test "${RQS}" -ne "${TRQS}"
then
  echo "$0: wrong number of requests: expected=${TRQS} got=${RQS} (-X)"
  ERRS=`expr ${ERRS} + 1 `
fi
if egrep "^Recipients *${TR}$" ${SRVL} > /dev/null
then
  :
else
  echo "$0: wrong number of recipients in ${SRVL}: expected=${TR} (-E)"
  ${GREP} "^Recipients" ${SRVL}
  ERRS=`expr ${ERRS} + 1 `
fi

# LMTP checks
if test X"${LMTPRCPTS}" != "X"
then
  if egrep "^Recipients *${LMTPRCPTS}$" ${LMTPL}> /dev/null
  then
    :
  else
    echo "$0: wrong number of LMTP recipients: expected=${LMTPRCPTS} (-e)"
    ${GREP} "^Recipients" ${LMTPL}
    ERRS=`expr ${ERRS} + 1 `
  fi
fi

# check SMTP client (source)
if test ${MULTIPLE} -ge 2
then
  r=1
  msgs=0
  while test ${r} -le ${MULTIPLE}
  do
    SENT=`${GREP} "total=" ${CLTL}-${r} | sed -e 's/^.*total=\([0-9]*\) .*/\1/'`
    msgs=`expr ${SENT} + ${msgs}`
    r=`expr ${r} + 1 `
  done
  if test ${TOTAL} = ${msgs}
  then
    :
  else
    echo "$0: wrong number of mails sent: expected=${TOTAL}, got=${msgs} (-A)"
    ERRS=`expr ${ERRS} + 1 `
  fi

  if test ${TTAS} -ge 0
  then
    # the number of transactions can vary based on the scheduler...
    TASS=`${GREP} "^Transactions *" ${SRVL} | sed -e 's/^Transactions *//'`
    if test "${TASS}" -lt "${TTAS}"
    then
      echo "$0: wrong number of transactions: expected=${TTAS} got=${TASS}"
      ERRS=`expr ${ERRS} + 1 `
    fi
  fi

else
if ${GREP} "total=${TOTAL} " ${CLTL} > /dev/null
then
  :
else
  echo "$0: wrong number of mails sent (by SMTPC): expected=${TOTAL} (-A)"
  ${GREP} "total=" ${CLTL}
  ERRS=`expr ${ERRS} + 1 `
fi
fi

# ----------------
${WAIT4SINK} || kill -TERM ${SRVPID}
if test X"${LMTPPID}" != "X"
then
  kill -TERM ${LMTPPID}
fi

# ----------------
if ${IDBR0} >/dev/null
then
  if test "${ERRS}" = "0"
  then
    rm -f ibdd/ibd00000000*
  fi
else
  echo "$0: t-idbr-0 failed"
  ERRS=`expr ${ERRS} + 1 `
fi

# ----------------
# file for EDBR check provided?
if test X"${EDBOKIN}" = X
then
cp /dev/null ${EDBOK}
else
cp ${EDBOKIN} ${EDBOK}
fi

if ${EDBR} -r > ${EDBROUT} 2>&1
then
  egrep -v 'tests completed successfully|time|(id|cdb|srv_ip4)=' ${EDBROUT} > ${EDBOUT} 2>&1
  if diff ${EDBOUT} ${EDBOK}
  then
    :
  else
    ERRS=`expr ${ERRS} + 1 `
  fi
else
  echo "$0: ${EDBR} failed"
  ERRS=`expr ${ERRS} + 1 `
fi

# ----------------
for i in a c q s
do
  if egrep "${ERRORPAT}" ${i}${V}.log
  then
    ERRS=`expr ${ERRS} + 1 `
  fi
done

# ----------------
if test "${ERRS}" = "0"
then
  exit 0
else
  echo "${ERRS} error(s)"
  exit 1
fi


syntax highlighted by Code2HTML, v. 0.9.1