How to set up notification (Caller ID popup) on Mac OS X, Linux and other systems

[size=15]How to set up notification (Caller ID popup) on Mac OS X, Linux and other systems[/size]

If you have a Macintosh computer, you may have wondered if there is any way to have a pop-up notification of who is calling whenever your extension rings. It turns out that there is, but it's not exactly straightforward. This method may also work for certain systems running under Windows or Linux, although the client you use will be different. I will explain how I set it up on a Mac. There is one caveat, if your computer does not have a fixed IP address on your local network, then you'll have to make a file edit in the FreePBX configuration every time it changes. There may be a way around that, but I haven't found it yet. Note: If you have Growl notifications installed on your Macintosh or Windows system(s) (that will receive and display the popup notifications), AND you know how to install a Perl module on your FreePBX/Asterisk box, you will probably want to scroll down a bit and look at the "Alternate Method" first.

I do not consider the following an elegant solution, indeed there are parts of it I consider a hack. But it works (although I now prefer the "Alternate Method" shown below). To begin with, look over the page at http://mezzo.net/asterisk/app_notify.html - we are going to install the "Notify application module for the Asterisk PBX" at the top of the page, and then the appropriate client for your computer (lower on the page). Of course, the Notify application module must be installed on the system running Asterisk and FreePBX. So start there at the command prompt and do this:

cd /usr/src

Asterisk 1.2.x: wget http://mezzo.net/asterisk/app_notify-1.0.tgz
or
Asterisk 1.4.x: wget http://mezzo.net/asterisk/app_notify-2.0rc1.tgz
(These are just examples, you should probably use whichever download is the most recent for your version of Asterisk)

tar -xzf app_notify-1.0.tgz (replace filename with whatever you actually downloaded)

cd app_notify-1.0 (ditto, omitting the .tgz extension)

make install

Restart Asterisk or load the application module with:
load app_notify.so
(I went to the Asterisk CLI and did a restart when convenient just to make sure I wouldn't interrupt any calls)

That's all you have to do to install the module. While at the Linux command prompt, bring up your text editor of choice (nano, Midnight Commander's editor, or whatever you like) and edit etc/asterisk/extensions_custom.conf and, somewhere under the [from-internal-custom] context insert these two lines for each extension for which you wish to generate notification messages (this example assumes you want to monitor extension 525 and send the notifications to the computer at local IP address 192.168.0.123):

exten => ****525,1,Notify(${CALLERID(num)}|${CALLERID(name)}|525/192.168.0.123)
exten => ****525,n,Busy

Change the boldfaced items to the proper extension number and/or IP address of the computer to receive the notifications.

If you want notifications for more than one extension, repeat the above two lines for each extension you want to monitor. If you want the notifications to go to more than one computer, just duplicate the topmost line as many times as you need to, changing the 1,Notify to n,Notify in subsequent lines, and other than that changing only the target IP address (so it will send the notification to one computer, then the next, and so on). Note that you're actually creating a custom extension consisting of "****" + the extension number - you can change this to something else but it must be unique in your system. My goal was to make it something that no one would actually dial, since it's only used internally. When you're through with your edits, don't forget to save the changes!

Now it's time to use your web browser and browse to the FreePBX configuration. What you need to do is create a Follow-Me for the extensions you want to monitor. So make sure that FreePBX's Follow-me module is installed, then go there and select the follow-me for the extension you wish to monitor (again we're using 525 in this example). Add the Follow-Me, make the ring strategy firstnotonphone, set the ring time to whatever you want, and make the Destination if no answer whatever you want (probably the extensions's voicemail). In the Follow-Me List put two entries. At the top put the custom extension number with the four asterisks in front of the number, and (this is very important) a pound sign (hash mark for you Brits) on the end. On the next line, just put the extension number itself. So for extension 525, you'd have these two entries:

****525#
525

