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.
Any ideas how to do this on a FreePBX 2.8 and Asterisk 1.8.6 system?
Try the edited code above (the second example for Asterisk 1.6 and later). I discovered one interesting (and unexpected) thing, if in an Asterisk dialplan you try to go to a label that starts with a number, it treats the numeric portion of the label as a line number in that context (which probably won’t exist) and ignores the rest of the label completely. So, I changed the above examples to accommodate that behavior.
I could kiss you! The revised 1.6+ code works like a charm.
One further question, is there a way that the external number to dial could be pulled from a field in FreePBX? Like maybe the “DID Description” field that we do not normally use within our extensions?
Trying to figure out a way that a user could easily change the number to be dialed without touching the conf file.
Thanks so much!
scubes13, you should be able to pull a value from the database into a variable like this:
${DB(AMPUSER/${EXTEN}/database_field_name)}
You’d use ${EXTEN} in this situation because that should contain the number of the extension being called (if you were trying to do something like this in a different place in the dialplan, such as on an outgoing call, you might need to use a different variable such as ${AMPUSER}). If you have the Bulk Extensions module installed, you can go into that and it will show you a handy list of all the database field names associated with extensions. So you can pull the value from any of those. I’m not sure offhand if the “description” field is the one you want (I’m not all that familiar with the correlation between the extensions database and the field on the Extension configuration pages in the GUI) but if you know how to use either phpMyAdmin or the MySQL Database Server module in Webmin, you should be able to peer into the database and figure out which field contains the information you are trying to retrieve. Then all you should need to do is substitute the variable for the number in the appropriate line of the (newly modified) code (more on that in a moment):
exten => _X!,n,GotoIf($["${EXTEN}" = "1101"]?from-internal,${DB(AMPUSER/${EXTEN}/database_field_name)},1)
And extending that thought a bit further, if the above works you might be able to change the last few lines to remove hardcoded references to the individual extensions. You could try changing all of this:
;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)
To just something like this:
exten => _X!,n,GotoIf($["foo${DB(AMPUSER/${EXTEN}/database_field_name)}" = "foo"]?fieldempty)
exten => _X!,n,Goto(from-internal,${DB(AMPUSER/${EXTEN}/database_field_name)},1)
exten => _X!,n(fieldempty),Goto(from-internal,*${EXTEN},1)
The last three lines are untested at the moment, but the idea is that the first line determines if the database field is empty and if so jumps right to the extension’s voicemail (in the last line), otherwise it falls through to the line that attempts to transfer the call to whatever’s in that field (of course, it’s not doing any sanity checking to see if it’s a valid number first, so you need to make sure that if there is something in that field it’s a valid internal or external number). Be sure to replace both instances of database_field_name with the actual field name (which, again, might be description but without doing some investigation I would not know that).
This almost just begs for a new field in the database (Device Unreachable Transfer Number, or just “unreachable” as the database field name) but good luck getting anyone from F—PBX to implement that for you.
If you try any of the above please leave a comment and let us know how this worked for you.
By the way, I got to wondering why I was doing a jump to an unconditional jump, so I’ve modified the code yet again to shorten it at the end (why use two lines when one will do?), and to output a warning message to the CLI if you forgot to add a line defining the unavailable destination for an extension.
NOTICE: All comments above this one were imported from the original Michigan Telephone Blog and may or may not be relevant to the edited article above.