Автоматический обзвон абонентов, Asterisk автообзвон

Для этого нам понадобиться asterisk, ну и если ваш скрипт будет работать с базой тогда mysql

Конфигурация файлов asterisk


extensions.conf
Создадим контекст auto_dial, в котором опишем что и как мы проигрываем, и куда направляем исходящий вызов.

Код
[auto_dial]
exten => _X.,1,Dial(SIP/provider/${EXTEN:1})


Теперь проигрываем записанную запись
exten => s,1,Playback(Demo); - запись можно записать в формате mp3

Далее остается написать скрипт который будет создавать outgoing файлы.

Hам нужно будет помещать файлы в каталог /var/spool/asterisk/outgoing/, с таким содержанием
Channel: LOCAL/2222222@auto_dial - 2222222 -это телефон на который asterisk будет звонить и проигрывать demo.mp3.
CallerID: Ваш телефон - телефон который будет отображаться у него при определении
MaxRetries: 2
RetryTime: 10
WaitTime: 60
# MaxRetries: <number> количество попыток перезвонить
# RetryTime: <number> время между попытками перезвонить
# WaitTime: <number> сколько секунд ждать пока абонент ответит
Context: auto_dial
Extension: s
Priority: 2

Пример скрипта.
#!/usr/local/bin/perl
$file = "/var/spool/asterisk/outgoing/$ARGV[0]";
$phone = $ARGV[0];
open(FILE, "> $file");
print FILE "Channel: LOCAL/".$phone."\@auto_dial\n";
print FILE "CallerID: 5555555\n";
print FILE "MaxRetries: 2\n";
print FILE "RetryTime: 10\n";
print FILE "WaitTime: 60\n";
print FILE "Context: auto_dial\n";
print FILE "Extension: s\n";
print FILE "Priority: 2\n";
close(FILE);

Пример extensions.conf
[auto_dial]
exten => _X.,1,Dial(SIP/DenyaTelecom/${EXTEN:1})
exten => s,1,Playback(demo-congrats)

Это самый просто пример, который только показывает как это работает, вы вызываете этот скрипт вместе с телефоном на который нужно позвонить, пример:
./script.pl 8689390

То же самое на php, если нужно обзвонить пул номеров:
#!/usr/bin/php -q
<?php

$callto=111111; #первый номер списка
while ($callto<222222)
{
$callfile="/work/tmp/calls-".$callto.".call";
$cf =fopen($callfile,"w+"); 
fputs($cf,"Channel: SIP/".$callto."@trunkname\n");
fputs($cf,"Callerid: Your_callerid\n");
fputs($cf,"application: Playback\n");
fputs($cf,"Data:/work/zapisi\n");
fclose($cf);
copy($callfile,"/asteriskpath/var/spool/asterisk/outgoing/".$callto."call");
$callto=$callto+1;
if ($callto % 10 ==0) 
{
sleep(60); 
}
}
?>

sleep — для ограничие количества одновременных звонков

Как узнать модель материнской платы в Windows

Жмем Win-R, набираем cmd в открывшемся окне командной строки набираем
wmic baseboard get manufacturer, product

Результат например такой
C:\>wmic baseboard get manufacturer, product
Manufacturer  Product
Foxconn       H61MXE

Что мы еще можем собрать этим способом, например вот что:
Посмотреть объём памяти
wmic COMPUTERSYSTEM get TotalPhysicalMemory,caption

Посмотреть физически подключенные диски
wmic diskdrive get name,size,model

Посмотреть логические разделы на дисках
wmic volume WHERE DriveType=3 list brief

Просмотр информации о процессоре
wmic cpu get name, maxclockspeed

Просмотр информации о памяти
wmic MEMORYCHIP get banklabel, capacity, caption, devicelocator, partnumber

Скачать hyper terminal на Windows 7, 8, 8.1, 10

Судя по запросам в поисковике тема еще актуальна, поэтому повторюсь. Скачать hyper terminal на Windows 7 (8, 8.1, 10) можно на этом сайте. Это та же программа, что была в Windows XP. Я Скопировал с XP 2 файла hypertrm.dll, hypertrm.exe и выложил на этом сайте. Кому нужны эти файлы, качайте.
HyperTetminal Windows 7 8 8.1 10

Скачать hypertrm.rar (hypertrm.dll, hypertrm.exe)