Save this. Note that if you already have a Follow-me for the extension, it might complicate things a little bit, or maybe not. The basic idea is to attempt a call to the custom extension (which will always fail busy) just before you attempt the real extension. If you already have a certain configuration of Follow-me set up, it might be necessary to move some or all of the Follow-me settings to a Ring Group to make this work, and use the Ring Group as the destination of the Follow-me, but that's beyond the scope of this article (I only mention that because using a Ring Group as the destination of the Follow-me may help resolve some logical conflicts, and you can even chain ring groups if necessary. Most users won't have this issue, but I mention the possibility for those who do).

The one flaw in this is that you'll receive the popup notification even if you are currently on the phone, and the call ultimately goes to a different extension or to voicemail. For some situations that would be desirable behavior, whereas in others it would not. Personally I want the notifications of calls I missed, but maybe you don't. I did say this was a hack, right?!

Once you have this set up, and reload the configuration in FreePBX, the notifications will be sent out (if you have done everything correctly) One note, on the module download page, it shows specifying the target computer by name, not IP address. That trick only works if the computer name actually resolves to something, which means you'd have to have a line in /etc/hosts linking the computer name and IP address, or you'd have to have a local DNS server that resolves local machine names. Most home and small business users won't have either. So the best plan is, give the computer a fixed IP address (most routers provide a way to do this), then just specify that IP address in extensions_custom.conf.

Installing the client

Go back to http://mezzo.net/asterisk/app_notify.html and pick up the appropriate client for the target computer (that receives the notifications). I have only installed this on a Mac (OS X Leopard) so here are a few hints for that client:

I was not able to make the dialer function work - don't know why and don't really care because that wasn't my goal in the first place. So that will not be covered here (if you get it to work, please leave a comment and I may revise this).

To receive notifications you install the client (standard software install method), then go to System Preferences | Other | Asterisk (yes, the client is called "Asterisk" in the preference panel). Under "Notifier" I suggest you turn on Growl notifications if you have Growl installed, and turn off "Speak announcement" - although that would be a cool feature if it worked reliably, it appears that it only works once or twice and then you don't get ANY notifications at all until you turn "Speak announcement" back off (and usually you have to stop and restart the client as well).

