+38 063 731 76 76; +38 096 446 96 48 info@астериск.укр

Внедрение Asterisk в больших компаниях и интеграция с Active Directory.

Первое что нужно сделать, это создать пользователей, это тот шаг который сильно упростит задачу, и без которой нет смысла что-то продолжать, но поскольку пользователей не мало, то и скрипт вышел не простой, подробности в комментариях скрипта.
#!/usr/bin/perl
# users.pl v1.8
#
use Encode;
use strict;
use warnings;
use Net::LDAP;
use Lingua::Translit;

######################
### BEGIN SETTINGS ###
######################
my $debug = 0;
my $warning = 0;

# Имя домена
my $AD=”dc.local”;

# Имя домена в формате AD
my $ADDC=”dc=dc,dc=local”;

# Пользователь домена, с правами пользователь домена, больше не нужно
my $ADUserBind=”CN=user,OU=Usr,OU=Asterisk,OU=Tasks,$ADDC”;
my $ADpass=”pass”;
# Где искать, я указал по всему домену, так как дочернии компании
# разнесены по разным ОУ
my $ADUsersSearchBase=”$ADDC”;

# Тут создаем переменные с нужными нам полями
my $ADfieldTelephone=”ipphone”;
my $ADfieldFullName=”displayname”||cp1251;
my $ADfieldMail=”mail”;
my $ADfieldUser=”samaccountname”;
my $ADfieldMemberOf=”memberof”;
my $ADfiledConpany=”company”;
my $ADfiledPostOffice=”postofficebox”;
my $ADfiledUserOf=”useraccountcontrol”;
my $ADfiledCity=”st”;

# Задаем постоянные настройки пользователя
my $user_static =
“type=friend
host=dynamic
bindport=5060
bindaddr=0.0.0.0
match_auth_username=yes
srvlookup=no
jbenable=yes
jbforce=no
jbimpl=fixed
jbmaxsize=100
subscribemwi=no
subscribecontext=default
language=ru
videosupport=yes
nat=no
dtmfmode=rfc2833
disallow=all
qualify=yes
allow=ulaw,alaw,g723,gsm,iLBC,h263,h263p,h264
“;
#######################
### END OF SETTINGS ###
#######################

my $ldap;

# get array DNS names of AD controllers
my $dig = “dig -t srv _ldap._tcp.$AD” . ‘| grep -v “^;\|^$” | grep SRV | awk “{print \$8}”‘;
my @adControllers = `$dig`;
# try connect to AD controllers
foreach my $controller (@adControllers){
$controller =~ s/\n//;
#INITIALIZING
$ldap = Net::LDAP->new ( $controller ) or next;
print STDERR “Connected to AD controller: $controller\n” if $debug > 0;
last;
}
die “$@” unless $ldap;

my $mesg = $ldap->bind ( dn=>$ADUserBind, password =>$ADpass);

my $ldapUsers = LDAPsearch (
$ADUsersSearchBase,
“$ADfieldTelephone=*”,
[ $ADfieldFullName, $ADfieldTelephone, $ADfiledCity, $ADfieldMail, $ADfieldUser, $ADfieldMemberOf, $ADfiledConpany, $ADfiledPostOffice, $ADfiledUserOf ]
)->as_struct;

my $tr = new Lingua::Translit (“GOST 7.79 RUS”);

my %hashPhones = ();
my $phones = \%hashPhones;

my @out;

