YAC Caller ID Server for Asterisk

I recently upgraded the firmware of the IP phones in a small office using my Grandstream HTTP configuration pusher. One of the users complained that the Caller ID display under the new firmware was too small to be legible. I’m not convinced that the size of the font actually changed, but I wanted to offer some kind of solution. The ever helpful (although often outdated) voip-info.org wiki lists several options for call notifications under asterisk (the PBX in use in the office):

http://www.voip-info.org/wiki/view/Asterisk+call+notification

I liked the look of YAC: Yet Another Caller ID Program, by Jensen Harris the best. It is intended for use with a Caller ID capable modem, but works fine for my purpose as well. YAC has two pieces, a YAC listener, which runs on workstations that want to see incoming Caller ID, and a YAC server which collects Caller ID and sends to the listener(s). I’m using just the listener side and have written my own YAC server portion that collects its information through the Asterisk Management Interface. I used the SiComponents Resource Builder 3 resource editor to replace the yak graphic normally shown in YAC with the office’s logo inside of the yak.exe binary (a fake example is shown below).

yac_sample

Here is my YAC Caller ID server for Asterisk:

#!/bin/bash

extensions=(1100[192.168.1.100] 1101[192.168.1.101] 1102[192.168.1.102])

ami_user="admin"
ami_pass="elastix456"
server="127.0.0.1"
port="5038"

if [ "$1" == "--detach" ] ; then
        $0 >/dev/null &
        exit
fi

exec 3<>/dev/tcp/$server/$port

ami_write() {
        echo "$@" >&3
}

ami_read() {
        read -t1 server_out  <&3
        # strip CR 0x0d line terminator
        server_out="${server_out%$'\x0d'*}"
        echo "$server_out"

}

ami_get_response() {
        while [ 1 ]
        do
                response="$(ami_read)"
                if [ "${response:0:10}" == "Response: " ]; then
                        response="${response:10}"
                        echo "$response"
                        break
                fi
        done
}

ami_logout() {
        if [ -n "$connected" ]; then
                ami_write "Action: Logoff"
                ami_write ""
                if [ "$(ami_get_response)" == "Goodbye" ]; then
                        echo "Logged out."
                fi
        fi
}

trap "ami_logout; exit" EXIT SIGTERM

ami_login() {
        ami_write "Action: Login"
        ami_write "Username: $ami_user"
        ami_write "Secret: $ami_pass"
        ami_write ""
        if [ "$(ami_get_response)" != "Success" ]; then
                echo "Login failed." >&2
                exit
        else
                echo "Logged in."
                connected=1
        fi
}

ami_login

echo "Waiting for calls..."

while [ 1 ];
do
        line="$(ami_read)"

        if [ "${line:0:11}" == "Event: Dial" ]; then
                while [ -n "$line" ]
                do
                        line="$(ami_read)"
                        if [ "${line:0:13}" == "CallerIDNum: " ]; then
                                callerid="~${line:13}"
                        fi
                        if [ "${line:0:14}" == "CallerIDName: " ]; then
                                callerid="${line:14} $callerid"
                        fi
                        if [ "${line:0:12}" == "Dialstring: " ]; then
                                called_extension="${line:12}"
                        fi
                done
        fi

        if [ -n "$called_extension" ] && [ -n "$callerid" ]; then
                for extension in ${extensions[@]}
                do
                        ip="${extension##*'['}"
                        ip="${ip//]/}"
                        extension="${extension%%'['*}"
                        if [ "$extension" == "$called_extension" ]; then
                                echo "New call to $extension from $callerid"
                                exec 4<>/dev/tcp/$ip/10629
                                echo "@CALL$callerid" >&4
                                exec 4>&-
                        fi

                done
                unset called_extension
                unset callerid
        fi
done

exec 3>&-
echo "Quit."

You’ll need to replace the server, port, user and password with the correct information for your AMI setup. The “extensions” variable includes the internal extension and the IP address of the associated desktop/workstation that is running the YAC listener. The format is 1100[192.168.1.100] where 1100 is the extension, and 192.168.1.100 is the This way people see the Caller ID destined for their extension on their desktop. In environments with dynamically assigned desktop IP addresses this will require some additional effort to keep updated. Ideally I’d like to see something like YAC that logs in to a SIP server to monitor calls that way, seems like less to deal with, but many offerings like that included too many other features for my liking (click to call functionality, dial pad, etc).

The server captures SIGTERM and tries to logoff the AMI server before exiting

[root@phone ~]# ./yac-d.sh
Logged in.
Waiting for calls...
New call to 1100 from WIRELESS CALLER ~5551212"
^C
Logged out.

You can start the script into the background by using the –detach switch.

[root@phone ~]# ./yac-d.sh --detach
This entry was posted in Telephony and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *