В нашей организации используется ip телефония на базе Trixbox (по сути тот же FreePBX с некоторыми отличиями), а также телефонные апараты фирмы Polycom. С каждым днем штат компании рос и стало все тяжелее запоминать кучу внутренних номеров сотрудников. Часть сотрудников начала вручную вбивать адресную книгу в телефоне, но большая ее половина тратила тонны бумаги на распечатку очередного измененного справочника, а также еще больше времени на поиски нужного номера. С этим нужно было что то делать.
Все телефоны получают свою конфигурацию через tftp сервер, туда и полезем. Обнаружилось что при загрузке, телефон проверяет наличие *macaddr*-directory.xml в директории *tftpserver_dir*/polycom/contacts/, и подгружает его если находит. Этим и воспользуемся.
Сформируем план действий:
- Формирование файла xml с контактами. Чтобы не городить сервисы, надо добиться формирования через bash скрипты.
- Получать информацию о существующих телефонах нужно из CLI asterisk. #Проблема №1.
- Загрузка справочников, путем перезагрузки телефонов 1 раз в сутки ночью.
trixbox1*CLI> sip show peer 114
trixbox1*CLI>
* Name : 114
Secret : <Set>
MD5Secret : <Not set>
Context : from-internal
Subscr.Cont. : <Not set>
Language : ru
AMA flags : Unknown
Transfer mode: open
CallingPres : Presentation Allowed, Not Screened
Callgroup :
Pickupgroup :
Mailbox : 114@device
VM Extension : *97
LastMsgsSent : 0/0
Call limit : 50
Dynamic : Yes
Callerid : "device" <114>
MaxCallBR : 384 kbps
Expire : 1410
Insecure : no
Nat : Always
ACL : Yes
T38 pt UDPTL : No
CanReinvite : No
PromiscRedir : No
User=Phone : No
Video Support: Yes
Trust RPID : No
Send RPID : No
Subscriptions: Yes
Overlap dial : Yes
DTMFmode : rfc2833
LastMsg : 0
ToHost :
Addr->IP : 192.168.0.95 Port 5060
Defaddr->IP : 0.0.0.0 Port 5060
Def. Username: 114
SIP Options : (none)
Codecs : 0x28000c (ulaw|alaw|h263|h264)
Codec Order : (ulaw:20,alaw:20)
Auto-Framing: No
Status : OK (18 ms)
Useragent : PolycomSoundPointIP-SPIP_321-UA/3.1.3.0507
Reg. Contact : sip:114@192.168.0.95
Нас интересует строка Callerid: «device» <114> Вместо информации о CallerID (ФИО) сотрудника мы видим злополучное «device».
Решить можно двумя способами. Первый найти в базе MySQL где хранит информацию по CallerID и на лету при формировании XML получать данные через запросы. Либо вторым менее трудоемким и менее ресурсоемким.
Зная что trixbox целиком и полностью на php мы можем попытаться найти в исходных кодах где же trixbox пишет это «device». Поковырявшись немного в /var/www/ находим файлик /var/www/html/admin/modules/core/functions.inc.php с очень интересным комментарием разработчиков.
// Very bad
$iaxfields[] = array($account,'account',$account);
$iaxfields[] = array($account,'callerid',(isset($_REQUEST['description']) && $_REQUEST['description'] != '')?$_REQUEST['description']." <".$account.'>':'device'." <".$account.'>');
Не будем думать и искать откуда разработчики берут этот description, при создании extension обязательное поле Display name и как раз туда мы вносим ФИО сотрудника, исходя из этого подправим немного файлик.
Не забываем про бекап файла вдруг что пойдет не так или лишнее зацепим, и да не следует это делать сразу на боевом сервере.
Меняем в строке
$_REQUEST['description']
на
$_REQUEST['name']
получаем:
$sipfields[] = array($account,'callerid',(isset($_REQUEST['name']) && $_REQUEST['name'])?$_REQUEST['name']." <".$account.'>':'device'." <".$account.'>');
Сохраняем, идем в веб и пересохраняем extension.
Заходим в CLI asterisk смотрим и радуемся:
trixbox1*CLI> sip show peer 114
trixbox1*CLI>
* Name : 114
Secret : <Set>
MD5Secret : <Not set>
Context : from-internal
Subscr.Cont. : <Not set>
Language : ru
AMA flags : Unknown
Transfer mode: open
CallingPres : Presentation Allowed, Not Screened
Callgroup :
Pickupgroup :
Mailbox : 114@device
VM Extension : *97
LastMsgsSent : 0/0
Call limit : 50
Dynamic : Yes
Callerid : "Ivan Petrov" <114>
MaxCallBR : 384 kbps
Expire : 1410
Insecure : no
Nat : Always
ACL : Yes
T38 pt UDPTL : No
CanReinvite : No
PromiscRedir : No
User=Phone : No
Video Support: Yes
Trust RPID : No
Send RPID : No
Subscriptions: Yes
Overlap dial : Yes
DTMFmode : rfc2833
LastMsg : 0
ToHost :
Addr->IP : 192.168.0.95 Port 5060
Defaddr->IP : 0.0.0.0 Port 5060
Def. Username: 114
SIP Options : (none)
Codecs : 0x28000c (ulaw|alaw|h263|h264)
Codec Order : (ulaw:20,alaw:20)
Auto-Framing: No
Status : OK (18 ms)
Useragent : PolycomSoundPointIP-SPIP_321-UA/3.1.3.0507
Reg. Contact : sip:114@192.168.0.95
Проблема решена, осталось пройти только по всем extension и пересохранить их, чтобы trixbox переписал конфиг файлы с правильным caller id.
Идем далее.
Научим asterisk удаленно перегружать телефоны Polycom. Для этого в файлик /etc/asterisk/sip_notify.conf добавляем следующие строки:
[polycom-check-cfg]
Event=>check-sync
Content-Length=>0
Рестартим asterisk.
После этого если в CLI asterisk выполнить
sip notify polycom-check-cfg 114
телефонный апарат Polycom на котором зарегистрирован extension 114 перезагрузится.
Далее получим список зарегистрированных телефонов, он нам нужен для их удаленной перезагрузки
asterisk -rx 'sip show peers'
получаем
354/354 192.168.0.226 D N A 5060 OK (19 ms)
353/353 192.168.0.108 D N A 5060 OK (15 ms)
352 (Unspecified) D N A 0 UNKNOWN
351 (Unspecified) D N A 0 UNKNOWN
342/342 192.168.0.138 D N A 5061 OK (7 ms)
341/341 192.168.0.138 D N A 5060 OK (7 ms)
C помощью grep уберем лишнее (нас интересуют только апараты зарегистрированные на текущий момент они в списке со статусом «ОК» и отделяем только номера телефонов)
asterisk -rx 'sip show peers' |grep OK |awk '{print $1}'|awk -F'/' '{print $1}'
получаем
400
363
362
361
359
357
356
355
354
353
342
Направляем полученный результат во временный файл оттуда будет проще читать построчно.
asterisk -rx 'sip show peers' |grep OK |awk '{print $1}'|awk -F'/' '{print $1}' > numbers.txt
В данном списке мы получили те телефоны которые надо будет перезагрузить и подгрузить в них справочник.
Вторым заходом формируем сам xml файл справочник (снова исключая ненужное) и пишем в файлик.
asterisk -rx 'sip show peers' |egrep 'OK|UNKNOWN' |grep -v 'GSM' > extensions.txt
Caller id получаем следующим образом
asterisk -rx 'sip show peer 114' |grep Callerid
Далее нам нужно построчно читая extensions.txt получать caller id и писать в файлик формируя на лету куски xml.
Для начала сформируем эталонный 000000000000-directory.xml он загружается телефонами по умолчанию только 1 раз при первой загрузке телефона, далее в папке /tftpboot/polycom/contacts/ формируется файл macaddress-directory.xml который в дальнейшем и будет постоянно подгружаться (тут надо не забыть после формирования эталонного файла заменять им текущие чтобы те подгрузились в телефон). Так как это xml нужны заголовки и структура которую понимает телефон. Набираем:
echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' > 000000000000-directory.xml
echo '<!-- $RCSfile$ $Revision: 35928 $ -->' >> 000000000000-directory.xml
echo '<directory>' >> 000000000000-directory.xml
echo ' <item_list>' >> 000000000000-directory.xml
Заметьте последняя строка с табуляцией, чтобы файл был красивым при формировании, и структурированным.
Далее цикл чтения extensions.txt
cat extensions.txt | while read line
do
Во первых избавляемся от всего лишнего (факсов, free extensinons, запасных номеров начинающихся с 1000х и т.д.)
RES=$(asterisk -rx "sip show peer $line" |grep Callerid |grep -v 'Free' |grep -v 'free' |grep -v 'fax' |grep -v '1000' |grep -v 'device' |grep -v 'FAX' |grep -v 'Test');
if [ "$RES" != "" ]; then
и тут уже формируем красивый кусок кода xml
asterisk -rx "sip show peer $line" |grep Callerid | awk -F': "' '{print $2}' | awk -F'" <' '{print
"tt<item>nttt<ln>"$1"</ln>nttt<ct>"$2"</ct>ntt</item>"}' >> 000000000000-directory.xml
пример
<item>
<ln>Ivan Petrov</ln>
<ct>114></ct>
</item>
ну и дописываем структуру xml
echo ' </item_list>' >> 000000000000-directory.xml
echo '</directory>' >> 000000000000-directory.xml
Полный код формирования xml файла:
echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' > 000000000000-directory.xml
echo '<!-- $RCSfile$ $Revision: 35928 $ -->' >> 000000000000-directory.xml
echo '<directory>' >> 000000000000-directory.xml
echo ' <item_list>' >> 000000000000-directory.xml
cat extensions.txt | while read line
do
RES=$(asterisk -rx "sip show peer $line" |grep Callerid |grep -v 'Free' |grep -v 'free' |grep -v 'fax' |grep -v '1000' |grep -v 'device' |grep -v 'FAX' |grep -v 'Test');
if [ "$RES" != "" ]; then
asterisk -rx "sip show peer $line" |grep Callerid | awk -F': "' '{print $2}' | awk -F'" <' '{print
"tt<item>nttt<ln>"$1"</ln>nttt<ct>"$2"</ct>ntt</item>"}' >> 000000000000-directory.xml
fi
done
echo ' </item_list>' >> 000000000000-directory.xml
echo '</directory>' >> 000000000000-directory.xml
У всех апаратов Polycom mac-адрес начинается с 00:04:F, отсюда можно в сети найти все телефоны через arp
arp -a |grep 00:04:F |awk '{print $4}' > mac.txt
по циклу копируем 000000000000-directory.xml в macaddress-directory.xml
cat mac.txt |while read phonemac
do
MAC=${phonemac//:/}; #регулярка для того чтобы убрать ":" из строки
cp /tftpboot/polycom/contacts/000000000000-directory.xml /tftpboot/polycom/contacts/$MAC-directory.xml
done
Ну и почти финишная прямая по циклу из файла numbers.txt полученного вначале ребутаем телефоны:
cat numbers.txt |while read number
do
asterisk -rx "sip notify polycom-check-cfg $number"
done
Полный код скрипта:
#!/bin/sh
asterisk -rx 'sip show peers' |grep OK |awk '{print $1}'|awk -F'/' '{print $1}' > numbers.txt
asterisk -rx 'sip show peers' |egrep 'OK|UNKNOWN' |grep -v 'GSM' |awk '{print $1}'|awk -F'/' '{print $1}' > extensions.txt
arp -a |grep 00:04:F |awk '{print $4}' > mac.txt
echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' > 000000000000-directory.xml
echo '<!-- $RCSfile$ $Revision: 35928 $ -->' >> 000000000000-directory.xml
echo '<directory>' >> 000000000000-directory.xml
echo ' <item_list>' >> 000000000000-directory.xml
cat extensions.txt | while read line
do
RES=$(asterisk -rx "sip show peer $line" |grep Callerid |grep -v 'Free' |grep -v 'free' |grep -v 'fax' |grep -v '1000' |grep -v 'device' |grep -v 'FAX' |grep -v 'Test');
if [ "$RES" != "" ]; then
asterisk -rx "sip show peer $line" |grep Callerid | awk -F': "' '{print $2}' | awk -F'" <' '{print "tt<item>nttt<ln>"$1"</ln>nttt<ct>"$2"</ct>ntt</item>"}' >> 000000000000-directory.xml
fi
done
echo ' </item_list>' >> 000000000000-directory.xml
echo '</directory>' >> 000000000000-directory.xml
cat mac.txt |while read phonemac
do
MAC=${phonemac//:/};
cp /tftpboot/polycom/contacts/000000000000-directory.xml /tftpboot/polycom/contacts/$MAC-directory.xml
done
cat numbers.txt |while read number
do
asterisk -rx "sip notify polycom-check-cfg $number"
done
rm numbers.txt
rm extensions.txt
rm mac.txt
rm 000000000000-directory.xml
Сохраняем скрипт в папке /etc/cron.daily и после этого каждую ночь все изменения будут загружаться в телефонный справочник настольного телефона с возможностью быстрого поиска по нему. Пользователи довольны, бумага в офисе зря не переводится.
Автор: albertxyc