[FreePBX/Asterisk]Multiple / Rotary Call Flow Toggles

We got a customer the other day who wanted to manually override their normal call flow. This could have been easily achieved by a single toggle if it was to a single destination. But this customer wanted wanted to be able select multiple destination and also only wanted to push one button to do so.

This meant we had to write custom code to get this done and it was achieved by writing a code to manipulate call flow toggles.

What you need to add is the following to the extensions_custom.conf

[from-internal-custom]
include => enable-switch

[check-active-switch]
exten => s,1,NoOp("This context loops through all the switches and checks which one is ON. Than it follows its destination")
exten => s,n,GoSub(sub-get-nr-of-switches,s,1)
exten => s,n,Set(nrofs=${GOSUB_RETVAL})
exten => s,n,Set(i=0)
exten => s,n,Set(default-dest=app-daynight,4,1)
exten => s,n,Set(switchnr="NULL")
exten => s,n,While($[$[${i} < ${nrofs}] & $[${switchnr} = "NULL"]])
exten => s,n,Set(switchnr=${IF($["${DB(DAYNIGHT/C${i})}" = "NIGHT"]?${i}:"NULL")})
exten => s,n,Set(i=$[${i} + 1])
exten => s,n,EndWhile
exten => s,n,GotoIf($[${switchnr}!="NULL"]?app-daynight,${switchnr},1:${default-dest})
exten => s,n,Hangup()

[sub-get-nr-of-switches]
exten => s,1,Set(nr_of_s=0)
exten => s,n,Set(exten_state="NOT_ACQUIRED")
exten => s,n,While($[${exten_state}!=0])
exten => s,n,Set(exten_state=$[${VALID_EXTEN(app-daynight,${nr_of_s},1)}])
exten => s,n,NoOp(Exten nr ${nr_of_s} of app-daynight is ${exten_state})
exten => s,n,Set(nr_of_s=${IF($[${exten_state}=1]?$[${nr_of_s}+1]:${nr_of_s})})
exten => s,n,EndWhile
exten => s,n,NoOp(${nr_of_s} switches found)
exten => s,n,Return(${nr_of_s})

[enable-switch]
exten => _*20X,1,NoOp("Enable selected Switch and disable others")
same => n,GoSub(sub-get-nr-of-switches,s,1)
same => n,Set(nrofs=${GOSUB_RETVAL})
same => n,Set(switchtoactivate=${EXTEN:3})
same => n,Set(CSTATE=${DB(DAYNIGHT/C${switchtoactivate})})
same => n,NoOp(Activated Switch nr ${switchtoactivate})
same => n,Set(i=0)
same => n,While($[${i}<${nrofs}])
same => n,GotoIf($["${CSTATE}" = "NIGHT"]?end1)
same => n,Set(DB(DAYNIGHT/C${i})=DAY)
same => n(end1),NoOp(Dialing the same toggle code. Switch it off)
same => n,Set(DEVICE_STATE(Custom:AHTGL${i})=NOT_INUSE)
same => n,Set(DEVICE_STATE(Custom:DAYNIGHT${i})=NOT_INUSE)
same => n,Set(i=$[${i}+1])
same => n,EndWhile
same => n,Set(freepbx_toggle_dest=*28${switchtoactivate})
same => n,GotoIf($["${CSTATE}" = "NIGHT"]?end2)
same => n,Set(DEVICE_STATE(Custom:AHTGL${switchtoactivate})=INUSE)
same => n(end2),NoOp(Skip setting BLF)
same => n,Goto(app-daynight-toggle,${freepbx_toggle_dest},1)
same => n,Hangup
same => hint,Custom:AHTGL${EXTEN:3}

Then from FreePBX add custom destination with check-active-switch,s,1 as the value and point the inbound route to this custom destination.

Now, you create all the call flow toggles with their override mode set to the destinations you want to go and the normal mode is set identical on each toggle the normal operation you want to work.

Finally, create BLF keys to see which switch is active using *20X as the value to dial/monitor.

Modify the following line to point calls to a default destination if none of the toggles are on override  mode. On the below code it is set to app-daynight,4,1

exten => s,n,Set(default-dest=app-daynight,4,1)

The original code is via : https://community.freepbx.org/t/multiple-daynight-toggles-aka-call-flow-control/27518

Modifications on this code helps you use BLF to monitor currently selected toggles as well as ability to turn off the the override.

[Asterisk/FreePBX]Set Inbound DID as Caller-ID for Forwarded Calls

