<proxy>

USECALLMANAGER.nz

</proxy>

Phone Services

The phone can make HTTP requests to a remote web-server to display text, menus and images as well as check whether a CGI Execute requests will be allowed. URLs assigned to fixed-keys (eg: services, directories) and line keys are defined in SEPMAC.cnf.xml. An archive containing these sample scripts can be downloaded from the URL below.

file_download services.tar.bz2 (9.5K) event 06/06/2016 security SHA256:5b2c898f08e96fa9333b686b7694531563398e51f42d61d6f62a2129f18b1d5c.

See the open_in_browser Cisco Unified IP Phone Services Application Development Notes for a list of XML objects the each phone model supports.

authenticationURL

If defined, the phone will make requests to this URL containing the username and password that was included in the Authorization header in the request to http://x.x.x.x/CGI/Execute. See CGI Execute for more information.

The script handling the request must respond exactly with AUTHORIZED (with no newline character at end) otherwise the request will be denied.

#!/usr/bin/perl # # Copyright (c) 2015 Gareth Palmer <gareth.palmer3@gmail.com> # This program is free software, distributed under the terms of # the GNU General Public License Version 2. use strict; use English qw/-no_match_vars/; use CGI::Simple; # Directory containing the SEPMAC.cnf.xml files our $TFTPBOOT_DIRECTORY = '/var/lib/tftpboot'; # Basic-auth username and password credentials our $CGI_USERNAME = 'cisco'; our $CGI_PASSWORD = 'cisco'; eval { my $cgi = CGI::Simple->new; # Fix silly capitization of UserID and Password foreach my $name (qw/UserID Password/) { $cgi->param (lc $name, $cgi->param ($name)); $cgi->delete ($name); } print 'Status: 200 OK', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n"; # Check that the device exists and the username and password are correct if ($cgi->param ('devicename') =~ m/^SEP[0-9A-F]{12}$/ && stat ($TFTPBOOT_DIRECTORY . '/' . $cgi->param ('devicename') . '.cnf.xml') && $cgi->param ('userid') eq $CGI_USERNAME && $cgi->param ('password') eq $CGI_PASSWORD) { print 'AUTHORIZED'; } else { print 'UNAUTHORIZED'; } }; warn $EVAL_ERROR if (length $EVAL_ERROR);

directoryURL

The URL accessed when the directories button is pressed. Requires that the Asterisk manager web-interface is enabled.

