#! /bin/sh

# graph collected DCC statistics in .png files.
#   [-x]	    debugging
#   [-q]	    quiet
#   [-B]	    make big graphs
#   [-G db]	    generate graphs of database sizes
#   [-G traffic-noratio]	    database sizes without spam ratios
#   [-G traffic]		    mail message rates and spam ratios
#   [-G ratio]			    spam ratios
#   [-h dcc_homedir]
#   [-T /usr/local/bin/rrdtool]
#		    see http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
#			or the FreeBSD package.
#   [-O rrdopts]    additional rrdtool options for all graphs
#   [-t title]	    for graphs; '%1' is replaced with the type of graph
#   [-s span]	    time covered by graphs.
#			The default is "1day,1week,1month,1year"
#   [-S stop-epoch] end of the graph
#   gname	    basic file name for graphs, - for stdout
#   rrd1,...	    RRD databases that will be combined to produce the graphs

# The rrd files must be initialzed with dcc-stats-init, which is called
#   automatically by dcc-stats-collect.  Data must be collected very
#   10 minutes with dcc-stats-collect.  The rrd files should be in
#   /var/dcc/stats


# Copyright (c) 2006 by Rhyolite Software, LLC
#
# This agreement is not applicable to any entity which sells anti-spam
# solutions to others or provides an anti-spam solution as part of a
# security solution sold to other entities, or to a private network
# which employs the DCC or uses data provided by operation of the DCC
# but does not provide corresponding data to other users.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# Parties not eligible to receive a license under this agreement can
# obtain a commercial license to use DCC and permission to use
# U.S. Patent 6,330,590 by contacting Commtouch at http://www.commtouch.com/
# or by email to nospam@commtouch.com.
#
# A commercial license would be for Distributed Checksum and Reputation
# Clearinghouse software.  That software includes additional features.  This
# free license for Distributed ChecksumClearinghouse Software does not in any
# way grant permision to use Distributed Checksum and Reputation Clearinghouse
# software
#
# THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
# SOFTWARE.
#	Rhyolite Software DCC 1.3.45-1.43 $Revision$
#	Generated automatically from dcc-stats-graph.in by configure.

DCC_HOMEDIR=/etc/dcc
DEBUG=
# check the args once to get the home directory
while getopts "xqBdRmh:G:T:O:t:s:S:" c; do
    case $c in
	x) set -x; DEBUG=-x=;;
	h) DCC_HOMEDIR="$OPTARG";;
	*) ;;
    esac
done
. $DCC_HOMEDIR/dcc_conf

QUIET=
ATTRIBS="--width 200 --height 40"
AVGFMT="%.1lf %S"
M_YGRID="--alt-y-mrtg"
P_YGRID="--y-grid 25:2"
H_YGRID="--alt-y-mrtg"
XYEAR_MONTHS=2
GRAPH_DB=
GRAPH_TRAFFIC=
GRAPH_RATIO=
GRAPH_SET=
RRDOPTS=
RRDTOOL=/usr/local/bin/rrdtool
TITLE_SET=
SPANS="1day,1week,1month,1year"
STOP=
USAGE="`basename $0`: [-xqB] [-h homedir] [-T rrdtool] [-O rrdopts]
    [-G type] [t title] [-s spans] [-S stop-epoch] gname rrd1 rrd2 rrd3 ..."
OPTIND=1
while getopts "xqBdRmh:G:T:O:t:s:S:" c; do
    case $c in
	x) ;;
	q) QUIET="-q";;
	h) ;;
	B) ATTRIBS="--width 600 --height 240"; AVGFMT="%.0lf/day"
	    M_YGRID= P_YGRID= H_YGRID="--alt-autoscale-max"
	    XYEAR_MONTHS=1;;
	d) GRAPH_SET=yes; GRAPH_DB=yes;;			# obsolete
	R) GRAPH_RATIO=;;					# obsolete
	m) GRAPH_SET=yes; GRAPH_TRAFFIC=yes; GRAPH_RATIO=yes;;	# obsolete
	G) GRAPH_SET=yes
	    case "$OPTARG" in
		db) GRAPH_DB=yes;;
		traffic-noratio) GRAPH_TRAFFIC=yes;;
		traffic) GRAPH_TRAFFIC=yes; GRAPH_RATIO=yes;;
		ratio) GRAPH_RATIO=yes;;
		*) echo "$USAGE" 1>&2; exit 1;;
	    esac
	    ;;
	T) RRDTOOL="$OPTARG";;
	O) RRDOPTS="$RRDOPTS $OPTARG";;
	t) TITLE_SET=yes; TITLE_PAT="$OPTARG";;
	s) SPANS="$OPTARG";;
	S) if expr "$OPTARG" : '[0-9]*$' >/dev/null		\
		&& test "$OPTARG" -gt 1033870038		\
		     -a "$OPTARG" -lt 2000000000; then
		STOP=$OPTARG
	    else
		echo "$OPTARG is a bad number of seconds since the Epoch" 1>&2
		exit 1;
	    fi
	    ;;
	*) echo "$USAGE" 1>&2; exit 1;;
    esac
