Google Integration +IM

Хотел написать о Интеграции с гуглопочтой, гуглокалендарем.. Но решил более детально остановится на Gtalk, гугложабер называйте как хотите, лишь бы было понятно о чем)
1.Небольшой обзор функций в *1.8
2.Плавно переходим к *10
3.Неожиданно «написался» кусочек статьи о мгновенных сообщениях, спс хабру)
4. Функции которые будут в *11(уже 2 бета доступна)
но обо всем по порядку…

Для начала нам нужна учетка гугла.
Формат файлов в 1.8 и 10 идентичен
Сначала правим jabber.conf(подключаем туда учетку гугла)
Как и во всех файла астериска присутствует секция general(для общих настроек)
А дальше мы сами придумываем нужную нам секцию, например asterisk

[general]
; вкл режим отладки(более детальные сообщения)
debug=no
; удалять или нет людей из списка контактов, каждый раз при подкл к серверу
autoprune=no
; проводить ли авторегистрацию пользователей из списка контактов
autoregister=yes
; поведение при запросе авторизации(разрешить/запретить)
auth_policy=accept

[asterisk]
;тип клиента  client или component, в 99% используется первое
type=client
;сервер куда будем коннектится
serverhost=talk.google.com
; учетка на гугле
username=avenue.com.ua@gmail.com
; пароль к учетке
secret=vtufctrhtnysqgfhjkm
;Приоритет этого ресурса, по отношению к другим. 
priority=1
;порт соединения
port=5222
; использовать TLS или нет
usetls=yes
; Использовать SASL или нет
usesasl=yes
;Устанавливаем статус контакта(chat, available, away, xaway, и dnd.)
status=available
; сообщение статуса(обязательно в кавычках)
statusmessage="Asterisk Online"
;Добавляем человека в свой список контактов при соединение с сервером
buddy=bos.avenue.com.ua@gmail.com
; Можно другим серверам рассказывать о том что у вас творится(передавать статусы и события)
;distribute_events=yes                
; Сколько секунд хранить сообщение в очереди. По умолчанию 5. Только для входящих сообщений которые планируется обрабатывать в  функцией диалплана JABBER_RECEIVE().
timeout=5  
;;Добавлено в ASTERISK10
; Отправлять входящие сообщения в диалплан. По умолчанию выкл
;sendtodialplan=yes 
; Контекст для отправки входящих сообщений, по умолчанию "default"              
;context=messages                       

Перезагружаем модуль

*CLI> jabber reload
Jabber Reloaded.

Проверяем соединение:

bos*CLI> jabber show connections
Jabber Users and their status:
       [asterisk] avenue.com.ua@gmail.com     - Connected
----
   Number of users: 1

Если проблемы с соединением:
1. проверяем правильность настроек
2. логин пароль
3. перезагружаем модуль еще раз
4. перезагружаем астериск
5. Выполняем jabber purge nodes

Все работает переходим к Диалплану
JabberSend(account,jid,message) — Отправить сообщение из диалплана
account — имя секции в jabber.conf,
jid — человек кому мы будем отправлять,
message — текст сообщения.

[LocalSets]
exten => 104,1,Answer()
same => n,JabberSend(asterisk,bos.avenue.com.ua@gmail.com,Call from ${CALLERID(all)})
same => n,Dial(SIP/103,30)
same => n,Hangup()

JABBER_RECEIVE(account,jid[,timeout]) Функция диалплана которая получает ответы
account — имя секции в jabber.conf,
jid — человек от кого мы получаем ответ,
timeout — время ожидания ответа, по умолчанию 20сек.

Поскольку обработка диалплана замирает пока мы ожидаем ввода, или таймаута, то лучше использовать каналы local

exten => 106,1,Dial(Local/jabber@${CONTEXT}/n&Local/dial@${CONTEXT}/n)

exten => jabber,1,Verbose(2,Send an XMPP message and expect a response)
 same => n,JabberSend(asterisk,bos.avenue.com.ua@gmail.com,Incoming call from ${CALLERID(all)}. Press 2 to send to voicemail.)
 same => n,Set(JabberResponse=${JABBER_RECEIVE(asterisk,bos.avenue.com.ua@gmail.com,6)})
 same => n,GotoIf($["${JabberResponse}" = "2"]?voicemail,1)
 same => n,Hangup()

exten => dial,1,Verbose(2,Calling our desk)
  same => n,Dial(SIP/678,15)
  same => n,Goto(voicemail,1)

exten => voicemail,1,Verbose(2,VoiceMail)
   same => n,Answer()
   same => n,Set(VoiceMailStatus=${IF($[${ISNULL(${DIALSTATUS})} | "${DIALSTATUS}" = "BUSY"]?b:u)})
   same => n,Playback(silence/1)
   same => n,VoiceMail(100@office,${VoiceMailStatus})
   same => n,Hangup()

JABBER_STATUS(account,jid) возвращает статус человека из списка контактов
account — имя секции в jabber.conf,
jid — человек статус которого мы хотим узнать
Статусы от 1 до 7.
1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline 7= Не в списке контактов.

Также можно использовать приложения JabberJoin() и JabberLeave(), который используется для входа/выхода из XMPP конференц комнаты; и JabberSendGroup() позволяет отослать сообщение в XMPP чат комнату.

Звонки с помощью chan_gtalk правим gtalk.conf

[general]
bindaddr=0.0.0.0        ; Адрес ифейса к какому привязываемся 
allowguests=yes         ; принимать звонки от людей не из контакт листа
; Доп параметры, например если вы за натом 
; externip=
; stunaddr=
;context=default        ; контекст по умолчанию
; Настройка кодеков
;disallow=all
;allow=gsm
;allow=ulaw
;parkinglot=soccer              ; Слот парковки по умолчанию 
                                ; сам слот должен быть настроен в features.conf
