#!/usr/bin/perl

use Net::SMTP;
use DBI;
use Getopt::Long;
use Email::Simple;
use DateTime::Format::Mail;
use Sys::Hostname;

# setup my defaults
my $help     = 0;
my $origin = hostname;
my $our_domain = "hzsol.eu";
my $reply_smtpd = "192.168.10.50";
my $warning_smtpd = "192.168.10.50";
my $user = "mailtestor";

#my $smtpd = "";

GetOptions(
    'send'       => \$send_option,
    'receive'    => \$receive_option,
    'recreatedb' => \$recreate_db,
    'reply'      => \$reply,
    'report'     => \$report,
    'dailyreport'=> \$report_d,
    'help!'      => \$help,
) or die "Incorrect usage!\n";


if ($help) {
    print "$0 --help.\n";

    print "send\n";   
    print "receive\n";
    print "recreatedb\n";
    print "reply\n";
    print "report\n";
    print "dailyreport\n";
    print "help\n";

    exit 1;
}

my $maildb = "/home/mailtestor/mailtestor/data.dbl";

$dbh = DBI->connect( "dbi:SQLite:$maildb" ) || die "Cannot connect to $maildb: $DBI::errstr";

if ($send_option) {
  print("*** Sending mails...\n");
  &launch_test();
} elsif ($receive_option) {
  &receive_email();
} elsif ($recreate_db) {
  &create_table();
} elsif ($reply) {
  &auto_reply();
} elsif ($report) {
  &report("full");
} elsif ($report_d) {
  &report("daily");
}

$dbh->disconnect;
&log_string("Yo! bye!");



################################################################################
################################################################################
################################################################################

################################################################################
sub launch_test
################################################################################
{
  &prepare_test("mailtest\@grezl.eu", "grezl.eu");

  &prepare_test("mailtest\@hzsol.cz", "mx.cesnet.cz");
  &prepare_test("mailtest\@hasici-ol.cz", "mx.cesnet.cz");
  &prepare_test("mailtest\@izsol.cz", "mx.cesnet.cz");
  &prepare_test("mailtest\@olk.izscr.cz", "mx.cesnet.cz");

#  &prepare_test("mailtest\@hzsol.cz", "mail.hzsol.cz");
#  &prepare_test("mailtest\@hasici-ol.cz", "mail.hzsol.cz");
#  &prepare_test("mailtest\@izsol.cz", "mail.hzsol.cz");
#  &prepare_test("mailtest\@olk.izscr.cz", "mail.hzsol.cz");
}

################################################################################
sub prepare_test
################################################################################
{
  $id = &get_id();

  ($recipient,$smtp_server) = @_;

  $answer = &send_mail($id, $recipient, $smtp_server);

  if ($answer eq "timeout") {
    &log_string("prepare test failed, timeout");
    return;
  }

  $sent_timestamp = time;

  my $sql;
  $sql = "update mail set sent=$sent_timestamp,out_smtp_answer='$answer',smtpd='$smtp_server',email='$recipient' where id=$id";
  &log_string("generated sql:" . $sql);

  $dbh->do($sql) or do {
    &log_string("prepare test sql failed, sql:" . $sql);
    return;
  };
}

################################################################################
sub send_mail()
################################################################################
{
  my ($id, $recipient, $smtpd) = @_;


  my $smtp = Net::SMTP->new($smtpd,
                        Hello => $our_domain,
                        Timeout => 120,
                        Debug   => 1,
                      ) or do {
                        &log_string("cannot create smtp object");
                        return "timeout";
                      };

  my $useraddress = $user . "\@" . $our_domain;

  &log_string("from $useraddress send_mail($id, $recipient, $smtpd) hello:$our_domain ...");

  $smtp->mail($useraddress)  or do {
    my $from_err = "from error:" . $smtp->message;
    chomp $from_err;
    &log_string($from_err);
    return $from_err;
  };
  $smtp->to($recipient) or do {
    my $recp_err = "recipient error:" . $smtp->message;
    chomp $recp_err;
    &log_string($recp_err);
    return $recp_err;
  };
  $smtp->data();
  $smtp->datasend("From: " . $useraddress . "\n");
  $smtp->datasend("To: $recipient\n");
  $smtp->datasend("Date: " . date_r() . "\n");
  $smtp->datasend("Subject: testmail number $id\n");
  $smtp->datasend("\n");
  $smtp->datasend("I came from $origin.\n");
  $smtp->datasend("A simple test message, its id is $id\n");
  $smtp->datasend("some other useful stuff follows: $id, $recipient, $smtpd\n");
  $smtp->dataend();
  $m = $smtp->message;
  $smtp->quit;

  chomp $m;

  &log_string("smtp code: ".$smtp->code);
  &log_string("sent: " . $recipient . " id: " . $id);

  return $m;
}

