Two things I wish you could do in Asterisk or FreePBX, or ANY free software PBX

 

Important
This is a heavily 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.

I want to explain a problem that apparently exists in current implementations of Asterisk and FreePBX (and by extension, all distributions based on those pieces of software).

Let’s say you have several extensions on your system and many, if not all of them, have a specific “trunk” associated with that extension.  It may be a provider account or a Google Voice account that’s used exclusively by that extension.  Routing INCOMING calls is usually not difficult at all, you simply use the trunk’s DID in an Inbound Route and then route the calls from that DID directly to the desired extension.  However, OUTBOUND is another matter.  You have to create an Outbound Route, and in that route you have to put your dial patterns and use the /extension suffix. It can still be difficult to set up the dial patterns the way you need them.  In 2.8 and later it is much harder because of the individual boxes for each segment of each pattern.

Let’s say you want certain extensions to only be able to call numbers in U.S. area codes, but each of those extensions has its own trunk. And let’s say your extensions are numbered 1000 through 1099. Oh, and you want to support both 10 and 11 digit dialing. So in your outbound route for extension 1000, you might have a list of patterns like this (please scroll down to the end of this long list — it’s only about 600 lines!):

1201NXXXXXX/1000
1202NXXXXXX/1000
1203NXXXXXX/1000
1205NXXXXXX/1000
1206NXXXXXX/1000
1207NXXXXXX/1000
1208NXXXXXX/1000
1209NXXXXXX/1000
1210NXXXXXX/1000
1212NXXXXXX/1000
1213NXXXXXX/1000
1214NXXXXXX/1000
1215NXXXXXX/1000
1216NXXXXXX/1000
1217NXXXXXX/1000
1218NXXXXXX/1000
1219NXXXXXX/1000
1224NXXXXXX/1000
1225NXXXXXX/1000
1228NXXXXXX/1000
1229NXXXXXX/1000
1231NXXXXXX/1000
1234NXXXXXX/1000
1239NXXXXXX/1000
1240NXXXXXX/1000
1248NXXXXXX/1000
1251NXXXXXX/1000
1252NXXXXXX/1000
1253NXXXXXX/1000
1254NXXXXXX/1000
1256NXXXXXX/1000
1260NXXXXXX/1000
1262NXXXXXX/1000
1267NXXXXXX/1000
1269NXXXXXX/1000
1270NXXXXXX/1000
1274NXXXXXX/1000
1276NXXXXXX/1000
1281NXXXXXX/1000
1301NXXXXXX/1000
1302NXXXXXX/1000
1303NXXXXXX/1000
1304NXXXXXX/1000
1305NXXXXXX/1000
1307NXXXXXX/1000
1308NXXXXXX/1000
1309NXXXXXX/1000
1310NXXXXXX/1000
1312NXXXXXX/1000
1313NXXXXXX/1000
1314NXXXXXX/1000
1315NXXXXXX/1000
1316NXXXXXX/1000
1317NXXXXXX/1000
1318NXXXXXX/1000
1319NXXXXXX/1000
1320NXXXXXX/1000
1321NXXXXXX/1000
1323NXXXXXX/1000
1325NXXXXXX/1000
1327NXXXXXX/1000
1330NXXXXXX/1000
1331NXXXXXX/1000
1334NXXXXXX/1000
1336NXXXXXX/1000
1337NXXXXXX/1000
1339NXXXXXX/1000
1347NXXXXXX/1000
1351NXXXXXX/1000
1352NXXXXXX/1000
1360NXXXXXX/1000
1361NXXXXXX/1000
1364NXXXXXX/1000
1385NXXXXXX/1000
1386NXXXXXX/1000
1401NXXXXXX/1000
1402NXXXXXX/1000
1404NXXXXXX/1000
1405NXXXXXX/1000
1406NXXXXXX/1000
1407NXXXXXX/1000
1408NXXXXXX/1000
1409NXXXXXX/1000
1410NXXXXXX/1000
1412NXXXXXX/1000
1413NXXXXXX/1000
1414NXXXXXX/1000
1415NXXXXXX/1000
1417NXXXXXX/1000
1419NXXXXXX/1000
1423NXXXXXX/1000
1424NXXXXXX/1000
1425NXXXXXX/1000
1430NXXXXXX/1000
1432NXXXXXX/1000
1434NXXXXXX/1000
1435NXXXXXX/1000
1440NXXXXXX/1000
1442NXXXXXX/1000
1443NXXXXXX/1000
1458NXXXXXX/1000
1469NXXXXXX/1000
1470NXXXXXX/1000
1475NXXXXXX/1000
1478NXXXXXX/1000
1479NXXXXXX/1000
1480NXXXXXX/1000
1484NXXXXXX/1000
1501NXXXXXX/1000
1502NXXXXXX/1000
1503NXXXXXX/1000
1504NXXXXXX/1000
1505NXXXXXX/1000
1507NXXXXXX/1000
1508NXXXXXX/1000
1509NXXXXXX/1000
1510NXXXXXX/1000
1512NXXXXXX/1000
1513NXXXXXX/1000
1515NXXXXXX/1000
1516NXXXXXX/1000
1517NXXXXXX/1000
1518NXXXXXX/1000
1520NXXXXXX/1000
1530NXXXXXX/1000
1534NXXXXXX/1000
1539NXXXXXX/1000
1540NXXXXXX/1000
1541NXXXXXX/1000
1551NXXXXXX/1000
1559NXXXXXX/1000
1561NXXXXXX/1000
1562NXXXXXX/1000
1563NXXXXXX/1000
1567NXXXXXX/1000
1570NXXXXXX/1000
1571NXXXXXX/1000
1573NXXXXXX/1000
1574NXXXXXX/1000
1575NXXXXXX/1000
1580NXXXXXX/1000
1585NXXXXXX/1000
1586NXXXXXX/1000
1601NXXXXXX/1000
1602NXXXXXX/1000
1603NXXXXXX/1000
1605NXXXXXX/1000
1606NXXXXXX/1000
1607NXXXXXX/1000
1608NXXXXXX/1000
1609NXXXXXX/1000
1610NXXXXXX/1000
1612NXXXXXX/1000
1614NXXXXXX/1000
1615NXXXXXX/1000
1616NXXXXXX/1000
1617NXXXXXX/1000
1618NXXXXXX/1000
1619NXXXXXX/1000
1620NXXXXXX/1000
1623NXXXXXX/1000
1626NXXXXXX/1000
1630NXXXXXX/1000
1631NXXXXXX/1000
1636NXXXXXX/1000
1641NXXXXXX/1000
1646NXXXXXX/1000
1650NXXXXXX/1000
1651NXXXXXX/1000
1657NXXXXXX/1000
1660NXXXXXX/1000
1661NXXXXXX/1000
1662NXXXXXX/1000
1667NXXXXXX/1000
1669NXXXXXX/1000
1678NXXXXXX/1000
1681NXXXXXX/1000
1682NXXXXXX/1000
1701NXXXXXX/1000
1702NXXXXXX/1000
1703NXXXXXX/1000
1704NXXXXXX/1000
1706NXXXXXX/1000
1707NXXXXXX/1000
1708NXXXXXX/1000
1712NXXXXXX/1000
1713NXXXXXX/1000
1714NXXXXXX/1000
1715NXXXXXX/1000
1716NXXXXXX/1000
1717NXXXXXX/1000
1718NXXXXXX/1000
1719NXXXXXX/1000
1720NXXXXXX/1000
1724NXXXXXX/1000
1727NXXXXXX/1000
1731NXXXXXX/1000
1732NXXXXXX/1000
1734NXXXXXX/1000
1737NXXXXXX/1000
1740NXXXXXX/1000
1747NXXXXXX/1000
1754NXXXXXX/1000
1757NXXXXXX/1000
1760NXXXXXX/1000
1762NXXXXXX/1000
1763NXXXXXX/1000
1765NXXXXXX/1000
1769NXXXXXX/1000
1770NXXXXXX/1000
1772NXXXXXX/1000
1773NXXXXXX/1000
1774NXXXXXX/1000
1775NXXXXXX/1000
1779NXXXXXX/1000
1781NXXXXXX/1000
1785NXXXXXX/1000
1786NXXXXXX/1000
1801NXXXXXX/1000
1802NXXXXXX/1000
1803NXXXXXX/1000
1804NXXXXXX/1000
1805NXXXXXX/1000
1806NXXXXXX/1000
1808NXXXXXX/1000
1810NXXXXXX/1000
1812NXXXXXX/1000
1813NXXXXXX/1000
1814NXXXXXX/1000
1815NXXXXXX/1000
1816NXXXXXX/1000
1817NXXXXXX/1000
1818NXXXXXX/1000
1828NXXXXXX/1000
1830NXXXXXX/1000
1831NXXXXXX/1000
1832NXXXXXX/1000
1843NXXXXXX/1000
1845NXXXXXX/1000
1847NXXXXXX/1000
1848NXXXXXX/1000
1850NXXXXXX/1000
1856NXXXXXX/1000
1857NXXXXXX/1000
1858NXXXXXX/1000
1859NXXXXXX/1000
1860NXXXXXX/1000
1862NXXXXXX/1000
1863NXXXXXX/1000
1864NXXXXXX/1000
1865NXXXXXX/1000
1870NXXXXXX/1000
1872NXXXXXX/1000
1878NXXXXXX/1000
1901NXXXXXX/1000
1903NXXXXXX/1000
1904NXXXXXX/1000
1906NXXXXXX/1000
1907NXXXXXX/1000
1908NXXXXXX/1000
1909NXXXXXX/1000
1910NXXXXXX/1000
1912NXXXXXX/1000
1913NXXXXXX/1000
1914NXXXXXX/1000
1915NXXXXXX/1000
1916NXXXXXX/1000
1917NXXXXXX/1000
1918NXXXXXX/1000
1919NXXXXXX/1000
1920NXXXXXX/1000
1925NXXXXXX/1000
1928NXXXXXX/1000
1929NXXXXXX/1000
1931NXXXXXX/1000
1936NXXXXXX/1000
1937NXXXXXX/1000
1938NXXXXXX/1000
1940NXXXXXX/1000
1941NXXXXXX/1000
1947NXXXXXX/1000
1949NXXXXXX/1000
1951NXXXXXX/1000
1952NXXXXXX/1000
1954NXXXXXX/1000
1956NXXXXXX/1000
1970NXXXXXX/1000
1971NXXXXXX/1000
1972NXXXXXX/1000
1973NXXXXXX/1000
1978NXXXXXX/1000
1979NXXXXXX/1000
1980NXXXXXX/1000
1984NXXXXXX/1000
1985NXXXXXX/1000
1989NXXXXXX/1000
201NXXXXXX/1000
202NXXXXXX/1000
203NXXXXXX/1000
205NXXXXXX/1000
206NXXXXXX/1000
207NXXXXXX/1000
208NXXXXXX/1000
209NXXXXXX/1000
210NXXXXXX/1000
212NXXXXXX/1000
213NXXXXXX/1000
214NXXXXXX/1000
215NXXXXXX/1000
216NXXXXXX/1000
217NXXXXXX/1000
218NXXXXXX/1000
219NXXXXXX/1000
224NXXXXXX/1000
225NXXXXXX/1000
228NXXXXXX/1000
229NXXXXXX/1000
231NXXXXXX/1000
234NXXXXXX/1000
239NXXXXXX/1000
240NXXXXXX/1000
248NXXXXXX/1000
251NXXXXXX/1000
252NXXXXXX/1000
253NXXXXXX/1000
254NXXXXXX/1000
256NXXXXXX/1000
260NXXXXXX/1000
262NXXXXXX/1000
267NXXXXXX/1000
269NXXXXXX/1000
270NXXXXXX/1000
274NXXXXXX/1000
276NXXXXXX/1000
281NXXXXXX/1000
301NXXXXXX/1000
302NXXXXXX/1000
303NXXXXXX/1000
304NXXXXXX/1000
305NXXXXXX/1000
307NXXXXXX/1000
308NXXXXXX/1000
309NXXXXXX/1000
310NXXXXXX/1000
312NXXXXXX/1000
313NXXXXXX/1000
314NXXXXXX/1000
315NXXXXXX/1000
316NXXXXXX/1000
317NXXXXXX/1000
318NXXXXXX/1000
319NXXXXXX/1000
320NXXXXXX/1000
321NXXXXXX/1000
323NXXXXXX/1000
325NXXXXXX/1000
327NXXXXXX/1000
330NXXXXXX/1000
331NXXXXXX/1000
334NXXXXXX/1000
336NXXXXXX/1000
337NXXXXXX/1000
339NXXXXXX/1000
347NXXXXXX/1000
351NXXXXXX/1000
352NXXXXXX/1000
360NXXXXXX/1000
361NXXXXXX/1000
364NXXXXXX/1000
385NXXXXXX/1000
386NXXXXXX/1000
401NXXXXXX/1000
402NXXXXXX/1000
404NXXXXXX/1000
405NXXXXXX/1000
406NXXXXXX/1000
407NXXXXXX/1000
408NXXXXXX/1000
409NXXXXXX/1000
410NXXXXXX/1000
412NXXXXXX/1000
413NXXXXXX/1000
414NXXXXXX/1000
415NXXXXXX/1000
417NXXXXXX/1000
419NXXXXXX/1000
423NXXXXXX/1000
424NXXXXXX/1000
425NXXXXXX/1000
430NXXXXXX/1000
432NXXXXXX/1000
434NXXXXXX/1000
435NXXXXXX/1000
440NXXXXXX/1000
442NXXXXXX/1000
443NXXXXXX/1000
458NXXXXXX/1000
469NXXXXXX/1000
470NXXXXXX/1000
475NXXXXXX/1000
478NXXXXXX/1000
479NXXXXXX/1000
480NXXXXXX/1000
484NXXXXXX/1000
501NXXXXXX/1000
502NXXXXXX/1000
503NXXXXXX/1000
504NXXXXXX/1000
505NXXXXXX/1000
507NXXXXXX/1000
508NXXXXXX/1000
509NXXXXXX/1000
510NXXXXXX/1000
512NXXXXXX/1000
513NXXXXXX/1000
515NXXXXXX/1000
516NXXXXXX/1000
517NXXXXXX/1000
518NXXXXXX/1000
520NXXXXXX/1000
530NXXXXXX/1000
534NXXXXXX/1000
539NXXXXXX/1000
540NXXXXXX/1000
541NXXXXXX/1000
551NXXXXXX/1000
559NXXXXXX/1000
561NXXXXXX/1000
562NXXXXXX/1000
563NXXXXXX/1000
567NXXXXXX/1000
570NXXXXXX/1000
571NXXXXXX/1000
573NXXXXXX/1000
574NXXXXXX/1000
575NXXXXXX/1000
580NXXXXXX/1000
585NXXXXXX/1000
586NXXXXXX/1000
601NXXXXXX/1000
602NXXXXXX/1000
603NXXXXXX/1000
605NXXXXXX/1000
606NXXXXXX/1000
607NXXXXXX/1000
608NXXXXXX/1000
609NXXXXXX/1000
610NXXXXXX/1000
612NXXXXXX/1000
614NXXXXXX/1000
615NXXXXXX/1000
616NXXXXXX/1000
617NXXXXXX/1000
618NXXXXXX/1000
619NXXXXXX/1000
620NXXXXXX/1000
623NXXXXXX/1000
626NXXXXXX/1000
630NXXXXXX/1000
631NXXXXXX/1000
636NXXXXXX/1000
641NXXXXXX/1000
646NXXXXXX/1000
650NXXXXXX/1000
651NXXXXXX/1000
657NXXXXXX/1000
660NXXXXXX/1000
661NXXXXXX/1000
662NXXXXXX/1000
667NXXXXXX/1000
669NXXXXXX/1000
678NXXXXXX/1000
681NXXXXXX/1000
682NXXXXXX/1000
701NXXXXXX/1000
702NXXXXXX/1000
703NXXXXXX/1000
704NXXXXXX/1000
706NXXXXXX/1000
707NXXXXXX/1000
708NXXXXXX/1000
712NXXXXXX/1000
713NXXXXXX/1000
714NXXXXXX/1000
715NXXXXXX/1000
716NXXXXXX/1000
717NXXXXXX/1000
718NXXXXXX/1000
719NXXXXXX/1000
720NXXXXXX/1000
724NXXXXXX/1000
727NXXXXXX/1000
731NXXXXXX/1000
732NXXXXXX/1000
734NXXXXXX/1000
737NXXXXXX/1000
740NXXXXXX/1000
747NXXXXXX/1000
754NXXXXXX/1000
757NXXXXXX/1000
760NXXXXXX/1000
762NXXXXXX/1000
763NXXXXXX/1000
765NXXXXXX/1000
769NXXXXXX/1000
770NXXXXXX/1000
772NXXXXXX/1000
773NXXXXXX/1000
774NXXXXXX/1000
775NXXXXXX/1000
779NXXXXXX/1000
781NXXXXXX/1000
785NXXXXXX/1000
786NXXXXXX/1000
801NXXXXXX/1000
802NXXXXXX/1000
803NXXXXXX/1000
804NXXXXXX/1000
805NXXXXXX/1000
806NXXXXXX/1000
808NXXXXXX/1000
810NXXXXXX/1000
812NXXXXXX/1000
813NXXXXXX/1000
814NXXXXXX/1000
815NXXXXXX/1000
816NXXXXXX/1000
817NXXXXXX/1000
818NXXXXXX/1000
828NXXXXXX/1000
830NXXXXXX/1000
831NXXXXXX/1000
832NXXXXXX/1000
843NXXXXXX/1000
845NXXXXXX/1000
847NXXXXXX/1000
848NXXXXXX/1000
850NXXXXXX/1000
856NXXXXXX/1000
857NXXXXXX/1000
858NXXXXXX/1000
859NXXXXXX/1000
860NXXXXXX/1000
862NXXXXXX/1000
863NXXXXXX/1000
864NXXXXXX/1000
865NXXXXXX/1000
870NXXXXXX/1000
872NXXXXXX/1000
878NXXXXXX/1000
901NXXXXXX/1000
903NXXXXXX/1000
904NXXXXXX/1000
906NXXXXXX/1000
907NXXXXXX/1000
908NXXXXXX/1000
909NXXXXXX/1000
910NXXXXXX/1000
912NXXXXXX/1000
913NXXXXXX/1000
914NXXXXXX/1000
915NXXXXXX/1000
916NXXXXXX/1000
917NXXXXXX/1000
918NXXXXXX/1000
919NXXXXXX/1000
920NXXXXXX/1000
925NXXXXXX/1000
928NXXXXXX/1000
929NXXXXXX/1000
931NXXXXXX/1000
936NXXXXXX/1000
937NXXXXXX/1000
938NXXXXXX/1000
940NXXXXXX/1000
941NXXXXXX/1000
947NXXXXXX/1000
949NXXXXXX/1000
951NXXXXXX/1000
952NXXXXXX/1000
954NXXXXXX/1000
956NXXXXXX/1000
970NXXXXXX/1000
971NXXXXXX/1000
972NXXXXXX/1000
973NXXXXXX/1000
978NXXXXXX/1000
979NXXXXXX/1000
980NXXXXXX/1000
984NXXXXXX/1000
985NXXXXXX/1000
989NXXXXXX/1000

