Настройка офисного комбайна на Asterisk (Голосовая почта, логирование звонков, синхронизация с Google Контакты)

07.12.2014 - 22:32

Имеем офис на 20 абонентов (101-120), каждый внутренний номер имеет по 5 внутренних номеров. Например, мой внур. номер 101, при этом мои номера 1011 настроен на PC, 1012 настроен на Android, 1013 на аппаратном телефоне и т.д.
При входящем звонке на номер 101, звонок автоматически перенаправляется на все мои внутр.номера (1011-1015), и на оборот, если я звоню с (1011-1015) все исходящие номера определяются как 101, то есть для других абонентов все прозрачно, как бы я звонил с номера 101.

asterisk_full.png

Так же имеем 2 SIP пира от провайдеров (multifon и youmagic).

Необходимо реализовать:
1. Локальную маршрутизацию звонков между внутренними номерами _XXX и _XXXX. Внутренние номера - каждый пользователь имеет несколько внутренних номеров при этом вызов должен идти параллельно на все номера выбранного абонента (например: мой внутренний номер 101, на моих устройствах настроены номера 1101, 1102, 1103 и т. д. Набирая 101 вызов идет на все зарегистрированные номера).
2. Правила входящих, исходящих на внешние номера.
3. IVR меню - "введите внутренний номер абонента", на внешнем номере - youmagic. Если ничего не ввели, вызов пошел на определенный внутр. номер, если он неактивен, отправляем на голосовую почту.
4. Настройка голосовой почты. Если все внутренние номера вызываемого абонента не зарегистрированы в сети, предложить отправить голосовое сообщение. Голосовые сообщения доставлять абонентам на их адреса электронной почты в виде аудио файла с темой письма: “номер имя (если есть в книге контактов) hh.mm/dd.mm” и текстом в письме: “номер имя(если есть в книге контактов) hh.mm/dd.mm”. Так же должно прийти sms уведомление на мобильный о том, что Вам оставили голосовое сообщение. Сделать возможность оставить голосовое сообщение выбранному абоненту заменив первую цифру внутреннего номера на другую (например внутренний номер 101 - голосовая почта 0101, 0102 - 0102 и т. д.).
5. Запись всех разговоров. Разработать способ поиска записей разговоров по дате, направлению (входящие/исходящие), номеру (входящего/исходящего), примерной длительности.
6. Возможность полного логирования всех звонков (web интерфейс), прослушивание записанных разговоров.
7. Книга контактов. Разработать способ добавления контактов для последующего их определения на SIP клиентах.
8. Если номер входит в список известных номеров то отправлять вызов на “Группу №1”.
9. Разработать способ установки режима обработки входящего звонка для каждого пользователя.
Пример реализации: Если перед внутр. номером я ставлю "*", например *101, *102 - мне предлагается “Установите режим работы: 0 - “Оффлайн”, 1 - “Офисный режим”, 2 - “Мобильный режим”,
При нажатии на "0", устанавливаем режим оффлайн - все входящие звонки отправляем на голосовую почту.
При нажатии на "1" - “Офисный режим” - вызовы отправляются на SIP.
При нажатии на "2" - “Мобильный режим” - все звонки отправляются на мобильный.

Имеется облачный сервер:

debian 7.0
asterisk 1.8.13
mysql ver. 5.5

Для корректной работы часового пояса в BD и логере, хочу заметить что нужно его установить в UTC, а не в Europe/Kiev или Europe/Moscow:

root@voip-srv:~# cp /usr/share/zoneinfo/UTC /etc/localtime

На установке Asterisk пожалуй останавливаться не буду, перейдем сразу к настройке.

root@voip-srv:/etc/asterisk# cat /etc/asterisk/sip.conf
[general]
videosupport=yes ;поддержка видео для ip вызывной панели bas-ip.
alwaysauthreject = yes ;Отключаем оповещение о неверном пароле
tcpenable=yes
allow=all
allowguest=no
bindaddr=<Внешний IP>
externip = <Внешний IP>:5060
tcpbindaddr = <Внешний IP>
allowoverlap=no
transport=udp
srvlookup=yes
minexpiry=60
defaultexpiry=300
pedantic=no
language=ru
jbenable = yes
jbmaxsize = 100
jbimpl = fixed
directmedia=no                  ; запрещаем прямые соединения клиентов (только через asterisk)

;multifon
register => <номер>@multifon.ru:<пароль>:<номер>@sbc.megafon.ru:5060/<номер>

;youmagic-office
register => <номер>:<пароль>@voip.mtt.ru/<номер>

