package Mail::Toaster::Base; use strict; use warnings; our $VERSION = '5.50'; use Carp; use Params::Validate ':all'; our $verbose = our $last_audit = our $last_error = 0; # package variables our (@audit, @errors); # package wide message stacks our ($conf, $log); our ($darwin, $dns, $freebsd, $qmail, $logs, $mysql, $setup, $toaster, $util); our %std_opts = ( test_ok => { type => BOOLEAN, optional => 1 }, verbose => { type => BOOLEAN, optional => 1, default => $verbose }, fatal => { type => BOOLEAN, optional => 1, default => 1 }, ); sub new { my $class = shift; my %p = validate( @_, { %std_opts } ); my @caller = caller; # warn sprintf( "Base.pm loaded by %s, %s, %s\n", @caller ) if $caller[0] ne 'main'; return bless {}, $class; } sub darwin { my $self = shift; return $darwin if ref $darwin; require Mail::Toaster::Darwin; return $darwin = Mail::Toaster::Darwin->new(); } sub dns { my $self = shift; return $dns if ref $dns; require Mail::Toaster::DNS; return $dns = Mail::Toaster::DNS->new(); } sub freebsd { my $self = shift; return $freebsd if ref $freebsd; require Mail::Toaster::FreeBSD; return $freebsd = Mail::Toaster::FreeBSD->new(); } sub logs { my $self = shift; return $logs if ref $logs; require Mail::Toaster::Logs; return $logs = Mail::Toaster::Logs->new(); } sub mysql { my $self = shift; return $mysql if ref $mysql; require Mail::Toaster::Mysql; return $mysql = Mail::Toaster::Mysql->new(); } sub qmail { my $self = shift; return $qmail if ref $qmail; require Mail::Toaster::Qmail; return $qmail = Mail::Toaster::Qmail->new(); } sub setup { my $self = shift; return $setup if ref $setup; require Mail::Toaster::Setup; return $setup = Mail::Toaster::Setup->new(); } sub toaster { my $self = shift; return $toaster if ref $toaster; require Mail::Toaster; return $toaster = Mail::Toaster->new(); } sub util { my $self = shift; return $util if ref $util; require Mail::Toaster::Utility; return $util = Mail::Toaster::Utility->new(); } sub verbose { return $verbose if 1 == scalar @_; return $verbose = $std_opts{verbose}{default} = $_[1]; }; sub conf { $conf = $_[1] if $_[1]; return $conf if $conf; $conf = $_[0]->util->parse_config( "toaster-watcher.conf" ); }; sub audit { my $self = shift; my $mess = shift; my %p = validate( @_, { %std_opts } ); if ($mess) { push @audit, $mess; print "$mess\n" if $verbose || $p{verbose}; } return \@audit; } sub dump_audit { my $self = shift; my %p = validate( @_, { quiet => { type => BOOLEAN, optional => 1, default => 0 }, %std_opts, } ); if ( 0 == scalar @audit ) { print "dump_audit: no audit messages\n" if $p{verbose}; return 1; }; if ( $last_audit == scalar @audit ) { print "dump_audit: all messages dumped\n" if $p{verbose}; return 1; }; if ( $p{quiet} ) { # hide/mask unreported messages $last_audit = scalar @audit; $last_error = scalar @errors; return 1; }; print "\n\t\t\tAudit History Report \n\n"; for( my $i = $last_audit; $i < scalar @audit; $i++ ) { print " $audit[$i]\n"; $last_audit++; }; return 1; }; sub error { my $self = shift; my $message = shift or carp "why call error w/o message?"; my %p = validate( @_, { location => { type => SCALAR, optional => 1 }, frames => { type => SCALAR, optional => 1, default => 0 }, %std_opts, }, ); if ( $message ) { # append message and location to the error stack my @call = caller $p{frames}; my $location = $p{location}; if ( ! $location && scalar @call ) { $location = join( ', ', $call[0], $call[2] ); }; push @errors, { errmsg => $message, errloc => $location }; } else { $message = $errors[-1]; } $self->dump_audit if $self->verbose; $self->dump_errors if $p{fatal}; exit 1 if $p{fatal}; return; } sub dump_errors { my $self = shift; if ( $last_error == scalar @errors ) { print "all error messages dumped!\n" if $verbose; return 1; }; print "\n\t\t\t Error History Report \n\n"; my $i = 0; foreach ( @errors ) { $i++; next if $i < $last_error; my $msg = $_->{errmsg}; my $loc = $_->{errloc} ? " at $_->{errloc}" : ''; print $msg; for (my $j=length($msg); $j < 90-length($loc); $j++) { print '.'; }; print " $loc\n"; }; print "\n"; $last_error = $i; return 1; }; sub get_std_args { my $self = shift; my %p = @_; my %args; foreach ( qw/ verbose fatal test_ok / ) { if ( defined $p{$_} ) { $args{$_} = $p{$_}; next; }; if ( $self->{$_} ) { $args{$_} = $self->{$_}; }; }; return %args; }; sub get_std_opts { return %std_opts }; sub log { my $self = shift; my $mess = shift or return; my $logfile = $conf->{'toaster_watcher_log'} or do { warn "ERROR: no log file defined!\n"; return; }; return if ( -e $logfile && ! -w $logfile ); $self->util->logfile_append( $logfile, lines => [$mess], fatal => 0 ); }; 1;