Ограничение входящих вызовов в Elastix (Asterisk)

Ограничить исходящие вызовы через SIP транк легко, для этого есть опция
call-limit=N

Но для входящих вызовов нужно использовать счетчик количества вызовов в диалплане. В случае чистого астериска это выглядит так:
exten => 559558,1,Set(GROUP()=group1)  ; Объединяем вызовы в группу
exten => 559558,n,Set(CALLS1=${GROUP_COUNT(group1)})  ; Считаем сколько вызовов в группе
exten => 559558,n,NoOp(${CALLS1})  ; Выводим в консоль счетчик (хотя строка выше и так должна вывести счетчик)
exten => 559558,n,ExecIf($[ ${CALLS1} > 4 ]?Hangup(34)) ; Если вызовов больше 4, сбрасываем. 34 это код отбоя  
exten => 559558,n,Dial(sip/101/${EXTEN},20)  ;  Отправляем вызов дальше

В случае с Elastix нужно добавить подобные строки в файл extensions_override_elastix.conf.
Читать дальше →

Do You Know That? Как раскрывается "${array[@]}" и "${array[*]}"

Оказывается, в зависимости от режима интерполяции, внутри двойных кавычек массивы раскрываются принципиально по разному:

  • В случае с "${array[*]}" — массив интерполируется в один аргумент (одну строку), представляющий собой результат простой конкатенации всех элементов массива через пробел
  • В случае "${array[@]}" — каждый элемент массива становится отдельным аргументом так, словно каждый элемент взял себе внешние двойные кавычки, что уберегло его от дробления по пробельному символу (точнее, по IFS)

Тестовый пример:

Читать дальше →

Вдогонку к Tips&Tricks'у #10h

Конечно же, для функции join2 должна быть и комплементарная split.

Учитывая то, что просто split — это «split a file into pieces», а также принимая во внимание тот факт, что split-функция всё-таки будет писать в переменную-массив, а не просто на STDOUT, я добавил к привычному имени циферку 2, дабы получилось у нас «SplitTo (the) arrayName».

Ну а теперь код:

