#!/usr/bin/perl
#
#
#
use strict;
use Getopt::Long qw(GetOptions);
use MIME::Base64;
use LWP::UserAgent;
use Carp;
use JSON;
no warnings 'utf8';

my $container   = 'BennoContainer';
my $export      = '';
my $filter      = '*'; 
my $first       = 0;
my $help        = '';
my $resthost    = 'localhost';
my $instanceid  = '';
my $json        = '';
my $limit       = 20;
my $licenseinfo = '';
my $mailid      = '';
my $port        = 21080;
my $query       = '';
my $repofile    = '';
my $scid        = '';
my $secret      = fetchSecret('/etc/benno/rest.secret','/etc/benno/benno.xml');
my $xheader     = '';
my $verbose     = 0;

GetOptions (
    'container=s'   => \$container,
    'export=s'      => \$export,
    'filter=s'      => \$filter,
    'first=i'       => \$first,
    'help'          => \$help,
    'json'          => \$json,
    'limit|l=i'     => \$limit,
    'instance-id'   => \$instanceid,
    'id|i=s'        => \$mailid,
    'license'       => \$licenseinfo,
    'port=s'        => \$port,
    'query=s'       => \$query,
    'repofile'      => \$repofile,
    'resthost=s'    => \$resthost,
    'secret=s'      => \$secret,
    'scid|u=s'      => \$scid,
    'verbose+'      => \$verbose,
    'xheader=s'     => \$xheader,
) or help_exit();

help_exit() if $help;
help_exit() unless $secret;
help_exit("No query or mailid given.") unless ($query || $mailid || $instanceid || $licenseinfo);

my $proto = 'http';