################################################################################
sub send_warning()
################################################################################
{
  $recipient = @_[0];

  my $smtp = Net::SMTP->new($warning_smtpd,
                        Hello => $our_domain,
                        Timeout => 30,
                        Debug   => 1,
                      );

  $smtp->mail($user . "\@" . $our_domain);
  $smtp->to($recipient);
  $smtp->data();
  $smtp->datasend("From: mailtestor\@". $our_domain . "\n");
  $smtp->datasend("To: $recipient\n");
  $smtp->datasend("Subject: Mailtestor warning\n");
  $smtp->datasend("\n");
  $smtp->datasend("Something is wrong!\n");
  $smtp->dataend();
  $m = $smtp->message;
  $smtp->quit;

  return $m;
}

################################################################################
sub create_table
################################################################################
{
  my $sql;
  $sql = "drop table mail";
  $dbh->do($sql) or print "no need to drop\n";

$sql = "
CREATE TABLE mail(
  id integer primary key AUTOINCREMENT,
  start integer,
  sent integer,
  received integer,
  smtpd text,
  email text,
  out_smtp_answer text
)
";

print $sql."\n";
  $dbh->do($sql) or die;
}

################################################################################
sub get_id
################################################################################
{
  my $sql = "insert into mail values(null,".time.",0,0,'example.example.com','smtpd.example.com','nothing sent yet')";
  $dbh->do($sql) or die;
  $row_id = $dbh->sqlite_last_insert_rowid();
  return $row_id;
}

################################################################################
sub receive_email
################################################################################
{
  $content = join('', <>);

  my $email = Email::Simple->new($content) or die;

  my $from = $email->header("From");
  my $subject = $email->header("Subject");

  @subj_arr = split(' ', $subject);

  if ($subj_arr[0] ne "testmail") {
    &log_string("received: wrong subject, strange mail ".$from." subject: ".$subject);
    $dbh->disconnect();
    return;
  }

  &log_string("received: ".$from." subject: ".$subject."\n");

  my $id = $subj_arr[2];
  my $received_timestamp = time;
  $sql = "update mail set received=$received_timestamp where id=$id";

  &log_string("sql: $sql");

  $dbh->do($sql) or die;
  $dbh->disconnect();
}

################################################################################
sub log_string
################################################################################
{
  my ($p) = @_;
  my $fh;
  open($fh, ">>/tmp/mailtestor.log") or die "log";
  print $fh time . " ";
  print $fh $p."\n";
  close($fh);
}