[multifon-out8001]
defaultuser=<номер>
fromuser=<номер>
secret=<пароль>
host=sbc.megafon.ru
fromdomain=multifon.ru
insecure=invite,port
type=peer
dtmfmode=inband
disallow=all
allow=ulaw,alaw
context=in-mf8001
transport=tcp
;nat=force_rport,comedia
nat=no
ualify=15000
hasexten = no
hassip = yes
hasiax = no
registeriax = no
registersip = yes
canreinvite=no
directmedia=no
directrtpsetup=no
regseconds=120

[youmagic-out1406]
trunkname=<номер>
host=voip.mtt.ru
type=friend
nat=force_rport,comedia
hasexten=no
hassip=yes
hasiax=no
username=<номер>
fromuser=<номер>
fromdomain=voip.mtt.ru
secret=<пароль>
context=in
;context=incoming
insecure=invite
canreinvite=no
disallow=all
allow=ulaw
allow=alaw
allow=gsm
qualify=yes

[OFFICE](!)
type=friend ; может как принимать, так и совершать звонки
host=dynamic
nat=force_rport,comedia ; указываем, что клиент подключен через nat
canreinvite=no ;блокирует отправку сообщений re-INVITE
disallow=all ; разрешить только определенные кодэки
allow=ulaw ; данная конфигурация лучше подходит
allow=alaw ; для локальной сети - без сжатия.
allow=h264 ; разрешаем видео-кодек для передачи видео (bas-ip).
monitor=yes
language=ru ; язык
dtmfmode=rfc2833
allowguest=no
subscribemwi = no ;voice mail led
alwaysauthreject=yes ;ошибках авторизации отвечает 401 Unauthorized
qualify=200  ;проверяет какой пинг НА ПОЛЬЗОВАТЕЛЯ
;qualify=yes            ; поддерживаем SIP каждые 300 мс
;rtpkeepalive=10                ; поддерживаем RTP каждые 10 сек

[101](OFFICE)
defaultuser=user1
secret=<пароль>
call-limit=5
callerid="User01" <101>
context=out-mf8001
mailbox=0101@voicemailcontext

[1011](OFFICE)
defaultuser=user1
secret=<пароль>
call-limit=5
callerid="User01" <101>
context=out-mf8001
mailbox=0101@voicemailcontext

[1012](OFFICE)
defaultuser=user1
secret=<пароль>
call-limit=5
callerid="User01" <101>
context=out-mf8001
mailbox=0101@voicemailcontext

[1013](OFFICE)
defaultuser=user1
secret=<пароль>
call-limit=5
callerid="User01" <101>
context=out-mf8001
mailbox=0101@voicemailcontext

[102](OFFICE)
defaultuser=user2
secret=<пароль>
call-limit=5
callerid="User02" <102>
context=for-office
mailbox=0102@voicemailcontext

;-----------------------------------------
[103](OFFICE)
defaultuser=user3
secret=<пароль>
call-limit=5
callerid="User03" <103>
context=for-office
mailbox=0103@voicemailcontext

;-----------------------------------------
;остальные номера по аналогии.

root@voip-srv:/etc/asterisk# cat extensions.conf
[general]
static=yes
writeprotect=no
clearglobalvars=no

;=============IN-CALL==========================================================
[in]
exten => 74900001406,1,Goto(in-ym1406,1406,1)
exten => 74900007573,1,Goto(in-ym7573,7573,1)
exten => i,1,Goto(in-ym1406,s,1)

[in-ym1406]                                                                                                                                                                                                        
exten => 1406,1,Answer()                                                                                                                                                                                          
exten => 1406,n,MYSQL(Connect connid 127.0.0.1 root mysql_passwd asterisk)  ; подключаемся к БД.
exten => 1406,n,MYSQL(Query resultid ${connid} SET NAMES utf8)     ; что бы избежать дальнейших проблем с перекодировками и кракозябрами  используйте UTF-8.
exten => 1406,n,GotoIf($["${connid}" = ""]?nodb)                                                                                                                                                                  
exten => 1406,n,MYSQL(Query resultid ${connid} SELECT displayname FROM user1 WHERE phonenumber="${CALLERID(num)}" LIMIT 1) ; если находим соответствие ${CALLERID(num)} - ${displayname}, подставляем Имя пользователя.
exten => 1406,n,MYSQL(Fetch fetchid ${resultid} displayname)
exten => 1406,n,NoOp(${fetchid})
exten => 1406,n,MYSQL(Clear ${resultid})
exten => 1406,n,Set(CALLERID(name)=${displayname})
exten => 1406,n,MYSQL(Disconnect ${connid}); отключаемся от базы, что бы не плодить незавершенные сессии.
exten => 1406,n(nodb),NoOp(DoneDB) ;пишем в лог.
exten => 1406,n,GotoIf($["${CALLERID(number)}"="+79000004535"]?redirect,108,1) ; тут пишу номера, которые я сразу перевожу на определенный внутр. номер.в данном случае - 108.
exten => 1406,n,Background(/var/lib/asterisk/moh2/add) ;ivr меню - Введите внутр.номер абонента:
exten => 1406,n,Background(/var/lib/asterisk/moh/output-30) ; фоновая музыка 30с,нарезка звуковым редактором.
exten => 1406,n,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID}) ; начинаем запись разговора
exten => 1406,n,MixMonitor(${MONITOR_FILE}.wav,b) ;сохраняем запись в файл с синхронизацией 2-х каналов.
exten => 1406,n,Dial(SIP/1011&SIP/1012&SIP/1013&SIP/1014&SIP/1015&SIP/1016&SIP/1017&SIP/1018&SIP/1019,30,m) ; если никто не взял трубку, звоним на этот номер (101).
exten => 1406,n,NoOp(Voicemail handler) ;если на 101 никто не взял трубку, предлагаем оставить голосовое сообщение.
exten => 1406,n,Set(CDR(accountcode)=voicemail)
exten => 1406,n,VoiceMail(0101@voicemailcontext)
exten => 1406,n,Hangup
include => redirect

[in-mf8001]
exten => 79200008001,1,Answer()
exten => 79200008001,n,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => 79200008001,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => 79200008001,n,MYSQL(Connect connid 127.0.0.1 root mysql_passwd asterisk)
exten => 79200008001,n,MYSQL(Query resultid ${connid} SET NAMES utf8)
exten => 79200008001,n,GotoIf($["${connid}" = ""]?nodb)
exten => 79200008001,n,MYSQL(Query resultid ${connid} SELECT displayname FROM user1 WHERE phonenumber="${CALLERID(num)}" LIMIT 1)
exten => 79200008001,n,MYSQL(Fetch fetchid ${resultid} displayname)
exten => 79200008001,n,MYSQL(Clear ${resultid})
exten => 79200008001,n,Set(CALLERID(name)=${displayname})
exten => 79200008001,n,MYSQL(Disconnect ${connid})
exten => 79200008001,n(nodb),NoOp(DoneDB)
exten => 79200008001,n,Set(load_fun=${FILE(/etc/asterisk/db/fun-101.txt,0,2)})
exten => 79200008001,n,GotoIf($["${load_fun}"="1"]?up)
exten => 79200008001,n,GotoIf($["${load_fun}"="0"]?down)
exten => 79200008001,n(up),Dial(SIP/1011&SIP/1012&SIP/1013&SIP/1014&SIP/1015&SIP/1016&SIP/1017&SIP/1018&SIP/1019,30,m(my8001))
exten => 79200008001,n(down),NoOp(Voicemail handler)
exten => 79200008001,n,Set(CDR(accountcode)=voicemail)
exten => 79200008001,n,VoiceMail(0101@voicemailcontext)
exten => 79200008001,n,Hangup
include => redirect

[in-ym7573]
exten => 7573,1,Answer()
exten => 7573,n,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => 7573,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => 7573,n,Dial(SIP/1071&SIP/1072&SIP/1073&SIP/1074&SIP/1075&SIP/1076&SIP/1077&SIP/1078&SIP/1079,30,m)
exten => 7573,n,NoOp(Voicemail handler)
exten => 7573,n,Set(CDR(accountcode)=voicemail)
exten => 7573,n,VoiceMail(0107@voicemailcontext)
exten => 7573,n,Hangup()

;=====================ROUTERS=================================================
[for-office]
include => redirect
include => local
include => out-office
include => for-sales
include => out-mf8001

;=============LOCAL-CALL=======================================================
[local]

;voice mail server
exten => 500,1,Log(NOTICE, Dialing out from ${CALLERID(all)} to VoiceMail (500))
exten => 500,n, VoiceMailMain(@voicemailcontext)
exten => 500,n, Hangup

;time voice
exten => 400,1,Answer()
exten => 400,n,SayUnixTime(,,QdhAR)
;exten => 400,n,WaitMusicOnHold(5)
exten => 400,n,Hangup

exten => _XXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _XXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _XXX,n,Dial(SIP/${EXTEN},30,m);
exten => _XXX,n,Hangup

exten => _XXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _XXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _XXXX,n,Dial(SIP/${EXTEN},30,m);
exten => _XXXX,n,Hangup

;Устанавливаем режим работы номера, для этого необходимо набрать "*внутр.номер"
exten => _*XXX,1,Answer()
exten => _*XXX,n,Background(/var/lib/asterisk/mode2/012) ; Голосовое меню, Выберете режим работы: 0 - перевести звонки на голос.почту, 1 - Режим в офисе, 2 - Перевести все звонки на мобильный.
exten => _*XXX,n,WaitExten(5) ;для осознания ивр и правильного выбора пользователем.)
exten => 0,1,Goto(fun0,5,1)
exten => 1,1,Goto(fun1,6,1)
exten => 2,1,Goto(fun2,7,1)

