#!/usr/bin/perl
##
##  asterisk-mail.pl -- Asterisk Mail User Agent
##  Copyright (c) 2008 Ralf S. Engelschall <rse@engelschall.com>
##  License: GPL (version 2 or higher)
##  Usage: asterisk-mail.pl <src> <dst> <name> <file>
##

require 5.008;
use IO::File;
use IO::All;
use Asterisk::Manager;
use Data::Dumper;
use MIME::Entity;

#   local configuration
my $my = {
    -prog_name       => "asterisk-mail",
    -prog_version    => "0.9.0",
    -asterisk_name   => "OpenPKG Asterisk PBX",
    -asterisk_host   => "127.0.0.1",
    -asterisk_port   => "5038",
    -asterisk_user   => "asterisk",
    -asterisk_secret => "asterisk",
    -sendmail        => "/usr/sbin/sendmail",
};

##
##  use Asterisk Manager Interface (AMI)
##  to retrieve information about users
##

my $cfg = {
    -extension2realname => {},
    -realname2extension => {},
    -extension2mailaddr => {},
    -mailaddr2extension => {},
    -extension2sipuser  => {},
    -sipuser2extension  => {}
};
my $astman = new Asterisk::Manager;
$astman->host($my->{-asterisk_host});
$astman->port($my->{-asterisk_port});
$astman->user($my->{-asterisk_user});
$astman->secret($my->{-asterisk_secret});
$astman->connect() or die sprintf(
    "Could not connect to Asterisk Manager Interface (AMI) at %s:%s\n",
    $astman->host(), $astman->port()
);
my %response = $astman->action("VoicemailUsersList", 1);
if ($response{"Response"} eq "Success") {
    while (1) {
        %response = map { 
            Asterisk::Manager::splitresult($_);
        } $astman->read_response();
        if ($response{"Event"} eq "VoicemailUserEntry") {
            $cfg->{-extension2mailaddr}->{$response{"VoiceMailbox"}} = $response{"Email"};
            $cfg->{-mailaddr2extension}->{$response{"Email"}} = $response{"VoiceMailbox"};
            $cfg->{-extension2realname}->{$response{"VoiceMailbox"}} = $response{"Fullname"};
            $cfg->{-realname2extension}->{$response{"Fullname"}} = $response{"VoiceMailbox"};
        }
        else {
            last;
        }
    }
}
my $response = $astman->sendcommand("Action" => "Command", "Command" => "sip show users", 1);
$response =~ s/^.+Username\s+.+?NAT\r?\n//si;
my @sipusers = map { s/^(\S+).*$/$1/; $_ } split(/\r?\n/, $response);
foreach my $sipuser (@sipusers) {
    $response = $astman->sendcommand("Action" => "Command", "Command" => "sip show user $sipuser", 1);
    if ($response =~ m/^.*?Callerid\s*:\s*(.+?)\r?\n.*$/si) {
        $response = $1;
        if ($response =~ m/<(\d+)>/s) {
            $cfg->{-extension2sipuser}->{$1} = $sipuser;
            $cfg->{-sipuser2extension}->{$sipuser} = $1;
        }
        if ($response =~ m/"(.+?)"/s) {
            $cfg->{-extension2realname}->{$cfg->{-sipuser2extension}->{$sipuser}} = $1
                if (        defined $cfg->{-sipuser2extension}->{$sipuser}
                    and not defined $cfg->{-extension2realname}->{$cfg->{-sipuser2extension}->{$sipuser}});
            $cfg->{-realname2extension}->{$1} = $cfg->{-sipuser2extension}->{$sipuser} 
                if (        defined $cfg->{-sipuser2extension}->{$sipuser}
                    and not defined $cfg->{-realname2extension}->{$1});
        }
    }
}
$astman->disconnect();

##
##  resolve user information
##

my ($src, $dst, $name, $wavfile) = @ARGV;
$src = &resolve_user($src);
$dst = &resolve_user($dst);
sub resolve_user ($) {
    my ($id) = @_;
    my $user = {
        -extension => ''
        -sipuser   => ''
        -realname  => ''
        -mailaddr  => ''
    };
    if ($id =~ m/^.+\@.+$/) {
        $user->{-mailaddr}  = $id;
        $user->{-extension} = $cfg->{-mailaddr2extension}->{$user->{-mailaddr}};
        $user->{-sipuser}   = $cfg->{-extension2sipuser}->{$user->{-extension}};
        $user->{-realname}  = $cfg->{-extension2realname}->{$user->{-extension}};
    }
    elsif ($id =~ m/^\S+\s+\S+.*$/) {
        $user->{-realname}  = $id;
        $user->{-extension} = $cfg->{-realname2extension}->{$user->{-realname}};
        $user->{-sipuser}   = $cfg->{-extension2sipuser}->{$user->{-extension}};
        $user->{-mailaddr}  = $cfg->{-extension2mailaddr}->{$user->{-extension}};
    }
    elsif ($id =~ m/^\d+$/) {
        $user->{-extension} = $id;
        $user->{-sipuser}   = $cfg->{-extension2sipuser}->{$user->{-extension}};
        $user->{-mailaddr}  = $cfg->{-extension2mailaddr}->{$user->{-extension}};
        $user->{-realname}  = $cfg->{-extension2realname}->{$user->{-extension}};
    }
    else {
        $user->{-sipuser}   = $id;
        $user->{-extension} = $cfg->{-sipuser2extension}->{$user->{-sipuser}};
        $user->{-mailaddr}  = $cfg->{-extension2mailaddr}->{$user->{-extension}};
        $user->{-realname}  = $cfg->{-extension2realname}->{$user->{-extension}};
    }
    $user->{-extension} = "0"               if (not defined $user->{-extension});
    $user->{-sipuser}   = "unknown"         if (not defined $user->{-sipuser});
    $user->{-realname}  = ""                if (not defined $user->{-realname});
    $user->{-mailaddr}  = "unknown@unknown" if (not defined $user->{-mailaddr});
    return $user;
}

##
##  send file as a mail
##

my $text =
    "Dear " . $dst->{-realname} . ",\n" .
    "\n" .
    "here is your audio recording of\n" .
    "$name.\n" .
    "\n" .
    "Yours,\n" .
    "\n" .
    "-- \n" .
    $my->{-asterisk_name} . "\n";

my $mail = MIME::Entity->build(
    From       => sprintf("%s <%s>", $src->{-realname} || $my->{-asterisk_name}, $src->{-mailaddr}),
    To         => sprintf("%s <%s>", $dst->{-realname} || $my->{-asterisk_name}, $dst->{-mailaddr}),
    'X-Mailer' => sprintf("%s/%s", $my->{-prog_name}, $my->{-prog_version}),
    Subject    => sprintf("[%s] Your audio recording of %s", $my->{-asterisk_name}, $name),
    Data       => $text,
);

if (-f $wavfile) {
    my $data = io($wavfile)->slurp();
    $mail->attach(Data => $data, Type => "audio/x-wav");
}
else {
    my $data = "ERROR: WAV file \"$wavfile\" not found\n";
    $mail->attach(Data => $data, Type => "text/plain");
}

my $io = new IO::File sprintf("|%s -oi -oem -f '%s' -t", $my->{-sendmail}, $dst->{-mailaddr}) or die;
$io->printf($mail->stringify);
$io->close();