split2 () {
        local arrName=$1
        [[ $arrName =~ ^[0-9_A-Za-z]+$ ]] || return 1
        local delim=$2
        shift 2
        local args
        while (( $# )); do
         args+=${args:+$delim}$1
         shift
        done  
        readarray -t $arrName < <(echo -n "${args//$delim/$'\x0a'}")
        return $?
}


Пример использования:

split2 dir '/' '/usr/share/doc/LaTeX' 'a/b' 'c/d/e f g/h'
declare -p dir
# OUTPUT:
# declare -a dir='([0]="" [1]="usr" [2]="share" [3]="doc" [4]="LaTeX" [5]="a" [6]="b" [7]="c" [8]="d" [9]="e f g" [10]="h")'


Enjoy! :)

BASH Tips&Tricks #0010: И на BASH'е будут join'иться массивы!

Когда я пишу на Perl, у меня буквально всё под рукой. Кое-что даже мешается и заставляет постоянно проверять кусочки кода в командной строке (perl -e или perl -E), дабы сделать полёт моей фантазии более комфортным и безопасным для здоровья разрабатываемой софтины.

Когда я пишу на BASH, мне, конечно же, многого не хватает: необъятные возможности работы с текстом в Perl'е накладывают свой отпечаток на отношение к другим языкам. Кое-что приходится терпеть, но многое вполне можно исправить, предоставив самому себе привычное окружение, пусть и несколько… задумчивое («бытует мнение», что в случае с BASH скоростью работы обычно можно пренебречь).

Так случилось и с функцией join, которой мне всегда так не хватало в BASH. Я, конечно же, говорю не о той join, которая «join lines of two files on a common field», а об одноимённой функции Perl, «склеивающей» элементы массива (если быть точным, то всё-таки «вектора») в строку.

Я долго терпел сие неудобство и всячески его игнорировал, но… в какой-то момент терпение моё лопнуло, и я решился на сотворение мира в атомарных масштаба. По итогам краткого ознакомления с бесплодными исканиями на StackOverflow и захватывающе познавательного обсуждения join-вопросов с умными людьми © на linux.org.ru, мною был исторгнут приведённый ниже код:

join2 () {
 (( $# == 2 || $# == 3 )) || return 1
 local delim=$1
 local arrName=$2
 local join2var=$3
 local v
 for v in ${join2var:+join2var} arrName; do
  [[ ${!v} =~ ^[_0-9A-Za-z]+$ ]] || return 2
 done
 [[ $join2var ]] || join2var='v'
 source <(
        cat <<SOURCE
         printf -v $join2var "%s${delim}" "\${$arrName[@]}" || return \$?
         [[ \$delim ]] && $join2var=\${$join2var:0:-${#delim}}
SOURCE
 )
 (( $# == 2 )) && echo "$v"
 return 0
}


Бесспорно, он (код) как всегда великолепен и безупречен… пока мною же не будет доказано обратное :)

Квинтэссенция сути функции join2 (звучит как «Join To») заключается в том, что встроенная команда BASH printf понимает конструкцию ${arr[@]} не как уже интерполированную строку из элементов массива, объединённых абы чем (пробелами), но как именно набор элементов. Что эта белиберда значит? А то, что если какой-либо элемент массива уже содержит пробелы, а его объединят пробелом с элементом соседним, printf всё равно «увидит» каждый элемент в отдельности.

Пользоваться join2 можно двояко:
  1. 
    declare -a arr=('a b c' 'd e f' 'g h i')
    join2 '///' arr
    

    — и в этом случае результат конкатенации элементов массива будет «выведен на экран», то есть отправлен на STDOUT, где его легко подобрать так:
    str=$(join2  '///' arr)


    ИЛИ… (барабанная дробь, фанфары!)
  2. 
    declare -a arr=('a b c' 'd e f' 'g h i')
    join2 '///' arr str
    echo "$str"
    

    — а в этом случае название функции окажется весьма неслучайным, поскольку результат join'а запишется сразу в переменную str.

Cакральное знание об особенностях работы printf с массивами в BASH нагло сп скромно почёрпнуто из Yet Another BASH FAQ'а.

Пример преобразования форматов на BASH 4

Если кто-нибудь скажет Вам, что BASH — это какой-то недостойный внимания недоязык для написания циклов из командочек, киньте ему ссылку на данный пример.

Пример совсем несложный, я только что написал его для StackOverflow (где, к сожалению, люди всё ещё живут в криогенных камерах, не ведая о существовании BASH 4-й версии):

#!/bin/bash
inFile=$1
outFile=$2

join () {
 local del=$1
 shift
 IFS="$del"
 source <(
        cat <<SOURCE
 echo "\${$1[*]}"
SOURCE
 ) 
 unset IFS
}

declare -a CSV=('"Module Name","Module Group","Module Version"')
declare -a keysAccepted=('Name' 'Group' 'Version')

declare -i nMandatoryKeys=${#keysAccepted[@]}
declare -A KeyFilled
rxKeysAccepted='('$(join '|' keysAccepted)')'
while read line; do
        [[ $line =~ \<strong\>Module\ $rxKeysAccepted:\</strong\>[[:space:]]*([^<]+)\</p\> ]] || continue
        key=${BASH_REMATCH[1]}
        val=${BASH_REMATCH[2]}
        KeyFilled[$key]=$val
        if (( ${#KeyFilled[@]} == nMandatoryKeys )); then
                unset csvLine
                for k in ${keysAccepted[@]}; do
                        csvLine+=${csvLine:+,}${KeyFilled[$k]}
                done
                KeyFilled=()
                CSV+=($csvLine)
        fi
done <"$inFile"

(( ${#CSV[@]} > 1 )) || exit 1

join $'\x0a' CSV >"$outFile"


BASH-скрипт состоит из sed'ов, awk и grep'ов?
Давайте подсчитаем количество вхождений того, другого и третьего в данном примере!

Не спорю, тот же самый код на Perl, лучшем языке для работы с текстами, получился бы и короче намного, и быстрее.

Но, например, не нагляднее (Perl немного провоцирует писать супер-лаконичную абракадарбру). А является ли свойством BASH как языка программирования его действительно порой раздражающая медлительность — это ещё большой вопрос.

Do You Know That? Особенности mkdir -p

Утилита mkdir из GNU coreutils (во всех Linux) отличается следующими особенностями работы в режиме создания иерархии каталогов «на лету»:

  1. Если целевой каталог существует — mkdir с ключом -p не только не сообщит Вам об этом, но и не вернёт код ошибки
  2. Если добавить ключ -v (verbose) впридачу к -p — mkdir сообщит на STDOUT о каждом созданном ею каталоге. Именно по отсутствию какого-либо вывода в режиме -vp легко понять, что целевой каталог уже существовал на момент попытки его создания
  3. Всем создаваемым каталогам, кроме целевого, будет присвоена маска доступа, установленная umask (или действующая по умолчанию), а не та, которую Вы укажете в качестве значения для ключа -m утилиты mkdir/ Тем не менее, если Вы всё же укажете маску значением ключа -m, она будет использована при создании целевого каталога

Получение информации о процессах в стиле BASH 4

При написании BASH-скриптов распространённой практикой является считывание любой информации о процессах с помощью утилиты ps в сочетании с awk. В большинстве случаев это делается не ради кроссплатформенности (ps весьма ограниченно кроссплатформенна), а просто в силу непонимания возможностей BASH и принципиального отсутствия желания писать на нём более-менее «традиционный» код вместо нагромождения pipe'ов.

В данном посте я покажу, что код на BASH может оперировать вполне «традиционными» собственными структурами данных — и при этом с минимальным использованием внешних утилит.

Читать дальше →

Используем PowerShell для получения информации о профиле пользователя

Резюме: Microsoft Scripting Guy, Ed Wilson рассказывает о том, как получить информацию о пользовательском профиле посредством Windows PowerShell.

Получаем информацию о профиле


Для того, чтобы получить информацию о профиле, нам необходимо запросить класс WMI Win32_UserProfile. Для этого я воспользуюсь командлетом Get-WmiObject (gwmi – его алиас).

gwmi win32_userprofile

Команда и ее вывод приведены на рисунке.



Вывод по умолчанию содержит множество ненужной мне в данный момент информации. Что мне сейчас нужно, так это свойства LastUseTime, LocalPath и SID. Слегка измененный запрос приведен ниже.

Читать дальше →

Как собрать все файлы deb-пакета в tar-архив?

Если у вас есть устанволенный deb-пакет и хочется аккуратно собрать все его файлы в архив TAR, то сделать это можно вот так:


PACKAGE='libmysqlclient-dev'
tar -cjf /tmp/$PACKAGE.tbz2 -T <(while read f; do [[ -d $f ]] || echo "$f"; done < <(dpkg -L $PACKAGE))


Бывает, что права root'а недоступны, пакеты deb вы нормальным образом установить не сможете (в том числе и любые инструменты сборки из исходников) и тогда подобный «перенос в tar-архивах» становится единственной возможностью для работы в сильно стеснённых условиях. При этом если вы оставите все пересённые tar-архивы на целевой системе, то сможете с помощью опции -t получить список файлов архива и, соответственно, при необходимости вычистить ненужное.

Этакая эмуляция «пакетной системы» Slackware получается :)

Microhint: Загрузка модуля OpenLDAP требует 2 файла, а не 1!

Модули, содержащиеся в contrib исходных кодов openldap'а (и любые другие), требуют для своей загрузки не только файл с расширением ".la", но и соответствующий файл с расширением ".so", лежащий в одном каталоге с ".la".

Проблема может возникнуть из-за того, что неторопливсые люди наподобие меня могут получить в результате простого make'а соответствующего модуля файл с расширением ".la", скопировать его в каталог olcModulePath, радостно попытаться модуль подгрузить olcModuleLoad'ом и… получить «file not found» в логах, который по какому-то глупому недоразумению разработчиков OpenLDAP ссылается не на нехватку ".so", а на якобы отсутствие ".la". Но вы-то знаете, что этот файл на самом деле есть!
А в действительности файлик с расширением ".so" создаётся make install'ом, и без него модуль грузится не будет.

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

Простейший hexdump, который делает именно то, что вам нужно

Хотите просто получить шестнадцатеричный дамп файла, при этом не занимаясь контрпродуктивным подбором опций командной строки для hexdump, который, как известно, вне зависимости от того, о чём вы его просите, всегда готов любезно сделать что-нибудь «совсем не то»?

Воспользуйтесь простейшим однострочником на Perl:

perl -e 'do { local $/; print unpack("H*",<>) }'  <FILE


Всё гениальное — это просто Perl!

P.S. То есть нет, простите,
«Всё гениальное — это просто Perl!» ©

Сжатие LOG файла в MS SQL Server по расписанию

Сжать базу логов можно с помощью shrink. Если у вас модель восстановления простая, то базу можно сразу сжимать. У меня полная, поэтому буду сначала менять модель восстановления:
Скрипт shrinkms.sql (его будем вызывать из следующего скрипта)
USE  [DBname];
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE  [DBname]
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 10 MB.
DBCC SHRINKFILE ( [DBname]_Log, 10);
GO
-- Reset the database recovery model.
ALTER DATABASE  [DBname]
SET RECOVERY FULL;
GO

Скрипт для планировщика shrink.cmd
sqlcmd -S [SERVERNAME] -U [USERNAME] -P [PASSWORD] -i c:\db\shrinkms.sql

Автоматическое создание резервных копий MS SQL Server

Я не стал пользоваться разными программами для резервного копирования и встроенными средствами, сделал скрипт и повесил его в автоматическое выполнение ночью.
Скрипт backupms.sql (его будем вызывать из следующего скрипта)
DECLARE @pathName NVARCHAR(512) 
SET @pathName = 'c:\db_backup_' + Convert(varchar(8), GETDATE(), 112) + '.bak' 
BACKUP DATABASE [DBname] TO  DISK = @pathName WITH NOFORMAT, NOINIT,  NAME = N'db_backup', SKIP, NOREWIND, NOUNLOAD,  STATS = 10

Скрипт для планировщика backup.cmd
sqlcmd -S [SERVERNAME] -U [USERNAME] -P [PASSWORD] -i c:\db\backupms.sql
copy /y c:\db_backup*.bak Z:\1c-back\
del /f c:\db_backup*.bak

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

Модификация поля, имеющего "номер в фигурных скобочках"

«Люди часто спрашивают меня», как изменить значение одного из полей объекта, если это поле многозначное?
Ответ на этот вопрос элементарен, как 3 копейки:

dn: cn=object,dc=domain,dc=com
changeType: modify
delete: attrType
attrType: SOME_OLD_VALUE
-
add: attrType
attrType: SOME_NEW_VALUE

Но после этого всё те же люди, которые часто спрашивают, озадачивают меня таким пожеланием: а вот есть поля типа olcAccess, которые хотелось бы изменять, не указывая полностью их старое значение, а указывая один лишь только их «номер», который в фигурных скобочках, то… что же нам делать?

«За чем же дело стало, господа?» — отвечу я им!

dn: cn=object,dc=domain,dc=com
changeType: modify
delete: olcAccess
olcAccess: {2}
-
add: olcAccess
olcAccess: {2}to * by * none


Вот и вся недолга: при модификации поля с автоматически созданным «порядковым номером» можно не указывать его старое значение полностью. И это хорошо :)

Простенький пример использования Moo

Неожиданно выяснил, что документации по модулю Moo, делающему возможным «ООП с человеческим лицом» в Perl практически нет, а та, что есть — вообще почему-то платная (?! я сам был удивлён весьма).

Для того, чтобы хоть немного ликвидировать столь странный «пробел» я написал по итогам нескольких часов «изучения» Moo маленький пример, которым и хочу с вами, мои дорогие читатели, поделиться:

Читать дальше →

Elastix съедает всю память

Есть у Elastix особенность, периодически память заканчивается и asterisk начинает тормозить. Для очистки памяти добавьте в cron задание:
echo 3 > /proc/sys/vm/drop_caches

Периодичность в зависимости от скорости заполнения памяти

Уведомления о пропущенных вызовах в Asterisk (Elastix 2.4)

Озадачился простейшей вроде задачей, уведомлением о пропущенных звонках. Как оказалось «из коробки» в Elastix не выберешь даже просто пропущенные вызовы. Все потому, что все вызовы попадают в очередь, где сразу помечаются как отвеченные. Так, что если вам нужно выбрать пропущенные вызовы, можете переделать какой-то из отчетов добавив туда фильтрацию такого вида:
dcontext =  'ext-queues' and dstchannel = ''

Если вам нужно уведомление о пропущенных вызовах в электронной почте в реальном режиме времени, то добавим поиск параметра dstchannel = '' при отбое звонка. Для этого добавим в начало файла /etc/asterisk/extensions_override_elastix.conf пару строк:
Читать дальше →