;значения выбора я храню в текстовых файлах.
[fun0]
exten => 5,1,Playback(digits/0)
exten => 5,n,system(printf '0' > /etc/asterisk/db/fun-${CALLERID(number)}.txt)
exten => 5,n,Playback(auth-thankyou)
exten => 5,n,Hangup

[fun1]
exten => 6,1,Playback(digits/1)
exten => 6,n,system(printf '1' > /etc/asterisk/db/fun-${CALLERID(number)}.txt)
exten => 6,n,Playback(auth-thankyou)
exten => 6,n,Hangup

[fun2]
exten => 7,1,Playback(digits/2)
exten => 7,n,system(printf '2' > /etc/asterisk/db/fun-${CALLERID(number)}.txt)
exten => 7,n,Playback(auth-thankyou)
exten => 7,n,Hangup

[redirect]
exten => 0101,1,NoOp(Voicemail handler)
exten => 0101,n,Set(CDR(accountcode)=voicemail)
exten => 0101,n,VoiceMail(0101@voicemailcontext)
exten => 0101,n,Hangup()

exten => 0102,1,NoOp(Voicemail handler)
exten => 0102,n,Set(CDR(accountcode)=voicemail)
exten => 0102,n,VoiceMail(0102@voicemailcontext)
exten => 0102,n,Hangup()

exten => 0103,1,NoOp(Voicemail handler)
exten => 0103,n,Set(CDR(accountcode)=voicemail)
exten => 0103,n,VoiceMail(0103@voicemailcontext)
exten => 0103,n,Hangup()

;описываем локальные номера пользователей
exten => 101,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => 101,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => 101,n,MYSQL(Connect connid 127.0.0.1 root mysql_passwd asterisk)
exten => 101,n,MYSQL(Query resultid ${connid} SET NAMES utf8)
exten => 101,n,GotoIf($["${connid}" = ""]?nodb)
exten => 101,n,MYSQL(Query resultid ${connid} SELECT displayname FROM user1 WHERE phonenumber="${CALLERID(num)}" LIMIT 1)
exten => 101,n,MYSQL(Fetch fetchid ${resultid} displayname)
exten => 101,n,MYSQL(Clear ${resultid})
exten => 101,n,Set(CALLERID(name)=${displayname})
exten => 101,n,MYSQL(Disconnect ${connid})
exten => 101,n(nodb),NoOp(DoneDB)
exten => 101,n,ReadFile(load_fun=/etc/asterisk/db/fun-101.txt,2)
exten => 101,n,NoOp(load_fun=${load_fun})
exten => 101,n,GotoIf($["${load_fun}"="1"]?up)
exten => 101,n,GotoIf($["${load_fun}"="0"]?down)
exten => 101,n,GotoIf($["${load_fun}"="2"]?ext)
exten => 101,n(ext),Dial(SIP/youmagic-out1406/79200008001)
exten => 101,n(up),Dial(SIP/1011&SIP/1012&SIP/1013&SIP/1014&SIP/1015&SIP/1016&SIP/1017&SIP/1018&SIP/1019,30,m)
exten => 101,n(down),NoOp(Voicemail handler)
exten => 101,n,Set(CDR(accountcode)=voicemail)
exten => 101,n,VoiceMail(0101@voicemailcontext)
exten => 101,n,Hangup()


exten => 102,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => 102,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => 102,n,MYSQL(Connect connid 127.0.0.1 root mysql_passwd asterisk)
exten => 102,n,MYSQL(Query resultid ${connid} SET NAMES utf8)
exten => 102,n,GotoIf($["${connid}" = ""]?nodb)
exten => 102,n,MYSQL(Query resultid ${connid} SELECT displayname FROM user1 WHERE phonenumber="${CALLERID(num)}" LIMIT 1)
exten => 102,n,MYSQL(Fetch fetchid ${resultid} displayname)
exten => 102,n,MYSQL(Clear ${resultid})
exten => 102,n,Set(CALLERID(name)=${displayname})
exten => 102,n,MYSQL(Disconnect ${connid})
exten => 102,n(nodb),NoOp(DoneDB)
exten => 102,n,ReadFile(load_fun=/etc/asterisk/db/fun-102.txt,2)
exten => 102,n,NoOp(load_fun=${load_fun})
exten => 102,n,GotoIf($["${load_fun}"="1"]?up)
exten => 102,n,GotoIf($["${load_fun}"="0"]?down)
exten => 102,n,GotoIf($["${load_fun}"="2"]?ext)
exten => 102,n(ext),Dial(SIP/youmagic-out1406/79100000641)
exten => 102,n(up),Dial(SIP/102&SIP/1021&SIP/1022&SIP/1023&SIP/1024&SIP/1025&SIP/1026&SIP/1027&SIP/1028&SIP/1029,30,m)
exten => 102,n(down),NoOp(Voicemail handler)
exten => 102,n,Set(CDR(accountcode)=voicemail)
exten => 102,n,VoiceMail(0102@voicemailcontext)
exten => 102,n,Hangup()


