Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.
DISCLAIMER AND WARNING: This article contains EXPERIMENTAL code. DO NOT USE IT IN A PRODUCTION ENVIRONMENT until you have thoroughly tested it AND MODIFIED IT to meet your needs. It is guaranteed to NOT work (at least not in a way that will be useful to you) if you simply copy and paste it, and even if you read and follow the instructions below I don’t guarantee a thing (Asterisk can be funny, sometimes code that runs fine on one system will not on another). Anyway, you are NOT allowed to use this code unless you are willing to take ALL responsibility for modifying and testing it to make sure it will work in your situation. If you use this code and in some way it winds up not working and costing you money, don’t come after me because I’m warning you now that might happen, and it’s the risk you alone assume if you attempt to use this code!
FreePBX and Asterisk allow you to call forward a call on a busy or no-answer condition (as well as unconditionally), but there is no provision for specific forwarding if an extension (presumably an offsite one) is unreachable over the Internet. It is possible to do this, although in Asterisk 1.4 it’s not at all elegant. Some commercial VoIP providers offer a feature similar to this, calling it “Failover”, “Network Unavailable Forward” or just “Unavailable Forward”, “Network Availability Number ®” (Vonage trademarked that one!), or some similar name, but FreePBX and Asterisk do not offer similar functionality — there is no “Call Forwarding Unreachable” setting. However, with a bit of work and a minimal amount of dialplan creation, you can emulate this feature.
Here’s an example that may work in many situations (as written it works with SIP extensions only, but maybe you can modify it slightly if you need to use it with IAX2 extensions or some other type):
First, if you are still using Asterisk 1.4 or earlier, add the following code to etc/asterisk/extensions_custom.conf:
[custom-unreachable-test]
exten => _X!,1,Noop(Testing for unreachable extension ${EXTEN})
exten => _X!,n,TrySystem(asterisk -rx "sip show peers" | grep ^${EXTEN}/${EXTEN}[[:space:]] > /tmp/${EXTEN}.flag)
exten => _X!,n,ReadFile(reachable=/tmp/${EXTEN}.flag,1)
exten => _X!,n,GotoIf($["${LEN(${reachable})}" = "0"]?extoffline)
exten => _X!,n,Noop(Extension ${EXTEN} is reachable - sending to *${EXTEN} voice mailbox)
exten => _X!,n,Goto(from-internal,*${EXTEN},1)
exten => _X!,n(extoffline),Noop(Extension ${EXTEN} is NOT reachable)
;This is where you enter special forwarding conditionals for each unreachable extension
exten => _X!,n,GotoIf($["${EXTEN}" = "1101"]?from-internal,18005558355,1)
;This is the fallover (voicemail) destination in case no special destination is specified
exten => _X!,n,Noop(WARNING - no unreachable destination specified for extension ${EXTEN} - trying to send to voicemail)
exten => _X!,n,Goto(from-internal,*${EXTEN},1)
If you are using Asterisk 1.6 or later then use this instead:
[custom-unreachable-test]
exten => _X!,1,Noop(Testing for unreachable extension ${EXTEN})
exten => _X!,n,Set(reachable=${SHELL(asterisk -rx "sip show peers" | grep ^${EXTEN}/${EXTEN}[[:space:]])})
exten => _X!,n,GotoIf($["${LEN(${reachable})}" = "0"]?extoffline)
exten => _X!,n,Noop(Extension ${EXTEN} is reachable - sending to *${EXTEN} voice mailbox)
;This is where you enter special forwarding conditionals for each unreachable extension
exten => _X!,n,GotoIf($["${EXTEN}" = "1101"]?from-internal,18005558355,1)
;This is the fallover (voicemail) destination in case no special destination is specified
exten => _X!,n,Noop(WARNING - no unreachable destination specified for extension ${EXTEN} - trying to send to voicemail)
exten => _X!,n,Goto(from-internal,*${EXTEN},1)
In both of the above examples, change the number 1101 to match an actual extension number on your system and change the 18005558355 to the actual number you want to send calls to (note this could be another extension on your system, including a custom extension or a ring group). Duplicate the line containing those values for each extension you may want to forward, changing those two vales in each line appropriately (also see the comment section for another possible approach).
The above code assumes that if an extension is reachable, but is busy or does not answer, you want the call to go to voicemail (* + the original extension number — obviously, this would be easy to change if that’s an incorrect assumption). However, if the extension is unreachable, you want to reroute it to the user’s cell phone or some other number. In the above example, if extension 1101 receives a call and is unreachable, it would be forwarded to TellMe at 1-800-555-TELL (18005558355) – obviously not practical in a real-world situation, but it’s just an example. Again, note you have to duplicate that line in the code for each extension that might be forwarded in this way.
In order to make this work, you need to go into the FreePBX Tools menu and select “Custom Destinations”, then add a new custom destination. The destination must be custom-unreachable-test,${EXTEN},1 and the description can be anything you want (I suggest “Unreachable Extension Test” or something similar).
For each extension you wish to use this with, you must have qualify=yes (or set qualify to a valid numeric value) in the extension settings.
Finally, for each extension you want to use this with, create a Follow-Me (or edit any existing one) for that extension. You can leave the defaults as they are (or change them if you want – maybe you want to change the Ring Time, for example) but the one thing you must change is the Destination if no answer. Change that to the Custom Destination that you just created. Also, don’t forget to add the line in extensions_custom.conf to actually do something with calls to that extension when the extension is unreachable.
The reason I say this code is not elegant is because it relies on a kludge. It does a “sip show peers”, then looks for the pattern ${EXTEN}/${EXTEN} (e.g. 1101/1101) at the start of a line, which on most systems indicates the extension is connected. This may not be the case if you are using what is known as “deviceanduser” mode (which you probably aren’t unless you’re running a call center) so in that case you may need to use a different pattern match, for example:
exten => _X!,n,TrySystem(asterisk -rx "sip show peers" | grep ^${EXTEN}[[:space:]] | grep OK > /tmp/${EXTEN}.flag)
The result of the system call will be written to the file /tmp/1101.flag (or a similar file with a different extension number) and will either contain the full line from “sip show peers” (if the device or phone is reachable) or nothing (it will be an empty file). So in the next line we read the file in (actually just one character) and test the length – if it’s zero, then that’s when we do the unreachable processing. If it’s non-zero, we send the call to voicemail. EDIT: In Asterisk 1.6 and later there’s no need to create a temporary file.
I’m not saying this is the best way to do this, or the only way to do it, but it is a way that seems to work in VERY limited testing (at least on a system running Asterisk 1.4.35 and FreePBX 2.5).
This was inspired by a thread I saw on the PBX in a Flash forum, which also notes that there may be an even better way to do this in Asterisk 1.8, but since I don’t have it and VERY few FreePBX users are running 1.8 at this time, I’m not even going to touch that one.
EDIT: I did a VERY limited test of this (and made one change in the above code as a result) on an Asterisk 1.8 system running F—PBX 2.8. There are now two code sections above, one for those running Asterisk 1.4 or earlier, and one for those running Asterisk 1.6 or later (only tested with Asterisk 1.8). And before you try that “even better way” mentioned in the last paragraph, note that “Having chan_sip set HASH(SIP_CAUSE,) on the channel carries a significant performance penalty because of the usage of the MASTER_CHANNEL() dialplan function” and that Digium has “decided to disable this feature by default in future 1.8 versions” (see this page for more information). So, probably best to stick with the method shown here, if you can get it to work for you.
Like this:
Like Loading...
Recent Comments