(Note the above does not include the “toll free” area codes nor Canadian area codes; I have separate routes for those).

Now THAT is bad enough, but then imagine having to duplicate this list for each of your extensions (changing only the extension number after the / character), because each will need its own outbound route in order to select its own trunk. In pre-2.8 versions of Asterisk, you could simply copy this list into a text editor, do a search and replace on the /1000 (replacing it with the next extension number), and paste the changed list into a new outbound route. However, with the new way of entering dial plans, you have to enter each line in each field manually, OR (in 2.9 and later) mess with .CSV files, which although easier than manual entry are still a lot harder to deal with than simple cut-and-paste.

But that is actually not the subject of this article; it just sets the stage for what I’m thinking SHOULD be part of Asterisk (or any other soft PBX that requires entering patterns in a similar manner, that is, one line for each pattern). There are actually TWO ways this could be handled, but neither will work at present, as far as I know.

1) Stacking Routes

Let’s suppose you had an outbound route that had all the USA patterns, but did NOT include the extension field. You could have it near the top of your Outbound Route list. And let’s say that you could make the destination of that trunk another “group” of outbound routes rather than a trunk. In that second group, you could have routes with just two patterns per extension:

1XXXXXXXXXX/1000
XXXXXXXXXX/1000

So the call would be effectively pre-screened in the first (primary) group of outbound routes, then sent to the second group (NOT part of the primary group) which would route by extension. That way, you’d only need ONE route with a list of USA patterns, one route with a list of Canada patterns, one route with a list of “toll free” patterns, etc. Each could go directly to a trunk, or to a secondary group of outbound routes.