while ( my ($distinguishedName, $attrs) = each(%$ldapUsers) ) {
# if not exist phone or name – skipping
my $attrPhone = $attrs->{ “$ADfieldTelephone” } || next;
my $attrUser = $attrs->{ “$ADfieldUser” } || next;
my $attrName = $attrs->{ “$ADfieldFullName” } || next;
my $encName = “@$attrName”;
my $attrMail = $attrs->{ “$ADfieldMail” } || [“”];
my $attrCity = $attrs->{ “$ADfiledCity” } || [“”];
my $attrMemberOf = $attrs->{ “$ADfieldMemberOf” } || [“”];
my $attrConpany = $attrs->{ “$ADfiledConpany” } || [“”];
my $attrPostBox = $attrs->{ “$ADfiledPostOffice” } || [“”];
my $attrUsersDisabled = $attrs->{ “$ADfiledUserOf” } || [“”];
print “@$attrName — @$attrMemberOf\n” if $debug > 0;
print “@$attrName — @$attrConpany\n” if $debug > 0;
print “@$attrName — @$attrUsersDisabled\n” if $debug > 0;
print “@$attrName — @$attrCity\n” if $debug > 0;
# check for duplicates phone number
if ( $phones -> {“@$attrPhone”} ){
my $currUser = “@$attrName”;
my $existUser = $phones -> {“@$attrPhone”};
###############################
#### start send to maill ######
####Если мы в АД присвоили 2 раза 1 номер, то говорим об этом на почту##
###############################
open (SENDMAIL, “|/usr/sbin/sendmail -t”)
or die “sendmail not ready”;
print SENDMAIL “MIME-Version: 1.0\n”;
print SENDMAIL “Content-Type: text/plain; charset=\”kio8-r\”\n”;
print SENDMAIL “Content-Transfer-Encoding: 8bit\n”;
print SENDMAIL “From: пользователи active directory <support\@domain.com>\n”;
print SENDMAIL “To: Frank Smith <support\@domain.com>\n”;
print SENDMAIL “Reply-To: Frank Smith <user\@domain.com>\n”;
# print SENDMAIL “Subject: $subject_encoded \n\n”;
print SENDMAIL “Subject: Astrisk Server.\n”;
# print SENDMAIL “Content-Type: text/plain; charset=\”utf-8\”\n”;
print SENDMAIL “Номер @$attrPhone уже присвоен пользователю:’$existUser’ уже существует у пользователя:’$currUser’… пользователь не создан – ‘[@$attrPhone] $currUser’\n”;
close (SENDMAIL) or warn “sendmail didn’t close nicely”;
###############################
#### end send to mail ########
###############################
# print STDERR “@$attrPhone alredy exist! Exist:’$existUser’ Current:’$currUser’… skipping – ‘[@$attrPhone] $currUser’\n” if $warning;
# next;
} else {
$phones -> {“@$attrPhone”} = “@$attrName\n”;
}

###### fOR CONTEXT VAR ####
###### Смотрим в каких группах пользователь######
###### для дальнейшего разделения######
my $forcontext = “@$attrConpany @$attrMemberOf”;
print “@$attrName — $forcontext\n” if $debug > 0;
###### END fOR CONTEXT VAR ####

###### CONTEXT USER ######
###### Тут контекст зависит от группы в АД,######
###### для разделения маршрутизации ######
my $context;
foreach my $paira ($forcontext){
if($paira =~ /отделы_UA/){$context = “ualo”;last;}
elsif($paira =~ /отделы_RU/){$context = “rulo”;last;}
elsif($paira =~ /отделы_BL/){$context = “bllo”;last;}
elsif($paira =~ /Украина/){$context = “uaoffice”;last;}
elsif($paira =~ /Холдинг/){$context = “holdoffice”;last;}
elsif($paira =~ /Россия/){$context = “ruoffice”;last;}
else{
$context = “office”;
}
}#foreach
###### END CONTEXT USER ###

###### CONTEXT USER ######
### в ад уже указаны номера кабинетов пользователей, но в неудобном
##для нас формате, так как наш астериск умеет только 64 группы перехвата ##переименуем их в скрипте
my $callgroup;
foreach my $pairss (@$attrPostBox){
if($pairss =~ /101/){$callgroup = “1”;last;}
elsif($pairss =~ /210/){$callgroup = “2”;last;}
elsif($pairss =~ /200/){$callgroup = “3”;last;}
elsif($pairss =~ /201/){$callgroup = “4”;last;}
elsif($pairss =~ /202/){$callgroup = “5”;last;}
elsif($pairss =~ /203/){$callgroup = “6”;last;}
elsif($pairss =~ /204/){$callgroup = “7”;last;}
elsif($pairss =~ /205/){$callgroup = “8”;last;}
elsif($pairss =~ /206/){$callgroup = “9”;last;}
elsif($pairss =~ /210/){$callgroup = “10”;last;}
elsif($pairss =~ /301/){$callgroup = “11”;last;}
elsif($pairss =~ /302/){$callgroup = “12”;last;}
elsif($pairss =~ /303/){$callgroup = “13”;last;}
elsif($pairss =~ /304/){$callgroup = “14”;last;}
elsif($pairss =~ /305/){$callgroup = “15”;last;}
elsif($pairss =~ /306/){$callgroup = “16”;last;}
elsif($pairss =~ /307/){$callgroup = “17”;last;}
elsif($pairss =~ /308/){$callgroup = “18”;last;}
elsif($pairss =~ /309/){$callgroup = “19”;last;}
elsif($pairss =~ /310/){$callgroup = “20”;last;}
elsif($pairss =~ /602/){$callgroup = “21”;last;}
elsif($pairss =~ /603/){$callgroup = “22”;last;}
elsif($pairss =~ /604/){$callgroup = “23”;last;}
elsif($pairss =~ /605/){$callgroup = “24”;last;}
elsif($pairss =~ /606/){$callgroup = “25”;last;}
elsif($pairss =~ /607/){$callgroup = “26”;last;}
elsif($pairss =~ /900/){$callgroup = “27”;last;}
elsif($pairss =~ /901/){$callgroup = “28”;last;}
elsif($pairss =~ /902/){$callgroup = “29”;last;}
elsif($pairss =~ /903/){$callgroup = “30”;last;}
elsif($pairss =~ /904/){$callgroup = “31”;last;}
elsif($pairss =~ /905/){$callgroup = “32”;last;}
elsif($pairss =~ /800/){$callgroup = “33”;last;}
elsif($pairss =~ /101/){$callgroup = “34”;last;}
elsif($pairss =~ /110/){$callgroup = “35”;last;}
else{
$callgroup = “”;
}
}#foreach
###### END CONTEXT USER ###
######PASSWD USER ########
######Пароль будет зависть от группы#
my $phsecret;
foreach my $pair (@$attrMemberOf){
if($pair =~ /UA/){$phsecret = “erwgzfx@{$attrPhone}”;last;}
elsif($pair =~ /KR/){$phsecret = “sdfgsdf@{$attrPhone}”;last;}
elsif($pair =~ /RM_RD_SS_Zoiper/){$phsecret = “dsfgg5df@{$attrPhone}”;last;}
elsif($pair =~ /Invest/){$phsecret = “wertsgd@{$attrPhone}”;last;}
else{
$phsecret = “ash5hbdf{$attrPhone}”;
}
}#foreach
###### END PASSWD USER #######

##### USEROFF VAR ########
#my $useroffvar = “@$attrName @$attrCity @$attrMemberOf”;
##### END USEROFF VAR ########

#print “@$attrMemberOf\n”;
foreach my $pairr (@$attrMemberOf){
if($pairr =~ /asteriskuseroff/){
push (@out,
“\; $encName пользователь c телефоном @$attrPhone отключен, находится в группе asteriskuseroff\n”
);last;}
elsif($pairr =~ /Asterisk-MobileSip/){
push (@out,
“[@$attrPhone]\n”
. “fullname=$encName\n”
. “email=@$attrMail\n”
. “context=$context\n”
. “callgroup=$callgroup\n”
. “pickupgroup=$callgroup\n”
. “username=@$attrUser\n”
. “mailbox=@{$attrPhone}\@default\ \n”
. “callerid=\”$encName\”\<@$attrPhone\>\n”
. “secret=$phsecret\n”
. “transfer=yes\n”
. “$user_static\n”
. “[@$attrPhone\m]\n”
. “fullname=$encName\n”
. “email=@$attrMail\n”
. “context=$context\n”
. “callgroup=$callgroup\n”
. “pickupgroup=$callgroup\n”
. “username=@$attrUser\n”
. “mailbox=@{$attrPhone}\@default\ \n”
. “callerid=\”$encName\”\<@$attrPhone\>\n”
. “secret=$phsecret\n”
. “transfer=yes\n”
. “$user_static\n”
);last;}
elsif($pairr =~ /NR_213451234/){
push (@out,
“1\n”
);last;}
else{
push (@out,
“[@$attrPhone]\n”
. “fullname=$encName\n”
. “context=$context\n”
. “callgroup=$callgroup\n”
. “pickupgroup=$callgroup\n”
. “email=@$attrMail\n”
. “username=@$attrUser\n”
. “mailbox=@{$attrPhone}\@default\n”
. “callerid=\”$encName\”\<@$attrPhone\>\n”
. “secret=$phsecret\n”
. “transfer=yes\n”
. “$user_static\n”
);
}
}; # End of that DN
}#foreach