exten => 103,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => 103,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => 103,n,MYSQL(Connect connid 127.0.0.1 root mysql_passwd asterisk)
exten => 103,n,MYSQL(Query resultid ${connid} SET NAMES utf8)
exten => 103,n,GotoIf($["${connid}" = ""]?nodb)
exten => 103,n,MYSQL(Query resultid ${connid} SELECT displayname FROM user1 WHERE phonenumber="${CALLERID(num)}" LIMIT 1)
exten => 103,n,MYSQL(Fetch fetchid ${resultid} displayname)
exten => 103,n,MYSQL(Clear ${resultid})
exten => 103,n,Set(CALLERID(name)=${displayname})
exten => 103,n,MYSQL(Disconnect ${connid})
exten => 103,n(nodb),NoOp(DoneDB)
exten => 103,n,ReadFile(load_fun=/etc/asterisk/db/fun-103.txt,2)
exten => 103,n,NoOp(load_fun=${load_fun})
exten => 103,n,GotoIf($["${load_fun}"="1"]?up)
exten => 103,n,GotoIf($["${load_fun}"="0"]?down)
exten => 103,n,GotoIf($["${load_fun}"="2"]?ext)
exten => 103,n(ext),Dial(SIP/youmagic-out1406/8920000131)
exten => 103,n(up),Dial(SIP/103&SIP/1031&SIP/1032&SIP/1033&SIP/1034&SIP/1035&SIP/1036&SIP/1037&SIP/1038&SIP/1039,30,m)
exten => 103,n(down),NoOp(Voicemail handler)
exten => 103,n,Set(CDR(accountcode)=voicemail)
exten => 103,n,VoiceMail(0103@voicemailcontext)
exten => 103,n,Hangup()

;=============OUT-CALL=======================================================
[out-office]
;youmagic-office 1406
exten => _+7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _+7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _+7XXXXXXXXXX,n,Dial(SIP/youmagic-out1406/${EXTEN})
exten => _+7XXXXXXXXXX,n,Hangup()

exten => _7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _7XXXXXXXXXX,n,Dial(SIP/youmagic-out1406/+${EXTEN})
exten => _7XXXXXXXXXX,n,Hangup()

exten => _8XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _8XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _8XXXXXXXXXX,n,Dial(SIP/youmagic-out1406/+7${EXTEN:1})
exten => _8XXXXXXXXXX,n,Hangup()

exten => _XXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _XXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _XXXXXXX,n,Dial(SIP/youmagic-out1406/+7495${EXTEN})
exten => _XXXXXXX,n,Hangup()

[out-mf8001]
;multifon 8001 + убираем
exten => _+7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _+7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _+7XXXXXXXXXX,n,Dial(SIP/multifon-out8001/${EXTEN:1})
exten => _+7XXXXXXXXXX,n,Hangup()

exten => _7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _7XXXXXXXXXX,n,Dial(SIP/multifon-out8001/${EXTEN})
exten => _7XXXXXXXXXX,n,Hangup()

exten => _8XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _8XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _8XXXXXXXXXX,n,Dial(SIP/multifon-out8001/7${EXTEN:1})
exten => _8XXXXXXXXXX,n,Hangup()

;add *
exten => _749[5,9]XXXXXXX*,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _749[5,9]XXXXXXX*,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _749[5,9]XXXXXXX*,n,Dial(SIP/multifon-out8001/${EXTEN:0:11})
exten => _749[5,9]XXXXXXX*,n,Hangup()

exten => _XXXXXXX*,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _XXXXXXX*,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _XXXXXXX*,n,Dial(SIP/multifon-out8001/7495${EXTEN:0:7})
exten => _XXXXXXX*,n,Hangup()

exten => _+7XXXXXXXXXX*,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _+7XXXXXXXXXX*,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _+7XXXXXXXXXX*,n,Dial(SIP/multifon-out8001/${EXTEN:1:11})
exten => _+7XXXXXXXXXX*,n,Hangup()

exten => _7XXXXXXXXXX*,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _7XXXXXXXXXX*,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _7XXXXXXXXXX*,n,Dial(SIP/multifon-out8001/${EXTEN:0:11})
exten => _7XXXXXXXXXX*,n,Hangup()