This is a snippet developed by a colleague of mine. This is for people who’s supplier’s doesn’t allow passing original Caller ID for forwarded calls. What this does is it will show the DID where the calling party called in as the caller ID instead of showing up your default trunk number for the caller ID.

First add the below code to extensions_override_freepbx.conf, next restart/reload asterisk and you’re good to go.

[macro-outbound-callerid]
include => macro-outbound-callerid-custom
exten => s,1,ExecIf($["${CHANNEL(channeltype)}" = "Local"]?Set(CALLERID(all)=${MASTER_CHANNEL(DEXTEN)}))
exten => s,n,ExecIf($["${CHANNEL(channeltype)}" = "Local"]?Set(AMPUSER=${MASTER_CHANNEL(DEXTEN)}))
exten => s,n,ExecIf($["${CALLINGNAMEPRES_SV}" != ""]?Set(CALLERPRES(name-pres)=${CALLINGNAMEPRES_SV}))
exten => s,n,ExecIf($["${CALLINGNUMPRES_SV}" != ""]?Set(CALLERPRES(num-pres)=${CALLINGNUMPRES_SV}))
exten => s,n,ExecIf($["${REALCALLERIDNUM:1:2}" = ""]?Set(REALCALLERIDNUM=${CALLERID(number)}))
exten => s,n(start),GotoIf($[ $["${REALCALLERIDNUM}" = ""] | $["${KEEPCID}" != "TRUE"] | $["${OUTKEEPCID_${ARG1}}" = "on"] ]?normcid)
exten => s,n,Set(USEROUTCID=${REALCALLERIDNUM})
exten => s,n,GotoIf($["foo${DB(AMPUSER/${REALCALLERIDNUM}/device)}" = "foo"]?bypass)
exten => s,n(normcid),Set(USEROUTCID=${DB(AMPUSER/${AMPUSER}/outboundcid)})
exten => s,n(bypass),Set(EMERGENCYCID=${DB(DEVICE/${REALCALLERIDNUM}/emergency_cid)})
exten => s,n,Set(TRUNKOUTCID=${OUTCID_${ARG1}})
exten => s,n,GotoIf($["${EMERGENCYROUTE:1:2}" = "" | "${EMERGENCYCID:1:2}" = ""]?trunkcid)
exten => s,n,Set(CALLERID(all)=${EMERGENCYCID})
exten => s,n,Set(CDR(outbound_cnum)=${CALLERID(num)})
exten => s,n,Set(CDR(outbound_cnam)=${CALLERID(name)})
exten => s,n(exit),MacroExit()
exten => s,n(trunkcid),ExecIf($[${LEN(${TRUNKOUTCID})} != 0]?Set(CALLERID(all)=${TRUNKOUTCID}))
exten => s,n(usercid),ExecIf($[${LEN(${USEROUTCID})} != 0]?Set(CALLERID(all)=${USEROUTCID}))
exten => s,n,ExecIf($[${LEN(${TRUNKCIDOVERRIDE})} != 0 | ${LEN(${FORCEDOUTCID_${ARG1}})} != 0]?Set(CALLERID(all)=${IF($[${LEN(${FORCEDOUTCID_${ARG1}})}=0]?${TRUNKCIDOVERRIDE}:${FORCEDOUTCID_${ARG1}})}))
exten => s,n(hidecid),ExecIf($["${CALLERID(name)}"="hidden"]?Set(CALLERPRES(name-pres)=prohib_passed_screen))
exten => s,n,ExecIf($["${CALLERID(name)}"="hidden"]?Set(CALLERPRES(num-pres)=prohib_passed_screen))
exten => s,n,Set(CDR(outbound_cnum)=${CALLERID(num)})
exten => s,n,Set(CDR(outbound_cnam)=${CALLERID(name)})

 

Connecting two Asterisk/FreePBX using SIP Trunks

This was a project that I’ve been working on and off for some time and always ended up with failure. There are many documentations available on the net however the one that worked for me is using IP trunks and here’s how it is done.

Lets take an example so it’s easy to identify. Let’s assume the the two PBXes are at Sydney & Melbourne.

In Sydney PABX, create a new trunk, name it to-Melbourne. For the peer details set it up as follows:

Trunk Name: melbPABX

type=friend
context=from-trunk
host=Melbourne-PABX-IP-OR-FQDN
username=sydPABX
password=superstrongsecretpassword
qualify=yes

In the Melbourne PABX, create a new trunk with a name to-Sydney. For the peer details set it up as follows:

