Создание телефонного справочника для ip-телефонов Cisco

image

IP-телефоны от Cisco, например, популярный 7911G (на анигифе именно он) и более старшие модели, поддерживают возможность выполнения http-запросов для создания сервисов, в частности, телефонного справочника организации.

Как всё это работает. Мы настраиваем скрипт на веб-сервере, которых в ответ на GET-запрос от телефона возвращает строго определённый XML, отображаемый телефоном. Для телефонной книги сначала отображается список отделов:
<CiscoIPPhoneMenu>
<MenuItem>
  <Name>Administration</Name>
  <URL>http://webserver/phone/telbook.asp?depid=10</URL>
</MenuItem>
</CiscoIPPhoneMenu>


При выборе отдела телефон делает второй запрос по адресу из URL и отображает уже список сотрудников и их телефонов.
Вот картинка и пример структуры для списка из официального хелпа:

<CiscoIPPhoneDirectory>
  <Title>Заголовок</Title>
  <Prompt>Подсказка/подзаголовок</Prompt>
  <DirectoryEntry>
    <Name>Имя</Name>
    <Telephone>Телефон</Telephone>
  </DirectoryEntry>
</CiscoIPPhoneDirectory>



Со стороны администратора телефонов требуется прописать вызов нашего скрипта при нажатии какой-то из клавиш или выборе пункта меню, конкретно с 7911G мы используем Application->Help. В настройках телефона вызов задается как <InformationURL> webserver/phone/directory.asp </InformationURL>. А вот модель 7965G имеет отдельную клавишу для телефонного справочника, и её нажатие вызывает уже адрес из <DirectoryURL>. Поэтому у нас у всех телефонов все возможные *URL просто указывают на один и тот же скрипт.

Доступны мелкие удобства, такие как кнопка «Назад» и выбор отдела или телефона по индексу. Важным удобством является то, что телефон сам преобразует запись вида 8(495)555-11-22 в номер для набора 84955551122, это позволяет показывать людям удобно читаемый номер.

Как именно скрипт генерирует нужные нам XML, каждый может выбрать сам. У нас этот же скрипт используется для отображения телефонной книжки в браузере, через XSL. Для этого мы добавляем в генерируемый XML одну строчку
<?xml-stylesheet type="text/xsl" href="http://<%=servernamepath%>/telbook.xsl"?>
и дополнительно выводим элементом RusName с русским написанием ФИО. Поскольку RusName телефоном воспринимается как ошибка в структуре, а скрипт один, банальным способом определяем, кто вызвал скрипт:
if InStr(1,Request.ServerVariables(«http_user_agent»),«allegro»,1)>0 then isphone=1

А еще телефон умеет воспринимать данные от пользователя, мы пробно делали поиск телефонов контрагентов по их внутреннему коду, фича работала, но не прижилась:

<CiscoIPPhoneInput>
  <Title>Vuz search</Title>
  <Prompt>Enter vuz kod: </Prompt>
  <URL>http://webserver/phone/search.asp?type=vuz</URL>
  <InputItem>
   <DisplayName>KOD</DisplayName>
   <QueryStringParam>kod</QueryStringParam>
   <InputFlags>T</InputFlags>
  </InputItem>
</CiscoIPPhoneInput>


Вызов самого CiscoIPPhoneInput это еще одна строчка в главном CiscoIPPhoneMenu, а после ввода пользователем числа телефон передаёт параметр KOD скрипту и тот отображает найденный список телефонов через CiscoIPPhoneDirectory.

