#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use YAML;
use Net::SIP;
use Net::SIP::Util qw(invoke_callback);
use Net::SIP::Debug;
use POSIX qw(strftime);
my $conf_default;
if ($0 =~ m@.*/@) {
    $conf_default = $& . "config.yaml";
    chdir $&;
} else {
    $conf_default = "config.yaml";
}
my %opt = (
   conf => $conf_default,
);
GetOptions( \%opt, 'conf=s', 'help' ) || pod2usage(2);
pod2usage(1) if $opt{help};

my ($cfg) = YAML::LoadFile($opt{conf});
die "Fail to read yaml file: $@" if $@;
die "Fail to read answer sound: " . $cfg->{answer_sound}
    unless -f $cfg->{answer_sound};
my $rings = 0;
$rings = $cfg->{answer_rings} if $cfg->{answer_rings} =~ /^\d+$/;

my @legs;
if ($cfg->{sip_legs}) {
    for (split(/\s+/, $cfg->{sip_legs})) {
	push @legs, Net::SIP::Leg->new(addr => $_);
    }
}
Net::SIP::Debug->level($cfg->{sip_debug_level}) if $cfg->{sip_debug_level};
my $ua = Net::SIP::Simple->new(
    leg => \@legs,
    outgoing_proxy => $cfg->{sip_domain},
    registrar => $cfg->{sip_domain},
    domain => $cfg->{sip_domain},
    from => $cfg->{sip_user},
    auth => [$cfg->{sip_user}, $cfg->{sip_passwd}],
    ) || die;
my $register;
$register = sub {
    my $expire = $ua->register || die "Fail to register";
    $ua->add_timer($expire/2, $register);
};
$register->();
$ua->listen(
    init_media => \&answering,
    recv_bye => sub {
	my $param = shift;
	my $t = delete $param->{stop_rtp_timer};
	$t && $t->cancel;
    }
    );

if ($rings > 0) {
    my $sub = $ua->{endpoint}->{application}->[0];
    $ua->{endpoint}->{application}->[0] = sub {
	my ($self, $args, $endpoint, $ctx, $request, $leg, $from) = @_;
	my $meth = $request->method;
	if ($meth eq 'INVITE') {
	    my $res = $request->create_response('180', 'Ringing');
	    $endpoint->new_response($ctx, $res, $leg, $from);
	    $self->add_timer($rings, [$sub, $self, $args,
				      $endpoint, $ctx, $request, $leg, $from]);
	} else {
	    $endpoint->close_context($ctx);
	}
    };
}

$ua->loop;
exit 0;

sub answering {
    my ($call, $param) = @_;
    my $answer_fd;
    my $answer_buf;
    my $answer = sub {
	$answer_fd || open($answer_fd, '<', $cfg->{answer_sound}) || die $!;
	my $buf;
	$answer_buf = $buf if read($answer_fd, $buf, 160);
	$answer_buf;
    };
    my $out = $call->get_peer;
    $out =~ s/\s*\"?\s*\<?sip:/./;
    $out =~ s/[\"\<\>\/\:]//g;
    $out =~ s/\s+/_/g;
    $out = sprintf("%s.%s.raw", strftime("%Y%m%d-%H%M%S", localtime), $out);
    $out = $cfg->{voicemail_dir} . "/$out" if $cfg->{voicemail_dir};
    $param->{stop_rtp_timer} = $call->add_timer(
	$cfg->{voicemail_time}, [sub { shift->bye; }, $call]);
    return invoke_callback($call->rtp('media_send_recv', $answer, 1, $out),
			   $call, $param);
}

__END__

=head1 NAME

answer_machine - answering machine

=head1 SYNOPSIS

  % answer_machine
  % answer_machine --conf /path/to/config.yaml

=head1 DESCRIPTION

C<answering machine> is a command line application that answers
to the incoming SIP calls.
