Skip to main content

Pin based dialing - the final word

Posted by conraddewet on Wed, 02/16/2011

Ok i think this has been addressed before but im not sure what the final outcome was. Also im using Multi Tenant with Asterisk 1.6 - so from my understanding "Agent Logins" where removed.

Here is my scenario... what would be the best option?
I have to roll out Thirdlane in an "insecure" office, as in, there will be phones on the desks that will be unmonitored, anyone can sit down at a desk and pick up a phone. Joe Blogs could say sit down at desk A or B or C etc and also the client wants it that any one who makes an outbound call MUST type a pin or something to make a call.

I have heard of Agent Logins... whats the latest script for that?

Also i have heard of IRV dialing, making it that you have to dial into an IVR in order to make a call... like "press one to make an outbound call... beeb... now dial the number and press hash... bla blah" ?

Lastly the client wants it that if say Joe Blogs "logs in" or makes an IVR call, the CDR must reflect that Joe Blogs made the call - not ext 101 etc since the extension would just be a dumb terminal.

Any thoughts? scripts or advice for me here?


Submitted by eeman on Wed, 02/16/2011 Permalink

that's a massive amount of custom programming you are asking for. Nothing that a simple forum post will resolve for you.

you're talking about a separate database of user identities, practically a double set of extensions, a complete re-write of the outbound route scripts, and a modification to queue logging to write out identities from the database in the queue_log. When all is complete you would have nothing left that resembles thirdlane outside of the appearance of the web pages; and you would likely have to make manual alterations to get one of your requirements to work since internal callerid is set on the channel driver.

AgentCallbackLogin was depreciated in 1.2 and removed in 1.6. It no longer exists.

The scenario you are asking for is called 'Hot Desking'. Your requirements are actually above and beyond any hot desking code I have seen. Usually Hot Desking code was just for queue handling and the forgery of the queue_log file. The parts where callerID gets altered changes this to a considerably larger level of complexity. Additionally certain functions/features were performed at the channel_driver level and do not 'hot desk' such as MWI (message waiting indication) and BLF (busy lamps) as its the phone's identity that manages this, the only way around that would be a constant alteration of the sip.conf settings and phone configuration settings.

to forge your callerid on everything, including internal calls, would require a deep modification to thirdlane and the standard context= statements of sip.conf.

to require PIN numbers to make calls (as long as its not required to make internal calls) is actually the easier peice. Thirdlane already has restricted/unrestricted settings. A combination of these partitions, well crafted outbound route scripts, and the Authenticate() application will make restricting toll incurring calls.

This requirement is no small task. the scope of this project is immense. The basic construct of a PBX is that the phone is more of an identity than the user. Your design separates a 'user' from the phone and sip.conf entries entirely.

Submitted by conraddewet on Wed, 02/16/2011 Permalink

Hey Erik, my kung fu is strong... and i fear not the custom scripts.

I'm happy to contribute. What i will do is post my findings to this blog. Seems like most things are close, but just not quite. I will look at various options like AGI also. But I pretty much have no choice but to get it working.

With regards to the CDR altering - no i see that's probably not going to happen - however i was thinking about post-processing the data or do custom reporting. So all i need is to "tag" the call so although ext 101 makes the call - if the call gets tagged with an agent code - i could pick this up and this would solve my problem.
I see the CDR has an accountcode that comes from the accountcode of the sif.conf. Can this be altered at runtime?

Ill research the Authenticate() application - i saw a few things on this will post my findings.

