stocksy.co.uk
"the site for those who crave disappointment"

Sponsored Links

How I used Asterisk to Take Back Control of my Telephone

1st Nov 2009, 14:34:52

By James Stocks

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 logo

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:

My setup

The features I enjoy the most are:

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 :)

New Comments

Some Rights Reserved