Mahlon's initial version.
[asterisk-agi-enum.git] / enum.agi
1 #!/usr/bin/env perl
2 #
3 # Make outgoing calls via enum NAPTR records.
4
5 # Add to your extensions.conf like so:
6 #       exten => _*164X.,n,AGI(enum.agi, +${EXTEN:4})
7 #
8 # Requires Net::DNS and Asterisk::AGI perl modules.
9 #
10 # Mahlon E. Smith <mahlon@martini.nu>
11 #
12 # ---------------------------------------------------------
13
14 use strict;
15 use warnings;
16
17 use Net::DNS;
18 use Asterisk::AGI;
19
20 my (
21     @resolvers,
22     $A,
23     %AGI,
24     $num,
25     $resources
26 );
27
28 # in order of preference
29 @resolvers = qw/ e164.org e164.arpa /;
30
31 # setup AGI environment
32 $A = Asterisk::AGI->new();
33 %AGI = $A->ReadParse;
34
35 unless ( $num = $ARGV[0] ) {
36     $A->verbose( "No number to parse!  Exiting.", 4 );
37     exit;
38 }
39 $ARGV[0] =~ s/\s+//g;
40 $num =~ s/[^\d]//g;
41 $num = join '.', split //, reverse $num;
42
43 foreach ( @resolvers ) {
44     last if $resources;
45     $A->verbose("Finding resource at $_ for $ARGV[0]...", 4);
46     $resources = get_resources( $num, $_ );
47 }
48 unless ( $resources ) {
49     $A->verbose( "No valid resources found for $ARGV[0].", 4 );
50     exit;
51 }
52
53 foreach ( sort { $resources->{$a}->{'preference'} <=> $resources->{$b}->{'preference'} }
54             keys %$resources ) {
55     my $resource = $resources->{$_}->{'resource'};
56     if ( $A->exec( 'Dial', "$resource|60|r" ) ) {
57         last;
58         $A->hangup;
59     }
60 }
61
62 exit;
63
64 sub get_resources
65 {
66     my ( $num, $resolver ) = @_;
67     my $resource;
68
69     my $res = Net::DNS::Resolver->new;
70     my $query = $res->query( "$num.$_", 'NAPTR' );
71
72     unless ( $query ) {
73         $A->verbose("ENUM query failed at $_ for $ARGV[0]: " . $res->errorstring, 4);
74         return;
75     }
76
77     # build hash of potential resources to use
78     my %records;
79     my $count = 0;
80     foreach my $rr ( $query->answer ) {
81         next unless $rr->type eq 'NAPTR';
82         next unless $rr->service =~ /(sip|iax)/i;
83         $count++;
84
85         $resource = $ARGV[0];
86         my ( $pattern, $replacement ) = (split '!', $rr->regexp)[1,2];
87         print "$pattern, $replacement\n";
88         unless ( $resource =~ s/$pattern/$replacement/ ) {
89             $A->verbose("Unable to apply regexp to $ARGV[0]", 4);
90         }
91         $resource =~ s/^(\w+):/\U$1\//;
92         $records{$count} = { preference => $rr->preference, resource => $resource };
93     }
94
95     return \%records;
96 }