exten => _8XXXXXXXXXX*,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _8XXXXXXXXXX*,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _8XXXXXXXXXX*,n,Dial(SIP/multifon-out8001/7${EXTEN:1:10})
exten => _8XXXXXXXXXX*,n,Hangup()

;youmagic-office-1406
exten => _749[5,9]XXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _749[5,9]XXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _749[5,9]XXXXXXX,n,Dial(SIP/youmagic-out1406/+${EXTEN})
exten => _749[5,9]XXXXXXX,n,Hangup()

exten => _XXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _XXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _XXXXXXX,n,Dial(SIP/youmagic-out1406/+7495${EXTEN})
exten => _XXXXXXX,n,Hangup()

;add #
exten => _+7XXXXXXXXXX#,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _+7XXXXXXXXXX#,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _+7XXXXXXXXXX#,n,Dial(SIP/youmagic-out1406/${EXTEN:0:12})
exten => _+7XXXXXXXXXX#,n,Hangup()

exten => _7XXXXXXXXXX#,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _7XXXXXXXXXX#,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _7XXXXXXXXXX#,n,Dial(SIP/youmagic-out1406/+${EXTEN:0:11})
exten => _7XXXXXXXXXX#,n,Hangup()

exten => _8XXXXXXXXXX#,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _8XXXXXXXXXX#,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _8XXXXXXXXXX#,n,Dial(SIP/youmagic-out1406/+7${EXTEN:1:10})
exten => _8XXXXXXXXXX#,n,Hangup()

include => redirect
include => local

[for-sales]
;youmagic-office 7573
exten => _+7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _+7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _+7XXXXXXXXXX,n,Dial(SIP/youmagic-out7573/${EXTEN})
exten => _+7XXXXXXXXXX,n,Hangup()

exten => _7XXXXXXXXXX,1,Set(MONITOR_FILE=/var/spool/asterisk/monitor/${UNIQUEID})
exten => _7XXXXXXXXXX,n,MixMonitor(${MONITOR_FILE}.wav,b)
exten => _7XXXXXXXXXX,n,Dial(SIP/youmagic-out7573/+${EXTEN})
exten => _7XXXXXXXXXX,n,Hangup()

include => redirect
include => local

;Отправляем в /dev/null
[default]
exten => _X.,1,Hangup

Настройка голосовой почты

root@voip-srv:/etc/asterisk# cat voicemail.conf
[general]
format=wav49|gsm|wav
serveremail=no_reply@example.org
attach=yes ; да, нам нужны вложения со звуковым файлом
maxmsg=100  ; максимальное кол-во сообщений для ящика. 100 будет достаточно
maxsecs=600 ; максимальная длинна сообщения, 3 минуту обычно больше чем достаточно...
minsecs=3
maxgreet=60
skipms=3000
;maxsilence=1
;silencethreshold=128
maxlogins=3
moveheard=yes
charset=UTF-8  ; поменяйте кодировку, чтобы избежать проблем с русским текстом
pbxskip=yes
fromstring=VoiceMail ; от этого "лица" будут приходить сообщения
emailsubject=Сообщение от ${VM_CALLERID} длиной ${VM_DUR} в ${VM_DATE}
emailbody=Уважаемый(мая) ${VM_NAME}:\n\nХотим сообщить, что Вам пришло новое голосовое сообщение длиной ${VM_DUR} под номером (number ${VM_MSGNUM})\nв ящик ${VM_MAILBOX} от ${VM_CALLERID}, в ${VM_DATE}. \nКак будет время, проверьте его!  Спасибо!\n\n\t\t
emaildateformat=%A, %B %d, %Y at %r
pagerdateformat=%A, %B %d, %Y at %r
;mailcmd=/usr/sbin/sendmail -t  ; если у вас какой-то особенный MTA агент - его можно указать тут.
;delete=yes              ; Для варианта, когда голосовая почта отправляется только на email - это хорошая опция. Сообщение будет удалено из системы как только будет отправлено

[zonemessages]
ru=Europe/Moscow|'vm-received' q 'digits/at' H 'digits/hundred' M 'hours'
ua=Europe/Kiev|'vm-received' q 'digits/at' H 'digits/hundred' M 'hours'

[voicemailcontext]
101 => 1234,Ivan Vasilevich,user1@example.org,,attach=yes|tz=ua
102 => 1234,Nikolay Petrovich,user2@example.org,,attach=yes|tz=ru
103 => 1234,Ekaterina Nikolaevna,user3@example.org,,attach=yes|tz=ru

;тут установил немного своих рингтонов на входящие звонки)

root@voip-srv:/etc/asterisk# cat musiconhold.conf
[general]
[default]
mode=files
directory=moh

[my8001]
mode=files
directory=/var/lib/asterisk/8001

Логгер звонков