There also currently a bug where you enter the server address. Unless you have Bonjour installed on your Asterisk server (something also offered at this site, but good luck in getting it set up and working if you're not a true Linux geek - and if you are and you make it work, please leave a comment and give us step by step instructions!), you will have to enter the IP address manually. But the keyboard input routine is buggy! So go to another application (text editor, e-mail program, whatever) and type in your Asterisk server address, then highlight and copy it (Option-C) so it's in your clipboard. Go back to the preferences panel, click the plus (+) to add a server, then click in the location where the server address should be, and then a text box should appear which SHOULD allow you to enter the address. Click in it and paste the server address (Option-V) from the clipboard. If you still get extraneous characters, highlight all the characters other than the correct ones using the mouse, then right-click and select "cut", and you should be left with the correct server address. Yes, I know that's a screwy way to do it, but whatever works...

Once the client is configured you may need to instruct the computer's firewall to allow it to receive the incoming notifications. The listen port defaults to 40000 (I don't advise trying to change that unless there's a serious conflict). As soon as I configured the client, I got a popup asking if I wanted to allow incoming communications to that program, to which I answered in the affirmative, and that's all there was to it.

I do wish there were a better way to insert some custom code into the FreePBX generated dial plan, that would fire off a custom dialplan fragment just prior to ringing an extension. That would not only be useful for this application, but probably for several others where you might want to do something special just before an extension rings. I'm aware that you can modify the dialplan if you create a module; p_lindheimer (one of the developers) said, "...you can splice a line in to the dialplan. Take a look at pinset module, you will see how it splices a call to it's own macro in the outbound route macros, or I think cidlookup does the same into ext-did. It would require writing a simple module to do what you want but that is not really all that hard." Well, it might not be hard for some people, but it would be impossible for me (I have only a VERY limited knowledge of Perl, none at all of PHP, and don't have a clue how a module is constructed - I know you can view module code easily but unless I'm told exactly what I'm looking at, it usually makes no sense at all to me). My point is, if you have the knowledge that I lack, there are much better ways to accomplish this, but until someone creates a module (or ANYTHING better than what I've described), the above is the only way I know how to do it, particularly with the client on a Mac computer.

[size=15]Alternate Method[/size]

The main problem with the above method is that you must install a module in Asterisk (that may or may not be updated to keep up with future versions of Asterisk) and, depending on the target platform, a possibly buggy client that may be difficult to configure. In contrast, the following method relies on a simple Perl AGI script on the FreePBX system, and the presence of the Growl notification system on the target computers. Growl is a fairly standard notification system for Macintosh computers, and now there is a Growl for Windows as well. This method uses Growl's ability to receive a message over the network. The only real "catch" is that you will most likely need to install a Perl module on your FreePBX/Asterisk box. If you have Webmin installed, look under the "Others" heading in the left-hand menu and see if you have an entry for "Perl Modules" (if not, you may want to add the "Perl Modules" module to Webmin), or perhaps you already know how to install a Perl module.

The Perl module you need is called Net::Growl and it must be installed on your FreePBX/Asterisk box, not the computer receiving the notification. You must then create a Perl script with the filename /var/lib/asterisk/agi-bin/growlsend.agi which should contain this code:
[code]
#!/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'};
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 eq 12 ) { $ampm = "PM"; }
if ( $hour eq 0 ) { $hour = "12"; }
if ( $hour > 12 ) {
$ampm = "PM";
$hour = ( $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 => "$ARGV[0]",
application=>"Incoming Call",
password=>"$ARGV[1]", );
notify(host => "$ARGV[0]",
application=>"Incoming Call",
title=>"$name",
description=>"$num\nfor $ext\n$fulldate",
priority=>1,
sticky=>'True',
password=>"$ARGV[1]",
);
[/code]

After you have created that file, check the ownership and permissions to make sure that it is the same as the other agi files in that directory (owner and group are asterisk, and the file should be executable). I use Midnight Commander's "Advanced Chown" to do that sort of thing, but some people prefer to do it from the Linux command prompt - whatever works for you is fine.

After that, use your text editor of choice to edit etc/asterisk/extensions_custom.conf and, somewhere under the [from-internal-custom] context insert these two lines for each extension for which you wish to generate notification messages (this example assumes you want to monitor extension 525 and send the notifications to the computer at local IP address 192.168.0.123):

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

Change the boldfaced items to the proper extension number, IP address of the computer to receive the notifications, and network password for Growl on that computer. Note the three arguments following growlsend.agi are as follows: The first is the IP address of the system to receive the notifications, the second is the server password for Growl on that remote system (more on that below), and the third is the actual extension number that is being called. The first two arguments are required, while the third is optional, however if you don't use the third it defaults to the extension called to reach the agi script (****525 in this case) rather than the extension that's actually being called (525), so in most cases in FreePBX you're going to want to include the third argument.

If you want notifications for more than one extension, repeat the above two lines for each extension you want to monitor. If you want the notifications to go to more than one computer, just duplicate the topmost line as many times as you need to, changing the 1,AGI to n,AGI in subsequent lines, and other than that, changing only the target IP address and password (so it will send the notification to one computer, then the next, and so on). Note that you're actually creating a custom extension consisting of "****" + the extension number - you can change this to something else but it must be unique in your system. My goal was to make it something that no one would actually dial, since it's only used internally. When you're through with your edits, don't forget to save the changes!

On your client computers, bring up the Growl preference panel and go to the Network tab. Make sure that "Listen for incoming notifications" and "Allow remote application registration" are checked. Set the Server Password to the same password you used in place of "GrowlPassWord" (you DID change the password to something more secure, right?!) in the line in extensions_custom.conf that corresponds to that machine. Users of Growl for Windows may find that some display styles do not permit all of the text to be displayed (for example, the time and date may be missing) - if that is the case, we suggest using the Standard style for Incoming Call popups (and if you can't get the Standard style to work, try running the following from a Windows command prompt:
[code]regsvr32 "C:\Program Files\Vortex Software\Growl For Windows\Displays\WebDisplay\WebKitDependencies\WebKit.dll"[/code]
(That is all one line). This is per a suggestion in Comment 2 of this thread).

Now it's time to use your web browser and browse to the FreePBX configuration. What you need to do is create a Follow-Me for the extensions you want to monitor. So make sure that FreePBX's Follow-me module is installed, then go there and select the follow-me for the extension you wish to monitor (again we're using 525 in this example). Add the Follow-Me, make the ring strategy firstnotonphone, set the ring time to whatever you want, and make the Destination if no answer whatever you want (probably the extension's voicemail). In the Follow-Me List put two entries. At the top put the custom extension number with the four asterisks in front of the number, and (this is very important) a pound sign (hash mark for you Brits) on the end. On the next line, just put the extension number itself. So for extension 525, you'd have these two entries:

****525#
525

Save this. Note that if you already have a Follow-me for the extension, it might complicate things a little bit, or maybe not. The basic idea is to attempt a call to the custom extension (which will always fail busy) just before you attempt the real extension. If you already have a certain configuration of Follow-me set up, it might be necessary to move some or all of the Follow-me settings to a Ring Group to make this work, and use the Ring Group as the destination of the Follow-me, but that's beyond the scope of this article (I only mention that because using a Ring Group as the destination of the Follow-me may help resolve some logical conflicts, and you can even chain ring groups if necessary. Most users won't have this issue, but I mention the possibility for those who do).

