package Asterisk::AGI;

# $Id: AGI.pm 2244 2006-09-22 05:04:30Z tzafrir $
# This is a re-implementation if the module Asterisk::AGI from the 
# Asterisk-perl distribution (http://asterisk.gnuinter.net/ ), which, 
# unfortunetly, lacks any distribution license.
#
# Copyright 2006 Tzafrir Cohen <tzafrir.cohen@xorcom.com>
# 
# Portions taken from the script agi-test.agi in the asterisk distribution.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#  
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#  
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
#

=start

Perl interface for the Asterisk Gateway Interface (AGI) of the 
L<Asterisk PBX|http://asterisk.org/>

  #!/usr/bin/perl -w
  
  use strict;
  use Asterisk::AGI;
  
  my $AGI = new Asterisk::AGI;    # Create a new object
  my %input = $AGI->ReadParse();  # Get initial setup from Asterisk 
  $AGI->set_debug_mode(1);        # Verbose execusion
  
  #$AGI->verbose(2,"Testing, 123.");   # Use Verbose rather than printing
                                      # to standard error. The latter only
				      # works when the asterisk process is 
				      # attached to the original console.
  $AGI->stream_file('the-number-is'); # Running some commands:
  $AGI->say_digits($input{callerid}); # 
  
  $AGI->exec('WaitMusicOnHold','2');  # The command exec could be used to 
                                      # run an arbitrary command.
  
  $AGI->hangup();                     # If you want to hang-up the channel

=cut

=head1 new()

Returns a new Asterisk::AGI object.

=cut 

sub new {
  my $class = shift;
  my $self = {
    host_vars => {}, # we get those at startup. read-only?
    debug_mode => 1,
  };
  bless ($self,$class);
  return $self;
}

=head1 ReadParse()

Start an AGI session: reads variables from Asterisk. Should be called
exactly once at the beginning of a session.

Returns a hash of all the variables.

=cut 

sub ReadParse {
  my $self = shift;
  #return () if (%{$self->{host_vars}}); # if we already got variables.

  # code borrowed from agi-test.agi
  $|=1;

  while (<STDIN>) {
    chomp;
    last unless length($_);
    if (/^agi_(\w+):\s+(.*)$/) {
      $self->{host_vars}->{$1} = $2;
    }
  }
  return (%{$self->{host_vars}})
}

sub command($$) {
  my $self = shift;
  my $cmdline = shift;

  print STDERR "$cmdline\n" if $self->{debug_mode};
  print STDOUT "$cmdline\n";
  my $result = <STDIN>;
  chomp $result;
  print STDERR "$result" if $self->{debug_mode};
  return ($result =~ /^200/);
}

=head1 set_debug_mode(bool)

sets debug mode (of the Asterisk::AGI module) to either true or false.

=cut

sub set_debug_mode($$) {
  my $self = shift;
  my $new_mode = shift;
  $new_mode = ($new_mode)? 1:0; # convert to boolean
  $self->{debug_mode} = $new_mode;
}


=head1 stream_file(filename)

Asks asterisk to play the file I<filename>.

=cut

sub stream_file($$) {
  my $self = shift;
  my $file = shift;

  # TODO: filter parameter "$file" for special characters
  return $self->command("STREAM FILE $file \"\"");
}

=head1 say_digits(num)

Asks asterisk to say the digists of the number I<num>.

=cut

sub say_digits($$) {
  my $self = shift;
  my $num = shift;

  return $self->command("SAY DIGITS $num \"\"");
}

=head1 exec(command,args)

Asks asterisk to run the dialplan application I<command> with I<args>.

At this point I<args> should probably be a '|'-separated string. 
Needs changing.

=cut

sub exec {
  my $self = shift;
  my @args = @_;

  return $self->command("EXEC $args[0] $argv[1]");
}


=head1 hangup()

Hang up the current channel.

=cut

sub hangup($) {
  my $self = shift;

  return $self->command("HANGUP");
}

=head1 verbose(level, mesage)

Sends a verbose message to the console, with priority I<level>.

=cut

sub verbose($$$) {
  my $self = shift;
  my $level = shift;
  my $message = shift;

  # TODO: filter parameters $leve, $message for special characters
  # TODO: check that $level is a valid number
  return $self->command("VERBOSE $message $level");
}

=head1 dump_agi_vars()

Dump the variables that were read from Asterisk to the standard error.

=cut

sub dump_agi_vars($) {
  my $self = shift;
  my @keys = sort keys %{$self->{host_vars}};
  foreach (@keys) {
    print STDERR "$_ = ".$self->{host_vars}->{$_}."\n";
  }
  #return () if (%{$self->{host_vars}}); # if we already got variables.
}

1;
