Current File : /home/inlingua/public_html/decay_sym/root/var/softaculous/apps/exim/popb4smtp-watch |
#!/usr/bin/perl -w
use strict;
use Date::Parse;
use File::Tail;
use Unix::Syslog qw(:macros :subs);
$SIG{INT} = sub {
syslog(LOG_CRIT, "%s", "exiting on SIGINT\n");
exit 1;
};
$SIG{TERM} = sub {
syslog(LOG_CRIT, "%s", "exiting on SIGTERM\n");
exit 1;
};
my $DSEARCHDIR = '/var/webuzo-data/popb4smtp';
my $DEBIANLOG = '/var/log/mail.log';
my $POPLOG = '/var/log/maillog';
my $PROGNAME = 'popb4smtp-watch';
my $PIDFILE = '/var/run/popb4smtp-watch.pid';
sub dsearch_store_popauth($$$);
sub mkdirp($);
sub select_readable(\@);
sub xdie(@);
sub xwarn(@);
my (@readable_tails, @tail_refs);
openlog($PROGNAME, LOG_PERROR | LOG_PID, LOG_MAIL);
open(PID, "> $PIDFILE") or
xdie "$PIDFILE: $!\n";
print PID "$$\n";
close(PID);
foreach my $fn ($DEBIANLOG, $POPLOG) {
my $tail;
$tail = File::Tail->new(
name => $fn,
maxinterval => 1,
interval => 1,
ignore_nonexistant => 1
);
push(@tail_refs, $tail);
}
syslog(LOG_CRIT, "%s", "tailing files: $DEBIANLOG, $POPLOG\n");
while (1) {
@readable_tails = select_readable(@tail_refs);
if (not @readable_tails) {
# Give up our time slice so that the kernel treats us like
# a model citizen with respect to CPU utilization.
#
select(undef, undef, undef, 0.25);
next;
}
foreach my $tail (@readable_tails) {
my ($ip, $line, $timestr, $unixtime, $user);
$line = $tail->read();
chomp($line);
if ($line =~ /^(\w+\s+\d+\s+\d+:\d+:\d+).*user=<(.*?)>.*rip=(.*?),/ or
$line =~ /^(\w+\s+\d+\s+\d+:\d+:\d+) .* imapd: LOGIN, user=([^,]+), ip=\[.+:([0-9.]+)\]/) {
($timestr, $user, $ip) = ($1, $2, $3);
$unixtime = str2time($timestr);
dsearch_store_popauth($unixtime, $user, $ip);
}
}
}
sub dsearch_store_popauth($$$)
{
my ($unixtime, $user, $ip) = @_;
my ($subdir);
$ip =~ /(\d)$/;
$subdir = $1;
if (not mkdirp("$DSEARCHDIR/$subdir")) {
# mkdirp() logs its own warnings for us
} elsif (not open(IPFILE, "> $DSEARCHDIR/$subdir/$ip")) {
xwarn "$DSEARCHDIR/$subdir/$ip: $!\n";
} elsif (not print IPFILE "$unixtime:$user:$ip\n") {
xwarn "$DSEARCHDIR/$subdir/$ip: $!\n";
} elsif (not close(IPFILE)) {
xwarn "$DSEARCHDIR/$subdir/$ip: $!\n";
}
}
sub mkdirp($)
{
my ($dir) = @_;
my ($i, @parts, $path);
@parts = split(/\//, $dir);
if (not @parts or (@parts == 1 and not $parts[0])) {
xdie "panic: empty path passed to mkdirp()\n";
}
if (not $parts[0]) {
$path = '/';
shift @parts;
} else {
$path = '';
}
for ($i = 0; $i < @parts; $i++) {
if ($i > 0) {
$path .= "/$parts[$i]";
} else {
$path .= $parts[$i];
}
if (not -e $path) {
if (not mkdir($path, 0777)) {
xwarn "$path: $!\n";
return 0;
}
} elsif (not -d $path and not -l $path) {
return 0;
xwarn "$path: exists and is not a directory\n";
}
}
return 1;
}
# Given a list of File::Tail object references, block until one or more of
# the objects becomes readable and then return the list of readable objects.
#
sub select_readable(\@)
{
my ($tails) = @_;
my ($nfound, $timeleft, @pending);
($nfound, $timeleft, @pending) = File::Tail::select(
undef, undef, undef, undef, @{$tails}
);
return @pending;
}
sub xdie(@)
{
my (@msg) = @_;
my ($msgstr, $rv);
$rv = $! or 1;
$msgstr = join(' ', @msg);
chomp($msgstr);
syslog(LOG_CRIT, "%s", $msgstr);
exit $rv;
}
sub xwarn(@)
{
my (@msg) = @_;
my ($msgstr);
$msgstr = join(' ', @msg);
chomp($msgstr);
syslog(LOG_CRIT, "%s", $msgstr);
}