Once Growl has successfully received the first notification, you can go back into Growl's preference pane and go to the Applications tab. Click on "incoming Call" and then "Configure" (or in Growl for Windows, click on "incoming Call", then look in the bottom panel). I suggest setting Stay on Screen to Always (so the notification will stay there until you dismiss it), Priority to High, and (in the Mac version of Growl) Play Sound to whatever you like (I like the Pop sound, but it's entirely up to you).

[size=15]What if the IP address changes?[/size]

One limitation of both of the above methods is that you need to know the IP address of the computer you are sending the notification to, and in some cases this can change from time to time. However, if the remote extension is always at the same IP address as the computer receiving the notifications (note this will often NOT be the case on a local network, since the phone and computer will be at different IP addresses), then you may be able to use either of Asterisk's SIPPEER or IAXPEER functions (depending on the type of endpoint) to get the address. So, for example, instead of the following line in the second method:

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

You MIGHT be able to use this (assuming it's a SIP endpoint):

exten => ****525,1,AGI(growlsend.agi,${SIPPEER(525:ip)},GrowlPassWord,525)

Of course, the problem with the above is that if the endpoint is inaccessible then the SIPPEER function would not return any address, and I'm not sure if the call to the agi file would fail gracefully in such a case. If not, you may want to add some code to the perl script to bail out if the IP address is invalid or missing (if anyone really needs this, leave a comment and I may modify the script to add such a test, although I suspect it may fail gracefully in any case).

Note that at the distant end (assuming you are sending to a public IP address, and not one on your local network), a firewall rule may need to be implemented to direct the notifications to the proper computer. It appears that the Growl UDP port is 9887, so that would be the incoming port that needs to be sent to the proper machine in the firewall rules (once again, that is UDP port 9887, NOT TCP).

[size=15]Why Perl?[/size]

Because Perl and BASIC are the only high level languages I know at all (and I'm definitely not an expert in either). However, if you would like to convert the script into PHP or Python or some other language, feel free to have a go at it. You nay find it helpful to view the page on netgrowl.php and/or netgrowl.py if you intend to do this. If you do rewrite the script in either of those languages (or if you are able to improve upon the perl script, which probably wouldn't be too difficult) please post your results in a comment!