I think Asterisk might actually be capable of doing something like this (though I’m uncertain of that), but FreePBX definitely is not. So some FreePBX users literally have THOUSANDS of lines of dial patterns in their configuration. Does this slow things down? You betcha, at least when making a configuration change! It takes forever for that darn frog to stop eating flies (if a real frog ate that many flies in that short a time, its gut would probably explode!).

2) Macros

Now here we have a solution that would likely need to be implemented in Asterisk itself. The basic idea is to allow macros in dial patterns. For example, you create a list such as the one above (but without the /extension field – just the number patterns only) and call it [pattern-USA]. Then in your outbound routes, you do something like this:

[pattern-USA]/1000

Changing the extension as needed for each Outbound Route. As noted, this would require implementing this type of macro feature in Asterisk, but it would also necessitate a way to turn off the syntax checking in FreePBX, which is currently impossible.

EDIT: For another way to handle this that probably will work, see How to use the FreePBX [macro-dialout-trunk-predial-hook] macro and regular expressions to blacklist or whitelist outgoing calls on all trunks.

A Perl script to send Caller ID popups from Asterisk to computers running Notify OSD (such as Ubuntu Linux) or any command-line invoked notification system

 

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.

This is basically an update to my article, A Perl script to send Caller ID popups from Asterisk to computers running Growl under OS X on a Mac or Growl for Windows, and you should still use that article if you are sending notifications to a computer on your local network that runs Growl or Growl for Windows as the notification system.

