#!/usr/bin/perl
# $Id: modlog.pl,v 1.3 2000/04/11 04:57:34 aqua Exp aqua $
#
# modlog.pl -- abstracted moderation logger
#
# Serves as a numeric and list accumulator, storing named values
# and their values in a (as set) Berkeley DB database.
#
# Also provides the ability to plug in user-specified functions
# with the idea of providing periodic reporting (see testop).
#
# Copyright (c) 2000 by Devin Carraway <ssg-modlog@devin.com>;
# Licensed under terms of the GNU General Public License.

use strict;

use Fcntl;
use DB_File;
use Getopt::Long;

my $VERSION = '$Id: modlog.pl,v 1.3 2000/04/11 04:57:34 aqua Exp aqua $';

# user-specified routines go here.  Hash key should
# be the unique name with which you intend to call it on
# the commandline (generally one word).  Hash value should
# be a listref containing a reference to the subroutine
# and the number of arguments the routine requires.

my %operations = ( '10dayrpt' => [ \&op_10dayrpt, 0 ],
		   'testop' => [ \&testop, 2 ] );

my $dbfn = $ENV{HOME} . '/etc/modlog.db';
my $help = 0;
my $version = 0;
my $mode;
my $verbose = 0;
my @args;

my ($db,%db);

GetOptions("dbfn=s" => \$dbfn,
	   "h" => \$help,
	   "v" => \$verbose,
	   "V" => \$version);

$help and do { &usage(); exit; };
$version and do { print "$VERSION\n"; exit; };

@args = @ARGV;

if ($verbose) {
    print "mode = $mode\nargs = ",join(',',@args),"\n";
    print "db = $dbfn\n";
}

if ($args[0] =~ /^creat/) {
    if (-e $dbfn) {
	unlink($dbfn);
    }
    $db = tie(%db, 'DB_File', $dbfn, O_RDWR|O_CREAT, 0600);
    $db or die "Couldn't tie to $dbfn via DB_File";
    $db{__log_created} = scalar time;
    untie %db;
    $verbose and print "New modlog $dbfn created\n";
    exit(0);
}

-e $dbfn or die "DB $dbfn does not exist -- create it with $0 create";
-r $dbfn or die "DB $dbfn not readable";

$db = tie(%db,'DB_File',$dbfn,O_RDWR, 0600);
$db or die "tie $dbfn: $!";

while ($mode = shift @args) {
	$verbose and print "mode = $mode\n";
	if ($mode =~ /^dump/) {
		$verbose and print "dumping $dbfn\n";
		for (sort keys %db) {
			print $_,"\t",($db{$_} || ''),"\n";
		}
	}

    elsif ($mode =~ /^(set|add|sub|lapp)/) {
	my ($elem,$val) = splice(@args, 0, 2);
	$verbose and print "elem=$elem val=$val\n";
	($elem and defined $val) or
	    die "usage: $0 $mode {element} {value}";    
	if ($mode =~ /^set/) {
	    $db{$elem} = $val;
	} elsif ($mode =~ /^add/) {
	    $db{$elem} += $val;
	} elsif ($mode =~ /^sub/) {
	    $db{$elem} -= $val;
	} elsif ($mode =~ /^app/) {
		$db{$elem} .= $val;
	}
		$verbose and print "$mode db{$elem}=$db{$elem}\n";
    }

    elsif ($mode =~ /^(incr|decr|app|del)/) {
	my ($elem) = shift @args;
	$elem or die "usage: $0 $mode {element}";
	$mode =~ /^incr/ and $db{$elem}++;
	$mode =~ /^decr/ and $db{$elem}--;
	$mode =~ /^del/ and delete $db{$elem};
	$verbose and print "$mode db{$elem} = $db{$elem}\n";
    }

	elsif ($mode && $operations{$mode}) {
		&{ $operations{$mode}->[0] }
			(splice(@args,0,$operations{$mode}->[1]));
	} else {
		print "Unrecognized operation $mode\n";
		next;
	}
}

untie %db;
exit(0);





sub op_10dayrpt {

	(defined $db{approvedCount} and
	defined $db{autoCount} and
	defined $db{rejectedCount} and
	defined $db{preApprovedCount}) or
		warn "op_10dayrpt: Not all 10-day report values initialized";


	print "Approved:\t$db{approvedCount} messages ",
		"(of them, $db{autoCount}\tautomatically)\n",
		"Rejected:\t$db{rejectedCount} messages\n",
		"Preapproved:\t$db{preApprovedCount} new posters\n";
}

sub testop {
	print "testop(",join(',',@_),")\n";
}

sub usage {
    print <<"EOT";
usage: $0 [--dbfn /path/to/logdb] [-{h|v}] [ mode [ arg ... ] | ... ]

mode/arg from the following:

    create			-- initialize db
	(excludes other options)
    dump			-- dump db

    incr[ement] {category}	-- increment numeric
    decr[ement] {element}	-- decrement numeric
    add {element} {num}		-- add numeric
    sub {element} {num}		-- subtract numeric
    set {element} {value}	-- assign (any type)
    del {element}		-- delete
    app {element} {value}	-- append (scalar)
    ladd {element} {value}	-- append (list)

EOT
}




1;