###############################
#### Delite_old_config ########
#### я решил сохранять конфиг в файл для дебага ###
#### поэтому удаляем старый конфиг ###
###############################
while(){
do{unlink $_ or die “cant remove: $!”} if m!.*\.conf$!;
print $_,” удален\n”;
}
###############################
#### Crate_new_config ########
#### и создаем новый ########
###############################
open (FILE, “>>/etc/asterisk/users_ad/userss.conf”);
print FILE @out;
close (FILE);

exit 0;

# Ищем везде кроме отключенных пользователей
#$base, $searchString, $attrsArray;; filter => $searchString,
#my $searchString = (\&(objectCategory=person)(objectclass=user)(userAccountControl:1.2.840.113556.1.4.803:=2));

sub LDAPsearch
{
my ($base, $searchString, $attrs) = @_;
my $ret = $ldap->search ( base => $base,
scope => “sub”,
filter => “(&(|($searchString)) (|(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))))”,
attrs => $attrs
);
LDAPerror(“LDAPsearch”, $ret) && die if( $ret->code );
return $ret;
}

sub LDAPerror
{
my ($from, $mesg) = @_;
my $err = “[$from] – error”
.”\nCode: ” . $mesg->code
.”\nError: ” . $mesg->error . ” (” . $mesg->error_name . “)”
.”\nDescripton: ” . $mesg->error_desc . “. ” . $mesg->error_text;
print STDERR $err if $warning;
}