done
shift `expr $OPTIND - 1 || true`
if test "$#" -lt 1; then
    echo "$USAGE" 1>&2
    exit 1
fi

if test -z "$GRAPH_SET"; then
    GRAPH_RATIO=yes			# bug compatible with old versions
fi

cd $DCC_HOMEDIR/stats

GNAME=$1

if test -n "$QUIET"; then
    exec 1>/dev/null
fi

if test "$#" -ge 2; then
    # assume .rrd file is same as graph name if absent
    shift
fi
if test "$TITLE_SET" != yes; then
    if test "X$GNAME" != X-; then
	TITLE_PAT="%1 at $GNAME"
    else
	TITLE_PAT="%1"
    fi
fi

# find the number of databases, the latest timestamp among the databases,
#	and rrdtool expressions to combine the databases
NDBS=0
MAX_LAST=0
STEP=1
CDEF_reports="CDEF:reports=Ureports,UNKN"
CDEF_bulk="CDEF:bulk=Ubulk,UNKN"
CDEF_spam="CDEF:spam=Uspam,UNKN"
while test $# -gt 0; do
    FILE=$1; shift
    if test "$FILE" = "`basename $FILE .rrd`"; then
	# this round-about tactic expands "*.foo.com"
	set -- $FILE.rrd $*
	continue
    fi

    NDBS=`expr $NDBS + 1`
    LAST_FILE="$FILE"
    LAST=`$RRDTOOL last $FILE`
    if test "0$LAST" -gt $MAX_LAST; then
	MAX_LAST=$LAST
    fi

    NSTEP=`$RRDTOOL info $FILE | sed -n -e 's/^step = \([0-9][0-9]*\)/\1/p'`
    if test 0$NSTEP -gt $STEP; then
	STEP=$NSTEP
    fi

    for type in reports bulk spam; do
	eval DEFS_$type='"$DEFS_'$type DEF:$type$NDBS=$FILE:$type:AVERAGE'"'

	# When we sum data, count missing data as 0 instead of as unknown.
	if test "$NDBS" -eq 1; then
	    eval CDEF_U$type='"CDEF:'U$type=${type}1,UN'"'
	    eval CDEF_$type='"$CDEF_'$type,$type$NDBS,UN,0,$type$NDBS,IF'"'
	else
	    eval CDEF_U$type='"$CDEF_'U$type,$type$NDBS',UN,*"'
	    eval CDEF_$type='"$CDEF_'$type,$type$NDBS,UN,0,$type$NDBS,IF,+'"'
	fi
    done
done
CDEF_reports="$CDEF_reports,IF"
CDEF_bulk="$CDEF_bulk,IF"
CDEF_spam="$CDEF_spam,IF"


# find good ending dates
if test "$MAX_LAST" -ne 0; then
    if test -n "$STOP" -a "$MAX_LAST" -gt 0"$STOP"; then
	MAX_LAST="$STOP"
    fi
    # avoid odd times when individual servers were polled
    MAX_LAST=`expr $MAX_LAST - $MAX_LAST % $STEP`
    LAST=`expr $LAST - $LAST % $STEP`

    if TS="`date -r $MAX_LAST '+%x %R %Z'  2>/dev/null`"; then : ;
    else
	# deal with systems that do not have `date -r`
	TS="`/usr/bin/perl -e 'use POSIX qw(strftime);		\
		print strftime "%x %R %Z", localtime(time());'`"
    fi
    if test -z "`$RRDTOOL version | grep '^RRDtool 1\.0'`"; then
	TS=`echo "$TS" | sed -e 's/:/\\\:/g'`
    fi

    END=$MAX_LAST
    DB_END=`expr $MAX_LAST - $MAX_LAST % 86400`
else
    DB_END="now"
    END="now"
fi


FTYPE=png
ATTRIBS="$ATTRIBS --imgformat PNG"