I wanted to find a way to send Caller ID popups to a Ubuntu Linux box, and in the process I discovered a different method of sending such notifications.  There are pros and cons to using the new method, so let me explain those first:

Pros:

  • Can send notifications to any computer that supports command line generated notifications (so it could also be used with Growl, if you can use growlnotify from a command prompt to generate a notification).
  • Can send notifications to any computer that you can SSH into, provided you have it set up to use public/private key authentication rather than password authentication.

Cons:

  • Notifications typically display a couple of seconds later than under the previous method.  I suspect this is due to the SSH authentication taking a second or two.
  • It’s a little bit more complicated to set this up, though not horribly so.
  • Because this uses SSH and requires that Asterisk be granted permission to establish an SSH connection as the super user (by using sudo), there may be unforeseen security risks.

Read that last point again, and please understand that as with all projects on this site, I offer this for experimental purposes only.  I explicitly do not warrant this method as being 100% secure, nor will I tell you that it could not be exploited to do bad things on your system.  I don’t think it can (and feel free to leave a comment if you think I’m wrong), but I just don’t know that for sure.  So, if you decide to use anything in this article, you agree to assume all risks. If you’re the type that likes to sue other people when something goes wrong, then you do not have permission to use this code.  We’re all experimenters here, so no guarantees!