#!/usr/bin/perl # # Copyright (c) 2015 Gareth Palmer <gareth.palmer3@gmail.com> # This program is free software, distributed under the terms of # the GNU General Public License Version 2. use strict; use English qw/-no_match_vars/; use CGI::Simple; use URI::Escape; use HTML::Entities; use LWP::UserAgent; use HTTP::Cookies; use XML::LibXML; # Directory containing the SEPMAC.cnf.xml files our $TFTPBOOT_DIRECTORY = '/var/lib/tftpboot'; # Login credentials set in manager.conf our $MANAGER_HOSTNAME = 'localhost:8088'; our $MANAGER_USERNAME = 'asterisk'; our $MANAGER_PASSWORD = 'asterisk'; sub how_to_use { my $cgi = shift; print '<CiscoIPPhoneText>', '<Title>How To Use</Title>', '<Text>Use the keypad or navigation key to select the first letter of the person\'s name.</Text>', '<Prompt>Your current options</Prompt>', '<SoftKeyItem>', '<Name>Back</Name>', '<URL>SoftKey:Exit</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 3 : 1, '</Position>', '</SoftKeyItem>', '</CiscoIPPhoneText>'; } sub directory_index { my $cgi = shift; print '<CiscoIPPhoneMenu>', '<Title>Local Directory</Title>'; foreach my $index ('1', '2 ABC', '3 DEF', '4 GHI', '5 JKL', '6 MNO', '7 PRQS', '8 TUV', '9 WXYZ', '*', '0', '#') { print '<MenuItem>', '<Name>', encode_entities ($index), '</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;menuitem=yes&amp;index=', encode_entities ($index), '</URL>', '</MenuItem>'; } print '<SoftKeyItem>', '<Name>Exit</Name>', '<URL>Init:Directories</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 3 : 1, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Back</Name>', '<URL>SoftKey:Select</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 1 : 2, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Help</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;menuitem=yes&amp;index=howtouse</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 2 : 3, '</Position>', '</SoftKeyItem>', '</CiscoIPPhoneMenu>'; } sub directory_entries { my $cgi = shift; my $useragent = LWP::UserAgent->new; $useragent->cookie_jar (HTTP::Cookies->new (hide_cookie2 => 1)); my ($request, $response); $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=Login' . '&Username=' . uri_escape ($MANAGER_USERNAME) . '&Secret=' . uri_escape ($MANAGER_PASSWORD)); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=SIPPeers'); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); my $document = XML::LibXML->load_xml (string => $response->content); my $directory = {}; foreach my $element ($document->findnodes ('/ajax-response/response/generic[@event="PeerEntry"]')) { my $peer = $element->getAttribute ('objectname'); # This will be slow if you have a large number of SIP peers $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=SIPShowPeer' . '&Peer=' . uri_escape ($peer)); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); my $document = XML::LibXML->load_xml (string => $response->content); my ($name, $phone_number) = ($document->findvalue ('/ajax-response/response/generic/@callerid') =~ m/^"([^\"]*)" <([^>]*)>$/); next unless ($phone_number =~ m/^\d+$/); next if (index ($cgi->param ('index'), ucfirst substr ($name, 0, 1)) == -1); $directory->{$phone_number} = $name; } $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=Logoff'); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); print '<CiscoIPPhoneMenu>', '<Title>', encode_entities ($cgi->param ('index')), '</Title>'; foreach my $phone_number (sort ({$directory->{$a} cmp $directory->{$b}} keys %{$directory})) { my $name = $directory->{$phone_number}; print '<MenuItem>', '<Name>', encode_entities ($name), '</Name>', '<URL>Dial:', encode_entities ($phone_number), '</URL>', '</MenuItem>'; } print '<SoftKeyItem>', '<Name>Exit</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;menuitem=yes</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 3 : 1, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Dial</Name>', '<URL>SoftKey:Select</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 1 : 2, '</Position>', '</SoftKeyItem>', '</CiscoIPPhoneMenu>'; } eval { my $cgi = CGI::Simple->new; # Check that the device exists unless ($cgi->param ('name') =~ m/^SEP[0-9A-F]{12}$/ && stat ($TFTPBOOT_DIRECTORY . '/' . $cgi->param ('name') . '.cnf.xml')) { print 'Status: 403 Forbidden', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n", 'Invalid or unknown device name'; return; } print 'Status: 200 OK', "\r\n", 'Content-Type: text/xml', "\r\n", "\r\n"; # 7900 series need a menu item displayed first if ($cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ && !length $cgi->param ('menuitem')) { print '<CiscoIPPhoneMenu>', '<MenuItem>', '<Name>Local Directory</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;menuitem=yes</URL>', '</MenuItem>', '</CiscoIPPhoneMenu>'; } elsif ($cgi->param ('index') eq 'howtouse') { how_to_use ($cgi); } elsif ($cgi->param ('index') =~ m/^[A-Z0-9*#]+$/) { directory_entries ($cgi); } else { directory_index ($cgi); } }; warn $EVAL_ERROR if (length $EVAL_ERROR);

servicesURL

The URL accessed when the services button is pressed. Requires that the Asterisk manager web-interface is enabled.

