package MailBot;

$VERSION = "1.15";
sub version {$VERSION};

package MailBot::MailBot;

=head1 NAME

MailBot::MailBot - provide a uniform email, command-line, and CGI
interface

=head1 SYNOPSIS

 use MailBot::MailBot;
 use MailBot::Config;
 use MailBot::Entity;
 use MailBot::Envelope;

 package MyBot;
 @ISA = qw(MailBot::MailBot);
 sub vProcess
 {
    my ($self, $mail) = @_;
    MailBot::Entity -> setEnvelope(new MailBot::Envelope);
    my $entity = new MailBot::Entity("hello world");
    MailBot::UI::current -> send($entity);
 }

 package main;
 MailBot::Config -> setRoot("/usr/local/getweb");
 MyBot -> new -> run;

=head1 DESCRIPTION

 MailBot is a "virtual class" to allow code to be accessible through
 email, command-line, and CGI interfaces in a uniform way.

=head1 METHODS

=cut

use MailBot::Util;
use MailBot::UI;
use MailBot::Envelope;
use MailBot::Entity;

use strict;

sub d
{
    &MailBot::Util::debug(@_);
}

=head2 vProcess($message)

Virtual procedure which must be overridden in subclass.  The parameter
is a B<Mail::Internet> message.  You also can access information about
the environment through B<MailBot::Config> and B<MailBot::UI>.

=cut

sub vProcess
{
    die "procedure vProcess was not overridden!";
}

=head2 new()

returns a new MailBot.  You should not instantiate more than one
MailBot in any program.

=cut

sub new
{
    my $type = shift;

    my $self = {};
    bless($self,$type);
}

=head2 log($string_to_log)

logs the string, with date, to $MAILBOT_ROOT/log/log

=cut

sub log
{
    my $self = shift;
    my $config = MailBot::Config::current;

    $config -> log(@_);
}

=head2 run()

begins processing messages

=cut

sub run
{
    my $self = shift;
    my $ui = MailBot::UI::current;
    my $config = MailBot::Config::current;

    my $sleep = $config -> getIniVal("load","sleep.message",60);

    # for testing purposes
    my $count = $ENV{MAILBOT_TEST_COUNT};

    while (1)
    {
	if (defined $count)
	{
	    last if $count < 1;
	    $count--;
	}

	while (1)
	{
	    eval {$ui -> getMessage};
	    last unless ($@ ne "");
	    $@ =~ /^BOUNCE:/
		or die $@;
	    return unless $ui -> more;
	}

	my $incoming = $ui -> copyIncoming;

	my $timeout = $config -> getIniVal("load","timeout",60*60*24);

	eval
	{
	    $SIG{'ALRM'} = sub {die "request timed out\n"};
	    alarm($timeout);
	    $self -> vProcess($incoming);
	};
	if ($@)
	{
	    my $exception = $@;
	    $self -> log($exception);
	    $exception =~ /^SILENT/ and exit 0;
	    
	    my $condition;

	    if ($exception =~ s/^([A-Z ]+)://)
	    {
		$condition = $1;
	    }
	    
	    my $envelope = 
		$self -> newEnvelope($condition);
	    &MailBot::Entity::setEnvelope($envelope);

	    my $desc = $config -> getEnvelopeVal($condition,"desc");
	    
	    my $data = "$desc\n  $exception";
	    $data .= join('',$self -> appendOriginalRequest);
	    
	    my $entity = build MailBot::Entity (
						Data => $data
						);

	    my $fileName = $condition;
	    $fileName eq "" and
		$fileName = "INTERNAL ERROR";
	    $fileName =~ s/ /_/g;
	    $fileName = "exception.$fileName";
	    $ui -> save($entity,$fileName);
	    $fileName = "orig_$fileName";
	    $ui -> save($ui -> {INCOMING},$fileName);

	    $entity -> send;
      	}
	last unless $ui -> more;
	sleep $sleep;
    }
}

=head2 appendOriginalRequest()

returns an array of strings suitable for appending to outgoing
error messages.

    $message_text .= join(' ',$mailbot -> appendOriginalRequest());

=cut

sub appendOriginalRequest
{
    my $self = shift;

    my @appendix = ("\n","____original message follows____","\n","\n");

    my $ui = MailBot::UI::current;
    my $internet = $ui -> copyIncoming;

    push(@appendix,&MailBot::Util::messageToArray($internet));

    @appendix;
}

=head2 setEnvelopeByCondition($condition)

Set the current MailBot::Envelope to reflect the config values
for the given error condition.

    $mailBot -> setEnvelopeByCondition("UNAVAILABLE");
    $ui -> send($message);

=cut

sub setEnvelopeByCondition
{
    my $self = shift;
    my $condition = shift;

    my $envelope = $self -> newEnvelope($condition);

    &MailBot::Entity::setEnvelope($envelope);
}

sub newEnvelope
{
    my $self = shift;
    my $condition = shift;

    my $ui = MailBot::UI::current;
    my $config = MailBot::Config::current;

    $config -> log("exception is $condition");

    if ($condition eq 'QUOTA')
    {
	# try to bill 1 msg, just in case a user keeps trying
	# to squeeze out last few bytes
	my $quota = $ui -> getQuota; 
	eval {$quota -> bill(1,"message")};
    }

    my $envelope = new MailBot::Envelope();

    my $ccList = $config -> getEnvelopeVal($condition,"cc");
    my @aRecipient = ();

    if ($ccList ne "")
    {
	my $cc;
	foreach $cc (split(' ',$ccList))
	{
	    my $address = $config -> getIniVal("address",$cc);
	    defined $address or die "address not defined for $cc";
	    push (@aRecipient, $address);
	}
    }

    my $head = $ui -> copyIncomingHead;
    my $originalSender = $head -> get('From');

    my $exception = $config -> getIniVal('address','exception');
    unless ($exception eq '')
    {
	$originalSender = $exception;  #redirect errors
    }

    my $recipient = $originalSender;
    # &d("rec is $recipient");
    unshift(@aRecipient,$recipient);
    # &d("rec list is ",@aRecipient);
    $envelope -> setRecipientList(@aRecipient);
    $envelope -> setSubject($config -> getEnvelopeVal($condition,"subject"));

    my $quotaMultiplier = $config -> getEnvelopeVal($condition,
						    "quota_multiplier");
    defined $quotaMultiplier or $quotaMultiplier = 1;
    $envelope -> setQuotaMultiplier($quotaMultiplier);

    $envelope;
}

=head1 SEE ALSO

L<MailBot::Config>, L<getweb>, L<GetWeb::GetWeb>

=head1 COPYRIGHT

Copyright (c) 1997 SatelLife.  All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=head1 AUTHOR

Rolf Nelson <rolf@usa.healthnet.org>

=cut
