package Asterisk::AstMan; $|=1; use IO::Socket::INET; use Data::Dumper; use Digest::MD5; sub init($;$) { my $proto = shift; my $args = shift; my $class = ref($proto) || $proto; my $self = { _events => undef , _connected => undef }; $self->{_host} = $args->{-host} || "localhost"; $self->{_port} = $args->{-port} || 5038; $self->{_user} = $args->{-user} || undef; $self->{_secret} = $args->{-secret} || undef; my $me = bless $self,$class; $me->connect; $me; } sub DESTROY($) { my $self = shift; $self->disconnect; } sub error($$) { my($self,$error) = @_; die $error; } sub chomp($$) { my ($self,$str) = @_; $str =~ s/[\r\n]//g; $str; } sub input($;$) { my ($self,$m) = @_; my $i; my @r; my $s = $self->{_sock}; if($m) { $i = <$s>; return $self->chomp($i); } while($i = <$s>) { return @r if($i eq "\r\n"); $i =~ s/[\r\n]+$//g; push @r,$i; } @r; } sub output($$) { my ($self,$data) = @_; my $s = $self->{_sock}; print $s $data; } sub format($$;$) { my ($self,$data) = @_; my $ret; if(ref $data eq "HASH" ) { foreach my $k (sort keys %$data) { $ret .= "$k: $data->{$k}\r\n"; } $ret .= "\r\n"; } else { my %h = $data =~ /^([^:]+)\s*:\s*([^\r\n]*)/mg; $ret = \%h; } $ret; } sub send($$;$) { my ($self,$param,$reply) = @_; # 0 hash 1 array 2 scalar $reply ||= 0; $param->{Uniqueid} = $$; $self->output($self->format($param)); my $r; if($reply == 0) { $r = $self->format(join "\n",$self->input); } elsif($reply == 1) { $r = [$self->input]; } elsif($reply == 2) { $r = join "\n",$self->input; } $r; } sub connect($) { my $self = shift; $self->{_sock} = new IO::Socket::INET( Proto => 'tcp', PeerAddr => $self->{_host}, PeerPort => $self->{_port} ) or return $self->error("Connection refused $self->{_host} port $self->{_port}"); $self->{_sock}->autoflush(1); my $title = undef; ($title,$self->{_version}) = $self->input(1) =~ /^([^\/]+)\/(.*)/; if ($title !~ /Asterisk Call Manager/) { return $self->error("Com Error"); } my $reply = $self->send({ Action => 'Challenge', AuthType => 'MD5'}); my $auth; if($reply->{Response} eq 'Success') { my $md5 = new Digest::MD5; $md5->add($reply->{Challenge}); $md5->add($self->{_secret}); $auth = $self->send({Action => 'Login', AuthType => 'MD5', Username => $self->{_user}, Key => $md5->hexdigest }); } else { $auth = $self->send({ Action => 'Login', Username => $user, Secret => $secret }); } unless ($auth->{Response} eq 'Success' and $auth->{Message} eq 'Authentication accepted' ) { return $self->error("Connection Failed"); } } sub action($$) { my ($self,$action) = @_; $self->send({ Action => $action },2); } sub command($$) { my($self,$command) = @_; my $reply = $self->send({'Action' => 'Command', 'Command' => $command},2); my ($ret) = $reply =~ /Response: Follows(.*?)--END COMMAND--/s; $ret; } sub disconnect($) { my ($self) = @_; $self->action("Logoff"); } sub reg_event($$$) { my ($self,$event,$code) = @_; $self->{_events}->{$event} = $code; } sub listen($) { my ($self) = @_; while(my $r = $self->format(join "\n",$self->input)) { #print Dumper $r; #print "$r->{Event}\n"; my $func = $self->{_events}->{$r->{Event}} || $self->{_events}->{ALL} || undef; &$func($r) if(ref $func); } }