As with the previous method, you must have the Perl language installed on your Asterisk server, and you must have the Asterisk::AGI module installed (I’m going to assume you know how to install a Perl module from the CPAN repository – if you have Webmin installed, it can be done from within Webmin). Chances are you already have Asterisk::AGI installed, unless you built your Asterisk server “from scratch” and never installed it.

There’s one additional thing you must do on the Asterisk server before this will run, and that’s allow Asterisk to run the ssh command as root. So, add this to your /etc/sudoers file (probably at the very end, but in any case it should be obvious where to add this because it will be in a section where Asterisk is granted similar privileges with regard to other programs):

asterisk ALL = NOPASSWD: /usr/bin/ssh

Next you want to copy and paste the following Perl script to the filename /var/lib/asterisk/agi-bin/notifysend.agi on your Asterisk server (to create a non-existent file, you can use the touch command, and after that you can edit it in Midnight Commander or by using the text editor of your choice). If this code looks somewhat familiar, it’s because it’s adapted from some code that originally appeared in a FreePBX How-To, which I have modified.

#!/usr/bin/perl
use strict;
use warnings;
use Asterisk::AGI;
my $agi = new Asterisk::AGI;
my %input = $agi->ReadParse();

# Next two lines fork the process so Asterisk can get on with handling the call
open STDOUT, '>/dev/null';
fork and exit;

my $num = $input{'callerid'};
my $name = $input{'calleridname'};
my $ext = $input{'extension'};
my $user = $ARGV[0];
my $ip = $ARGV[1];

if ( $ip =~ /^([0-9a-f]{2}(:|$)){6}$/i ) {
    $ip = $agi->database_get('growlsend',uc($ip));
}

# OMIT this section if you don't want IP address
# checking (e.g. you want to use foo.bar.com)
unless ( $ip =~ /^(d+).(d+).(d+).(d+)$/ ) {
    exit;
}

if ( $ARGV[2] ne "" ) {
 $ext = $ARGV[2];
}

my @months = (
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
);
my @weekdays = (
    "Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday"
);
my (
    $sec,  $min,  $hour, $mday, $mon,
    $year, $wday, $yday, $isdst
) = localtime(time);
my $ampm = "AM";
if ( $hour > 12 ) {
    $ampm = "PM";
    $hour = ( $hour - 12 );
}
elsif ( $hour eq 12 ) { $ampm = "PM"; }
elsif ( $hour eq 0 )  { $hour = "12"; }
if ( $min < 10 ) { $min = "0" . $min; }
$year += 1900;
my $fulldate =
"$hour:$min $ampm on $weekdays[$wday], $months[$mon] $mday, $year";

# Next two lines normalize NANP numbers, probably not wanted outside of U.S.A./Canada/other NANP places
$num =~ s/^([2-9])(d{2})([2-9])(d{2})(d{4})$/$1$2-$3$4-$5/;
$num =~ s/^(1)([2-9])(d{2})([2-9])(d{2})(d{4})$/$1-$2$3-$4$5-$6/;

my $cmd = qq(./remotenotify.sh "$name" "$num calling $ext at $fulldate");
$cmd = "sudo ssh $user@$ip '$cmd'";
exec "$cmd";

Also, if you want to be able to specify computers that you wish to send notifications to using MAC addresses rather than IP addresses (in case computers on your network get their addresses via DHCP, and therefore the IP address of the target computer can change from time to time), then you must in addition install the following Perl script (if you have not already done so when using the previous method). Note that if you have a mix of computers on your network and you are using both the new and old methods, you only need to do this once — it works with both methods (hence the reference to “growlsend” in the database and “gshelper” as the name of this script). Call it /var/lib/asterisk/agi-bin/gshelper.agi and note that there is a line within it that you may need to change to reflect the scope of your local network:

#!/usr/bin/perl
use strict;
use warnings;
my ($prev, @mac, @ip);
# Change the 192.168.0.0/24 in the following line to reflect the scope of your local network, if necessary
my @nmap = `nmap -sP 192.168.0.0/24|grep -B 1 MAC`;
foreach (@nmap) {
    if (index($_, "MAC Address:") >= 0) {
        @mac = split(" ");
        @ip = split(" ",$prev);
        `/usr/sbin/asterisk -rx "database put growlsend $mac[2] $ip[1]"`;
    }
    $prev=$_;
}

