This is an old revision of the document!
hostname: mail.corpX.un ip/mask: 172.16.1.100+X/24 gate: 172.16.1.254 dns: 172.16.1.254
# wget ftp://www.communigate.com/pub/CommuniGatePro/6.2/CGatePro-Linux_6.2c-3_i386.deb # wget http://rep/unix/CGP/CGatePro-Linux_6.2c-3_i386.deb # dpkg -i CGatePro-Linux_6.2c-3_i386.deb # service CommuniGate start # cat /var/CommuniGate/ProcessID
# wget ftp://www.communigate.com/pub/CommuniGatePro/6.1/CGatePro-Linux-Intel-616.tgz # tar -xvf CGatePro-Linux-Intel.tgz # mv CGateProSoftware/ /opt # CGateProSoftware/CommuniGate/CGServer-static --Base /var/CommuniGate --LogAll # cat /var/CommuniGate/ProcessID
# service communigate start
Postmaster Password: xxxxxx Main Domain Name: corpX.un Time Zone: Europa/Moscow Interface: Expert # cat /var/CommuniGate/Settings/Main.settings Settings->Network->Blacklisted IPs->UnBlacklistable (White Hole) IP Addresses: 172.16.1.0/24 # cat /var/CommuniGate/Settings/WhiteHoles.data
# echo Hello | /opt/CommuniGate/mail -s Hello postmaster@localhost # cat /var/CommuniGate/Accounts/postmaster.macnt/INBOX.mbox или # cat /var/CommuniGate/Accounts/postmaster.macnt/INBOX.mslc/data1
Users->Account Defaults->Mail Settings->Mailbox Storage->New Mailbox Format: Sliced # cat /var/CommuniGate/Settings/DomainDefault.settings Users->Domains->corpX.un->Account Defaults->Mail Settings->Mailbox Storage->New Mailbox Format: Sliced # cat /var/CommuniGate/Accounts/Settings/domain.settings Users->Domains->corpX.un->Objects->Template->Mail Settings->Mailbox Storage->New Mailbox Format: Sliced # cat /var/CommuniGate/Accounts/Settings/template.settings Users->Domains->corpX.un->Objects->postmaster->Mail->Mailbox Storage->New Mailbox Format: Sliced # cat /var/CommuniGate/Accounts/postmaster.macnt/account.settings
Users->Domains->corpX.un->Objects-> Create Account: user1 Real Name: Иван Иванович Иванов CommuniGate Password: cpassword1 # ls /var/CommuniGate/Accounts/user1.macnt/
Задание: назначить учетной записи postmaster свое ФИО, должность, телефон …
shell> telnet localhost 106 или shell> nc localhost 106
USER postmaster PASS Pa$$w0rd NOTIMEOUT LISTACCOUNTS corpX.un GETACCOUNTSETTINGS user1 GETACCOUNTDEFAULTS corpX.un GETACCOUNTEFFECTIVESETTINGS user1 GETACCOUNTINFO user1 CREATEACCOUNT user2 {Password = "cpassword2";RealName = "Петр Петрович Петров";} QUIT
Примечание: демонстрирует преподаватель
Примечание:
Name RealName Password user3 Сидор Сидорович Сидоров cpassword3 user4 Василий Муркович Кошкин cpassword4
Users->Domains->CreateDomain->compX.un Users->Domains->compX.un->Domain Settings->Domain Aliases: mail.compX.un
Users->Domains->compX.un->Objects->Create Account: user3 Real Name: Сидоров Сидор Сидорович CommuniGate Password: cpassword3 Users->Domains->compX.un->Objects->user3->Settings-> Access Rights->Can Modify This Domain and its Accounts Settings !!!И Все галочки TABом и пробелом!!! # less /var/CommuniGate/Domains/compX.un/Settings/access.settings GETACCOUNTINFO user3@compX.un
Users->Domains->compX.un->Domain Settings->Assigned IP Addresses->[172.16.1.200+X] Users->Domains->corpX.un->Domain Settings->Assigned IP Addresses->[172.16.1.100+X], [127.0.0.1]
http://172.16.1.200+X:8010/
mail.corpX.un. A 172.16.1.100+X mail.compX.un. A 172.16.1.200+X
Users->Domains->corpX.un->Security->SSL/TLS
PKI Services: Enable
Private Key Key Size: 1024
Generate Key Certificate Generator Common Name: mail.corpX.un Country: RU State/Province: Moscow region City: Mosсow Organization: cko Unit: noc Contact: postmaster@corpX.un
Generate Self Signed
Безопасность->SSL/TLS->Генератор Сертификатов->Имя-Идентификатор: mail.compX.un
Directory->Browser
Примечание: демонстрирует преподаватель
Чтение данных с аутентификацией
# ldapsearch -x -D "user1@corpX.un" -W -b"cn=corpX.un" -H ldaps://mail.corpX.un:636
Чтение данных без аутентификации
Directory->Access Rights Name: ReadAll Bind DN: anyone вместо uid=*
# ldapsearch -x -b"cn=corpX.un" -H ldap://mail.corpX.un:389
Directory->Units->Main->Schema Users->Directory Integration Public Info: telephoneNumber
Users->Domains->corpX.un->Domain Settings->Domain Aliases: mail.corpX.un Settings->Services->HTTPU->Listener Port 80 Init SSL/TLS Off Port 443 Init SSL/TLS On # cat /var/CommuniGate/Settings/HTTPU.settings
Примечание: при первом подключении установить само подписанный сертификат в базу данных доверенных сертификатов серверов в firefox
Users->Account Defaults->Preferences Users->Domains->corpX.un->Account Defaults->Preferences Users->Domains->corpX.un->Objects->postmaster->Preferences Language: Russian Layout: Basic|Crystal|Pronto Flash(Pronto4)|hPronto(Pronto) Пользователи->Домены->corpX.un->Объекты->postmaster->Настройки->Язык: ...(English)
Monitors->Access->Sessions KILLACCOUNTSESSIONS user1
На уровне сервера: Users->Skins На уровне домена: Users->Domains->corpX.un->Skins Create Custom Unnamed Skin Upload File: logo.gif # ls /opt/CommuniGate/WebSkins/ # ls /var/CommuniGate/WebSkins/logo.gif # ls /var/CommuniGate/Accounts/WebSkins/logo.gif
# find /opt/CommuniGate/WebSkins/ -type d Named Skins: Create: hPronto- Upload File: logo-big-fresh.png
# ls /var/CommuniGate/Accounts/WebSkins/russian.data
... LoginTag1 = "..."; LoginTag2 = "..."; ...
Дополнительное задание: Сделать то же самое через пользовательский интерфейс postmaster
Users->Domains->corpX.un->Skins->Named Skins->Create: mySkin # cat /var/CommuniGate/Accounts/WebSkins/mySkin/navigation.wssi
... <td nowrap="nowrap"><a href="mailbox.wssp?mailbox=INBOX&">%%HTML:SETTINGS("InboxDisplay")%%</a></td> <td nowrap="nowrap"><a href="mailbox.wssp?mailbox=Sent Items&">Sent Items</a></td> ...
mail.corpX.un. A 172.16.1.100+X corpX.un. MX 10 mail.corpX.un. mail.corpX.un. A 172.16.1.200+X compX.un. MX 10 mail.corpX.un.
$ gate.isp.un$ mail postmaster@corpX.un
# cat /var/CommuniGate/Settings/WhiteHoles.data Settings->Network->Client IPs: !172.16.1.254 172.16.1.0/24
Settings->Mail->SMTP->Receiving Verify Return-Path for: ... Check SPF records: ... Non-Client Sender Delay Prompt for: 10
gate.isp.un% mail user1@corpX.un gate.isp.un% tail -f /var/log/maillog
Settings->Router ... <director> = spamtrap ... gate.isp.un% mail user1@corpX.un director@corpX.un
Сейчас, если вы используете какой-нибудь из наших плагинов (Cloudmark иди SpamCatcher), то в файле hPronto-/strings.data в строках SpamFalseNegativeReportEmail и SpamFalsePositiveReportEmail можете указать адреса, куда перенаправлять неправильно определённые письма, например как в <http://www.communigate.com/CGPSpamCatcher/#rprt> Тогда в hPronto появятся кнопки для этого.
# usermod -G mail clamav # service clamav-daemon restart # clamdscan /var/CommuniGate/eicar.zip
# cat /etc/default/spamassassin
... OPTIONS="-m 10 -x -q -u mail -i 127.0.0.1 -p 783" ...
# wget http://program.farit.ru/antivir/cgpav-1.4.tar.gz # tar -xvf cgpav-1.4.tar.gz # cd cgpav-1.4/ # ./configure --with-antivirus=clamav --with-spamassassin=yes --with-cgpro_dir=/var/CommuniGate # make && make install # cat /var/CommuniGate/Settings/cgpav.conf
... # не добавляется, если письмо распознано как SPAM add_not_infected_header = true ... clamd_socket = /var/run/clamav/clamd.ctl ... enable_spamassassin = true ... spam_scan_local = true ... spamassassin_socket_type = tcp ...
# /var/CommuniGate/cgpav 1 FILE eicar.zip 1 DISCARD
Settings->General->Helpers->Content Filtering Enabled: ClamSpam Program Path: /var/CommuniGate/cgpav
# ps ax | grep cgpav
Settings->Mail->Rules Name: ClamSpam Action: ExternalFilter Parameter: ClamSpam
!!! Заработало только на уровне сервера, поправить !!!
GETSERVERMAILRULES SETDOMAINMAILRULES corp1.un ((5,spam,(("Header Field", is, "X-Spam-Status: Yes*")),(("Store in", "~postmaster/spam"), (Discard)))) GETDOMAINMAILRULES corpX.un
200 data follow ( ( 5, spam, (("Header Field", is, "X-Spam-Status: Yes*")), (("Store in", "~postmaster/spam"), (Discard)) ) )
Для домена compX пользователи которого заведены на сервере преподавателя
Settings->Router ... <*@compX.un> = *%compX.un@mail.isp.un.25.via ...
По окончании тестирования, удалить правила и список рассылки
Set Reply-To to Group: no
GETSERVERMAILRULES
200 data follow ( ( 6, mark_to_group1, ((Subject, "is not", "*[group1]*"), ("Any To or Cc", is, "*group1@corpX*")), (("Tag Subject", "[group1] ")), "Помечаем тему всех писем, идущих в группу" ), ( 4, replace_from_group1, ((Subject, is, "*[group1]*"), (To, "is not", "*group1@corpX*")), (("Add Header", "Reply-To: group1@corpX.un")), "Устанавливаем Reply-To в группу для всех ответов из группы" ) )
Папки->Создать->Почтовый Ящик->group1 Папки->pubic1->Управление Папкой Идентификатор->user2->Все галочки (задание для слушателей - найти описание прав в справке)
Папки->Управление->Псевдонимы Папок Имя Псевдонима: group1 Имя Папки: ~user1/group1
gate.isp.un% mail group1#user1@corpX.un mail.corpX.un# echo Hello | mail -s Hello group1#user1@corpX.un
Направление публичной почты в соответствующий ящик
По окончании тестирования, правило удалить
Settings->Router ... <group1@corpX.un> = group1#user1@corpX.un ...
Users->Domains-corpX.un->Objects->user1->Settings Aliases: group1
Управление Почтой Добавить Правило: Move to group1 Изменить Любой Кому/Копия: равно *group1* Записать в: group1 Выбросить
Пользователь user1 создает у себя в интерфейсе сертификат для подписи и шифрования и отправляет подписанное письмо по адресу postmaster@corpX.un
Подделать текст письма можно:
# vim /var/CommuniGate/Accounts/postmaster.macnt/INBOX.mbox
Задача: Предоставить доступ администратора (postmaster) к ящикам пользователей
Folders->Management->Folder Aliases Open Folder: ~user1/Sent Items
Задача: сохранять всю исходящую почту в особой папке у системного администратора или у сотрудника, отвечающего за безопасность.
# ldapsearch -x -D "cn=Administrator,cn=Users,dc=corpX,dc=un" -W -h server -b "dc=corpX,dc=un" "sAMAccountName=user100+X" # wget http://www.stalker.com/CGPerl/CLI.pm # mv CLI.pm /etc/perl/ # apt install libauthen-simple-ldap-perl # wget http://www.communigate.com/CGAUTH/authLDAPNewAD.pl
# cat authLDAPNewAD.pl
... my %domains=( # e-mail domains 'corpX.un' => { address=>'ldap://pdc.valtest.bmstu.ru:389', #the URI or address of LDAP server timeout=>5, # timeout in seconds, 20 by default adminDN=>'CN=Administrator,CN=Users,DC=corpX,DC=un', # the DN for admin bind adminPassword=>'Pa$$w0rd', searchBase=>'CN=Users,DC=corpX,DC=un', searchFilter=>'(&(sAMAccountName=<user>)(objectclass=*))', updatePasswords=>1, #if need to update CommuniGate internal password }, ); my $CGServerAddress = '127.0.0.1'; # You should redefine these values my $CLILogin = 'postmaster'; my $CLIPassword = 'Pa$$w0rd'; ...
# chmod +x authLDAPNewAD.pl
Settings->General->Helpers->External Authentication Program Path: /root/authLDAPNewAD.pl или Program Path: C:\Perl\bin\perl C:\var\CommuniGate\authLDAPNewAD.pl
# ps ax | grep authLDAPNewAD
Users->Domains->corpX.ru->Domain Settings Consult External for Unknown: Yes Consult External on Provision: Yes Users->Domains->corpX.un->Account Defaults->Settings External Password: Enabled
cat /root/AccountList.txt Name Password user100+X Pa$$w0rd100+X cd /opt/CommuniGate/Migration/ ./MoveAccounts --IMAP /root/AccountList.txt 172.16.1.254 127.0.0.1
C:\>ktpass -princ imap/mail.corpX.un@CORPX.UN -mapuser cgatepro -pass Pa$$w0rd -out keytab.data -crypto RC4-HMAC-NT -ptype KRB5_NT_SRV_HST
Задача: Аутентификация доступа пользователей в Internet
Settings->Services->RADIUS Password: testing123 Channels: 3 Listener Port: 1812
# radtest user1 'cpassword1' mail.corpX.un 0 testing123
Users->Domains->corpX.un->PBX->Create Custom Enviroment Languages->Create: Russian select russian
!!! Upload tar файлов из архива !!! # ls CGateProSoftware/CommuniGate/PBXApps/ # ls /var/CommuniGate/Accounts/PBXApps
S:<6363@*> = gatewayincoming{pbx,media}#pbx
Users->Domains->corpX.un->Objects->user2->Settings Aliases: 402
Users->Domains->corpX.un->Objects->user1->Status или GETACCOUNTINFO user1 KEY SIPContacts 200 data follow ( { "" = "sip:user1@195.19.35.219:5060"; @regdata = { Allow = (ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, REFER); CSeq = #68190; Call-ID = 3498b62-d4014eab@195.19.35.219; Supported = (x-sipura); User-Agent = "Linksys/SPA3102-3.3.6(GW)"; }; Expires = #T14-10-2014_05:30:41; } )
Settings->Real-Time->Signals Record Call CDRs: yes # ls /var/CommuniGate/SystemLogs/CDRs/
Settings->Router ... Signal:<echotest@*> = echotest#pbx@localhost ; testing address ...
pbx - пользователь
Users->Domains->corpX.un->Objects->pbx->Settings->Access Rights Can Modify This Domain and its Accounts Settings Can Access All Files Can Impersonate Can Administer Other Domains
Users->Domains->corpX.un->Object->pbx->Real-Time->Advanced Department Menu: Custom: techsupport conference Directory Prefix: 4 - с какой цифры внутренний план нумерации Directory Digits: 3 - длина номера внутреннего плана нумерации
пункт techsupport - можно заменить на свое название, например abcd для озвучивания пункта необходимо загрузить файл forabcd.wav через Users->Domains->corpX.un->PBX
Для пере направления вызова сотрудникам необходимо включить их в одноименную с пунктом меню группу. Users->Domains->corpX.un->Objects->Create Group: techsupport Members: user1 Members: user2
Пользователю необходимо позвонить на свой номер и записать приветствие, далее из своего веб интерфейса выполнить: Управление Звонками->Голосовая Почта->После: 10 сек
Вариант1: Позвонить на номер 200, создать конференцию, получить по почте номер конференции, разослать этот номер всем участникам, через номер 200 подключиться вместе со всеми.
GETACCOUNTINFO pbx KEY Meetings ...
Вариант2: Создать событие, у которого место проведения (Location) установлено в phone или conference, а в качестве участников перечислены аккаунты.
GETACCOUNTINFO user1 KEY Meetings ...
Users->Domains-corpX.un->PBX->russian Upload File: sayhello.sppr или # cat /var/CommuniGate/Accounts/PBXApps/russian/sayhello.sppr
entry main is var errCode = AcceptCall(); if isString(errCode) then syslog("Failed to accept the call: " + errCode); else PlayFile("blank", 500); // 0.5 sec of silence PlayFile("Welcome"); end if; end entry;
Users->Domains-corpX.un Create Forwarder: 301 Forward To: sayhello#pbx
pbx - имя аккаунта от которой запускается приложение sayhello
# cat /var/CommuniGate/Accounts/PBXApps/russian/sayhello_cb.sppr
entry main is var data = Vars().startParameter[0]; syslog("Will call to " + ObjectToString(data)); var errCode = StartCall(EmailToSIPURI(data)); if isString(errCode) then syslog("Call failed: " + errCode); stop; end if; loop data = ReadInput(10); exitif isCallCompletedEvent(data); end loop; if isConnected() then PlayFile("blank", 500); PlayFile("welcome"); PlayFile("blank", 500); PlayFile("goodbye"); end if; end entry;
STARTPBXTASK pbx PROGRAM sayhello_cb PARAM ("401")
В приложении пример скрипта, реализующего b2bua в режиме бриджа (не миксера) и позволяющего с помощью DTMF команд выполнить перевод звонка без сопровождения (blind transfer). Данный скрипт воспринимает DTMF команды, посланные как SIP INFO запросы, а не в медиа канале (например, в hPronto на странице Preferences → Dialer опцию “Sending Method” нужно установить в signal). Если нужно, чтобы DTMF команды работали и в том случае, когда они посылаются в голосовом канале (rfc2833 или inband), то нужно подключать стороны через миксер, а не через бридж, для этого нужно немного модифицировать часть скрипта до вызова процедуры bridgedCallLoop().
Пожалуйста, дайте нам знать, если потребуется помощь в модификации скрипта для подключения сторон с использованием миксера (чтобы обрабатывать DTMF, отправленные как inband или rfc2833).
Сам механизм перевода следующий. При установлении соединения каждый из участников может набрать #nnnn (4-значный номер), чтобы дать сигнал для перевода партнера на 4-значный номер nnnn. После удачного перевода инициатор перевода будет отсоединен. На набор каждой цифры номера дается не более 5 секунд. Если за это время не было введена цифра, то перевод не осуществляется и нужно будет заново набирать #nnnn для осуществления попытки перевода (см. комментарии в скрипте). Также в процессе набора номера, если уже ошиблись, можно набрать *, чтобы начать набор #nnnn заново.
Логику меню набора номера для перевода можно адаптировать.
Приложение b2bua-transfer.sppr нужно закачать в PBX окружение (в WebAdmin → Users → PBX). Для направления звонков в это приложение лучше использовать серверное сигнальное правило, потому что при направлении через запись в маршрутизаторе нужно будет вводить префиксы, чтобы не было зацикливания.
Серверное сигнальное правило может выглядить примерно так:
Data Operation IS INVITE Call Type IS AV Submit Address IS NOT LOCAL [0.0.0.0]* Target Address IS sip:*@domain.name Action Redirect To b2bua-transfer#pbx@domain.name Discard Rules
Здесь первые три условия стандартные, третье условие позволяет избежать зацикливания данного правила, так как оно не будет применяться для звонков, инициированных PBX приложением (то есть для вызова из исходящей ноги Caller приложения правило уже применяться не будет). Далее нужно прописать набор условий (например, Target Address), которые будут задавать набор адресов отправителей и получателей звонка, для которых должно запускаться это приложение с логикой перевода через DTMF. В примере выше правило будет запускаться для всех номеров получателей в домене domain.name. В логике скрипта можно дополнительно добавить проверку, чтобы пользоваться данными DTMF командами могли только локальные пользователи, а не внешние и т.п.
Скрипт приведен как пример, он тщательно не тестировался, но функционал трансфера проверили - работает. Если будут какие-либо ошибки или вопросы по его использованию, пожалуйста, обращайтесь.
// ================================================== // // simple B2BUA application // // supporting DTMF commands // // ================================================== // entry Caller forward; procedure bridgedCallLoop(peerLeg) forward; function transferTo(numDigits) forward; procedure doSysLog(str) {SysLog("B2BUA: " + str);} // // ingress task entry // entry Main { var callParams = NewDictionary(); callParams.("") = LocalURI(); callParams.fromName = RemoteRealName(); callParams.From = RemoteURI(); callParams.("Call-ID") = PendingRequestData("Call-ID") + ".b2b"; callParams.("Max-Forwards") = PendingRequestData("Max-Forwards")-1; callParams.customIdentity = ""; doSysLog("callParams: " + callParams.objectToString()); var peerLeg = spawn Caller(callParams); if(!IsTask(peerLeg)) { doSysLog("failed to spawn Caller task"); RejectCall(peerLeg); stop; } var errorCode = StartBridge(peerLeg); if(errorCode != null) { void(SendEvent(peerLeg,"stop",errorCode)); doSysLog("call failed: " + errorCode.string()); RejectCall(errorCode); stop; } bridgedCallLoop(peerLeg); stop; } // // egress task entry // entry Caller { var peerLeg = Vars().parent, callParams = Vars().startParameter, bridgeEvent,input,errorCode; void(Impersonate(SIPURIToEmail(callParams.From))); void(SignalOption("refer","peer")); void(SignalOption("bridgeBreak","disconnect")); bridgeEvent = ReadInput(10); if(!IsStartBridgeEvent(bridgeEvent) || bridgeEvent.sender != peerLeg) {doSysLog("unexpected start event: " + bridgeEvent.objectToString()); stop;} errorCode = StartBridgedCall(callParams,bridgeEvent); if(errorCode) {RejectBridge(bridgeEvent,errorCode); stop;} while(true) { input = ReadInput(3600); exitif !IsCallProvisionEvent(input); } if((IsDictionary(input) && input.what == "stop") || IsBreakBridgeEvent(input)) {stop;} if(!IsCallCompletedEvent(input)) { doSysLog("unexpected event: " + input.objectToString()); errorCode = "unexpected event"; } elif(input.parameter != null) { doSysLog("call failed: " + input.parameter); errorCode = input.parameter; } if(errorCode) {RejectBridge(bridgeEvent,errorCode); stop;} bridgedCallLoop(peerLeg); stop; } // // Main loop: processing events and DTMF commands in the connected state // procedure bridgedCallLoop(peerLeg) { if(!IsTask(peerLeg)) {return;} while(IsConnected()) { var input = ReadInput(60); doSysLog("main loop INPUT: " + (input.string() || "NULL")); if(input == "#") { input = transferTo(4); // after "#" enter 4-digit number to transfer the call to if(IsString(input)) { void(SendEvent(peerLeg,"peerTransfer",input + "@" + MyDomain())); input = null; } } if(input == null) { null; } elif(IsDictionary(input) && input.sender == peerLeg && input.what == "peerTransfer" && IsString(input.parameter)) { var transferError = TransferCall(input.parameter); if(transferError == null) { doSysLog("call transferred to: " + input.parameter); Disconnect(); } else { doSysLog("transfer failed: " + transferError.string()); } } elif(IsDisconnectEvent(input) || IsBreakBridgeEvent(input)) { void(SendEvent(peerLeg,"stop","disconnected")); Disconnect(); } elif(IsDictionary(input) && input.what == "stop") { Disconnect(); } elif(IsString(input)) { void(SendEvent(peerLeg,"dtmf",input)); } elif(IsCallInfoEvent(input)) { doSysLog("relaying INFO received: " + input.objectToString()); void(SendEvent(peerLeg,"info",input.parameter)); } elif(IsDictionary(input) && input.what == "dtmf") { void(SendDTMF(input.parameter)); } elif(IsDictionary(input) && input.what == "info") { void(SendCallInfo(input.parameter)); } else { doSysLog("unknown event: " + input.objectToString()); } } return; } // // Entering a number with 'numDigits' digits, 5-second timeout to enter one digit. // If entered number has less than 'numDigits' digits, do nothing and return back to the main loop. // If '*' is entered, return back to the main loop immediately without waiting of 5-second timeout. // After returning to mail loop one can enter the '#' again and make another attempt to enter the number to transfer the call. // function transferTo(numDigits) { var buffer = ""; if(!IsNumber(numDigits) || numDigits <= 0) {return null;} for(var i = 0; i < numDigits; i += 1) { var input = ReadInput(5); doSysLog("transfer INPUT: " + (input.string() || "NULL")); if(input == null || input == "*") { // return to the mail loop where one can make another attempt to enter #nnnn return null; } elif(IsDigit(input)) { buffer += input; } else { // unexpected event, for example, Disconnect or BreakBridge event return input; } } return buffer; // return the entered number with 'numDigits' digits }
Settings->Router ... S:<1(2d)@*> = 1*@192.168.1.3 ;smg1016 S:<0X(3d)@*> = *@mail.corpX.un ...
Settings->Router ... <8(10d)@*> = 8*@telnum <+7(10d)@*> = +7*@telnum ;<+(7-20d)@*> = +*@telnum ; +nnnnn calls -> to telnum ;... ... Signal:telnum = pstn ; unknown telnum -> PSTN Signal:<*@pstn> = gatewaycaller{*}#pbx ; start 'gatewaycaller' app ... Users->Account Defaults->PSTN или Users->Domains->corpX.un->Account Defaults->PSTN или Users->Domains->corpX.un->Objects->user1->Real-Time->PSTN Gateway Domain: voip1.un Name for Gateway: 00000X Password for Gateway: spasswordX
Users->Domains->corpX.un->Objects->pbx->Real-Time->RSIP Name: voip1 Register Every: 5 min Account: 00000X at Host: voip1.un Authentication Name: 00000X Password: spasswordX Target: GETACCOUNTRSIPS pbx 200 data follow { sipnet = { authName = 00000X; domain = voip1.un; fromName = 00000X; password = spasswordX; period = 5m; }; } Users->Domains->corpX.un->Objects->pbx->Real-Time->Incoming Call Rules->Edit Redirect To is #pbx
Доступ: http://corpX.un/~user1
Местоположение и файл по умолчанию
# cat /var/CommuniGate/Accounts/user1.macnt/account.web/default.html
Доступ по имени http://user1.corpX.un (WebURL)
Settings->Router ... mail.corpX.un = corpX.un *.corpX.un = *@fict <LoginPage%*@fict> = *
Приложение Web Callback
STARTPBXTASK pbx PROGRAM rendezvous PARAM ("401","8916XXXXXXX")
Users->Skins->Upload File: webcallback.wcgp или # cat /var/CommuniGate/WebSkins/webcallback.wcgp
entry sysEntry is SetHTTPResponseType("text","html"); SetHTTPResponseCode(200); var phone = GetHTTPParameter("phone"); var operatorphone = "401"; var data = ""; var cmd = ""; if not isString(phone) then data = "<h1>Enter phone number</h1><form action=webcallback.wcgp><input name=phone><input type=submit></form>"; else cmd = "STARTPBXTASK pbx PROGRAM rendezvous PARAM(\"" + phone + "\",\"" + operatorphone + "\")"; data = "<h1>Waiting call on phone " + phone + "</h1>"; var errCode = ExecuteCLI(cmd); end if; SetHTTPResponseData(data); end entry;
http://mail.corpX.un/sys/webcallback.wcgp
Monitors->Logs # tail -f /var/CommuniGate/SystemLogs/`date '+%Y-%m-%d'`.log
Settings->General->Triggers Events httpAdminAuthFailed: ... failedAUTHs: ... Handlers Send URL: https://rest.nexmo.com/sms/json?api_key=e5610a90&api_secret=1d98ff2a&from=NEXMO&to=79164115716&text=mail.corpX.un+par+^0+val+=+^2
Параметр ^1 возвращает строку с пробелом, которая некорректно передается от CGP к NEXMO
Надо прописать его в Settings → Real-Time → SMPP server smpp0.nexmo.com:8000, SystemID и Password - из аккаунта на nexmo (api_key и api_secret).
GETMODULE SMPP
my $error = $cli->SendCommand('SetStatElement 1.3.6.1.4.1.5678.2.1.1000.1 SET '.$value);
> Здравствуйте. > > Подскажите, есть ли возможность средствами CGP перенаправлять подключения пользователей к > > http://student.bmstu.ru > > на > > https://student.bmstu.ru Да, конечно. Страничку login.wssp в дефолтном скине домена надо подправить, добавить что-то типа <!--%%IF NOT(REQUESTSECURE() | "YES") --><META HTTP-EQUIV="Refresh" CONTENT="0; URL=https://%%domainName%%"><!--%%ENDIF--> Со стандартным вариантом login.wssp можно поступить так: <!--%%IF secureChannel --> the standard login.wssp data <!--%%ELSE --> <HTML> <HEAD> <META HTTP-EQUIV=REFRESH CONTENT="0; url=https://%%domainName%%/"> <TITLE>Redirecting to secure interface</TITLE> </HEAD> </HTML> <!--%%ENDIF-->
Такое может произойти. если из директории аккаунта без ведома сервера были удалены почтовые папки. Проверьте соответствие списка папок в account.info куальному содержимому этого аккаунта. Можно просто удалить account.info (и, желательно, перезапустить сервер, потоьу что содержимое может кэшироваться в памяти) Сервер потом сам перечитает папки и воссоздаст строчки для них.