Кроме того, в теории телефон может делать запросы к скриптам в режиме idle, а также можно использовать refresh header и периодически автоматом запрашивать свежие данные. Это может быть курс доллара, хотя мы хотели сделать мониторинг нагрузки серверов, хотя бы в числовом виде – бросишь взгляд на телефон и сразу видно, что все ядра кто-то занял.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 24

    +1
    Как тема для будущего поста, гораздо интересней следующая задача: директор нажимает на своём телефоне пару кнопочек, у 10 подчинённых телефоны переводятся на громкую, после чего директор делает объявление.
    Или нажимаете пару кнопочек на своем телефоне и слушаете, что говорят в соседней комнате. Я когда-то давно делал…
      0
      Такое штатно делается и на простой LG Aria Soho, там даже можно отключить индикатор на телефоне, чтобы прослушка была вообще незаметной.

      Директору рассказывать про возможность прослушки не стал, чтобы не провоцировать.
      0
      Такую же инструкцию бы, но для IP телефонов Grandstream.
      +1
      Стоило бы еще добавить, что 79** не поддерживают более 32 записей телефонной книги на страницу, что вынуждает делить выдачу на части и добавлять кастомные кнопки вместо стандартных. это дает нам возможность сделать кнопку Next Page путем добавления такого кода:
      <SoftKeyItem>
      <Name>Next Page</Name>
      <URL>http://webserver/cisco/show_phones.php?from=32</URL>
      <Position>4</Position>
      </SoftKeyItem>
      
        0
        Проверил, действительно 32 записи максимум.

        Заодно добавил самый используемый справочник на отдельную софт-кнопку, спасибо! Пришлось только прописать сразу три кнопки, потому что когда хоть одну вручную прописываешь, штатные select & exit исчезают:
        <SoftKeyItem>
          <Name>Select</Name>
          <URL>SoftKey:Select</URL>
        <Position>1</Position>
        </SoftKeyItem>
        

          0
          Да, исчезают, но это ж мелочи. Вот на Linksys'ах 9** вообще нету корпоративного справочника, приходится им по http в личный справочник curl-ом пихать данные, вот это уже занятное извращение.
        0
        Я понимаю, что речь в статье идет не о связке IP-phone-cisco + CUCM, т.к. в CUCM фича справочника реализована по умолчанию :)
          0
          Я бы и справочник брал из конфигов cisco, но у нас разделение труда — админы отдельно, программисты отдельно, и этот проект был личной инициативой. Админам ковырять телефоны не интересно, они до сих пор русский не поддерживают.

          Так что несмотря на то, что уже через пару недель, судя по логам сервера, справочником пользовались немалая часть сотрудников, включая начальство, обновляется он вручную и с опозданием.
          0
          У меня справочник из AD берется. В idle отображается картинка с загрузкой каналов, новостями, прогнозом погоды и т.п.
            0
            Картинка на 79** или на старших моделях?
              0
              На 7975
            0
            Есть одна довольно интересная тема с телефонами… Как на всех телефонах компании, пусть это будет связка CUCM + Cisco7911/41, централизованно заменить фон экрана на картинку с логотипом компании? Я лично делал это довольно извратно, т.к. не нашел другой возможности:
            1) кладем в cucm подготовленные картинки, чтоб они были видны в телефонах в меню User Preferences
            2) делаем скрипт который будет исполняться где-то на сторонней машине.
            /*
            // в телефонах cisco есть встроенный web-серевер и апплет привязанный к url
            // на этом сервере, запуская который можно эмулировать нажатия кнопок на
            // клавиатуре телефона
            */
            3) скрипт обходит все телефоны по ip-адресам и передает нажатия кнопок на телефоны меню->настройки->фон->картинка 1->применить->выйти из меню

            есть другой способ?
              0
              Я тоже с такой проблемой сталкивался, и решения мне найти не удалось, так что не могли бы вы поподробнее про этот чудо-скрипт? Каким образом эмулируются нажатия на кнопки? В документации Cisco ничего подобного не наблюдал…
                +1
                есть такой AXL web api у CUCM и телефонов:
                www.cisco.com/en/US/docs/voice_ip_comm/cucm/devguide/5_0_4/ccmdvCh1.html
                документация довольно скудная. Сначала я изучил приведенную ссылку, потом скачал AXL SQL Toolkit, в нем есть описание xml схем всего API. и нашел чудную команду из этого api — CiscoIPPhoneExecute, которая собственно и говорит телефону выполнить действие. Суть — включаем сервис, дальше у телефона появляется рабочий скрипт /CGI/Execute. Этому скрипту POST-ом надо отдать soap-объект с командой CiscoIPPhoneExecute. По приведенной ссылке есть пример на C++, но я посчитал слишком геморным делать все это на cpp и переписал скриптик на JavaScript для WSH. Скрипт довольно топорный, работает только для моего случая :) Всмысле, выбирает на телефоне вторую картинку и сохраняет выбор. Картинка должна быть заранее подготовлена, и видна из меню телефона (как это делать — есть раздел в help на cucm).
                Собсвтенно скрипт:

                var myuserid="PhoneOwner";//this is the user object associated to the phone
                var mypassword="PhoneOwnerPassword";//this is the user password

                //modify the myphonelistr to include a list of phones you want updated, comma separated
                //a string value of one IP address is acceptable
                var myphoneliststr = "1.1.1.1,1.1.1.2,1.1.1.3"; //"10.3.199.32,10.3.199.33" is another example
                var myxmllist="XML=#XML=#XML=#XML=#XML=#XML=#XML=#XML=";
                var myxmlarr = myxmllist.split("#");

                var myphonearr = myphoneliststr.split(","); //create an array to walk through
                var myauth = text2base64(myuserid + ":" + mypassword);//Create HTML basic auth string
                var xmlhttp = new ActiveXObject("Msxml2.ServerXMLHTTP.6.0"); //Object used for client connection
                var fso = new ActiveXObject("Scripting.FileSystemObject");
                var fl = fso.CreateTextFile("log.txt", true);

                // Loop through the phone list
                for (var i=0;i<myphonearr.length;i++)
                {
                fl.WriteLine("---------------" + myphonearr[i] + "----------------------");
                for (var j=0;j<myxmlarr.length;j++)
                {
                var myxml = myxmlarr[j];
                fl.WriteLine(myxml);

                var WebServer = "http://" + myphonearr[i] + "/CGI/Execute";
                xmlhttp.open("POST", WebServer, false);
                with (xmlhttp){
                setRequestHeader("Man", "POST " + WebServer + " HTTP/1.1");
                setRequestHeader("MessageType", "CALL");
                setRequestHeader("Content-Type", "text/xml");
                setRequestHeader("Host", myphonearr[i] + ":80");
                setRequestHeader("Authorization", "Basic " + myauth);
                setRequestHeader("Content-length", myxml.length);
                }
                xmlhttp.send(myxml);

                fl.WriteLine("----------->" + xmlhttp.responseText);
                sleep(1000);
                }
                }

                fl.Close();

                /******************************************************
                function text2base64() Used to create hashed string
                ******************************************************/
                function text2base64(text) {
                var j = 0;
                var i = 0;
                var base64 = new Array();
                var base64string = "";
                var base64key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                var text0, text1, text2;

                ////////////////////////////////////////////////////////////////////////////////////////////////////
                // Step thru the input text string 3 characters per loop, creating 4 output characters per loop //
                ////////////////////////////////////////////////////////////////////////////////////////////////////

                for (i=0; i < text.length; )
                {
                text0 = text.charCodeAt(i);
                text1 = text.charCodeAt(i+1);
                text2 = text.charCodeAt(i+2);

                base64[j] = base64key.charCodeAt((text0 & 252) >> 2);
                if ((i+1)<text.length) // i+1 is still part of string
                {
                base64[j+1] = base64key.charCodeAt(((text0 & 3) << 4)|((text1 & 240) >> 4));
                if ((i+2)<text.length) // i+2 is still part of string
                {
                base64[j+2] = base64key.charCodeAt(((text1 & 15) << 2) | ((text2 & 192) >> 6));
                base64[j+3] = base64key.charCodeAt((text2 & 63));
                }
                else
                {
                base64[j+2] = base64key.charCodeAt(((text1 & 15) << 2));
                base64[j+3] = 61;
                }
                }
                else
                {
                base64[j+1] = base64key.charCodeAt(((text0 & 3) << 4));
                base64[j+2] = 61;
                base64[j+3] = 61;
                }
                i=i+3;
                j=j+4;
                }

                ////////////////////////////////////////////
                // Create output string from byte array //
                ////////////////////////////////////////////

                for (i=0; i<base64.length; i++)
                {
                base64string += String.fromCharCode(base64[i]);
                }

                return base64string;
                }

                function sleep(milliSeconds){
                var startTime = new Date().getTime(); // get the current time
                while (new Date().getTime() < startTime + milliSeconds); // hog cpu
                }
                  0
                  пардон, тег CODE не работает в комментах :(
                  codepaste.ru/8397/
                    0
                    Спасибо! Картинку-то я давно уже сделал, и большей части народа ручками сменил, но есть еще несколько 7911 в двух других, весьма неблизких зданиях нашей конторы, куда только ради этого идти глупо, а внедрить «корпоративный стандарт»- надо бы. Буду ковырять ваш скрипт,
                      +1
                      код скрипта лучше тут смотрите — codepaste.ru/8397/
                      в комменте парсер порезал его жестоко. Сами действия телефона задаются строчкой
                      var myxmllist=«XML= бла-бла-бла…
                      там каждая секция вида

                      это суть команда телефону „нажать кнопку“ (в данном случае — Settings) ну и далее в оригинальном скрипте там ещё какие-то кнопки нажимаются :)
                        +1
                        боже, я устал от хабрапарсера… интересно, щас получится?

                        каждая секция вида
                        <CiscoIPPhoneExecute><ExecuteItem URL=\"Key:Settings\"/></CiscoIPPhoneExecute>


                        и далее по тексту
                          0
                          Да я уже разобрался, спасибо. Попробую сейчас это-же телефону curl-ом подсунуть.
                        0
                        «Суть — включаем сервис, дальше у телефона появляется рабочий скрипт /CGI/Execute»

                        А подскажите, где включается сервис? Что-то не могу найти на SPA502G (хотя поддержка вроде декларирована)
                          0
                          на полном CUCM в контрольной панели Serviceability, меню tools->Services activation. Там будет список сервисов. Нужный сервис — Cisco AXL Web service.
                          на CCME — честно не знаю :)
                      0
                      Есть вот такой способ автонастройки телефонов, должен работать и на Cisco.
                        0
                        Этот способ подошел бы для телефонов с sip-прошивкой и не CUCM в качестве сервера. а так — да.

                    Only users with full accounts can post comments. Log in, please.