Make sure to modify the permissions on both scripts to make them the same as other scripts in that directory (owner and group should be asterisk, and the file should be executable), and if you use the gshelper script, make sure to set up a cron job to run it every so often (I would suggest once per hour, but it’s up to you).

Now go to this page and search for the paragraph starting with, “After you have created that file, check the ownership and permissions” (it’s right under a code block, just a bit more than halfway down the page) and if you are using FreePBX follow the instructions from there on out (if you are not using FreePBX then just read that section of the page so you understand how this works, and in any case ignore the top half of the page, it’s talking about a different notification system entirely). However, note that the syntax used in extensions_custom.conf differs from what is shown there, depending on whether you are specifying an IP address or a MAC address to identify the target computer.

First, if you are specifying the IP address of the target computer, then instead of using this syntax:

exten => ****525,1,AGI(growlsend.agi,192.168.0.123,GrowlPassWord,525)

You will need to use this:

exten => ****525,1,AGI(notifysend.agi,username,192.168.0.123,525)

Note that username is the account name you use when doing an ssh login into the destination system, and it should also be the desktop user on the system (not root!). Let’s say that the system is currently at IP address 192.168.0.123. In order for this to work, you need to be able to ssh into your Ubuntu box from your Asterisk server, using the following command from the Asterisk server’s command line:

ssh username@192.168.0.123

If it asks for a password, then you need to follow the instructions at Stop entering passwords: How to set up ssh public/private key authentication for connections to a remote server, and get it set up so that it will not ask for a password (if you don’t like my article, maybe this one will make it clearer).

It’s probably easiest to configure each computer that is to receive notifications to use a static IP address. But note that if you use the above code and have the gshelper.agi program running as a cron job, then after the first time it has run while the computer to receive the notifications is online you should be able to use a computer’s MAC address instead of the IP address. This only works if you’ve used the modified script on this page, not the one shown in the FreePBX How-To. As an example, instead of

exten => ****525,1,AGI(growlsend.agi,192.168.0.123,GrowlPassWord,525)

as shown in the example there, you could use

exten => ****525,1,AGI(notifysend.agi,username,01:23:45:AB:CD:EF,525)

