How I used Asterisk to Take Back Control of my Telephone
1st Nov 2009, 14:34:52
I turned to Asterisk to solve the problem of telemarketers cold calling us. Along the way, I discovered that it can do much more and it saves us money. Read on to see my configuration.
Asterisk is a complete PABX implemented in software. It allows computers to do what futurologists always promised; do your busy work and give you more time. I have become a complete Asterisk fanboy since setting up my PABX earlier this year. This is my layout:
The features I enjoy the most are:
- Internal calls - I can ring the kitchen from the garage and order a cup of coffee (I wish!).
- Callers who withhold their caller ID do not ring the phones.
- Calls received during the night or at dinner time do not ring the phones.
- Nuisance callers are blocked entirely based on their caller ID.
- Answer phone messages get emailed to me as an attachment.
- Outgoing calls are 'least cost' routed to PSTN or VoIP based on the time of day.
- Multiple concurrent calls can be made over the PSTN and VoIP services.
- Each member of the household can have their own 0871 telephone number.
- 0871 numbers can be pre-paid with a specified amount of credit for each user.
- If I can do it with a bash/perl/php script, I can do it over the phone with Asterisk!
The least-cost routing, multiple concurrent calls and anonymous call blocking scored a very high WAF for me, so bear that in mind if this is a consideration for you.
Requirements
Asterisk doesn't require much processing power. For home use, a Pentium III or better system will be sufficient. My installation runs on an old Power Mac G4.
In order to interface with your phone line, you'll need an FXO card. In most cases and ordinary modem will not work. The cheapest FXO card is the X100P Wildcard; I do not reccomend that you purchase this card. I am very happy with the performance of my OpenVox A400P card, as are others to whom I have recommended it. Yes it's nearly four times the price, but it is worth £50.00 to retain your sanity.
Finally, you really need some proper handsets. Softphones are OK for testing to begin with but they proved to be too impractical for my household. You can reuse your existing PSTN telephones using an ATA such as the Linksys PAP2 or Cisco ATA-186. Although I don't use it in my live setup right now, I found the PAP2 to be a very impressive and full featured device for the price and I recommend it as a good starter device.
My hardphones are currently a mix of Cisco 7940 and 7912 handsets. My main reason for choosing these was that I am already familiar with them because I use them at work. Configuring these handsets really did leave a lot to be desired; each device requires a number of configuration files and firmware images to be available on a TFTP server. However, once properly set up, these little workhorses are very reliable.
Getting Going - a Very Basic Setup
I used Debian stable as the operating system because it is my favourite Linux distribution. Asterisk ought to work with any reasonably up to date Linux distribution.
Apart from one small but crucial change, I found this asterisk 'getting started' guide very straightforward and useful, so I won't reproduce all the steps for installing Asterisk here.
Just follow the guide, but when it is time to retrieve the Asterisk source, you'll need to apply a patch. You only need this patch if you have a UK phone line and you want to use V23 caller ID.
# cd /usr/src # wget http://downloads.digium.com/pub/asterisk/asterisk-1.4-current.tar.gz # cd asterisk-1.4* # wget http://www.stocksy.co.uk/files/asterisk/cid.patch # patch -p0 < cid.patch
Then continue with the ./configure
, make
, make install
steps in the guide. At this point, you'll have a working Asterisk install, but it'll be sat there
not doing much.
Asterisk's configuration files are stored in /etc/asterisk
. There are a lot of files
here, but really we need only be concerned with a handful of them. extensions.conf
is
your dialplan where most important stuff gets done. I like to start with this:
# cd /etc/asterisk # mkdir backup # mv extensions.conf backup/ # vi extensions.conf [global] [house-phones] exten => 200,1,Dial(SIP/200) exten => 201,1,Dial(SIP/201)
The above is a minimal extensions.conf; it defines extensions 200 and 201 in the context
house-phones
. Now we may create two SIP users for these phones:
# cd /etc/asterisk # mv sip.conf backup/ # vi sip.conf [200] type=friend host=dynamic username=200 secret=xyzxyz context=house-phones canreinvite=no [201] type=friend host=dynamic username=201 secret=xyzxyz context=house-phones canreinvite=no
This creates our SIP accounts. Any two SIP phones will be able to use these details to log in to asterisk and call each other, provided that we ask asterisk to reload our config changes:
# rasterisk pabx*CLI> reload ......much output..... pabx*CLI> quit
OK, we have two SIP phones ringing each other. This is cool, but probably not terribly useful. If you wish to call the outside world, you'll need to configure the A400P device:
# genzaptelconf -c uk
This creates /etc/asterisk/zapata.conf
and /etc/zaptel.conf
.
/etc/asterisk/zapata.conf
won't be quite right and needs editing. I ignored the warning
about not hand-editing it:
# cd /etc/asterisk # cp zapata.conf backup/ # vi zapata.conf ; Autogenerated by /usr/sbin/genzaptelconf -- do not hand edit ; Zaptel Channels Configurations (zapata.conf) ; ; This is not intended to be a complete zapata.conf. Rather, it is intended ; to be #include-d by /etc/zapata.conf that will include the global settings ; ; Span 1: WCTDM/0 "Wildcard TDM400P REV E/F Board 1" (MASTER) ;;; line="1 WCTDM/0/0 FXSKS" [channels] usecallerid=yes cidsignalling=v23 cidstart=polarity sendcalleridafter=2 signalling=fxs_ks callerid=asreceived context=from-pstn rxgain = 7.0 txgain = 5.0 group=0 channel => 1
Now we must edit extensions.conf to take account of this development:
# cd /etc/asterisk # vi extensions.conf [global] [house-phones] exten => 200,1,Dial(SIP/200) exten => 201,1,Dial(SIP/201) ; Entries in [to-pstn] can be dialled from SIP extensions 200 and 201 include => to-pstn [to-pstn] ; Emergency numbers 999 and 112 need to go to the PSTN, clearly exten => 999,1,Dial(ZAP/1/${EXTEN},60,rTK) exten => 112,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Starts with a 0 and contains more than 5 digits - it's a phone number, dial it exten => _0XXXX.,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Six digits? It's a local call, dial it exten => _XXXXXX,1,Dial(ZAP/1/${EXTEN},60,rTK) ; BT Test number, very useful, try it exten => 17070,1,Dial(ZAP/1/${EXTEN},60,rTK) [from-pstn] ; All incoming calls ('s') cause phones 200 and 201 to ring exten=> s,1,Dial(SIP/200&SIP/201)
And reload:
# rasterisk pabx*CLI> reload ......much output..... pabx*CLI> quit
We now have the ability to place calls to and answer calls from the PSTN. If it's not working for you, you can monitor what's going on through the asterisk monitor:
# rasterisk pabx*CLI> core set debug 10 pabx*CLI> core set verbosity 10 pabx*CLI>
You'll notice that that
the [house-phones]
are in a different context to the PSTN, so we use an
include =>
statement. This allows SIP extensions in [house-phones]
to dial PSTN numbers directly.
We don't
include =>
the house phones in [from-pstn]
because outside callers
always reach the special extension s
which triggers the Dial()
function.
How about an answer phone? Asterisk can do this for you using voicemail.conf
# cd /etc/asterisk # mv voicemail.conf backup/ # vi voicemail.conf [general] format = wav ; limit messages to 5 minutes maxmessage=300 ; less than 2 seconds? probably not a valid message minmessage=2 [default] ; This creates mailbox 298 with pin 1234. Specifying an email address causes you to receive ; messages as email attachments 298 => 1234,James Stocks,stocksy@stocksy.co.uk
Add a voicemail line to the [from-pstn]
context and an extension through which
voicemail will be accessed:
# cd /etc/asterisk # vi extensions.conf [global] [house-phones] exten => 200,1,Dial(SIP/200) exten => 201,1,Dial(SIP/201) ; Entries in [to-pstn] can be dialled from SIP extensions 200 and 201 include => to-pstn ; Dial to access voicemail exten => 299,1,VoiceMailMain(298) [to-pstn] ; Emergency numbers 999 and 112 need to go to the PSTN, clearly exten => 999,1,Dial(ZAP/1/${EXTEN},60,rTK) exten => 112,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Starts with a 0 and contains more than 5 digits - it's a phone number, dial it exten => _0XXXX.,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Six digits? It's a local call, dial it exten => _XXXXXX,1,Dial(ZAP/1/${EXTEN},60,rTK) ; BT Test number, very useful, try it exten => 17070,1,Dial(ZAP/1/${EXTEN},60,rTK) [from-pstn] ; All incoming calls ('s') cause phones 200 and 201 to ring exten=> s,1,Dial(SIP/200&SIP/201,15) ; Go to voicemail after 15 seconds exten => s,n,VoiceMail(298,u)
This will cause the caller to be diverted to voicemail after 15 seconds. You'll need to set up your voice mailbox by dialling 299. Don't forget to reload Asterisk to pick up the changes.
Adding a VoIP Service
Now you've got an asterisk box you can start to recoup your hardware costs by saving money on your calls. There are many providers to chose from; I ended up choosing VoIPon partly because they had been very helpful when I was choosing my FXO card, but mainly because they offer an IAX connection. I recommend steering clear of companies that only offer a SIP connection - it isn't worth the aggravation of sorting out all the UDP based RTP streams and attendant NAT issues. IAX is just one UDP port in and out.
Assuming you want to use VoIPon, go along to their web site and sign up for an account. It doesn't cost anything to get them to allocate you an 0871 number and you only need to buy £5.00 worth of credit when you want to start making outgoing calls.
Once your account is set up, it's time to configure the Asterisk box at our end. Firstly, make sure that your firewall or router will allow UDP port 4569 out to the internet and that UDP 4569 is accepted (and NATed) through to your Asterisk server's internal IP address. Then, we put our account details into the IAX configuration file:
# cd /etc/asterisk/ # mv iax.conf backup/ # vi iax.conf [general] ; VoIPon don't seem to support call tokens at present, let's disable them for now calltokenoptional = 0.0.0.0/0.0.0.0 ; Set this to the maximum number of concurrent IAX calls you think you might need to handle ; 10 is probably more than you need for a home system maxcallnumbers = 10 ; This is where our outgoing calls get placed - use your own account details [voipon-stocksy] type=peer secret=aaa000 username=0000000 host=iax.voipon.co.uk context=to-voipon-stocksy qualify=yes ; DTMF seems to work only with ulaw disallow=all allow=ulaw ; Here are our incoming calls - use your own 0871 number here [08710000000] type=friend username=08710000000 context=from-voipon-stocksy ; DTMF seems to work only with ulaw disallow=all allow=ulaw
Reload Asterisk to pick up the changes. You can check the status of your new IAX connection from the Asterisk monitor:
pabx*CLI> iax2 show peers Name/Username Host Mask Port Status 08710000000/087 (Unspecified) (S) 0.0.0.0 4569 Unmonitored voipon-stocksy/ 217.14.138.130 (S) 255.255.255.255 4569 OK (29 ms) 2 iax2 peers [1 online, 0 offline, 1 unmonitored] pabx*CLI> iax2 show peer voipon-stocksy * Name : voipon-stocksy Secret : <Set> Context : to-voipon-stocksy Mailbox : Dynamic : No Callnum limit: 0 Calltoken req: No Trunk : No Callerid : "" <> Expire : -1 ACL : No Addr->IP : 217.14.138.130 Port 4569 Defaddr->IP : 0.0.0.0 Port 0 Username : 0000000 Codecs : 0x4 (ulaw) Codec Order : (ulaw) Status : OK (31 ms) Qualify : every 60000ms when OK, every 10000ms when UNREACHABLE (sample smoothing Off) pabx*CLI> iax2 show peer 0871000000 * Name : 08710000000 Secret : <Not set> Context : from-voipon-stocksy Mailbox : Dynamic : No Callnum limit: 0 Calltoken req: No Trunk : No Callerid : "" <> Expire : -1 ACL : No Addr->IP : (Unspecified) Port 4569 Defaddr->IP : 0.0.0.0 Port 0 Username : 0871000000 Codecs : 0x4 (ulaw) Codec Order : (ulaw) Status : Unmonitored Qualify : every 60000ms when OK, every 10000ms when UNREACHABLE (sample smoothing Off)
So, you can see that we have determined that our outgoing calls will be placed using the
[to-voipon-stocksy]
context and received in to the [from-voipon-stocksy]
context. We need to create those contexts:
# cd /etc/asterisk # vi extensions.conf [global] [house-phones] exten => 200,1,Dial(SIP/200) exten => 201,1,Dial(SIP/201) ; Dial to access voicemail exten => 299,1,VoiceMailMain(298) ; Heres the 'clever' bit I suppose ; ; Weekend calls (between 00:00 on saturday and 23:59 on sunday), go to the PSTN first because they ; are free of charge: include => to-pstn|00:00-23:59|sat-sun|*|* ; Evening calls (between 18:59 and 07:59 go to BT first because they are cheaper: include => to-pstn|18:00-07:59|mon-fri|*|* ; Daytime calls go to VoIPon first because they are cheaper: include => to-voipon|08:00-17:59|mon-fri|*|* include => to-pstn-force ; ; Some stuff always should go to the PSTN ; [to-pstn-force] ; ; **IMPORTANT** We need to make sure emergency calls always work irrespective of what time of ; day it is! exten => 999,1,Dial(ZAP/1/${EXTEN},60,rTK) exten => 112,1,Dial(ZAP/1/${EXTEN},60,rTK) ; No point sending BT specific number to VoIPon: exten => 17070,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Stuff breaks. Prefixing with 9 will send the call through to the oh-so-reliable PSTN :-) exten => _9.,1,Dial(ZAP/1/${EXTEN:1},60,rTK) [to-pstn] ; Starts with a 0 and contains more than 5 digits - it's a phone number, dial it exten => _0XXXX.,1,Dial(ZAP/1/${EXTEN},60,rTK) ; Six digits? It's a local call, dial it exten => _XXXXXX,1,Dial(ZAP/1/${EXTEN},60,rTK) [from-pstn] ; All incoming calls ('s') cause phones 200 and 201 to ring exten=> s,1,Dial(SIP/200&SIP/201,15) ; Go to voicemail after 15 seconds exten => s,n,VoiceMail(298,u) [to-voipon-stocksy] ; **Note:** VoIPon only accepts calls using the full '+44' format, so if your STD code is 01111, ; local calls need to be prefixed with 441111 - replace 1111 with your own STD code dropping the '0' exten => _XXXXXX,1,Dial(IAX2/voipon-stocksy/441111${EXTEN},60,rTK) ; Same story with out of STD code calls, prefix with 44 and drop the leading '0' with ${EXTEN:1} exten => _0[1-9]XXX.,1,Dial(IAX2/voipon-stocksy/44${EXTEN:1},60,rTK) ; International calls are easy, we just drop the '00' at the start with ${EXTEN:2} and dial it: exten => _00XXX.,1,Dial(IAX2/voipon-stocksy/${EXTEN:2},60,rTK) [from-voipon-stocksy] ; I don't want anyone dialling this number, so it goes straight to voicemail exten => 08713094004,1,VoiceMail(298,u)
Reload Asterisk and you should now find that your calls get routed to the least cost service depending on what time it is. You'll notice that when you place calls through VoIP your caller ID will be presented to the callee as 0871000000; this caused us problems because people would not recognise the number and wouldn't take our call. VoIPon will change your outgoing ID to your PSTN number as long as you send them proof that you own the number and pay them £15.00.
This is fine, but I got annoyed that I had effectively two telephone lines, but couldn't place another call if someone else is on the phone. I took the opportunity to learn about Macros in the dialplan. Here's the relevant bit:
# cd /etc/asterisk # vi extensions.conf ; ; These are our two Macros ; ; 'CONGESTION' and 'CHANUNAVAIL' are special extensions which we use to dial the other line which ; should be free. If both lines are busy, we don't need to do anything special, caller just gets ; fast busy tone. ; [macro-callbt] ; Call BT and fall back to voipon if line busy or otherwise not available exten => s,1,GotoIf($[${ARG1:0:2}=0]?int) exten => s,n,set(NUM=44${ARG1:1}) exten => s,n,goto(dialit) exten => s,n(int),set(NUM=${ARG1:2}) exten => s,n(dialit),Verbose(Full Number = ${NUM}) ; exten => s,n,Dial(ZAP/1/${ARG1},180,rTK) ; exten => s,n,Goto(${DIALSTATUS},1) exten => CONGESTION,1,Dial(IAX2/voipon-stocksy/${NUM},180,rTK) exten => CHANUNAVAIL,1,Dial(IAX2/voipon-stocksy/${NUM},180,rTK) exten => ANSWER,1,Hangup exten => CANCEL,1,Hangup [macro-callvoipon] ; Call voipon unless it is unavailable, in which case we try the BT line exten => s,1,GotoIf($[${ARG1:0:2}=0]?int) exten => s,n,set(NUM=44${ARG1:1}) exten => s,n,goto(dialit) exten => s,n(int),set(NUM=${ARG1:2}) exten => s,n(dialit),Verbose(Full Number = ${NUM}) ;exten => s,1,Set(NUM=${ARG1}) exten => s,n,Dial(IAX2/voipon-stocksy/${NUM},180,rTK) exten => s,n,Goto(${DIALSTATUS},1) exten => CONGESTION,1,Dial(ZAP/1/${ARG1},180,rTK) exten => CHANUNAVAIL,1,Dial(ZAP/1/${ARG1},180,rTK) exten => ANSWER,1,Hangup exten => CANCEL,1,Hangup ; ; I created a macro for our incoming calls since I was fed up of typing SIP/200&SIP/201&SIP/202 etc. ; Now we can just edit this one Dial() line to add and remove extensions to ring: ; [macro-call-house-phones] exten => s,1,Dial(SIP/200&SIP/201,15,tk) exten => s,n,VoiceMail(298,u) ; ; Now we adjust our outgoing contexts: ; [to-pstn] ; Starts with a 0 and contains more than 5 digits - it's a phone number, dial it ; Don't need this now ; exten => _0XXXX.,1,Dial(ZAP/1/${EXTEN},60,rTK) exten => _0XXXX.,1,Macro(callbt|${EXTEN}) ; Six digits? It's a local call, dial it ; Don't need this now ; exten => _XXXXXX,1,Dial(ZAP/1/${EXTEN},60,rTK) exten => _XXXXXX,1,Macro(callbt|${EXTEN}) [to-voipon-stocksy] ; **Note:** VoIPon only accepts calls using the full '+44' format, so if your STD code is 01111, ; local calls need to be prefixed with 441111 - replace 1111 with your own STD code dropping the '0' exten => _XXXXXX,1,Dial(IAX2/voipon-stocksy/441111${EXTEN},60,rTK) ; Same story with out of STD code calls, prefix with 44 and drop the leading '0' with ${EXTEN:1} ; don't need this now; exten => _0[1-9]XXX.,1,Dial(IAX2/voipon-stocksy/44${EXTEN:1},60,rTK) exten => _0[1-9]XXX.,1,Macro(callvoipon|${EXTEN}) ; International calls are easy, we just drop the '00' at the start with ${EXTEN:2} and dial it: ; don't need this now ; exten => _00XXX.,1,Dial(IAX2/voipon-stocksy/${EXTEN:2},60,rTK) ; Set 01111 to your STD code exten => _XXXXXX,1,Macro(callvoipon|01111${EXTEN}) [from-pstn] ;;; All incoming calls ('s') cause phones 200 and 201 to ring ;;exten=> s,1,Dial(SIP/200&SIP/201,15) ;;; Go to voicemail after 15 seconds ;;exten => s,n,VoiceMail(298,u) ; ; We don't need any of the above rubbish anymore, just this one Macro: ; exten => s,n,Macro(call-house-phones)
Reload Asterisk and test this.
Before moving on to the next step, a word about emergency calls. Make sure you have emergency calls working properly under all conditions and at all times of the day. I have this set up so that 999 or 112 is always routed to the PSTN under all circumstances because the emergency services use your telephone number to route you through to the correct control room. After I make any major changes, I always unplug the Asterisk box from the PSTN and watch the output of Asterisk's CLI to make sure that 999 would be routed properly.
Finally, make sure you have an old fashioned phone somewhere which you could use in the event of a power outage. Don't leave it plugged in though or it'll ring before the Asterisk server picks up and annoy the tits off you.
Dealing With Unwanted Calls
For me this is the most interesting part. I started by dreaming up all sorts of elaborate ways to torture cold callers; I'd loop them in infinite menus, set up intelligent agents to pretend to be interested in what they were selling or play recordings of screaming monkeys at them. I certainly had lots of fun creating them, but in the end I didn't use any of these ideas for real, the possibility of accidentally sending legitimate calls into these extensions was just to great. For example, if your employer looks up your number in your employee file and is then told that "all members of the household are currently assisting other telemarketers, please hold " you're sure to have some explainin' to do in the morning.
tl;dr: Please consider what unintended consequences your telemarketer torture dialplan might have.
My first line of defence against unwanted calls is some simple time-based routing. Except for a couple of numbers on my whitelist database, no calls at all ring the phone before 06:00 or after 22:00:
# cd /etc/asterisk # vi asterisk.conf ; ; First of all, remove any Dial() lines for your incoming context. Then we set up our routing ; [from-pstn] ; Store the caller's number to use later: exten => s,1,Set(DB(cid/last)=${CALLERID(num)}) ; If it's number we like, always go to 'day' context in case it's an emergency exten => s,n,GotoIf(${DB_EXISTS(whitelist/${CALLERID(num)})}?day,s,1) ; If it's later than 6:00 but earlier than 22:00, go to 'day' context ; else, go to the 'night' context exten => s,n,Set(dayornight=${IFTIME(06:00-22:00|*|*|*?day:night)}) exten => s,n,GotoIf($["${dayornight}" = "day"]?day,s,1:night,s,1) exten => s,n,Hangup ; ; Now we need a day and a night context ; [day] exten => s,1,Macro(call-house-phones) exten => s,n,Hangup [night] exten => s,1,Background(daynight/intro) exten => s,n,Background(silence/5) exten => s,n,VoiceMail(298,u) exten => s,n,Hangup ; The PIN is just an extension, pick something better than 1111! exten => 1111,1,Macro(call-house-phones) exten => 1111,n,Hangup ; If the caller enters anything other then 1111, say "That's not valid, try again" and go back to ; the start (s,1) exten => i,1,Playback(invalid) exten => i,n,Goto(s,1)
Anyone calling outside 06:00 - 22:00 gets a recording and is offered the opportunity to enter a PIN. Obviously, it's pretty easy to extend this setup to block calls during mealtimes, holidays or any other time you want by just adding more contexts and including them at the desired time. You'll probably want to record your own message for this, which you can do by setting up a special extension (of course!). Put this in your dialplan under [house-phones]
; For recording prompts ; When dialled, you'll get a tone and then it records. Press # to stop recording and the message ; will be played back to you. exten => *50,1,Answer exten => *50,n,Record(custom-message:alaw) exten => *50,n,Wait(2) exten => *50,n,Playback(custom-message) exten => *50,n,Hangup
Reload asterisk and dial *50 to record your message. You can move it into the right place with:
# mkdir /var/lib/asterisk/sounds/daynight # mv /var/lib/asterisk/sounds/custom-message.ulaw /var/lib/asterisk/sounds/daynight/intro.ulaw
If you want to use mine just for testing, you can do this, but I'll warn you, I'm no voice actor!
# cd /var/lib/asterisk/sounds # mkdir daynight # cd daynight # wget http://www.stocksy.co.uk/files/asterisk/daynight/intro.ulaw
If you want a list of whitelisted numbers, we can do that on the Asterisk CLI:
# rasterisk pabx*CLI> database put whitelist 01111222222 1 Updated database successfully pabx*CLI> database put whitelist 01111333333 1 Updated database successfully pabx*CLI> database show whitelist /whitelist/01111222222 : 1 /whitelist/01111333333 : 1
If you want to test any of these without having to call in from the outside, you can do so by creating
a special extension in [house-phones]
using the GoTo command for example this
would send you to the night context at priority 1 if you dial *52:
exten => *52,1,Goto(night,s,1)
That was easy enough. Lets tackle anonymous calls next. Just as we did with out-of-hours callers, we send anonymous callers to a different context and handle the call there.
# cd /etc/asterisk # vi extensions.conf [day] ; If the number is withheld or international, go to nocid context exten => s,1,GotoIf($["${CALLERID(name)}" = "WITHHELD"]?nocid,s,1) exten => s,n,GotoIf($["${CALLERID(name)}" = "INTERNATIONAL"]?nocid,s,1) exten => s,n,GotoIf($["${CALLERID(name)}" = "UNAVAILABLE"]?nocid,s,1) exten => s,n,GotoIf($["${CALLERID(name)}" = "PAYPHONE"]?nocid,s,1) exten => s,n,Macro(call-house-phones) exten => s,n,Hangup ; ; Create the nocid context referenced above: ; [nocid] exten => s,1,Answer exten => s,n,Set(CALLERID(name)=0) exten => s,n,Set(CALLERID(num)=0) ; Tell the caller they need to key in their number and read it up to 16 digits exten => s,n,Read(manualcid,nocid/intro4,16) exten => s,n,Set(CALLERID(name)=Manual CID) exten => s,n,Set(CALLERID(num)=${manualcid}) ; If nothing gets keyed (${manualcid} is null then go straight to voicemail exten => s,n,GotoIf($["${manualcid}" = ""]?17) ; If caller keyed less than 6 digits, go to 'wrong' recording exten => s,n,GotoIf($[${LEN(${manualcid})} < 6]?11:9) ; Otherwise, dial the phones exten => s,n,Macro(call-house-phones) exten => s,n,Hangup ; If our caller was well behaved, it ends with the hangup above. ; Otherwise, we give them one more chance exten => s,n,Read(manualcid,nocid/wrong2,16) ; If they still enter less than six digits or the entry is null, go to voicemail exten => s,n,GotoIf($[${LEN(${manualcid})} < 6]?17:13) ; Otherwise dial the phones exten => s,n,Set(CALLERID(name)=Manual CID) exten => s,n,Set(CALLERID(num)=${manualcid}) exten => s,n,Macro(call-house-phones) exten => s,n,Hangup exten => s,n,VoiceMail(298,u) exten => i,1,Playback(invalid)
OK, that's a big mess of crap, but let me explain a bit. We needed to modify the
[day]
context since night-time calls don't ring the
phones any way. I've included the four caller ID strings that BT send - change to match your
requirements. Once we have established that a call is anonymous, we send it to the nocid
context where the caller hears that we don't allow anonymous calls and gives them the
chance to enter their telephone number using their keypad. If the caller doesn't enter a number
they go straight to voicemail. If a number of six digits or more is entered we ring the phones,
but prefix the incoming ID like Manual CID: 01111 2222222
. So far, I have not had a
single cold caller choose to enter their number - they just hang up whereas genuine callers don't
seem to mind putting in their number.
As before, you'll need to record your own prompts, or you can use my nerdy voice:
# mkdir /var/lib/asterisk/sounds/nocid # cd /var/lib/asterisk/sounds/nocid # wget http://www.stocksy.co.uk/files/asterisk/nocid/intro4.alaw # wget http://www.stocksy.co.uk/files/asterisk/nocid/wrong2.alaw
We've covered withheld numbers and night time calls, that just leaves unwanted calls that do display their number. This is my other half's favourite thing about our set up; it deals with the caller in an effective and non-confrontational way.
In a similar way to the whitelist we used earlier, I just store my blacklist in Asterisk's DB. As you would expect, we test the caller ID against this list and move it to another context if it matches:
# cd /etc/asterisk # vi extensions.conf ; ; First, add extensions to [my-phones] that jump to the blacklist contexts. ; [my-phones] ; Add a number to the blacklist exten => *30,1,Goto(blacklist-add,s,1) ; Remove a number exten => *31,1,Goto(blacklist-remove,s,1) ; Blacklist the last caller exten => *32,1,Goto(blacklist-last,s,1) ; Transfer a caller to this extension to blacklist them and politely tell them to go away. exten => *666,1,Goto(blacklisted-live,s,1) ; ; When a blacklisted caller calls, they are twice told to stop calling and then we hang up. ; [blacklisted] exten => s,1,Wait(3) exten => s,n,Playback(extra/privacy-stop-calling-not-welcome) exten => s,n,Wait(3) exten => s,n,Playback(extra/privacy-stop-calling-not-welcome) exten => s,n,Wait(3) exten => s,n,Hangup ; ; Transfer a caller to this extension to: ; 1. Add them to the blacklist ; 2. Tell them five times to stop calling ; 3. Hang up on them ; [blacklisted-live] exten => s,1,Answer exten => s,n,Set(number=${DB(cid/last)}) exten => s,n,GotoIf($["${number}" = ""]?104) ; also if it's blank (caller id blocked) exten => s,n,Set(DB(blacklist/${number})=1) exten => s,n,Goto(104,1) exten => 104,1,Wait(3) exten => 104,n,Playback(extra/privacy-stop-calling-not-welcome) exten => 104,n,Wait(3) exten => 104,n,Playback(extra/privacy-stop-calling-not-welcome) exten => 104,n,Wait(3) exten => 104,n,Playback(extra/privacy-stop-calling-not-welcome) exten => 104,n,Wait(3) exten => 104,n,Playback(extra/privacy-stop-calling-not-welcome) exten => 104,n,Wait(3) exten => 104,n,Playback(extra/privacy-stop-calling-not-welcome) exten => 104,n,Wait(3) exten => 104,n,Hangup ; ; This allows you to manually add any number to the blacklist ; [blacklist-add] exten => s,1,Answer exten => s,n,Wait(1) exten => s,n,Playback(extra/enter-num-blacklist) ; Give 30 seconds to enter the number instead of the default of 5! exten => s,n,Set(TIMEOUT(response)=30) exten => s,n,Read(blacknr,extra/then-press-pound) ; Read back the number to and ask to confirm (jump to extension 1) else hang up if not confirmed exten => s,n,SayDigits(${blacknr}) exten => s,n,Background(extra/if-correct-press) exten => s,n,Background(digits/1) exten => s,n,Background(silence/5) exten => s,n,Hangup exten => 1,1,Set(DB(blacklist/${blacknr})=1) exten => 1,n,Playback(extra/num-was-successfully) exten => 1,n,Playback(extra/added) exten => 1,n,Wait(1) exten => 1,n,Hangup ; ; Manually remove a number from the blacklist ; [blacklist-remove] exten => s,1,Answer exten => s,2,Wait(1) exten => s,3,Playback(extra/entr-num-rmv-blklist) exten => s,4,Set(TIMEOUT(digit)=5) ; Give 30 seconds to enter the number instead of the default of 5! exten => s,5,Set(TIMEOUT(response)=30) ; Read back the number to and ask to confirm (jump to extension 1) else hang up if not confirmed exten => s,6,Read(blacknr,extra/then-press-pound) exten => s,7,SayDigits(${blacknr}) exten => s,8,Background(extra/if-correct-press) exten => s,9,Background(digits/1) exten => s,10,Background(silence/5) exten => s,11,Hangup exten => 1,1,DBdel(blacklist/${blacknr}) exten => 1,2,SayDigits(${blacknr}) exten => 1,3,Playback(extra/num-was-successfully) exten => 1,4,Playback(extra/removed) exten => 1,5,Hangup ; ; This blacklists the last caller ; [blacklist-last] exten => s,1,Answer exten => s,n,Wait(1) exten => s,n,Set(number=${DB(cid/last)}) ; Jump to priority s,104 if no caller ID was available, else carry on exten => s,n,GotoIf($["${number}" = ""]?104) exten => s,n,Playback(extra/privacy-to-blacklist-last-caller) exten => s,n,Playback(extra/telephone-number) ; Read back what the number was and ask to confirm (jump to extension 1) exten => s,n,SayDigits(${number}) exten => s,n,Wait,1 exten => s,n,Background(extra/press-1) exten => s,n,Background(extra/or) exten => s,n,Background(extra/press-star-cancel) ; Give user 30 seconds to decide exten => s,n,Background(silence/10) exten => s,n,Background(silence/10) exten => s,n,Background(silence/10) exten => s,n,Hangup exten => s,104,Playback(extra/unidentified-no-callback) exten => s,n,Playback(extra/goodbye) exten => s,n,Hangup ; ; If user confirms by pressing 1, get to work ; exten => 1,1,Set(DB(blacklist/${number})=1) ; Read the number again and say that it has been added exten => 1,n,Playback(extra/telephone-number) exten => 1,n,Playback(extra/privacy-blacklisted) exten => 1,n,Wait,1 exten => 1,n,Playback(extra/goodbye) exten => 1,n,Hangup ; Handle cases where someone has dialled something daft exten => t,1,Playback(extra/goodbye) exten => t,n,Hangup exten => i,1,Playback(extra/goodbye) exten => i,n,Hangup exten => o,1,Playback(extra/goodbye) exten => o,n,Hangup
Don't forget to reload Asterisk.
With the above in your dialplan, you'll be able to dial *30 - *32 to control entries in your
blacklist. Transferring to *666 plays a message to get rid of the caller and blacklists them.
If you're not using VoIP phones you need to enable transferring in features.conf
for this to work, uncomment the line that says:
blindxfer => #1 ; Blind transfer (default is #)
Then you can just dial #1*666# to kill off the pesky caller.
3 Archived Comments
6th Dec 2009, 09:11:30 by cronky
Wow this is impressive, how much did your setup cost in total?
http://twitter.com/cronky
4th Jan 2010, 11:58:03 by stocksy
10th Jan 2010, 10:43:52 by uxbod
You could also enable the use of http://www.phonespamfilter.co.uk/ in your dial plan and the use something like;
[marketing]
exten => check,1,AGI(phonespamfilter.php)
exten => check,n,GotoIf($["${PHONESPAMFILTER}" = "2"]?spam,1:)
exten => check,n,GotoIf($["${PHONESPAMFILTER}" = "0"]?notspam,1:)
exten => spam,1,Answer()
exten => spam,n,Playback(yes-dear)
exten => spam,n,Hangup()
exten => notspam,1,Goto(home,s,1)
You can get the PHP script from: http://projects.colsolgrp.net/projects/list_files/superfecta
and you will need to enable AGI in Asterisk.
Great tutorial by the way :)