Trunk Name: sydPABX

type=friend
context=from-trunk
host=Sydney-PABX-IP-OR-FQDN
username=melbPABX
password=superstrongsecretpassword
qualify=yes

Points to remember:

  • Password common for both trunks.
  • Trunk names used under Peer Details acts as the usernames.
  • Extension numbers should differ on each PABX otherwise it would not be possible to route calls correctly.

[Asterisk/FreePBX] Blocking incoming calls to an extension

You may have a scenario where you’ve a particular extension assigned to a special service and you want only a select group of people/extensions to be able to make calls to this extension.

This can be easily achieved with the dial plan below. There’s just one file to edit : extensions_custom.conf

[kick]
exten => _X.,1,Playback(invalid)
exten => _X.,n,Hangup

[from-internal-custom]
exten => 7572/7520,1,Answer()
exten => 7572/7507,1,Answer()
exten => 7572/7584,1,Answer()
exten => 7572/4914,1,Answer()
exten => 7572/7500,1,Answer()
exten => 7572/_XXXX,1,Goto(kick,${EXTEN},1)
exten => 7572/_X.,1,Answer()

Let’s analyse what’s happening here.

The first section [kick] tells Asterisk to play a message saying the dialed destination is invalid and then to hang up.

The next section [from-internal-custom] defines what extension can connect/dial to this particular extension (in this example ext 7572 is the one needing incoming restrictions).
The part before the “/” defines the destination extension and the part after the “/” defines the source extensions.
So in this scenario extensions 7500, 7507, 7520, 7584 and 4914 will be able to call 7572. All other 4 digit extensions will be sent to [kick] which will terminate their calls.

The last part will allow any other call to be picked up by the extension (for example, an external call).

 

Original idea from : source

Asterisk/FreePBX Time Conditions with Multiple Time Zones / Daylight Saving

This solution is for older Asterisk/FreePBX installations (v2.11 and below) where the Time Condition module doesn’t have the Time Zone dropdown.

TZThis is based on a bash script which alters MySQL DB values to represent the change in DST.

This script will help you to automate DST changes easily and and have peace of mind about not having to manually change every year.

Scenario:

PABX is for an Australian company which has offices in multiple states. Main office is in NSW which observes daylight saving whereas a branch office is in QLD which does not observe daylight saving. Server time is set for NSW timezone. Continue reading “Asterisk/FreePBX Time Conditions with Multiple Time Zones / Daylight Saving”

Asterisk Phone Inventory / Useragent List

Create batch file with below and run the script. It will list down the Useragent, Contact & Username.

asterisk -rx “sip show peers” | cut -f1 -d/ | grep -P ‘\d\d\d\d’ | grep -vP ‘(UNKNOWN|Unmonitored)’ |
while read PEER
do
asterisk -rx “sip show peer ${PEER}” |
grep -P “(Useragent|Contact|Username)”
echo “====”
done

Asterisk/FreePBX – How to restrict an extension to call certain extension only

There may come a time that you want a public access phone that can only dial out a certain set of extensions. To accomplish this, a custom context needs to be created and applied to that extension.

Here’s the scenario.
Extension 312 is the public access phone. This should only be able to dial x530 & x555. All other calls needs to be terminated.

Define the context in extensions_additional.conf

[from-intercom]
exten => 530,1,goto(from-internal,${EXTEN},1)
exten => 555,1,goto(from-internal,${EXTEN},1)
exten => _.,1,hangup()

If FreePBX, go inside the extension and the context from from-internal->from-intercom. Apply the settings and you’re good to go.

Asterisk/FreePBX Blind Transfer Return Call to Origin

Another customer of ours requested this feature. By default, with blind transfers if the internal destination doesn’t answer the call, it goes to vociemail or terminates if vociemail is not configured. This customer wanted to return the call to the originator so that they can direct the call elsewhere.

You need to modify two places. They’re listed below.

globals_custom.conf:
TRANSFER_CONTEXT = custom-test_transfer

extensions_custom.conf:
[custom-test_transfer]
exten => _X.,1,NOOP(entering custom-test_transfer)
exten => _X.,n,set(timeoutd=25) ; set timeout in seconds
exten => _X.,n,set(extLeng=${LEN(${EXTEN})})
exten => _X.,n,noop(the extenlength is ${extLeng})
exten => _x.,n,dial(local/${EXTEN}@from-internal,${timeoutd})
exten => _X.,n,Gotoif($[“$\{DIALSTATUS}”=”ANSWER”]?hangup,callback)
exten => _X.,n,Set(CALLERID(name)=RB:${CALLERID(name)})
exten => _X.,n(callback),dial(local/${BLINDTRANSFER:4:${extLeng}}@from-internal)
exten => _X.,n(hangup),hangup()
exten => _*X.,1,dial(local/${EXTEN}@from-internal,15)
exten => _*X.,n,hangup()