Итак мы получили на выходе файл с настройками пользователей со следующим разделением, тут опишу по ходу добавления

  1. те пользователи которым нужен софтфон на мобильном имеют 2 аккаунта, для стационарного и для мобильного телефона
  2. у пользователей в разных регионах разный контекст, что позволяет нам четко разграничить входящею и исходящею маршрутизацию по регионам
  3. работает перехват звонков по кабинетам в зависимости от расположения пользователя

в общем и целом пользователи готовы, но еще есть гора стационарных телефонов, которые нужно настраивать, а ведь они могут получать настройки по tftp из xml файлов, именно тогда я узнал что xml нужно валидировать, но уже после долгих мучений и написания следующего скрипта, я не буду так тщательно его комментировать, разница с предыдущим не большая, тут добавилось поле мак адреса телефона, для него мы использовали в АД поле пейджер, так как все пейджеры у нас в компании поломались а новые мы купить не смогли, так-же мы выводили конфиг каждого аппарата в свой файл, и по разному задавали настройки часового пояса, в соответствии с регионом:

#!/usr/bin/perl
# Print config to file:
# cfg$MacAddres.xml
#
use strict;
use warnings;
use Net::LDAP;
use Lingua::Translit;

######################
### BEGIN SETTINGS ###
######################
my $debug = 1;
my $warning = 1;

# name of Domain
my $AD=”ad.local”;

# Domain name in format AD
my $ADDC=”dc=ad,dc=local”;

# user in Active directory
# example: “CN=user,CN=Users,$ADDC”
my $ADUserBind=”CN=user,OU=Usr,OU=Asterisk,OU=Tasks,$ADDC”;
my $ADpass=”pass”;

# base search tree
# example “OU=Users,$ADDC”
my $ADUsersSearchBase=”$ADDC”;

# Field in active directory where telephone number, display name, phone stored
# “telephonenumber”, “displayname”, “mail”
# my $ADfieldTelephone=”telephonenumber”;
my $ADfieldTelephone=”ipphone”;
my $ADfieldFullName=”displayname”;
my $ADfieldMail=”mail”;
my $ADfieldUser=”samaccountname”;
my $MAcAddres=”pager”;
my $ADfiledConpany=”company”;
my $ADfieldMemberOf=”memberof”;

# You need to create a dialplan in your asterisk server;
# my $dialplan=”office”;

# default settings
my $user_macst0 =

“;
my $user_macst1 =
“”;
my $user_macst4=
“sege5gsf 1 10.0.1.133 500 0 2 0 1 1 10.0.1.133 120 1 1 1 10.0.1.133 0 c ru”;
my $user_macst2 =

“;

#######################
### END OF SETTINGS ###
#######################

my $ldap;