#!/usr/bin/perl # # Copyright (c) 2015 Gareth Palmer <gareth.palmer3@gmail.com> # This program is free software, distributed under the terms of # the GNU General Public License Version 2. use strict; use English qw/-no_match_vars/; use CGI::Simple; use URI::Escape; use HTML::Entities; use LWP::UserAgent; use HTTP::Cookies; use XML::LibXML; # Directory containing the SEPMAC.cnf.xml files our $TFTPBOOT_DIRECTORY = '/var/lib/tftpboot'; # Login credentials set in manager.conf our $MANAGER_HOSTNAME = 'localhost:8088'; our $MANAGER_USERNAME = 'asterisk'; our $MANAGER_PASSWORD = 'asterisk'; sub parked_calls { my $cgi = shift; my $useragent = LWP::UserAgent->new; $useragent->cookie_jar (HTTP::Cookies->new (hide_cookie2 => 1)); my ($request, $response); $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=Login' . '&Username=' . uri_escape ($MANAGER_USERNAME) . '&Secret=' . uri_escape ($MANAGER_PASSWORD)); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=ParkedCalls'); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); my $document = XML::LibXML->load_xml (string => $response->content); my $parked_calls = {}; foreach my $element ($document->findnodes ('/ajax-response/response/generic[@event="ParkedCall"]')) { my ($extension, $name); $extension = $element->getAttribute ('exten'); $name = $element->getAttribute ('callerdidname') || $element->getAttribute ('calleridnum'); $parked_calls->{$extension} = $name; } $request = HTTP::Request->new (GET => 'http://' . $MANAGER_HOSTNAME . '/mxml?Action=Logoff'); $response = $useragent->request ($request); die $response->as_string unless ($response->is_success); print '<CiscoIPPhoneMenu>', '<Title>Parked Calls</Title>'; foreach my $extension (sort ({$parked_calls->{$a} cmp $parked_calls->{$b}} keys %{$parked_calls})) { my $name = $parked_calls->{$extension}; print '<MenuItem>', '<Name>', encode_entities ($name), '</Name>', '<URL>Dial:', encode_entities ($extension), '</URL>', '</MenuItem>'; } print '<SoftKeyItem>', '<Name>Exit</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 3 : 1, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Dial</Name>', '<URL>SoftKey:Select</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 1 : 2, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Update</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;view=parkedcalls</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 2 : 3, '</Position>', '</SoftKeyItem>', '</CiscoIPPhoneMenu>'; } sub services_menu { my $cgi = shift; print '<CiscoIPPhoneMenu>', '<Title>Services</Title>', '<MenuItem>', '<Name>Parked Calls</Name>', '<URL>', $cgi->url, '?name=', encode_entities ($cgi->param ('name')), '&amp;view=parkedcalls<URL>', '</MenuItem>', '<Prompt>Your current options</Prompt>', '<SoftKeyItem>', '<Name>Exit</Name>', '<URL>Init:Services</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 3 : 1, '</Position>', '</SoftKeyItem>', '<SoftKeyItem>', '<Name>Select</Name>', '<URL>SoftKey:Select</URL>', '<Position>', $cgi->http ('X-Cisco-IPPhoneModelName') =~ m/^CP-79/ ? 1 : 2, '</Position>', '</SoftKeyItem>', '</CiscoIPPhoneMenu>'; } eval { my $cgi = CGI::Simple->new; # Check that the device exists unless ($cgi->param ('name') =~ m/^SEP[0-9A-F]{12}$/ && stat ($TFTPBOOT_DIRECTORY . '/' . $cgi->param ('name') . '.cnf.xml')) { print 'Status: 403 Forbidden', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n", 'Invalid or unknown device name'; return; } print 'Status: 200 OK', "\r\n", 'Content-Type: text/xml', "\r\n", "\r\n"; if ($cgi->param ('view') eq 'parkedcalls') { parked_calls ($cgi); } else { services_menu ($cgi); } }; warn $EVAL_ERROR if (length $EVAL_ERROR);

problemReportUploadURL

The URL that the logs are uploaded to when the report problem option is selected. 7800 and 8800 series only.

#!/usr/bin/perl # # Copyright (c) 2015 Gareth Palmer <gareth.palmer3@gmail.com> # This program is free software, distributed under the terms of # the GNU General Public License Version 2. use strict; use English qw/-no_match_vars/; use CGI::Simple; use POSIX qw/strftime/; # Directory containing the SEPMAC.cnf.xml files our $TFTPBOOT_DIRECTORY = '/var/lib/tftpboot'; # Directory to store uploaded log files our $PRT_LOGS_DIRECTORY = '/var/log/cisco'; eval { $CGI::Simple::DISABLE_UPLOADS = 0; $CGI::Simple::POST_MAX = -1; my $cgi = CGI::Simple->new; # Check that the device exists unless ($cgi->param ('devicename') =~ m/^SEP[0-9A-F]{12}$/ && stat ($TFTPBOOT_DIRECTORY . '/' . $cgi->param ('devicename') . '.cnf.xml')) { print 'Status: 403 Forbidden', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n", 'Invalid or unknown device name'; return; } # Include a timestamp in the filename so the phone can upload multiple logs my $time = strftime ('%Y%m%d%H%M', localtime time); unless ($cgi->upload ($cgi->param ('prt_file'), $PRT_LOGS_DIRECTORY . '/' . $cgi->param ('devicename') . '-' . $time . '.tar.gz')) { print 'Status: 500 Internal Server Error', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n", 'Unable to create log file'; return; } print 'Status: 200 OK', "\r\n", 'Content-Type: text/plain', "\r\n", "\r\n", 'Log file saved'; }; warn $EVAL_ERROR if (length $EVAL_ERROR);