#!/bin/bash

if [ -z "${CLIENTHOSTNAME}" ]
then
    # not debian-based
    if [ -z "${MACHINE}" ]
    then
    echo "Error: MACHINE not defined !"
    exit 1
    fi
else
    # Debian-based
    MACHINE=${CLIENTHOSTNAME}
fi

#Change to fit your system/wills :
LOGFILE="/var/log/mail.log"
TEST="mailgraph"

MESSAGECOMMAND="status" # MESSAGECOMMAND: data or status
COLOR="green"
ERRORCOLOR="yellow"

BC="/usr/bin/bc"
LOGTAIL2="/usr/sbin/logtail2" # logtail2 executable. logtail2 can find a file that might be the rotated.
                              # For debian/ubuntu: apt-get install logtail
OFFSETFILE="${BBTMP}/${TEST}.${MACHINE}.offset" # logtail2 stores here offset of previous run

if [ ! -e ${XYMONCLIENTHOME}/etc/mailgraph.cfg ]; then echo -e "#DEBUG=\"TRUE\"\n#LOG_LINES_TO_IGNORE=\"\"\n#REGEX_HOSTS_TLS_IGNORE=\"\"\n#REGEX_LINES_TLS_IGNORE=\"\"" > ${XYMONCLIENTHOME}/etc/mailgraph.cfg; fi
DEBUG="FALSE"
if [ -r ${XYMONCLIENTHOME}/etc/mailgraph.cfg ]; then . ${XYMONCLIENTHOME}/etc/mailgraph.cfg; fi

REGEX_CLIENT4="client=.*\[([0-9]{1,3}[\.]){3}[0-9]{1,3}\]"
REGEX_CLIENT6="client=.*\[([a-f0-9]{0,4}:)+[a-f0-9]{0,4}\]"
REGEX_SENT4="relay=.*\[([0-9]{1,3}[\.]){3}[0-9]{1,3}\]"
REGEX_SENT6="relay=.*\[([a-f0-9]{0,4}:)+[a-f0-9]{0,4}\]"

### here working:
function debug () {
    if [ "${DEBUG}" = "TRUE" ]
    then
        echo "Debug: $@"
    fi
}

function sendmessage () {
case ${MESSAGECOMMAND}
in
    status)
    MSG="${MESSAGECOMMAND} ${MACHINE}.${TEST} ${COLOR} ${DATE_NOW}"
    ;;
    data)
    MSG="${MESSAGECOMMAND} ${MACHINE}.${TEST}"
    ;;
esac
MSG="${MSG}

loglines = ${TAILLINES}
runtime = ${RUNTIME}

mails
received = ${RECEIVED}
sent = ${SENT}
deferred = ${DEFERRED}
bounced = ${BOUNCED}
rejected = ${REJECTED}
reject_warning = ${REJECT_WARNING}
warning = ${WARNING}
received_local = ${RECEIVED_LOCAL}
sent_local = ${SENT_LOCAL}

proto
received4 = ${RECEIVED4}
received6 = ${RECEIVED6}
sent4 = ${SENT4}
sent6 = ${SENT6}

tls
in_tls = ${IN_TLS}
in_notls = ${IN_NOTLS}
mail_tls = ${MAIL_TLS}
mail_notls = ${MAIL_NOTLS}

amavis
passed_clean = ${PASSED_CLEAN}
blocked_virus = ${BLOCKED_VIRUS}
blocked_banned = ${BLOCKED_BANNED}

spamd
spam = ${SPAM}
non_spam = ${NON_SPAM}

postgrey
greylisted = ${GREYLISTED}
early-retry = ${EARLY_RETRY}
delayed = ${DELAYED}
passed = ${PASSED}
reason_triplet_found = ${REASON_TRIPLET_FOUND}
reason_awl = ${REASON_AWL}
reason_client_wl = ${REASON_CLIENT_WL}
reason_recip_wl = ${REASON_RECIP_WL}
"

debug "${BB} ${BBDISP} ${MSG}"
${BB} ${BBDISP} "${MSG}"
}