# get array DNS names of AD controllers
my $dig = “dig -t srv _ldap._tcp.$AD” . ‘| grep -v “^;\|^$” | grep SRV | awk “{print \$8}”‘;
my @adControllers = `$dig`;
# try connect to AD controllers
foreach my $controller (@adControllers){
$controller =~ s/\n//;
#INITIALIZING
$ldap = Net::LDAP->new ( $controller ) or next;
print STDERR “Connected to AD controller: $controller\n” if $debug > 0;
last;
}
die “$@” unless $ldap;

my $mesg = $ldap->bind ( dn=>$ADUserBind, password =>$ADpass);

#PROCESSING – Displaying SEARCH Results
# Accessing the data as if in a structure
# i.e. Using the “as_struct” method
my $ldapUsers = LDAPsearch (
$ADUsersSearchBase,
“$ADfieldTelephone=*”,
[ $ADfieldFullName, $ADfieldTelephone, $ADfieldMail, $ADfieldUser, $MAcAddres, $ADfiledConpany, $ADfieldMemberOf ]
)->as_struct;

# translit RUS module.
# GOST 7.79 RUS, reversible, GOST 7.79:2000 (table B), Cyrillic to Latin, Russian
my $tr = new Lingua::Translit (“GOST 7.79 RUS”);

my %hashPhones = ();
my $phones = \%hashPhones;
while(){
do{unlink $_ or die “cant remove: $!”} if m!.*\.xml$!;
print $_,” удален\n”;
}
my @out;
my $inc;
while ( my ($distinguishedName, $attrs) = each(%$ldapUsers) ) {
# if not exist phone or name – skipping
my $attrPhone = $attrs->{ “$ADfieldTelephone” } || next;
my $attrUser = $attrs->{ “$ADfieldUser” } || next;
my $attrmac = $attrs->{ “$MAcAddres” } || next;
my $attrName = $attrs->{ “$ADfieldFullName” } || next;
my $encName = “@$attrName”;
my $attrMail = $attrs->{ “$ADfieldMail” } || [“”];
my $attrConpany = $attrs->{ “$ADfiledConpany” } || [“”];
my $attrMemberOf = $attrs->{ “$ADfieldMemberOf” } || [“”];
print “@$attrName — @$attrConpany\n”;
$inc++;

#kyiv time EET-2EEST,M3.5.0/3,M10.5.0/4

my $timezone;
foreach my $pair (@$attrConpany){
if($pair =~ /Украина/){$timezone = “EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00”;last;}
elsif($pair =~ /Холдинг/){$timezone = “EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00”;last;}
elsif($pair =~ /Россия/){$timezone = “MST-3MDT,M3.5.0/2,M10.5.0/3”;last;}
else{
$timezone = “EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00”;
}
}#foreach
# check for duplicates phone number
if ( $phones -> {“@$attrPhone”} ){
my $currUser = “@$attrName”;
my $existUser = $phones -> {“@$attrPhone”};
print STDERR “@$attrPhone alredy exist! Exist:’$existUser’ Current:’$currUser’… skipping – ‘[@$attrPhone] $currUser’\n” if $warning;
next;
} else {
$phones -> {“@$attrPhone”} = “@$attrName”;
# my $phsecret = “Projectvoip@{$attrPhone}”;

my $phsecret;
foreach my $pair (@$attrMemberOf){
if($pair =~ /dd_UA/){$phsecret = “dfsgsdf@{$attrPhone}”;last;}
elsif($pair =~ /_Zoiper/){$phsecret = “asdfsd@{$attrPhone}”;last;}
elsif($pair =~ /Invest/){$phsecret = “fdf4asd@{$attrPhone}”;last;}
else{
$phsecret = “asdfsd@{$attrPhone}”;
}
}#foreach
open(OUT,”>/var/lib/tftpboot/cfg@$attrmac.xml”);
print “create file cfg@$attrmac.xml\n”;
print OUT “$user_macst0\n@$attrmac\n$user_macst1\n$timezone\n$user_macst4\n@$attrPhone\n$phsecret\n@$attrPhone\n@$attrPhone\n$encName\n$user_macst2\n”;

close OUT;
}# While

} # End of that DN
print “$inc\n”;