;Создаем секцию для принятия ВХОДЯЩИХ звонков.
;Исходящие роутятся на основании профиля в jabber.conf

[avenue.com.ua]
username=avenue.com.ua@gmail.com    ; имя пользователя от кого будем инициировать вызов, или кому предназначаются вызовы
disallow=all
allow=alaw
allow=ulaw
context=gtalk_incoming
connection=asterisk             ; имя соединения заданного в jabber.conf

Теперь диалплан
Входящие

[gtalk_incoming]
exten => my_asterisk_user,1,Verbose(2,Gtalk call from ${CALLERID(all)})
 same => n,Answer() 
 same => n,Wait(2)
 same => n,SendDTMF(1)
 same => n,Dial(SIP/765,20)

Где my_asterisk_user — имя нашего ящика без @gmail.com(удобно если есть несколько гугл аккаунтов)
«Wait» должен быть от 2 секунд, иногда больше, зависит от настроения гугла), иначе Ваш звонок может быть не совсем успешен;) Без SendDTMF(1) гугл будет спрашивать хотим мы принять звонок или нет. Поэтому нужно всегда отсылать 1.

Исходящие

[LocalSets]
exten => 123,1,Verbose(2,Extension 123 calling some_user@gmail.com)
   same => n,Dial(Gtalk/asterisk/some_user@gmail.com,30)
   same => n,Hangup()
;Для звонков в забугряндию  через гугл войс(если вам разрешено)
[LocalSets]
exten => _1NXXNXXXXXX,1,Verbose(2,Placing call to ${EXTEN} via Google Voice)
   same => n,Dial(Gtalk/asterisk/+${EXTEN}@voice.google.com)
   same => n,Hangup()

Где:
Gtalk — технология
asterisk — имя соединения в jabber.conf
some_user@gmail.com — кому будем звонить

Если вдруг CallerID «НиПаНяТнЫй» можно обрезать первую часть.

exten => s,1,NoOp()
 same => n,Set(crazygooglecid=${CALLERID(name)})
 same => n,Set(stripcrazysuffix=${CUT(crazygooglecid,@,1)})
 same => n,Set(CALLERID(all)=${stripcrazysuffix})
 same => n,Dial(SIP/malcolm,20,D(:1))

В Asterisk 10, добавлена поддержка онлайн сообщений без звонка SIP абонентам, делаем свою асю с блекджеком и…
правим sip.conf

accept_outofcall_message = yes 
outofcall_message_context = messages 
auth_message_requests = yes
textsupport=yes 

Добавляем контекст messages в extensions.conf

[messages]
exten => _X.,1,Set(ACTUALTO=${CUT(MESSAGE(to),@,1)}) ;отрезаем адрес назначения без домена
same => n,Set(ACTUALFROM1=${CUT(MESSAGE(from),@,1)}) ;приводим в порядок CID, 
same => n,Set(ACTUALFROM=${CUT(ACTUALFROM1,:,2)})    ;грандстримы в упор не хотели видеть от кого сообщение   
same => n,Set(MESSAGE(body)=${ACTUALFROM}:${MESSAGE(body)})  ; правим текст сообщения для грандстримов
same => n,MessageSend(${ACTUALTO},${MESSAGE(from)})       ; отправляем
same => n,NoOp(Send status is ${MESSAGE_SEND_STATUS})     
same => n,GotoIf($["${MESSAGE_SEND_STATUS}" != "SUCCESS"]?sendfailedmsg)  ; статус отправки
same => n,Hangup()   
same => n(sendfailedmsg),Set(MESSAGE(body)="[${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)}]Your message to ${EXTEN} has failed. Retry later.")    ; делаем печальный текст
same => n,Set(ME_1=${CUT(MESSAGE(from),<,2)}) ; обрезаем откого
same => n,Set(ACTUALFROM=${CUT(ME_1,@,1)})   ;
same => n,MessageSend(${ACTUALFROM},"ServiceCenter" <700>) ; отправляем c указанием от кого) 
same => n,Hangup()

Как все это работает?
Сначала устанавливаем текст сообщения, а потом собственно отправляем)
Используем функцию MESSAGE(arg)

В качестве аргументов:
to -только чтение. Адрес назначения сообщения
from — только чтение. Адрес отправителя
body — Текст сообщения. UTF-8

С помощью Set(MESSAGE(body)=TXT) устанавливаем текст сообщения который потом отправим из Астериска.

MessageSend(to[,from])
to — кому отправить
from — от кого
!!! для SIP этот параметр может быть задан как имя пира или в формате «display-name» .
Приложение возвращает переменную ${MESSAGE_SEND_STATUS}:
INVALID_PROTOCOL: не знает как обработать технологию в адресе назначения
INVALID_URI: неверный адрес назначения
SUCCESS: Сообщение успешно ушло по протоколу, но это не гарантия того, что сообщение будет получено)
FAILURE: Сообщение не доставлено

В 11 версии MESSAGE(from) будет в виде «display-name» вместо простого uri.

А теперь о будущем, в Asterisk 11 будет реализована поддержка общения через res_xmpp и chan_motif
motif.conf

[google]
context=incoming-motif
disallow=all
allow=ulaw
connection=google

xmmp.conf

[general]
[google]
type=client
serverhost=talk.google.com
username=example@gmail.com
secret=examplepassword
priority=1
port=5222
usetls=yes
usesasl=yes
status=available
statusmessage="I am available"
timeout=5

Дальше все без изменений


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