################################################################################
sub auto_reply
################################################################################
{
  $content = join('', <STDIN>);
  &log_string(">>> autoreply start.\n");
  &log_string("content: ((($content)))");

  my $email = Email::Simple->new($content) or die;

  my $from = $email->header("From");
  my $to = $email->header("To");
  my $subject = $email->header("Subject");

  &log_string("from: $from");
  &log_string("to: $to");
  &log_string("subj: $subject");

  if ($subject eq "Undelivered Mail Returned to Sender") {
    &log_string(">>> Failed. \n");
    &log_string(">>> autoreply end.\n");
    return
  }

  @subj_arr = split(' ', $subject);
  my $id = $subj_arr[2];
  my $received_timestamp = time;

  @smtpd_arr = split('@', $from);
 
  &log_string("smtpd: $reply_smtpd");
  &log_string("session start");

  $reply_smtpd =~ s/\>//g;
  $reply_smtpd =~ s/\<//g;
  
  $smtp = Net::SMTP -> new($reply_smtpd,
    Hello => 'mail.hzsol.cz',
    Timeout => 30,
    Debug   => 0,
  ) or die " Smtp bad ".$reply_smtpd;
  
  $smtp->mail($to);
  $smtp->to($from);
  $smtp->data();
  $smtp->datasend("From: $to\n");
  $smtp->datasend("To: $from\n");
  $smtp->datasend("Subject: $subject\n");
  $smtp->datasend("\n");
  $smtp->datasend("A simple test message, its id is $id\n");
  $smtp->datasend("This is returned message from test, mail route is ok\n");
  $smtp->dataend();
  $m = $smtp->message;
  print $smtp->code;
  $smtp->quit;

  &log_string("smtpd answer message: $m");
  &log_string(">>> autoreply end.\n");
}

################################################################################
sub td
################################################################################
{
  my ($h, $s, $c) = @_;
  print $h "<td bgcolor='$c'>";
  print $h $s;
  print $h "</td>\n";
}

################################################################################
sub report
################################################################################
{

  ($report_type) = @_;

  open (my $rep, ">report".$report_type.".html");
  print $rep "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'> \n";
  print $rep "<html>\n";
  print $rep "<head>\n";
  print $rep "<title>".$report_type." report ".localtime(time)."</title>\n";
  print $rep "<meta http-equiv='content-type' content='text/html; charset=utf-8'>\n";
  print $rep "<meta name='language' content='en'>\n";
  print $rep "<meta name='author' content='openstreetmap.cz'>\n";
  print $rep "</head>\n";
  print $rep "<body>\n";

  print $rep "<table border='1'>\n";

  my $sql = "select * from mail";

  if ($report_type eq "daily") {
    $sql .= " where start > " . (time() - 86400);
  }

#  print $sql."\n";

  my $sth = $dbh->prepare($sql);
  $sth->execute();
  my $row;
  my $t;
  print $rep "<tr>\n";
  print $rep "<th>id</th>";
  print $rep "<th>start</th>";
  print $rep "<th>sent</th>";
  print $rep "<th>received</th>";
  print $rep "<th>email</th>";
  print $rep "<th>smtpd</th>";
  print $rep "<th>answer</th>";
  print $rep "</tr>\n";

  while($row = $sth->fetchrow_hashref()) {
    my $tdcolor = "green";
    print $rep "<tr>\n";
    print $rep "<td>$row->{id}</td>\n";

    my $istart = $row->{start};
    my $isnt = $row->{sent};
    my $ircvd = $row->{received};

    $tstart = ($row->{start})?localtime($row->{start}):"not started?";
    $tsnt = ($row->{sent})?localtime($row->{sent}):"not sent";
    $trcvd = ($row->{received})?localtime($row->{received}):"not received";

    #time limit
    my $pause = 10 * 60;
    my $time_limit = $istart + $pause;

    if ($ircvd > $time_limit) {
      $tdcolor = "red";
    }

    if ($trcvd eq "not received") {
      $tdcolor = "blue";
      if ($report_type eq "daily") {
        &send_warning('postmaster@tykadlo.cz');
        &send_warning('michal.grezl@gmail.com');
        &send_warning('pavel.ma@post.cz');
      }
    }

    &td($rep, $tstart, $tdcolor);
    &td($rep, $tsnt, $tdcolor);
    &td($rep, $trcvd, $tdcolor);

    &td($rep, $row->{email});
    &td($rep, $row->{smtpd});
    &td($rep, $row->{out_smtp_answer});
    print $rep "</tr>\n";
  }
  print $rep "</table>\n";
  print $rep "</body>\n";

  $sth->finish();
  $dbh->disconnect();
  close($rep);
}

sub date_r
{
  my $dt = DateTime->now(time_zone=>'local');
  my $str = DateTime::Format::Mail->format_datetime($dt);

  return $str;
}