function senderrormessage () {
    debug "${MSG}"
    ${BB} ${BBDISP} "status ${MACHINE}.${TEST} ${COLOR} ${DATE_NOW}
    ${MSG}"
}

RUNTIME=0

declare -i TAILLINES=0
declare -i RECEIVED=0
declare -i SENT=0
declare -i DEFERRED=0
declare -i BOUNCED=0

declare -i RECEIVED4=0
declare -i RECEIVED6=0
declare -i SENT4=0
declare -i SENT6=0

declare -i REJECTED=0
declare -i REJECT_WARNING=0
declare -i WARNING=0

declare -i RECEIVED_LOCAL=0
declare -i SENT_LOCAL=0

declare -i IN_TLS=0
declare -i IN_NOTLS=0
declare -i MAIL_TLS=0
declare -i MAIL_NOTLS=0

declare -i PASSED_CLEAN=0
declare -i BLOCKED_VIRUS=0
declare -i BLOCKED_BANNED=0

declare -i SPAM=0
declare -i NON_SPAM=0

declare -i GREYLISTED=0
declare -i EARLY_RETRY=0
declare -i DELAYED=0
declare -i PASSED=0

declare -i REASON_TRIPLET_FOUND=0
declare -i REASON_AWL=0
declare -i REASON_CLIENT_WL=0
declare -i REASON_RECIP_WL=0

LC_ALL=C
LANG=C
LANGUAGE=C
MSG=""

STARTTIME=$(date +%s.%N)
DATE_NOW=$(date)
debug "$DATE_NOW $0 "

if [ ! -x ${LOGTAIL2} ]; then
    COLOR="${ERRORCOLOR}"
    MSG="Error: ${LOGTAIL2} not found"
    senderrormessage
    exit 0
fi

if [ ! -x ${BC} ]; then
    COLOR="${ERRORCOLOR}"
    MSG="Error: ${BC} not found"
    senderrormessage
    exit 0
fi

if [ -e ${LOGFILE} ]; then
    if [ ! -e ${OFFSETFILE} ]
    then
    debug "First run. Start monitoring at end of ${LOGFILE}"
    # First run. All data must be = 0. Initialize offsetfile, send message and exit.
    ${LOGTAIL2} -f ${LOGFILE} -o ${OFFSETFILE} > /dev/null
     if [ ${?} != 0 ]
     then
        COLOR="${ERRORCOLOR}"
        MSG=$(echo -e "Error while reading ${LOGFILE}\n${LINES}")
        senderrormessage
        exit 0
     fi
    # send message with first run data (=0):
    sendmessage
    exit 0
    fi

    # Fetching new loglines
    ${LOGTAIL2} -f ${LOGFILE} -o ${OFFSETFILE} > ${XYMONTMP}/mailgraph-loglines.tmp
    if [ ${?} != 0 ]
    then
    # send errormessage:
    COLOR="${ERRORCOLOR}"
    MSG=$(echo -e "Error while reading ${LOGFILE}\n${LINES}")
    senderrormessage
    exit 0
    fi

else
    # send errormessage:
    COLOR="${ERRORCOLOR}"
    MSG="Error: ${LOGFILE} not found."
    senderrormessage
    exit 0
fi