В качестве логгера звонков я использовал, ACViewer. Очень понравился, ничего лишнего, возможность поиска по критериям, прослушивание записанных разговоров. Спасибо автору проекта.

20_2.png

Останавливаться на установке не буду, так как все хорошо описано автором в прилагаемом мануале. Приведу некоторые настройки базы:

root@voip-srv:/etc/asterisk# cat cdr_mysql.conf
[global]
;hostname=127.0.0.1
dbname=aret
user=user1
password=passwd1
table=cdr
;port=3306
sock=/var/run/mysqld/mysqld.sock
timezone=UTC
;
charset=utf8
;
; ssl connections (optional)
;ssl_ca=<path to CA cert>
;ssl_cert=<path to cert>
;ssl_key=<path to keyfile>
;

Привязываем контакты Google к Asterisk
Google Контакты полезная функция для пользователей которые могут синхронизировать контакты между Google Apps и мобильным устройством на Android. В данном случае при внешнем входящем звонке Asterisk должен сопоставить CallerID с БД, если соответствие найдено - подменить его на Имя абонента.
Для работы скрипта понадобится установить zend.

root@tower:/home/vlymar# dpkg -l |grep zend
ii  zendframework                         1.11.13-1.1                        all          powerful PHP framework
ii  zendframework-bin                     1.11.13-1.1                        all          binary scripts for zendframework
ii  zendframework-resources               1.11.13-1.1                        all          resource scripts for zendframework

или

apt-get download zendframework
apt-get download zendframework-bin
apt-get download zendframework-resources

dpkg -i zendframework_1.11.13-1.1_all.deb
dpkg -i zendframework-bin_1.11.13-1.1_all.deb
dpkg -i zendframework-resources_1.11.13-1.1_all.deb

SQL запрос создает БД contacts.sql, в ней таблицы пользователей, user1, user2, user3.

SET time_zone = "+00:00";
CREATE DATABASE contacts;
USE asterisk1;