sub LDAPsearch
{
my ($base, $searchString, $attrs) = @_;
my $ret = $ldap->search ( base => $base,
scope => “sub”,
filter => “(&(|($searchString)) (|(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))))”,
attrs => $attrs
);
LDAPerror(“LDAPsearch”, $ret) && die if( $ret->code );
return $ret;
}

sub LDAPerror
{
my ($from, $mesg) = @_;
my $err = “[$from] – error”
.”\nCode: ” . $mesg->code
.”\nError: ” . $mesg->error . ” (” . $mesg->error_name . “)”
.”\nDescripton: ” . $mesg->error_desc . “. ” . $mesg->error_text;
print STDERR $err if $warning;
}

На выходе мы получили файлик типа /var/lib/tftpboot/cfg00b1fc1f8d0e.xml
который телефон заберирал себе и настраивался, чудо – говорили юзеры, а я с облегчением вздохнул, и пошел дальше.
Так как телефоны могли подвисать и никому об этом не говорить, я решил узнавать об этом раньше пользователя, и тоже скриптом, но мониторить нужно только физические телефоны, так как софтфон не всегда в сети и это норма, получилось что -то вроде

#!/usr/bin/perl
# users.pl v1.1
# send to mail
#
use Encode;
use strict;
use warnings;
use Net::LDAP;
use Lingua::Translit;

######################
### BEGIN SETTINGS ###
######################
my $debug = 1;
my $warning = 1;

# name of Domain
my $AD=”dc.local”;

# Domain name in format AD
# for example mydomain.ru
my $ADDC=”dc=dc,dc=local”;

# user in Active directory
my $ADUserBind=”CN=user,OU=Usr,OU=Asterisk,OU=Tasks,$ADDC”;
my $ADpass=”mypass”;

# base search tree
# example “OU=Users,$ADDC”
my $ADUsersSearchBase=”$ADDC”;

# Field in active directory where telephone number, display name, phone stored
# “telephonenumber”, “displayname”, “mail”
# my $ADfieldTelephone=”telephonenumber”;
my $ADfieldTelephone=”ipphone”;
my $ADfieldFullName=”displayname”||cp1251;
my $ADfieldMail=”mail”;
my $ADfieldUser=”samaccountname”;
my $ADfieldMac=”pager”;

#######################
### END OF SETTINGS ###
#######################

my $ldap;

# get array DNS names of AD controllers
my $dig = “dig -t srv _ldap._tcp.$AD” . ‘| grep -v “^;\|^$” | grep SRV | awk “{print \$8}”‘;
my @adControllers = `$dig`;
# try connect to AD controllers
foreach my $controller (@adControllers){
$controller =~ s/\n//;
#INITIALIZING
$ldap = Net::LDAP->new ( $controller ) or next;
print STDERR “Connected to AD controller: $controller\n” if $debug > 0;
last;
}
die “$@” unless $ldap;

my $mesg = $ldap->bind ( dn=>$ADUserBind, password =>$ADpass);

#PROCESSING – Displaying SEARCH Results
# Accessing the data as if in a structure
# i.e. Using the “as_struct” method
my $ldapUsers = LDAPsearch (
$ADUsersSearchBase,
“$ADfieldMac=*”,
[ $ADfieldFullName, $ADfieldTelephone, $ADfieldMail, $ADfieldUser, $ADfieldMac ]
)->as_struct;

my %hashPhones = ();
my $phones = \%hashPhones;

