Tag: YAC

  • YAC Caller ID Server for Asterisk

    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