-- Структура таблицы `user1`
CREATE TABLE IF NOT EXISTS `user1` (
  `phonenumber` bigint(15) NOT NULL,
  `displayname` varchar(50) NOT NULL,
  `iconv` varchar(50) NOT NULL,
  KEY `phonenumber` (`phonenumber`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- Структура таблицы `user2`
CREATE TABLE IF NOT EXISTS `user2` (
  `phonenumber` bigint(15) NOT NULL,
  `displayname` varchar(50) NOT NULL,
  `iconv` varchar(50) NOT NULL,
  KEY `phonenumber` (`phonenumber`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- Структура таблицы `user3`
CREATE TABLE IF NOT EXISTS `user3` (
  `phonenumber` bigint(15) NOT NULL,
  `displayname` varchar(50) NOT NULL,
  `iconv` varchar(50) NOT NULL,
  KEY `phonenumber` (`phonenumber`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Скрипт логинится в google контакты и експортирует их в mysql базу.
Для скрипта нужно перевести свой пароль в base64, я делаю это так, мой пароль"Cae3a4" конвертирует в "Q2FlM2E0Cg==":

vlymar@tower:/mnt/sda5/tmp_work$ echo "Cae3a4" | base64
Q2FlM2E0Cg==

root@voip-srv:/etc/asterisk/sync# cat gsync.php
#!/usr/bin/php -q
<?php
$user = array("0" => "user@gmail.com");
$pass = array("0" => "Q2FlM2E0Cg==");   // base64 encoded
$table = array("0" => "user1");
$con=mysql_connect("127.0.0.1","root","mysql_passwd");

ob_implicit_flush(false);
set_time_limit(10);
error_reporting(0);
$arg = $argv[1];

if(isset($argv[1])) { $user = $user[$arg]; $pass = $pass[$arg]; $table = $table[$arg]; }
else { $user = $user[0]; $pass = $pass[0]; $table = $table[0]; } // Default if no arg

// load Zend Gdata libraries
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');

try {
        $client = Zend_Gdata_ClientLogin::getHttpClient($user, base64_decode($pass), 'cp');
        $gdata = new Zend_Gdata($client);
        $gdata->setMajorProtocolVersion(3);
        $query = new Zend_Gdata_Query('http://www.google.com/m8/feeds/contacts/default/full?max-results=1000');
        $feed = $gdata->getFeed($query);
        $results = array();
        foreach($feed as $entry){
                $xml = simplexml_load_string($entry->getXML());
                $obj = new stdClass;
                $obj->name = (string) $xml->name->fullName;
                foreach ($xml-> phoneNumber as $p) {
                        $obj-> phoneNumber[] = (string) $p;
                }

                $results[] = $obj;
        }
} catch (Exception $e) {
        die('ERROR:' . $e->getMessage());
}

mysql_select_db('asterisk', $con);
mysql_query("TRUNCATE TABLE ".$table);
$data = "";
foreach ($results as $r) {
        if(isset($r->phoneNumber)) {
                foreach ($r->phoneNumber as $ph) {
                        $displayname = str_replace("&","and",$r->name); //My XML Services dont like ampersand
                        $displayname = ereg_replace("[,]","",mysql_real_escape_string(filter_var($displayname, FILTER_SANITIZE_STRING)));
                        $phonenumber = ltrim(ereg_replace("[^0-9]", "",$ph),1);
                        if ((strlen($phonenumber) > 9) && (strlen($phonenumber) < 16) && ($displayname != "")) {
                                $data .= "('$phonenumber','$displayname'),";
                        }
                }
        }
}

$data = rtrim($data, ',');
mysql_query("SET NAMES 'utf8'");
mysql_query("INSERT INTO $table (phonenumber,displayname) VALUES $data");
?>

и ставим в крон раз 5 мин., проверено гугл не банит..))

*/5 * * * *     root    /usr/bin/php /etc/asterisk/sync/gsync.php

Работа над ошибками

Если не используете cdr в radius, что бы не сыпались ошибки вида:

Oct 20 09:32:08 localhost asterisk[2917]: rc_avpair_new: unknown attribute 1490026597

в modules.conf
noload => cdr_radius.so

ну и чтобы не перезагружать asterisk:
asterisk -rx "module unload cdr_radius.so"

Если Мультифон теряет роутинг, а такое происходит часто если на счету закончились деньги, написал скрипт-подпорку, который проверяет его и в случае отменного от 1, меняет его на 1:

root@voip-srv/# cat  /etc/asterisk/rout_mf.sh
#!/bin/bash
status=$(wget 'https://sm.megafon.ru/sm/client/routing/?login=792XXXXXXXX@multifon.ru&password=<Ваш пароль>' --quiet -O - | grep routing | cut -c-10 | sed 's/[<routing>]//g')
if [ $status = "0" ]; then
wget 'https://sm.megafon.ru/sm/client/routing/set?login=792XXXXXXXX@multifon.ru&password=<Ваш пароль>&routing=1' --quiet -O -
asterisk -rx "sip reload"
else
    echo "ROUTE OK"
fi

ставим его в крон например раз с 5 минут.

#asterisk crontab

0 3 * * * find /var/spool/asterisk/monitor -mtime +40 -exec rm {} \;
*/5 * * * *     root    /etc/asterisk/sync/rout_mf.sh

Не забываем сделать необходимые изменения в firewall:

iptables -A INPUT -p tcp --dport 8080 -i eth0 -j ACCEPT #web logger
iptables -A INPUT -p udp --dport 5060 -i eth0 -j ACCEPT #SIP tcp
iptables -A INPUT -p tcp --dport 5060 -i eth0 -j ACCEPT #SIP udp
iptables -A INPUT -p udp --dport 10000:20000 -i eth0 -j ACCEPT #SIP_MEDIA_RTP
iptables -A INPUT -p tcp --dport 10000:20000 -i eth0 -j ACCEPT #SIP_MEDIA_RTP

Ваша оценка: Нет Средняя: 4 (7 votes)

Комментарии:


Спасибо за статью...

Все работало идеально, но в последнее время не хочет синхронизировать контакты google с помощью zendframework. Логин и пароль правильные. Php скрипт выдает следующий результат:

ERROR:Expected response code 200, got 401
<?xml version="1.0" encoding="UTF-8"?>

GData
required
Authorization
Login Required

В чем может быть причина?



да действительно, имею ту же проблему, видать гугл "обновился"..пока не решил.Sad



Может уже кто решил?



Зачётно. Но, мне кажется стоит упростить описание вн. номеров за счёт использования макроса, а вторую линию обзвона за счет очереди.



Если поможете с примерами макросов буду признателен, так как если много номеров, то реально неудобно их забивать.



По примерам чуть позже. Из устройств доступа к интернету только смарт. Доберусь до компа скину. P.S. : Почему-то не смог на сайте зарегистрироваться, гляньте если не сложно. Спс.



напишите мне на почту



Привет!
Очень хорошая статья!!!
Извините, я не очень разбираюсь в MySQL.
Скажите как выполнить "SQL запрос создает БД contacts.sql, в ней таблицы пользователей, user1, user2, user3."
Не очень понял как его выполнить или куда то надо прописать?



все просто

#mysql --user=пользователь --password=пароль --database=имя БД < contacts.sql



Здравствуйте, не могу настроить входящие с Мультифона на примере ваших конфигураций!( можете помочь? P_dvx@mail.ru



Мои конфиги выложены в статье, у меня работает.



З розуму зійти можна ), надіюсь шо з таким ніколи не буду стикатися ))))