my @out;
while ( my ($distinguishedName, $attrs) = each(%$ldapUsers) ) {
my $attrPhone = $attrs->{ “$ADfieldTelephone” } || next;
my $attrUser = $attrs->{ “$ADfieldUser” } || next;
my $attrName = $attrs->{ “$ADfieldFullName” } || next;
my $encName = “@$attrName”;
my $attrMail = $attrs->{ “$ADfieldMail” } || [“”];
my $attrMac = $attrs->{ “$ADfieldMac” } || [“”];
my $HardPhone = `/usr/sbin/asterisk -rvvvvvx ‘sip show peers’ | egrep -w @$attrPhone`;

# check for duplicates phone number
if ( $phones -> {“@$attrPhone”} ){
my $currUser = “@$attrName”;
my $existUser = $phones -> {“@$attrPhone”};
print STDERR “@$attrPhone alredy exist! Exist:’$existUser’ Current:’$currUser’… skipping – ‘[@$attrPhone] $currUser’\n” if $warning;
next;
} else {
$phones -> {“@$attrPhone”} = “@$attrName”;
}
my $ofline;
foreach my $array1 ($HardPhone){
if($array1 =~ /UNKNOWN/){
open (SENDMAIL, “|/usr/sbin/sendmail -t”)
or die “sendmail not ready”;
print SENDMAIL “MIME-Version: 1.0\n”;
print SENDMAIL “Content-Type: text/plain; charset=\”utf-8\”\n”;
print SENDMAIL “Content-Transfer-Encoding: 8bit\n”;
print SENDMAIL “From: У пользователя @$attrName не работает телефон <sevb\@mail.com>\n”;
print SENDMAIL “To: Frank Smith <sevb\@mail.com>\n”;
print SENDMAIL “Reply-To: Frank Smith <user\@mail.com>\n”;
print SENDMAIL “Subject: Phones_Ofline.\n”;
print SENDMAIL ” У пользователя @$attrName с номером @$attrPhone не работает телефон, необходимо проверить.\n”;
close (SENDMAIL) or warn “sendmail didn’t close nicely”;last;}
} #foreach

} # End of that DN

exit 0;

#OPERATION – Generating a SEARCH
#$base, $searchString, $attrsArray
sub LDAPsearch
{
my ($base, $searchString, $attrs) = @_;
my $ret = $ldap->search ( base => $base,
scope => “sub”,
filter => “(&(|($searchString)) (|(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))))”,
attrs => $attrs
);
LDAPerror(“LDAPsearch”, $ret) && die if( $ret->code );
return $ret;
}

sub LDAPerror
{
my ($from, $mesg) = @_;
my $err = “[$from] – error”
.”\nCode: ” . $mesg->code
.”\nError: ” . $mesg->error . ” (” . $mesg->error_name . “)”
.”\nDescripton: ” . $mesg->error_desc . “. ” . $mesg->error_text;
print STDERR $err if $warning;
}

После нам понадобилось принимать факс, еслественно на email, естественно захотели все, ну ок, сделаем, и написали скрипт с несложной задумкой, например у пользователя номер 100, для того чтобы принять факс нужно передать звонок на номер + 9 тоесть для 100 это 1009, и факс приходит ему на почту.
Скрипт все тот-же:
#!/usr/bin/perl
# fax.pl v1.3
#
use Encode;
use strict;
use warnings;
use Net::LDAP;
use Lingua::Translit;

######################
### BEGIN SETTINGS ###
######################
my $debug = 1;
my $warning = 1;

# name of Domain
my $AD=”dc.local”;

# Domain name in format AD
# for example mydomain.ru
my $ADDC=”dc=dc,dc=local”;

# user in Active directory
# example: “CN=user,CN=Users,$ADDC”
my $ADUserBind=”CN=user,OU=Usr,OU=Asterisk,OU=Tasks,$ADDC”;
my $ADpass=”pass”;

# base search tree
# example “OU=Users,$ADDC”
my $ADUsersSearchBase=”$ADDC”;

# Field in active directory where telephone number, display name, phone stored
# “telephonenumber”, “displayname”, “mail”
my $ADfieldTelephone=”ipphone”;
my $ADfieldFullName=”displayname”||cp1251;
my $ADfieldMail=”mail”;
my $ADfieldUser=”samaccountname”;

# default settings
#my $user_static =
#”context = $dialplan
#”;
#######################
### END OF SETTINGS ###
#######################

my $ldap;

# get array DNS names of AD controllers
my $dig = “dig -t srv _ldap._tcp.$AD” . ‘| grep -v “^;\|^$” | grep SRV | awk “{print \$8}”‘;
my @adControllers = `$dig`;
# try connect to AD controllers
foreach my $controller (@adControllers){
$controller =~ s/\n//;
#INITIALIZING
$ldap = Net::LDAP->new ( $controller ) or next;
print STDERR “Connected to AD controller: $controller\n” if $debug > 0;
last;
}
die “$@” unless $ldap;

my $mesg = $ldap->bind ( dn=>$ADUserBind, password =>$ADpass);

#PROCESSING – Displaying SEARCH Results
# Accessing the data as if in a structure
# i.e. Using the “as_struct” method
my $ldapUsers = LDAPsearch (
$ADUsersSearchBase,
“$ADfieldTelephone=*”,
[ $ADfieldFullName, $ADfieldTelephone, $ADfieldMail, $ADfieldUser ]
)->as_struct;

