38e8cced4ae6e4d0b59533da2bc6c176b87de99f
[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 ( @resolvers, $A, %AGI, $num, $resources );
21
22 # in order of preference
23 @resolvers = qw/ e164.org e164.arpa /;
24
25 # setup AGI environment
26 $A   = Asterisk::AGI->new();
27 %AGI = $A->ReadParse;
28
29 unless ( $num = $ARGV[0] ) {
30     $A->verbose( "No number to parse!  Exiting.", 4 );
31     exit;
32 }
33 $ARGV[0] =~ s/\s+//g;
34 $num =~ s/[^\d]//g;
35 $num = join '.', split //, reverse $num;
36
37 foreach (@resolvers) {
38     last if $resources;
39     $A->verbose( "Finding resource at $_ for $ARGV[0]...", 4 );
40     $resources = get_resources( $num, $_ );
41 }
42 unless ($resources) {
43     $A->verbose( "No valid resources found for $ARGV[0].", 4 );
44     exit;
45 }
46
47 foreach (
48     sort {
49         $resources->{$a}->{'preference'} <=> $resources->{$b}->{'preference'}
50     }
51     keys %$resources
52   )
53 {
54     my $resource = $resources->{$_}->{'resource'};
55     if ( $A->exec( 'Dial', "$resource|60|r" ) ) {
56         last;
57         $A->hangup;
58     }
59 }
60
61 exit;
62
63 sub get_resources {
64     my ( $num, $resolver ) = @_;
65     my $resource;
66
67     my $res = Net::DNS::Resolver->new;
68     my $query = $res->query( "$num.$_", 'NAPTR' );
69
70     unless ($query) {
71         $A->verbose(
72             "ENUM query failed at $_ for $ARGV[0]: " . $res->errorstring, 4 );
73         return;
74     }
75
76     # build hash of potential resources to use
77     my %records;
78     my $count = 0;
79     foreach my $rr ( $query->answer ) {
80         next unless $rr->type eq 'NAPTR';
81         next unless $rr->service =~ /(sip|iax)/i;
82         $count++;
83
84         $resource = $ARGV[0];
85         my ( $pattern, $replacement ) = ( split '!', $rr->regexp )[ 1, 2 ];
86         $replacement =~ s/\@/\\\@/;
87         $resource    =~ s/^\+//;
88         $A->verbose( "$pattern, $replacement", 4 );
89         my $regexp = "\$resource =~ s/$pattern/$replacement/";
90         eval "$regexp";
91         if ($@) {
92           $A->verbose( "ENUM replacement faileD: $@", 1 );
93           next;
94         }
95         $A->verbose( "new resource: $resource", 4 );
96         $resource =~ s/^(\w+):/\U$1\//;
97         $records{$count} =
98           { preference => $rr->preference, resource => $resource };
99     }
100
101     return \%records;
102 }