for DUR in `echo $SPANS | tr ',' ' '`; do
    case $DUR in
	1d*)
	    DUR=1day
	    SPAN=24h
	    XGRID="--x-grid HOUR:1:HOUR:2:HOUR:2:0:%k"
	    # as the "rdtool graph" man page suggests, don't be fooled
	    # by daylight savings time
	    ;;
	1w*)
	    DUR=1week
	    SPAN=168h
	    # 24*3600 = 86400
	    XGRID="--x-grid HOUR:6:DAY:1:DAY:1:86400:%a"
	    # as the "rdtool graph" man page suggests, don't be fooled
	    # by daylight savings time
	    ;;
	1m*)
	    DUR=1month
	    SPAN=$DUR
	    XGRID="--x-grid WEEK:1:WEEK:1:WEEK:1:0:%b/%d"
	    ;;
	1y*)
	    DUR=1year
	    SPAN=$DUR
	    # label every month on big graphs and every other on small
	    # 28*24*60*60 = 2419200
	    XGRID="--x-grid MONTH:1:YEAR:1:MONTH:$XYEAR_MONTHS:2419200:%b"
	    ;;
	2y*)
	    DUR=2years
	    SPAN=$DUR
	    if test "$XYEAR_MONTHS" = 2; then
		# small graph with 1 label/year
		# 365*24*60*60 = 31536000 = year
		XGRID="--x-grid YEAR:1:YEAR:1:YEAR:1:31536000:%Y"
	    else
		# label every other month on big graphs
		# 28*24*60*60 = 2419200
		XYEAR_MONTHS=2
		XGRID="--x-grid MONTH:1:YEAR:1:MONTH:2:2419200:%b"
	    fi
	    ;;
	*)
	    case $DUR in
		3y*) DUR=3years;;
		4y*) DUR=4years;;
		# assume everything else is the 5 year maximum in the RRD files
		*) DUR=5years;;
	    esac
	    SPAN=$DUR
	    if test "$XYEAR_MONTHS" = 2; then
		# small graph with 1 label/year
		# 365*24*60*60 = 31536000 = year
		XGRID="--x-grid YEAR:1:YEAR:1:YEAR:1:31536000:%Y"
	    else
		# big graph with 2 labels/year
		XGRID="--x-grid MONTH:1:MONTH:6:MONTH:6:0:%b,%y"
	    fi
	    ;;
    esac

    ONAME=-

    if test "$GRAPH_RATIO" = yes; then
	if test "X$GNAME" != X-; then
	    ONAME=$GNAME-spam-ratio.$DUR.$FTYPE
	    if test -z "$QUIET"; then
		echo "$ONAME: " | tr -d '\012' 1>&2
	    fi
	fi
	TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Spam Ratio/g'`
	$RRDTOOL graph $ONAME $RRDOPTS					\
	    --end $END --start end-$SPAN				\
	    $ATTRIBS --title "$TITLE"					\
	    $XGRID $P_YGRID						\
	    --unit '%%' --lower-limit 0 --upper-limit 100		\
	    $DEFS_reports $DEFS_bulk $DEFS_spam				\
	    "$CDEF_Ureports" "$CDEF_Ubulk" "$CDEF_Uspam"		\
	    "$CDEF_reports" "$CDEF_bulk" "$CDEF_spam"			\
	    'CDEF:percentbulk=bulk,reports,/,100,*,0,100,LIMIT'		\
	    'CDEF:percentspam=spam,reports,/,100,*,0,100,LIMIT'		\
	    'AREA:percentbulk#cc0000:likely spam'			\
	    'AREA:percentspam#ffb6c1:trapped spam\j'			\
	    'GPRINT:percentbulk:AVERAGE:average %.0lf%%        '	\
	    "COMMENT:$TS\j"
	if test "X$GNAME" = X-; then
	    exit
	fi
    fi

    if test "$GRAPH_TRAFFIC" = yes; then
	if test "X$GNAME" != X-; then
	    ONAME=$GNAME-spam.$DUR.$FTYPE
	    if test -z "$QUIET"; then
		echo "$ONAME: " | tr -d '\012' 1>&2
	    fi
	fi
	TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Mail Checked/g'`
	$RRDTOOL graph $ONAME $RRDOPTS					\
	    --end $END --start end-$SPAN				\
	    $ATTRIBS --title "$TITLE"					\
	    $XGRID $M_YGRID						\
	    --vertical-label "msgs/day"					\
	    $DEFS_bulk $DEFS_spam $DEFS_reports				\
	    "$CDEF_Ureports" "$CDEF_Ubulk" "$CDEF_Uspam"		\
	    "$CDEF_reports,86400,*" "$CDEF_bulk,86400,*"		\
	    "$CDEF_spam,86400,*"					\
	    'AREA:reports#87cefa:total mail'				\
	    'AREA:bulk#cc0000:likely spam'				\
	    'AREA:spam#ffb6c1:trapped spam\j'				\
	    "GPRINT:reports:AVERAGE:average $AVGFMT"			\
	    "GPRINT:bulk:AVERAGE:$AVGFMT"				\
	    "COMMENT:$TS\j"
	if test "X$GNAME" = X-; then
	    exit
	fi
    fi

    # the other graphs have resolutions only to days
    if test "$DUR" = 1day; then
	continue
    fi

    if test "$GRAPH_DB" = yes; then
	if test "X$GNAME" != X-; then
	    ONAME=$GNAME-hashes.$DUR.$FTYPE
	    if test -z "$QUIET"; then
		echo "$ONAME: " | tr -d '\012' 1>&2
	    fi
	fi
	TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Checksums/g'`
	# take the database values from the last server
	$RRDTOOL graph $ONAME $RRDOPTS					\
	    --end $DB_END --start end-$SPAN				\
	    $ATTRIBS --step 86400 --title "$TITLE"			\
	    $XGRID $H_YGRID -l 0					\
	    DEF:hashes=$LAST_FILE:hashes:MIN				\
	    'AREA:hashes#ffb6c1:'					\
	    "COMMENT:$TS\c"
    fi
done