(the above is all one line) where 01:23:45:AB:CD:EF is the MAC address of the computer you want to send the notification to. Once again, just in case you missed it the first time I said it, this won’t work until the gshelper.agi script has been run at least once while the computer to receive the notifications was online. If for some reason it still doesn’t appear to work, run the nmap command (from gshelper.agi) including everything between the two backticks (`) directly from a Linux command prompt and see if it’s finding the computer (depending on the size of your network, it might be several seconds before you see any output, which is why I don’t try to run this in real time while a call is coming in).

If you are NOT running FreePBX, but instead writing your Asterisk dial plans by hand, then you will have to insert a line similar to one of the above examples into your dial plan, except that you don’t need the four asterisks (****) in front of the extension number, and if it’s not the first line in the context, you’ll probably want to use n rather than 1 for the line designator (and, you won’t be putting the line into extensions_custom.conf because you probably don’t have such a file; instead you’ll just put it right in the appropriate section of your dial plan). In other words, something like this (using extension 525 as an example):

exten => 525,n,AGI(notifysend.agi,username,192.168.0.123,525)

This line should go before the line that actually connects the call through to extension 525. I do not write Asterisk dial plans by hand, so that’s about all the help I can give you. And if you don’t write your dial plans by hand, but you aren’t using FreePBX, then I’m afraid you’ll have to ask for help in whatever forum you use for advice on the particular software that you do use to generate dial plans, because I can’t tell you how to insert the above line (or something like it) into your dial plan.

Now is where it gets just a bit more complicated than in the original method. If you have followed the above instructions, you’ll be able to send the notifications to the remote system using SSH, but there will be nothing there to receive them. So we have to create a small script on the receiving system to do something with the received notifications. That script will vary depending on the receiving system, but it must be named remotenotify.sh and it must be placed in the destination user’s home directory, and don’t forget to make it executable! Here’s one that will work in most Ubuntu installations that have Notify OSD installed:

export DISPLAY=:0
notify-send --urgency="critical" --icon="phone" "$1" "$2"

Those two lines are all you need. On a different type of system (or if you have multiple displays) you may need to or wish to do something different. For example, as I mentioned above, if the destination system is running Growl then your remotenotify.sh script will need to call growlnotify, but beyond that I wouldn’t know what to use there (EDIT: But if the target system is a Mac that is running OS X, a pretty good guess would probably be that you’d only need one line, something like this:

growlnotify -s -p 1 -a Telephone -m "$2" $1

In this case it should make the notification sticky until dismissed by the user, give it a priority of 1 — the default is 0 — and use the application icon from the “Telephone” application if you have it installed. Instead of -a to specify an application’s icon you could use -I followed by a path to an .icns file that contains an icon you want to use.  Type growlnotify –help to see all the growlnotify options.  Oh, and before you can make an SSH connection to a Mac you have to go into System Preferences | Sharing and turn on Remote Login).

The beauty of this approach is that you can make the remotenotify.sh script as simple or as complicated as you need — you could even make it forward a notification to other devices if you wish, but figuring out how to do that is up to you (if you come up with something good, please leave a comment and tell us about it!).

If you’re running Ubuntu on the target system, here’s a few articles you may wish to use to help you get your notifications to look the way you want them to appear:

Tweak The NotifyOSD Notifications In Ubuntu 10.10 Maverick Meerkat [Patched NotifyOSD PPA Updated]
Get Notifications With A Close Button In Ubuntu
Configurable NotifyOSD Bubbles For Ubuntu 11.04: Move, Close On Click, Change Colors And More

If you want to be able to review missed notifications, you may be able to use this (as a side note, why don’t they have something like this for Growl?):

Never Miss A NotifyOSD Notification With “Recent Notifications” GNOME Applet

The idea behind the shell script that runs on the target system was found in a comment on the following article, which may be of special interest to MythTV users:

Send OSD notification messages to all systems on a network

There are links to other original sources throughout the article, so feel free to follow those if you want more in-depth commentary.

A Perl script to send Caller ID popups from Asterisk to computers running Growl under OS X on a Mac or Growl for Windows

 

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.
Notice
EDIT March, 2014 and August 2020: If you are running OS X Mavericks or later, or any version of MacOS we recommend that you do NOT use the script shown here, but instead send notifications to a XMPP/Jabber account and use either Apple’s Messages app (formerly iChat) or a third party messaging program such as Adium to receive them, since the message will then display in the Notifications Center and you do not need Growl. See How to send various types of notifications on an incoming call in FreePBX for more information. You may also find this thread on the RasPBX forum useful.

What follows will probably not work on ANY currently supported version of MacOS and is left here as a historical reference only.

Quite some time ago, I wrote a post explaining how you could poll a Linksys or Sipura VoIP adapter or phone once per second, and whenever there was an incoming call, generate a notification popup on your computer, if you have the Growl notification service installed.  However, that method doesn’t work if you’re not using a Linksys or Sipura phone or device.

If you are running Asterisk, there’s another way to do it, and that’s to get Asterisk to send the notifications directly. In order for this to work, the computer on which you want to receive the notifications has to be running Growl (under Mac OS X) or Growl for Windows. You must also configure Growl to receive network notifications. I will note here that if you are using a Mac and have never done that before, you may want to make sure that Growl network notifications work before proceeding, because it appears that under OS X, it’s pretty much a crap shoot whether Growl network notifications will work at all, and when they don’t the Growl folks apparently have no clue as to why they don’t. It seems to be a machine-specific thing – on some Macs they work fine, while on others they don’t work at all.

You must have the Perl language installed on your Asterisk server, and you must have the Net::Growl and Asterisk::AGI modules installed (I’m going to assume you know how to install a Perl module from the CPAN repository – if you have Webmin installed, it can be done from within Webmin). Chances are you already have Asterisk::AGI installed, unless you built your Asterisk server “from scratch” and never installed it, but if you’ve never installed Net::Growl you’ll need to do that first.

Next you want to copy and paste the following Perl script to the filename /var/lib/asterisk/agi-bin/growlsend.agi on your Asterisk server (to create a non-existent file, you can use the touch command, and after that you can edit it in Midnight Commander or by using the text editor of your choice). If this code looks somewhat familiar, it’s because it’s adapted from some code that originally appeared in a FreePBX How-To, which I modified.

#!/usr/bin/perl
use strict;
use warnings;
use Net::Growl;
use Asterisk::AGI;
my $agi = new Asterisk::AGI;
my %input = $agi->ReadParse();
my $num = $input{'callerid'};
my $name = $input{'calleridname'};
my $ext = $input{'extension'};
my $ip = $ARGV[0];

if ( $ip =~ /^([0-9a-f]{2}(:|$)){6}$/i ) {
    $ip = $agi->database_get('growlsend',uc($ip));
}

unless ( $ip =~ /^(d+).(d+).(d+).(d+)$/ ) {
    exit;
}

open STDOUT, '>/dev/null';
fork and exit;

if ( $ARGV[2] ne "" ) {
    $ext = $ARGV[2];
}

# Define months and weekdays in English

my @months = (
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
);
my @weekdays = (
    "Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday"
);

# Construct date/time string

my (
    $sec, $min, $hour, $mday, $mon,
    $year, $wday, $yday, $isdst
) = localtime(time);
my $ampm = "AM";
if ( $hour > 12 ) {
    $ampm = "PM";
    $hour = ( $hour - 12 );
}
elsif ( $hour eq 12 ) { $ampm = "PM"; }
elsif ( $hour eq 0 ) { $hour = "12"; }
if ( $min < 10 ) { $min = "0" . $min; }
$year += 1900;

my $fulldate =
"$hour:$min $ampm on $weekdays[$wday], $months[$mon] $mday, $year";

# Next two lines normalize NANP numbers, probably not wanted outside of U.S.A./Canada/other NANP places
$num =~ s/^([2-9])(d{2})([2-9])(d{2})(d{4})$/$1$2-$3$4-$5/;
$num =~ s/^(1)([2-9])(d{2})([2-9])(d{2})(d{4})$/$1-$2$3-$4$5-$6/;

register(host => "$ip",
    application=>"Incoming Call",
    password=>"$ARGV[1]", );
notify(host => "$ip",
    application=>"Incoming Call",
    title=>"$name",
    description=>"$numnfor $extn$fulldate",
    priority=>1,
    sticky=>'True',
    password=>"$ARGV[1]",
    );

Also, if you want to be able to specify computers that you wish to send notifications to using MAC addresses rather than IP addresses (in case computers on your network get their addresses via DHCP, and therefore the IP address of the target computer can change from time to time), then you must in addition install the following Perl script. It requires a command-line utility caller arp-scan so install that if you need to – I used to use nmap for this but they changed the output format, making it harder to parse, and arp-scan is much faster anyway. Call it /var/lib/asterisk/agi-bin/gshelper.agi and note that there are two references to 192.168.0… within it that you may need to change to reflect the scope of your local network, if your network’s IP addresses don’t start with 192.168.0.:

#!/usr/bin/perl
use strict;
use warnings;
my @mac;
# Change the following lines to reflect the scope of your local network, if necessary
my @arp = `arp-scan --quiet --interface=eth0 192.168.0.0/24`;
foreach (@arp) {
        if (index($_, "192.168.0.") == 0) {
                @mac = split(" ");
                `/usr/sbin/asterisk -rx "database put growlsend \U$mac[1] $mac[0]"`;
        }
}

Make sure to modify the permissions on both scripts to make them the same as other scripts in that directory (owner and group should be asterisk, and the file should be executable), and also, if you use the gshelper script, make sure to set up a cron job to run it every so often (I would suggest once per hour, but it’s up to you).

Now go to this page and search for the paragraph starting with, “After you have created that file, check the ownership and permissions” (it’s right under a code block, just a bit more than halfway down the page) and if you are using FreePBX follow the instructions from there on out (if you are not using FreePBX then just read that section of the page so you understand how this works, and in any case ignore the top half of the page, it’s talking about a different notification system entirely).  But note that if you use the above code and have the gshelper.agi program running as a cron job, then after the first time it has run while the computer to receive the notifications is online you should be able to use a computer’s MAC address instead of the IP address.  This only works if you’ve used the modified script on this page, not the one shown in the FreePBX How-To.  As an example, instead of

exten => ****525,1,AGI(growlsend.agi,192.168.0.123,GrowlPassWord,525)

as shown in the example there, you could use

exten => ****525,1,AGI(growlsend.agi,01:23:45:AB:CD:EF,GrowlPassWord,525)

(the above is all one line) where 01:23:45:AB:CD:EF is the MAC address of the computer you want to send the notification to.  Once again, just in case you missed it the first time I said it, this won’t work until the gshelper.agi script has been run at least once while the computer to receive the notifications was online.  If for some reason it still doesn’t appear to work, run the nmap command including everything between the two backticks (`) directly from a Linux command prompt and see if it’s finding the computer (depending on the size of your network, it might be several seconds before you see any output, which is why I don’t try to run this in real time while a call is coming in).