Thanks to Alexander for fixing my earlier code. I am yet to test this on a live site 🙂

extensions_custom.conf:
[custom-test_transfer]
exten => _X.,1,NoOp(Entering custom-test_transfer)
exten => _X.,n,Set(timeoutd=25) ; set timeout in seconds
exten => _X.,n,Set(extLeng=${LEN(${EXTEN})})
exten => _X.,n,NoOp(The extenlength is ${extLeng})
exten => _X.,n,Dial(Local/${EXTEN}@from-internal,${timeoutd})
exten => _X.,n,Set(CALLERID(name)=RB:${CALLERID(name)})
exten => _X.,n,Dial(Local/${BLINDTRANSFER:4:${extLeng}}@from-internal)
exten => _X.,n,Hangup()

Once setup, reload asterisk and test this out.

There are several other scripts out there, but this is the one that worked correctly for me.

Common Issues with MOH – Asterisk/FreePBX

When working with MOH (Music on Hold) files in Asterisk/FreePBX I’ve come across a few issues that can occur regularly mainly due to human error. Best way to identify the issue is to check CLI entries when putting on hold as they give distinct clues as to what the problem is.

First one is that you get an error message stating cannot open or find the file. This is a permission issue. Make sure the MOH files are awned by asterisk user and has correct file permissions. This has happened to me more than one occasion when I’ve uploaded the file via SSH instead of the GUI or after doing a volume change using sox.

Second one you’d get is something on the line of unknown stream or unsupported format. Which simply means that asterisk doesn’t have the required tools to play the file.
With my customers, what I normally do is convert the files to wav files, on 8000 Hz, 16 bit, Mono settings using “Nero Wave Editor” and upload the files. This resolves many problems with different formats as well as reduces CPU load.

Final issue can be rectified using one of my earlier post.  : http://www.asanka.me/?p=19

Asterisk/FreePBX add Listen/Whisper/Barge facilities to your PABX

This page shows you how to add Listen/Whisper/Barge facilities to your Asterisk based PABX

A few of our customers wanted a feature to listen to other calls. Asterisk/FreePBX already provides ChanSpy, but the problem with it is that you cannot select what extension to listen to. After some digging around, found a few sites with instructions to get this done.

So here’s what I used to implement this. If you’re using this as it is, make sure that there are no feature codes using *222/*223 & *224.

Add below snippet to extensions_custom.conf. Reload asterisk and you’re good to go. To listen on extension 123, simply dial *222123.

[ext-local-custom]

;listen
exten => _*222x.#,1,Macro(user-callerid,)
exten => _*222x.#,n,Answer
exten => _*222x.#,n,NoCDR
exten => _*222x.#,n,Wait(1)
exten => _*222x.#,n,ChanSpy(sip/${EXTEN:4},q)
exten => _*222x.#,n,Hangup

;whisper
exten => _*223x.#,1,Macro(user-callerid,)
exten => _*223x.#,n,Answer
exten => _*223x.#,n,NoCDR
exten => _*223x.#,n,Wait(1)
exten => _*223x.#,n,ChanSpy(sip/${EXTEN:4},qw)
exten => _*223x.#,n,Hangup

;barge
exten => _*224x.#,1,Macro(user-callerid,)
exten => _*224x.#,n,Answer
exten => _*224x.#,n,NoCDR
exten => _*224x.#,n,Wait(1)
exten => _*224x.#,n,ChanSpy(SIP/${EXTEN:4},qB)
exten => _*224x.#,n,Hangup

 

Now, say there are some extensions that you don’t want to be listened on (ex. a manager), there are few ways to do it. But the simplest method I found is using below context. This needs to be added before the above set.

Here, no one should be able to listen/whisper/barge on extension 5205’s calls. What this code does is if someone tries to do be naughty, it will simply hangup the call.

;blockaccess
exten => _*2225205,1,Macro(user-callerid,)
exten => _*2225205,n,Hangup
exten => _*2235205,1,Macro(user-callerid,)
exten => _*2235205,n,Hangup
exten => _*2245205,1,Macro(user-callerid,)
exten => _*2245205,n,Hangup