# translit RUS module.
# GOST 7.79 RUS, reversible, GOST 7.79:2000 (table B), Cyrillic to Latin, Russian
my $tr = new Lingua::Translit (“GOST 7.79 RUS”);

my %hashPhones = ();
my $phones = \%hashPhones;

my @out;

# my $runame = $ADfieldFullName;
while ( my ($distinguishedName, $attrs) = each(%$ldapUsers) ) {
# if not exist phone or name – skipping
my $attrPhone = $attrs->{ “$ADfieldTelephone” } || next;
my $attrUser = $attrs->{ “$ADfieldUser” } || next;
my $attrName = $attrs->{ “$ADfieldFullName” } || next;
my $encName = “@$attrName”;
my $attrMail = $attrs->{ “$ADfieldMail” } || [“”];

# check for duplicates phone number
if ( $phones -> {“@$attrPhone”} ){
my $currUser = “@$attrName”;
my $existUser = $phones -> {“@$attrPhone”};
print STDERR “@$attrPhone alredy exist! Exist:’$existUser’ Current:’$currUser’… skipping – ‘[@$attrPhone] $currUser’\n” if $warning;
next;
} else {
$phones -> {“@$attrPhone”} = “@$attrName”;
}
#my $pssswds = ;
# password for SID = (telephonenumber without first digit) + 1
# example: phone=6232 pass=233
# $phsecret =sprintf(“%03d”,( substr(“@$attrVal”,1,100)+1));
my $phsecret = “123@{$attrPhone}”;
push (@out,
“exten \=> @{$attrPhone}9\,1,Answer()\n”
.”exten \=> @{$attrPhone}9\,2,Set(FAXFILE=/tmp/fax/\${STRFTIME(\${EPOCH},,%Y%\m%d_%H_%M_%S)}-from-\${CALLERID(num)})\n”
.”exten \=> @{$attrPhone}9\,3,ReceiveFax(\${FAXFILE}.tif)\n”
.”exten \=> @{$attrPhone}9\,4,System(tiff2pdf \${FAXFILE}.tif -o \${FAXFILE}.pdf) \n”
.”exten \=> @{$attrPhone}9\,5,System(echo \”Вам пришел факс с номера \${CALLERID(num)} в \${STRFTIME(\${EPOCH},,%H:%M:%S)}. Факс во вложении.\” \| mail -s \”Входящий факс.\” -r fax\@example.com -a \${FAXFILE}.pdf @$attrMail) \n”
);
} # End of that DN

while(){
do{unlink $_ or die “cant remove: $!”} if m!.*\.conf$!;
print $_,” удален\n”;
}

open (FILE, “>>/etc/asterisk/extensions/ext_fax.conf”);
print FILE “[inpfax] \n”;
print FILE @out;
close (FILE);
# print to STDOUT
#else{
# print @out;
#}

exit 0;

#OPERATION – Generating a SEARCH
#$base, $searchString, $attrsArray
sub LDAPsearch
{
my ($base, $searchString, $attrs) = @_;
my $ret = $ldap->search ( base => $base,
scope => “sub”,
filter => “(&(|($searchString)) (|(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))))”,
attrs => $attrs
);
LDAPerror(“LDAPsearch”, $ret) && die if( $ret->code );
return $ret;
}

sub LDAPerror
{
my ($from, $mesg) = @_;
my $err = “[$from] – error”
.”\nCode: ” . $mesg->code
.”\nError: ” . $mesg->error . ” (” . $mesg->error_name . “)”
.”\nDescripton: ” . $mesg->error_desc . “. ” . $mesg->error_text;
print STDERR $err if $warning;
}

Дальше все эти скрипты добавили в крон, и раз в час, с последующим asterisk reload.
Таким-же образом была создана и телефонная книга в grandstream.
Итог был следующиим, приходит к нам в компанию новый сотрудник, девочки заводят его в AD, пишут там его ip телефон, а в поле пейджер добавляют мак адресс его аппарата, через час ребутаем телефон и все, можно звонить, если девочки дали кому-то существующий номер, то информаруем их об этом на почту, если тел не регистрируется на сервере, информаруем админа.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

22 − 12 =