my $params;
my $path;
if ($mailid) {
    $params = { 'archive' => $container,
                'id'      => $mailid,
              };
    $params->{'format'} = 'raw'  if not $json;
    $params->{'header'} = 'true' if not $repofile;

    $path  = '/mail/';
}
elsif ($instanceid or $licenseinfo) {
    $params = {};
    $params->{'format'} = 'raw' if not $json;
    $path  = '/license/';
}
else {
    $query =~ s/SortableDate:\[/Date:[/g;
    if (-f $query)  { $query  = read_first_line($query); }
    if (-f $filter) { $filter = read_first_line($filter); }
    $params = { 'archive' => $container,
                'query'   => '('.$query.')',
                'query'   => $query,
                'start'   => $first,
                'limit'   => $limit,
                'sort'    => 'Date',
                'sortAsk' => 'false',
                'filterQuery' => '('.$filter.')',
              };
    $path  = '/search/';
}
$scid and $params->{'scid'} = $scid;

my $uri = $proto.'://'.$resthost.':'.$port.$path;
my $UA = LWP::UserAgent->new;

my $b64creds = encode_base64('benno2'.':'.$secret,'');
$UA->default_header('Authorization' => 'Basic '.$b64creds);

my $Response = $UA->post($uri,$params);
my $return;
if ($Response->is_success) {
    $return = $Response->decoded_content;
}
else {
    print STDERR "Response status: ",$Response->status_line,"\n";
    print STDERR $Response->content,"\n";
    exit 1;
}

if ($mailid) {      # Response returned raw email
    my $content;
    if ($xheader) {
        $xheader =~ s/[\r\n]//g;        # normalize
        $xheader .= "\r\n";
        $content = $xheader.$return;
    }
    else {
        $content = $return;
    }
    if ($export) {
        my $filename = $mailid.'.eml';
        export2dir($export,$filename,$content);
    }
    else {
        print $return;
    }
    exit 0;
}

if ($json) {        # Response returned raw email
    print $return,"\n";
    exit 0;
}

# Response returned JSON data
my $JSON = JSON->new->allow_nonref;
my $data = $JSON->decode($return);

if ($data->{error}) {
    print STDERR "Error: ",$data->{error},"\n";
    exit 1;
}

if ($instanceid) {
    print 'Instance-ID: ',$data->{licenseInstanceId},"\n";
    exit 0;
}
if ($licenseinfo) {
    print_licenseinfo($data);
    exit 0;
}





my $first    = $data->{first};
my $last     = $data->{last};
my $limit = $data->{limit};
my $found    = $data->{found};
my $results  = $data->{results};

verbose(3,"\n****** REQUEST ******");
verbose(3,"URI: $uri");
verbose(3,"Parameter:");
foreach my $param (keys %{$params}) {
    verbose(3,"    $param => $params->{$param}");
}
verbose(3,"\n****** RESPONSE *******");

my $num = 0;
foreach my $item (@{$results}) {
    verbose(1, 'Id('.$num++.'): ',1);
    verbose(0, $item->{id});
    verbose(2, '  From: '.$item->{From});
    foreach my $to (@{$item->{To}}) {
        verbose(2,'  To: '.$to);
    }
    foreach my $cc (@{$item->{Cc}}) {
        verbose(2,'  Cc: '.$cc);
    }
    foreach my $bcc (@{$item->{Bcc}}) {
        verbose(2,'  Bcc: '.$bcc);
    }
    verbose(2,'  Subject: '.$item->{Subject});
    verbose(2, '  Date: '.$item->{Date});
    verbose(2, '  Attachment: '.$item->{hasAttachment});

}

if (!$num) {
    verbose(0, "No results found.");
    exit 0;
}

verbose(1, "$found mails found (first: $first, last: $last, limit: $limit)");


### SUBS ###
### print help and exit
sub help_exit
{
    my $msg = shift;

    if ($msg) {
        print $msg,"\n\n";
    }

    print "Usage: $0 [-h] [-s <secret>] [-r <rest host>] [-c <container>] [-p <port>] <-q <query>|-i <mailid>>\n";
    print "    -c '<container>'    archive container\n";
    print "    -u|--scid <scid>'   subcontainer id (if configured)\n";
    print "    --filter '<filter>' lucene filter string or file with filter\n";
    print "    --first '<num>'     first email in response list\n";
    print "    -l|--limit '<num>'  limit response list to <num> mails\n";
    print "    -i|--id '<id>'      fetch mail with id\n";
    print "    -j                  dump raw JSON response\n";
    print "    -p <port>           REST port (21080)\n";
    print "    -q '<query>'        lucene query string or file with filter\n";
    print "                        (search header as \"HEADER-<HEADER-NAME>\")\n";
    print "    -r <resthost>       (localhost)\n";
    print "    -s <secret>         shared secret\n";
    print "    -v                  verbose\n";
    print "    -h                  print this help\n";
    print "                        (search header as \"HEADER-<HEADER-NAME>\")\n";
    print "    --repofile          export mail raw with Benno header from repository\n";
    print "    --export <dir>      write emlfile to directory <dir>\n";
    print "    --xheader <string>  prepend output file with header string\n";
    print "    --instance-id       print Benno MailArchive Instance ID\n";
    print "    --license           print license data\n";
    print "\n";
    
    exit 1;
}


sub export2dir
{
    my ($edir,$filename,$content) = @_;

    my $efile = "$edir/$filename";
    open (my $fh,">","$edir/$filename") or croak "Cannot open outfile $efile: $!\n";
    print $fh $content;
    close $efile;
}


sub print_licenseinfo
{
    my ($data) = @_;

    foreach my $line (split /\n/,$data->{licenseFile}) {
        print "$line\n";
    }
    print "Status:",$data->{licenseStatus},"\n";
    verbose(1,'');
    verbose(1,'Archives:   '.$data->{archiveCount});
    verbose(1,'Benno Core: '.$data->{coreVersion});
    verbose(1,'Benno REST: '.$data->{restVersion});
}

### print and format debug messages
sub verbose
{
    my ($level,$string,$nonewline) = @_;
    my $newline = "\n" unless $nonewline;
    if ($verbose >= $level) {
        print $string,$newline;
    }   
}


### fetch password from config file
sub fetchSecret
{
    my $sfile    = shift;
    my $bennoxml = shift;
    my $secret;

    if (open SF, $sfile) {
        $secret = <SF>;
        chomp $secret;
        close SF;
        return $secret; 
    }

    open XMLFILE, $bennoxml;
    foreach my $line (<XMLFILE>) {
        chomp $line;
        ($secret) = $line =~ m!<sharedSecret>(.+)</sharedSecret>!;
        last if $secret;
    }
    return $secret;
}


### read first line from file
sub read_first_line
{
    my $filename = shift;

    if (!open FILE, $filename) {
        print STDERR "Cannot open file $filename. $!\n";
        exit 2;
    }
    my $line = <FILE>;
    chomp $line;

    return $line;
}
