Linux - Server This forum is for the discussion of Linux Software used in a server related context. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
11-26-2010, 10:16 AM
|
#1
|
Member
Registered: Apr 2006
Location: Enschede
Distribution: Debian, Red Hat/Fedora, Solaris, DD-WRT, NetBSD, Mac OS8/9, Mac OSX, UMP/OS, ESX
Posts: 42
Rep:
|
Asterisk DISA IVR
Hello,
I am having trouble solving an issue which I'm sure other people must have faced before:
I have Asterisk 1.2 running on a SPARC Solaris machine (I know there's a forum for that, but it doesn't directly relate to the issue at hand) with a number of extensions, queues and so on configured and working well. Recently I wanted to create an IVR including a PIN verification system, enabling a user to call the number, hear a message (welcome, enter your PIN, etc), enter his PIN in the DISA application and hear another message afterwards without any further input. To clarify, I can call the extension (IVR), hear the message and input my PIN, though after that I'm left with a dialtone and Asterisk waiting for me to enter a number(extension to call). If I do this, it forwards me correctly, though I'd prefer an intermediate step including a message for the user. The idea is the following:
User calls number.
User is greeted with 'Enter your PIN,etc'.
User enters PIN code, followed by a '#'.
User hears another message 'Thank you. Now you can...etc'.
User then provides further input, etc.
Here's an excerpt from my extensions.conf:
Code:
; Lights control
exten => 9994,1,Answer
exten => 9994,2,Playback(welcome)
exten => 9994,3,Playback(beep)
exten => 9994,n,DISA(4321|lcontrol)
;exten => 9994,n,Playback(code_accepted)
exten => 9994,105,Hangup
[lcontrol]
exten => s,1,Answer
exten => s,2,Playback(lights_explain)
exten => s,n,WaitExten
; turn off lights
exten => 0,1,Answer
exten => 0,n,Playback(code_accepted)
exten => 0,n,TrySystem(/usr/bin/lights_off.sh)
exten => 0,n,Playback(beep)
exten => 0,n,Playback(lights_off)
exten => 0,n,Wait(2)
exten => 0,n,Hangup
; turn on lights
exten => 1,1,Answer
exten => 1,n,Playback(code_accepted)
exten => 1,n,TrySystem(/usr/bin/lights_on.sh)
exten => 1,n,Playback(beep)
exten => 1,n,Playback(beep)
exten => 1,n,Playback(lights_on)
exten => 1,n,Wait(2)
exten => 1,n,Hangup
Obviously, I could simply define an extension as the PIN code, though this seems rather crude. The way that I understand it, is that DISA is designed to 'forward' the call to a context, NOT an extension or back to the current/previous context. I know that you could also use the Authenticate() application, though in that case I would either have to overwrite the default female voice or live with two different voices (of different sexes!) in one single IVR, and I'm reluctant to overwrite 'her'. I also don't want to use VMauthenticate() either for the same reason, and the fact that not all registered users should be able to pass the DISA() step with only their own credentials (the PIN would be a secret, available to a limited number of people).
Update: I have a working example defining the PIN as an extension followed by a hash. This is the exact desired functionality though I'd love to see a better way of implementing this:
extensions.conf:
Code:
; Lights control
exten => 9994,1,Answer
exten => 9994,2,Playback(lights_control)
exten => 9994,3,Playback(beep)
exten => 9994,4,WaitExten
exten => 4321#,1,Answer
exten => 4321#,2,Playback(code_accepted)
exten => 4321#,n,Goto(lcontrol|s|1)
exten => 4321#,n,Hangup
exten => i,1,Wait(4)
exten => i,2,Playback(code_invalid)
exten => i,3,Goto(queues|9994|2)
[lcontrol]
exten => s,1,Answer
exten => s,2,Playback(lights_explain)
exten => s,n,WaitExten
; turn off lights
exten => 0,1,Answer
exten => 0,n,TrySystem(/usr/bin/lights_off.sh)
exten => 0,n,Playback(beep)
exten => 0,n,Playback(lights_off)
exten => 0,n,Wait(2)
exten => 0,n,Hangup
; turn on lights
exten => 1,1,Answer
exten => 1,n,TrySystem(/usr/bin/lights_on.sh)
exten => 1,n,Playback(beep)
exten => 1,n,Playback(beep)
exten => 1,n,Playback(lights_on)
exten => 1,n,Wait(2)
exten => 1,n,Hangup
If anyone as has any ideas (or solutions!) please let me know.
Kind regards,
PelliX
Last edited by PelliX; 11-26-2010 at 11:57 AM.
|
|
|
11-30-2010, 07:32 AM
|
#2
|
Member
Registered: Apr 2006
Location: Enschede
Distribution: Debian, Red Hat/Fedora, Solaris, DD-WRT, NetBSD, Mac OS8/9, Mac OSX, UMP/OS, ESX
Posts: 42
Original Poster
Rep:
|
Well, after some analysis it became clear to me that Asterisk itself does not provide such functionality in a predefined way, and the obvious way to go is the AGI (Asterisk Gateway Interface). Although any programming language can be used for this, I decided to whip up a quick version in Perl:
Code:
#!/usr/bin/perl
#
# This script verifies a user's PIN code to grant access to secured
# systems and contexts.
#
# PelliX 2010
#
# Note that the numeric values from the $wait_for_digits() function
# are calculated by subtracting 48 when receiving numeric input, though
# the pound sign (or hash) is reported as 35 and the asterisk as 42.
#
use Asterisk::AGI;
use strict;
# location of PIN database and protected context
my $db = "/etc/opt/asterisk/PIN.db";
my $target_context = 'lcontrol';
my $source_context = 'queues';
my $source_exten = '7000';
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
my $callerid = $input{'callerid'};
$AGI->verbose('Initiating PIN check');
$AGI->stream_file('beep');
my $dig1 = ($AGI->wait_for_digit(-1) - 48);
my $dig2 = ($AGI->wait_for_digit(-1) - 48);
my $dig3 = ($AGI->wait_for_digit(-1) - 48);
my $dig4 = ($AGI->wait_for_digit(-1) - 48);
my $dig5 = ($AGI->wait_for_digit(-1));
my $pincode = $dig1.$dig2.$dig3.$dig4;
#$AGI->say_digits($pincode);
$AGI->verbose('PIN: '.$pincode);
my $result;
my $selection;
# if the PIN code was followed by a hash
if ($dig5 == 35)
{
open(PINDB, '<', $db);
while (<PINDB>)
{
if ((substr $_, 0, 4) eq $callerid)
{
$result = "Found $callerid in DB, verifiying PIN";
$AGI->verbose($result);
if ((substr $_, 5, 4) eq $pincode)
{
$result = "Matched user $callerid with PIN $pincode in DB";
$AGI->verbose($result);
$AGI->stream_file('code_accepted');
$AGI->stream_file('lights_explain');
$selection = ($AGI->wait_for_digit(-1) - 48);
# continue to protected context (and extension)
# in this example there are only two choices; 0 and 1
if ($selection < 2)
{
$AGI->set_priority('1');
$AGI->set_extension($selection);
$AGI->set_context($target_context);
}
else
{
$AGI->set_priority('1');
$AGI->set_extension($source_exten);
$AGI->set_context($source_context);
}
}
else
{
$result = "Failed to match user $callerid with PIN $pincode in DB";
$AGI->verbose($result);
$AGI->stream_file('code_invalid');
$AGI->set_priority('1');
$AGI->set_extension($source_exten);
$AGI->set_context($source_context);
}
}
}
}
else
{
$result = "PIN entry not followed by hash";
$AGI->verbose($result);
$AGI->stream_file('code_invalid');
$AGI->set_priority('1');
$AGI->set_extension($source_exten);
$AGI->set_context($source_context);
}
close(PINDB);
$AGI->verbose('PIN verification ended');
exit;
Note that in this case the extension that the user needs to dial has changed to 7000 for cosmetic reasons. The database can be implemented in MySQL or any other form of database by adding the relevant logic to the Perl script and including the required libraries. In this example the database consists of a plain text file, referred to as $db in the script, with the following layout ('callerid:PIN'):
Code:
3045:1234
4247:4321
2199:9072
Additionally, there was a slight modification to the dialplan for extension 7000:
Code:
[queues]
; Lights control (AGI)
exten => 7000,1,Answer
exten => 7000,2,Playback(lights_control)
exten => 7000,3,EAGI(PIN.agi)
exten => i,1,Wait(1)
exten => i,2,Hangup
Thanks,
PelliX
Last edited by PelliX; 12-01-2010 at 06:25 AM.
Reason: bad grammar!
|
|
|
All times are GMT -5. The time now is 10:30 AM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|