# Parse new loglines
ORIGIFS=${IFS}
IFS=$'\n'
while read LINE
do
    IFS=${ORIGIFS}
    ((TAILLINES++))
    set -- ${LINE}

    if [ "${LOG_LINES_TO_IGNORE}" != "" ]; then
      if [[ ${LINE} =~ ${LOG_LINES_TO_IGNORE} ]]; then debug " =${LINE}= to ignore"; continue; fi
    fi

    if [ "${5:0:8}" = "postgrey" ]
    then
    if [ "${LINE}" != "${LINE/action=greylist, reason=new}" ]; then ((GREYLISTED++)); continue; fi
    if [ "${LINE}" != "${LINE/action=greylist, reason=early-retry}" ]; then ((EARLY_RETRY++)); continue; fi
    if [ "${LINE}" != "${LINE/action=pass, reason=triplet found, delay=}" ]; then ((PASSED++)); ((REASON_TRIPLET_FOUND++)); ((DELAYED++)); continue; fi
    if [ "${LINE}" != "${LINE/action=pass, reason=triplet found, client_name=}" ]; then ((PASSED++)); ((REASON_TRIPLET_FOUND++)); continue; fi
    if [ "${LINE}" != "${LINE/action=pass, reason=client AWL}" ]; then ((PASSED++)); ((REASON_AWL++)); continue; fi
    if [ "${LINE}" != "${LINE/action=pass, reason=client whitelist}" ]; then ((PASSED++)); ((REASON_CLIENT_WL++)); continue; fi
    if [ "${LINE}" != "${LINE/action=pass, reason=recipient whitelist}" ]; then ((PASSED++)); ((REASON_RECIP_WL++)); continue; fi
    fi

    if [ "${5:0:5}" = "sSMTP" ]
    then
    if [ "${6} ${7} ${8}" = "Sent mail for" ]; then ((SENT++)); continue; fi
    if [ "${6} ${7:0:3} ${8:1:1}" = "RCPT TO: 4" ]; then ((BOUNCED++)); continue; fi
    if [ "${6} ${7:0:3} ${8:1:1}" = "RCPT TO: 5" ]; then ((BOUNCED++)); continue; fi
    fi

    if [ "${5:0:10}" = "nullmailer" ]
    then
    # smtp: Succeeded: 250 2.0.0 Ok: queued as 04B5D179
    if [ "${6} ${7}" = "smtp: Succeeded:" ]; then ((SENT++)); continue; fi
    # smtp: Failed: 450 4.7.1 Client host rejected: cannot find your reverse hostname, [192.168.77.2]
    if [ "${6} ${7}" = "smtp: Failed:" ]; then ((DEFERRED++)); continue; fi
    fi

    if [ "${5:0:7}" = "postfix" ]
    then
    PROG="${5:8}"; PROG="${PROG%%[*}"
    case ${PROG}
    in

    smtp|*/smtp)
        if [ "${LINE}" != "${LINE/ status=sent }" ]; then
    if [ "${LINE}" != "${LINE/ relay=127.0.0.1}" -o "${LINE}" != "${LINE/ relay=localhost}" ]; then
        ((SENT_LOCAL++)); continue;
    else
        if [[ ${LINE} =~ ${REGEX_SENT4} ]]; then ((SENT4++)); fi
        if [[ ${LINE} =~ ${REGEX_SENT6} ]]; then ((SENT6++)); fi
        ((SENT++)); continue;
    fi
        fi
        if [ "${LINE}" != "${LINE/ status=bounced }" ]; then ((BOUNCED++)); continue; fi
        if [ "${LINE}" != "${LINE/ status=deferred }" ]; then ((DEFERRED++)); continue; fi
    ;;

    lmtp)
        if [ "${LINE}" != "${LINE/ status=sent }" ]; then ((SENT_LOCAL++)); continue; fi
        if [ "${LINE}" != "${LINE/ status=bounced }" ]; then ((BOUNCED++)); continue; fi
        if [ "${LINE}" != "${LINE/ status=deferred }" ]; then ((DEFERRED++)); continue; fi
    ;;

    smtpd|*/smtpd)
        if [ "${17} ${18} ${20}" = "Greylisted for seconds;" ]; then continue; fi
        if [ "${6} ${7}" = "NOQUEUE: reject:" ]; then ((REJECTED++)); continue; fi
        if [ "${6} ${7}" = "NOQUEUE: reject_warning:" ]; then ((REJECT_WARNING++)); continue; fi
        if [ "${6} ${7}" = "NOQUEUE: warn:" ]; then ((WARNING++)); continue; fi
        if [ "${7:0:27}" = "client=localhost[127.0.0.1]" ]; then ((RECEIVED_LOCAL++)); continue; fi
        if [ "${7:0:39}" = "client=localhost.localdomain[127.0.0.1]" ]; then ((RECEIVED_LOCAL++)); continue; fi
        if [[ ${LINE} =~ ${REGEX_CLIENT4} ]]; then ((RECEIVED4++)); fi
        if [[ ${LINE} =~ ${REGEX_CLIENT6} ]]; then ((RECEIVED6++)); fi
        if [ "${7:0:7}" = "client=" ]; then ((RECEIVED++)); continue; fi
        if [ "${6} ${7}" = "disconnect from" ]; then
            debug "=${LINE}="
            if [ "${REGEX_LINES_TLS_IGNORE}" != "" ]; then if [[ ${LINE} =~ ${REGEX_LINES_TLS_IGNORE} ]]; then continue; fi; fi
            if [ "${REGEX_HOSTS_TLS_IGNORE}" != "" ]; then if [[ ${8} =~ ${REGEX_HOSTS_TLS_IGNORE} ]]; then continue; fi; fi
            if [[ "${LINE}" =~ .*" starttls=".* ]]; then
               if [[ "${LINE}" =~ .*" starttls=1 ".* ]]; then ((IN_TLS++))
                  if [[ "${LINE}" =~ .*" data=1 ".* ]]; then ((MAIL_TLS++)); fi
               fi
               if [[ "${LINE}" =~ .*" starttls=0".* ]]; then ((IN_NOTLS++)) 
                  if [[ "${LINE}" =~ .*" data=1 ".* ]]; then ((MAIL_NOTLS++)); fi
               fi
            else
               ((IN_NOTLS++))
               if [[ "${LINE}" =~ .*" data=1 ".* ]]; then ((MAIL_NOTLS++)); fi
           fi
        fi
    ;;

    pickup)
        if [ "${7:0:4} ${8:0:5}" = "uid= from=" ]; then ((RECEIVED_LOCAL++)); continue; fi
    ;;

    local|pipe)
        if [ "${LINE}" != "${LINE/ status=sent }" ]; then ((SENT_LOCAL++)); continue; fi
        if [ "${LINE}" != "${LINE/ status=bounced }" ]; then ((BOUNCED++)); continue; fi
    ;;

    cleanup)
        # fix me?
        continue
    ;;
    anvil|qmgr)
        # fix me?
        continue
    ;;
    *)
        continue
    ;;
    esac
    fi

    if [ "${5:0:6}" = "amavis" ]
    then
    # Feb 28 21:56:49 servername amavis[19268]: (19268-04) Passed CLEAN, LOCAL [192.168.6.13] [192.168.6.13] <user@domain.de> -> <user@domain.com>, Message-ID: <20100228205640.AF34B19F7C@pc.lan>, mail_id: MiyfCvjWKGzy, Hits: -, queued_as: 14DE01E7B30, 7166 ms
    if [ "${7}" = "Passed" ]; then ((PASSED_CLEAN++)); continue; fi
    if [ "${7} ${8}" = "Blocked INFECTED" ]; then ((BLOCKED_VIRUS++)); continue; fi
    if [ "${7} ${8}" = "Blocked BANNED" ]; then ((BLOCKED_BANNED++)); continue; fi
    fi

    if [ "${5:0:5}" = "spamd" ]
    then
    #Feb 28 22:21:00 servername spamd[1852]: spamd: clean message (-2.0/5.0) for spamfilter:1010 in 2.2 seconds, 4294 bytes.
    if [ "${7} ${8}" = "clean message" ]; then ((NON_SPAM++)); continue; fi
    if [ "${7} ${8}" = "identified spam" ]; then ((SPAM++)); continue; fi
    fi
done < ${XYMONTMP}/mailgraph-loglines.tmp

ENDTIME=$(date +%s.%N)
RUNTIME=$(echo "scale=2;${ENDTIME} - ${STARTTIME}" | ${BC})
#echo "e=${ENDTIME} s=${STARTTIME} r=${RUNTIME}"
sendmessage
exit 0