If you are NOT running FreePBX, but instead writing your Asterisk dial plans by hand, then you will have to insert a line similar to one of the above examples into your dial plan, except that you don’t need the four asterisks (****) in front of the extension number, and if it’s not the first line in the context, you’ll probably want to use n rather than 1 for the line designator (and, you won’t be putting the line into extensions_custom.conf because you probably don’t have such a file; instead you’ll just put it right in the appropriate section of your dial plan).  In other words, something like this (using extension 525 as an example):

exten => 525,n,AGI(growlsend.agi,192.168.0.123,GrowlPassWord,525)

This line should go before the line that actually connects the call through to extension 525.  I do not write Asterisk dial plans by hand, so that’s about all the help I can give you. And if you don’t write your dial plans by hand, but you aren’t using FreePBX, then I’m afraid you’ll have to ask for help in whatever forum you use for advice on the particular software that you do use to generate dial plans, because I can’t tell you how to insert the above line (or something like it) into your dial plan.

Virtually everything in this article has already been published in one place or another, but I wanted to get it into an article with a relevant title and cut out some of the extraneous explanations and such.  There are links to all the original sources throughout the article, so feel free to follow those if you want more in-depth commentary.

Linksys and Sipura adapter users – check your RTP Packet Size and Network Jitter Level

 

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.

Edit: Reader Christopher Woods notes in a comment that the following is also applicable to at least some models of Linksys phones, e.g. SPA942 and SPA962.

Do you use a Linksys or Sipura VoIP adapter? Do the people you are talking to ever complain about your voice breaking up, or missing or dropped syllables, or unexplained clicks or noise?

There is an obscure setting in Linksys/Sipura VoIP adapters that is usually set incorrectly for most applications, at least on a factory-fresh adapter. Go to the SIP tab and check the RTP Packet Size – for most users, it should be set to 0.020 rather than the factory preset of 0.030. If you are running a connection where latency is critical (say you have a cable or satellite box that requires a phone connection to “phone home”, or you are trying to use a FAX machine) then you may even wish to set this to 0.010, which further reduces latency, at the expense of using a bit more bandwidth. In any case, the default 0.030 is not the correct setting when using the most commonly-used codecs. For more discussion of this issue, see this thread at DSLreports.com, which discusses how the RTP Packet Size and Network Jitter Level settings can be tweaked to achieve lower latency, along with the tradeoffs.

Be aware that the RTP Packet Size setting is found under the SIP tab, and that setting is applied to all lines served through that adapter. However, the Network Jitter Level can be set individually for each line, under the Line tabs. One interesting comment in the above-mentioned thread is that if a provider forces you to use a low-bandwidth codec, decreasing the RTP Packet Size may increase the quality of your calls, but again at the expense of increasing bandwidth used.

Changing the RTP Packet Size on one VoIP adapter resolved a few strange issues with audio quality. In this case the adapter was being used to connect to an Asterisk box on the same local network, so bandwidth usage wasn’t an issue. We set the RTP Packet Size to 0.020 and the Network Jitter Level to low, and it made a noticeable difference in the reduction of strange noises and breakups heard by the party on the other end of the conversation. However, changing the Network Jitter Level isn’t as critical as changing the RTP Packet Size, and in fact, changing the Network Jitter Level may be entirely the wrong thing to do on certain types of connections (probably not a good idea if your adapter is connected through a Wireless ISP, for example).

I must thank Paul Timmins for being the first to point out that the Linksys PAP2 has a default packet size of 0.030, which is incompatible with the uLaw (G711u) codec (or at least in violation of the standard). With that lead, I then discovered other articles (including the discussion thread linked above) that said essentially the same thing. So check those adapter settings, folks!

(And by the way, this advice probably does apply to some other makes of VoIP adapters, and even some IP telephones, but since I don’t have any readily available to look at, I can’t say for sure. If you know of any others that need to have a similar setting tweaked, please feel free to add a comment to this post).