With regards to the "hot desk" - yes i see your concerns, but I may have worded it wrong. The deal is, Joe Blogs is "supposed" to sit at Desk A, but COULD also stand up and walk to another desk and call from there by entering his / her own code. It's more of a fraud/security option and less of a "hot-desk-trying-to-be-a-pbx". This way when an outbound call is made the boss knows that Joe Blogs did in fact make the call and that it wasn't some random chap just picking up the handset (something that's common among most Asterisk system)

With regards to the pin code... is it possible for this code to in fact be their mailbox pin number? This way they can even set it them self?

Thanks for the info so far.

Submitted by eeman on Wed, 02/16/2011 Permalink

if your not talking pure hot-desking but more of a extension/passcode restriction to make calls then instead of Authenticate() reading a separate file, consider using VMAuthenticate() and have them use their mailbox pin for voicemail. I do this a lot; prompt someone to enter their extension number, then prompt them for their password to access a feature.

Submitted by conraddewet on Wed, 02/16/2011 Permalink

Thanks Erik, the VMAuthenticate() worked a treat.

So this is what i have so far. On a demo tenant i created two accounts 222 and 333 with voice mail box passwords 1234 (or what ever).

Now I set 222 to "Disallow calling restricted numbers" and the 333 to allow all.

Then in Outbound routs I set up a trunk as per normal and set the dial pattern to _XXX. with the type on restricted. (also removed all the others). Effectively this would allow 333 to dial any number and 222 to dial basically nothing except internal numbers (no trunk dialing).

Then opened up the scripts.include and added this:

[macro-tl-vm-pin-dialing]
exten => s,1,Answer
exten => s,n,Read(ext_num,vm-extension)
exten => s,n,Read(ext_pwd,vm-password)
exten => s,n,VMAuthenticate(${ext_num}@default${TL_DASH}${tenant})
exten => s,n,Read(ext_numdial,vm-enter-num-to-call)
exten => s,n,Set(CDR(accountcode)=${ext_num}${TL_DASH}${tenant})
; exten => s,n,Set(CDR(dst)=${ext_numdial}) ; ERROR[25501]: cdr.c:303 ast_cdr_setvar: Attempt to set the 'dst' read-only variable!.
exten => s,n,Set(__DIALED_NUMBER=${ext_numdial})
exten => s,n,Macro(tl-dialout-1-trunk,${ARG1},${ARG2},${ARG3},${ARG4},${ARG5})
exten => t,1,Hangup
exten => h,1,Hangup
exten => i,1,Playback(invalid)
exten => i,n,Hangup

Then opened the scripts_source.include and added this:

[tl-vm-pin-dialing]
use=feature
friendlyname=Voicemail PIN required Dialling
description
If you have restricted dialing plans then this will allow you to dial unrestricted once the user authenticates using their voicenmail password.
args=1,How long to ring,text:2,Trunk,trunk:3,String to prepend,text:4,Number of digits to strip,text:5,Dial command options,text
body
exten => s,1,Answer
exten => s,n,Read(ext_num,vm-extension)
exten => s,n,Read(ext_pwd,vm-password)
exten => s,n,VMAuthenticate(${ext_num}@default${TL_DASH}${tenant})
exten => s,n,Read(ext_numdial,vm-enter-num-to-call)
exten => s,n,Set(CDR(accountcode)=${ext_num}${TL_DASH}${tenant})
; exten => s,n,Set(CDR(dst)=${ext_numdial}) ; ERROR[25501]: cdr.c:303 ast_cdr_setvar: Attempt to set the 'dst' read-only variable!.
exten => s,n,Set(__DIALED_NUMBER=${ext_numdial})
exten => s,n,Macro(tl-dialout-1-trunk,${ARG1},${ARG2},${ARG3},${ARG4},${ARG5})
exten => t,1,Hangup
exten => h,1,Hangup
exten => i,1,Playback(invalid)
exten => i,n,Hangup

I am borrowing some of the built in macros if you don't mind - thanks.

After a reload, I created a feature code *21 and selected the [tl-vm-pin-dialing] from the options. (not sure why i used "tl-..." in the beginning - i think that's "Thirdlane" hmmm anyway)

So when you select this script it shows the same options as the [tl-dialout-1-trunk] (thank goodness). So its quite easy to just select the Trunk and other options you want.

Quick reload and Off you go... Voice mail pin dialing, from any extension masquerading as your own extension.

Yo will see that in order to pick out masqueraded calls I have set the CDR with the accountcode set to the extension-tenant. You will also see i tried to set the dst and src to make it appear in the CDR records for that extension - but it says its read only.

This is pretty much where i got up to - good enough for my client, but i still want to know. What would i need to do to update the dst and src columns. May even be after the call?? any ideas?

TODO: Im also going to make a direct extension script that will pick up the users extension as they dial in (say *20) asking only for the password since this process is time consuming, and most of the time you will dial from your own phone - only when you are at another station would you dial *21.

Anyway, feel free to contribute. Ill post more if i get further.

Submitted by eeman on Wed, 02/16/2011 Permalink

This is pretty much where i got up to - good enough for my client, but i still want to know. What would i need to do to update the dst and src columns. May even be after the call?? any ideas?

I thought setting callerid in the dialplan would resolve it but unfortunately no. I checked a simple outbound call to the PSTN. It still showed extension 213 making the call even though we clearly see in dialplan that CALLERID(num) clearly gets set to a valid 10digit number.

the function is CDR but not every field is read/write. For example we do Set(CDR(userfield)=something) all the time. I dont know if CDR(src) is read/write but you could give that a try.

Submitted by conraddewet on Wed, 02/16/2011 Permalink

Yip,
ERROR[25501]: cdr.c:303 ast_cdr_setvar: Attempt to set the 'dst' read-only variable!.

Rather than editing the source code of Asterisks and changing it to read write... i was thinking of storing both sets of data in the accountcode column and doing some sort of cron job or post processing.

So like this:
exten => s,n,Set(CDR(accountcode)=${ext_num}${TL_DASH}${ext_numdial}{TL_DASH}${tenant})
; this would write something like: 222-0123456789-demoTenant

An hourly cron job - probably PHP or something (SELECT * FROM cdr WHERE (accountcode <> ''); could work.

Erik, I was wondering can you fire an AGI script on the exit of the DIAL command. so when the client puts the phone down it could run the PHP AGI?

Something like:
exten => s,1,Answer
exten => s,n,Dial(....)
exten => s,n,AGI(fixCallDetailRecords.php)
exten => s,n,Hangup

Would this work?

Submitted by eeman on Wed, 02/16/2011 Permalink

that would not work.. and you need the DeadAGI command

it would be something like

exten => h,1,DeadAGI(fixCallDetail.php)

the million dollar question is where to put your hangup extension, I dont think it executes inside the macro, i think it executes in the context that called the macro.

Submitted by conraddewet on Wed, 02/16/2011 Permalink

Ah yes, right... for those interested according to VoIP Info:

"DeadAGI is a variant of AGI that you use when the channel is hung up. The main difference is that the AGI application may terminate if the line is hung up during execution and DeadAGI will not terminate even if the call is hung up during execution, however, the call leg will not automatically enter a "down" state until execution is completed if executed on a live line. As such, commands and applications designed to return the call state will inaccurately return an "up" status. This also means that any calls stuck in a DeadAGI execution upon hangup will continue to be considered "up" by the CDR. It is very important for your script to be aggressive in completing after hangup in order to maintain accurate CDR records."

I also see that you can buffer the CDR writing so it accumulates rows "until it has a chance to write the data", so if your server is under stress and you are buffering the cdr data the rows will not even be there yet.

So it s crom job them. Ill write one and post it for those following.

Submitted by conraddewet on Thu, 02/17/2011 Permalink

I see the hangup is quite the controversial channel. Read this:

http://www.voip-info.org/wiki/view/Asterisk+h+extension

it seem that doing this:
exten => h,1,Hangup
is quite pointless. Its like saying if the call is hang up, then hang up. so then the script should actually be:

[macro-tl-vm-pin-dialing]

exten => s,1,Answer
exten => s,n,Read(ext_num,vm-extension)
exten => s,n,Wait(1)
exten => s,n,Read(ext_pwd,vm-password)
exten => s,n,Wait(1)
exten => s,n,VMAuthenticate(${ext_num}@default${TL_DASH}${tenant})
exten => s,n,Read(ext_numdial,vm-enter-num-to-call)
exten => s,n,Set(CDR(accountcode)=${ext_num}${TL_DASH}${ext_numdial})
exten => s,n,Set(__DIALED_NUMBER=${ext_numdial})
exten => s,n,Macro(tl-dialout-1-trunk,${ARG1},${ARG2},${ARG3},${ARG4},${ARG5})

exten => h,1,noop("cleaning up CDR")
exten => h,2,DeadAGI(fixCallDetailRecords.php)
exten => t,1,Hangup
exten => i,1,Playback(invalid)
exten => i,2,Hangup

I have also fixed this line:

exten => s,n,Set(CDR(accountcode)=${ext_num}${TL_DASH}${ext_numdial})

to just store the extension and the number dialed since the tenant info is already stored and also the ext-number-tenant format will probably be too long especially if your tenant name is quite long.

Submitted by eeman on Thu, 02/17/2011 Permalink

a veteran unix admin would use abbreviated tenant names so as to spare the poor customer having to typing in a ridiculously long username when accessing the portal. It follows the same naming conventions as email domains. Nobody, and I do mean nobody, wants to type out john.jacob.jingleheimer.schidt@pneumocerbocularetyconceptomoronophyliag… .. the same principles should apply to tenant names :-)