воскресенье, июля 11, 2010

Приём/отправка факсов в asetrisk с помощью Hylafax

Встала задача - настроить приём и отправку факсов через астериск. Была выбрана связка iaxmodem + hylafax. Причина такого выбора банальна: в ветке 1.4 астериска нет встроенного аппликейшена для приёма/отправка факсов. С rxfax/ReceiveFax заморачиваться не хотелось.
Итак, имеем сервер с Debian Lenny, asterisk-1.4.33.1 + freepbx-2.7. Ставим доп пакеты:
ip-pbx:~# aptitude install g++ libtiff-tools libtiff4 libtiff4-dev dpkg-dev
Заводим iax-абонентов на астериске, в моём случае это были номера 8001-8007. Не забываем также в конфиге iax_general_custom.conf указать calltokenoptional=<ваша подсеть>. Далее, качаем и ставим iaxmodem:
ip-pbx:~# cd /usr/src
ip-pbx:/usr/src# wget http://sourceforge.net/projects/iaxmodem/files/iaxmodem/iaxmodem-1.2.0/iaxmodem-1.2.0.tar.gz/download
ip-pbx:/usr/src# tar xzvf iaxmodem-1.2.0.tar.gz
ip-pbx:/usr/src# cd iaxmodem-1.2.0
ip-pbx:/usr/src/iaxmodem-1.2.0# ./configure && make
ip-pbx:/usr/src/iaxmodem-1.2.0# cp iaxmodem /usr/local/bin
ip-pbx:/usr/src/iaxmodem-1.2.0# mkdir /etc/iaxmodem

Здесь пропишу настройки для одного иаксмодема, остальные заводятся аналогично:
ip-pbx:/usr/src/iaxmodem-1.2.0# touch /etc/iaxmodem/ttyIAX0
ip-pbx:/usr/src/iaxmodem-1.2.0# echo "iax1:2345:respawn:/usr/local/bin/iaxmodem ttyIAX0" >> /etc/inittab
ip-pbx:/usr/src/iaxmodem-1.2.0# cd /etc/iaxmodem

Далее, прописываем в ttyIAX0 параметры для модема:
ip-pbx:/etc/iaxmodem# vim ttyIAX0

device /dev/ttyIAX0
owner uucp:uucp
mode 660
port 4570
refresh 50
server [ip астериска]
peername [peername]
secret [secret]
codec alaw


Здесь, [ip астериска] - айпишник, на котором стоит астериск, [peername] - имя иакспира, которого мы завели на астериске, [secret] - это, соответственно, пароль для авторизации этого пира.
Ставим и настраиваем hylafax:
ip-pbx:/etc/iaxmodem# cd /usr/src
ip-pbx:/usr/src# wget ftp://ftp.hylafax.org/source/hylafax-6.0.4.tar.gz
ip-pbx:/usr/src# tar xzvf hylafax-6.0.4.tar.gz
ip-pbx:/usr/src# cd hylafax-6.0.4
ip-pbx:/usr/src/hylafax-6.0.4# dpkg-buildpackage
ip-pbx:/usr/src/hylafax-6.0.4# dpkg -i ../hylafax*deb

ip-pbx:/usr/src/hylafax-6.0.4# faxsetup

[...]

Update /var/spool/hylafax/status/any.info.

HylaFAX configuration parameters are:

[1] Init script starts faxq: yes
[2] Init script starts hfaxd yes
[3] Start old protocol: no
[4] Start paging protocol: no

Are these ok [yes]?

[...]

Do you want to run faxaddmodem to configure a modem [yes]?
Serial port that modem is connected to [ttyS0]? ttyIAX0

[...]


Далее, вам будет предложено ввести параметры модема. Тут можете прописать свои значения. Сетап создаст в папке /var/spool/hylafax/etc файл config.ttyIAX0. У меня он выглядит следующим образом:

CountryCode: 7
AreaCode: 495
FAXNumber: +7.495.555.1234
LongDistancePrefix: 1
InternationalPrefix: 011
DialStringRules: etc/dialrules
ServerTracing: 1
SessionTracing: 11
RecvFileMode: 0600
LogFileMode: 0600
DeviceMode: 0600
RingsBeforeAnswer: 1
SpeakerVolume: off
GettyArgs: "-h %l dx_%s"
LocalIdentifier: "NothingSetup"
TagLineFont: etc/lutRS18.pcf
ModemType: Class1
ModemResetCmds: AT+VCID=1
PagerTTYParity: none
Class1Cmd: AT+FCLASS=1.0 # command to enter class 1.0
Class1PPMWaitCmd: AT+FTS=7 # command to stop and wait before PPM
Class1TCFWaitCmd: AT+FTS=7 # command to stop and wait before TCF
Class1EOPWaitCmd: AT+FTS=9 # command to stop and wait before EOP
Class1SwitchingCmd: AT+FRS=7 # command to stop and listen for silence
Class1RecvAbortOK: 200 # wait 200ms for abort response
Class1FrameOverhead: 4 # 4 byte overhead in recvd HDLC frames
Class1RecvIdentTimer: 40000 # 35+5secs waiting for ident frames
Class1TCFMaxNonZero: 10 # max 10% of data may be non-zero
Class1TCFMinRun: 1000 # min run is 2/3rds of TCF duration
CallIDPattern: "NMBR="
CallIDPattern: "NAME="
CallIDPattern: "ANID="
CallIDPattern: "NDID="


Можно подправить данный файл. Далее, прописываем
ip-pbx:/usr/src/hylafax-6.0.4# echo "t0:2345:respawn:/usr/sbin/faxgetty ttyIAX0" >> /etc/inittab
ip-pbx:/usr/src/hylafax-6.0.4# vim /etc/rc.local, сюда добавляем строчки
/usr/local/sbin/hfaxd
/usr/local/sbin/faxq
, после этого ребутаем серв:
ip-pbx:/usr/src/hylafax-6.0.4# reboot

После загрузки сервера проверьте, что у вас нормально работают hylafax и iaxmodem:
команда ps aux | grep iax должна выдать что то похожее на
uucp 5288 0.0 0.0 3084 1312 pts/3 Ss+ Jul07 1:07 /usr/local/bin/iaxmodem ttyIAX0
а команда ps aux | grep fax должна выдать
uucp 5059 0.0 0.0 4372 1108 ? Ss Jul07 0:00 /usr/sbin/faxq
uucp 5063 0.0 0.0 4704 1536 ? S Jul07 0:00 /usr/sbin/hfaxd -d -i 4559
uucp 5295 0.0 0.0 4944 2196 ? Ss Jul07 0:21 /usr/sbin/faxgetty ttyIAX0

Если этого нет, то что то вы сделали не так. Если у вас показывает так же как и у меня, то всё нормально и можно двигаться дальше.

Отправка факсов

По умолчанию, во freepbx пиры сидят в контексте from-internal, меня это вполне устраивает, я ничего не меняю. Если вы хотите выпускать факсы через какой то отдельный транк, то прописшите это в отдельный контекст, который потом поставьте для iax-пира в настройках.
Отправка факсов совершается командой sendfax. У меня она имеет следующий вид:
sendfax -n -T 2 -N -d [номер назначения] [файл факса]
-n - не генерить титульную страницу
-T 2 - совершить 2 попытки отправить факс, прежде чем посчитать отправку неуспешной(по умолчанию будет совершено 12 попыток)
-N - не посылать на электронную почту уведомление об отправке факса
-d [номер назначения] - номер, на который посылать факс
Если у вас всё настроено правильно, то в консоли астериска вы увидите исходящий звонок от iax-пира на номер назначения. Проверить статус отправки можно командами faxstat -s и faxstat -d

Приём факсов
Для того, чтобы принять факс, необходимо направить вызов на iax-пира, под которым в астериске зареган iaxmodem:
exten => _XXXX.,1,Dial(IAX2/iaxmodem/${EXTEN},30,)
После чего факс будет принят hylafax'ом и будет складирован в папку /var/spool/hylafax/recvq. В данном методе существует одна маленькая неприятность - имя файла в /var/spool/hylafax/recvq никак не будет отражать информацию о том, кто послал данный факс. Но, к счастью, эту проблему довольно просто решить. В hylafax есть встроенный инструмент, под названием FaxDispatch. Данный инструмент позволяет получить информацию о вызове. В частности, получить CLID и DID, которые использваолись в вызове. CALLERID звонящего сохраняется в переменной $CIDNUMBER, номер, на который пришёл вызов - в переменной $CALLID4. Необходимо отредактировать файл /var/spool/hylafax/etc/FaxDispatch (если его не существует, то создайте). У меня он выглядит следующим образом:
FILETYPE=tif
FOLDER="/var/spool/hylafax/recvq/"
FULLPATH="${FOLDER}${FILENAME}.tif"
cp $FULLPATH /tmp/$CIDNUMBER\_$CALLID4.tif
chmod 777 /tmp/$CIDNUMBER\_$CALLID4.tif

Думаю, объяснять особо не нужно. Все тифы копируются в папку tmp, им присваивается имя $CIDNUMBER_$CALLID4. В конфиге астериска у меня прописано:

exten => _[124]XX,1,Set(FAXFROM=${CALLERID(num)})
exten => _[124]XX,n,Set(FAXEXTEN=${EXTEN})
exten => _[124]XX,n,Set(FAXMAIL=${FAX_GET(${EXTEN})})
exten => _[124]XX,n,Goto(fax)
exten => _XX.,n(fax),Dial(IAX2/8001/${EXTEN})
exten => h,1,DumpChan()
exten => h,n,System(/usr/bin/perl /space/scripts/fax_handler.pl ${FAXFROM} ${FAXEXTEN} ${FAXMAIL})

т.е. после того, как был принят факс, запускается перловый скрипт следующего содержания:
#!/usr/bin/perl -w

use strict;
use POSIX;

my $tiff2pdf = '/usr/bin/tiff2pdf';
my $rm = '/bin/rm';
my $mv = '/bin/mv';
my $peer = $ARGV[0];
my $user = $ARGV[1];
my $mail = $ARGV[2];
my ($sec,$min,$hour,$mday,$mon,$year,$wday)=localtime(time());
$mon += 1;
$year += 1900;
$mday = '0' . "$mday" if (length($mday) == 1);
$mon = '0' . "$mon" if (length($mon) == 1);
$sec = '0' . "$sec" if (length($sec) == 1);
$min = '0' . "$min" if (length($min) == 1);
$hour = '0' . "$hour" if (length($hour) == 1);
my $_file = "$peer" . '_' . "$user";
my $file = "$peer" . '_' . "$user" . '_' . "$year" . "$mon" . "$mday" . '_' . "$hour:$min:$sec";
my $date = "$year" . "$mon" . "$mday" . '_' . "$hour" . ':' . "$min" . ':' . "$sec";
chdir '/tmp';
exit unless (-e "$_file.tif");
system("$tiff2pdf -o $file.pdf $_file.tif");
system("$rm -f $_file.tif");
system("/usr/local/bin/sendEmail -f [from_mail] -t $mail -u FAX from $peer to $user -m fax received $date -a /tmp/$file.pdf -s [smtp-сервер] -xu [from_mail] -xp [mail_passwd]");
system("$mv $file.pdf /var/spool/asterisk/fax");

Данному скрипту передаются CLID, DID и мейл, на который нужно отсылать письмо с факсом. Скрипт по CLID и DID ищет в папке /tmp нужный файл, конвертит его в pdf пуляет на почту.

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

http://www.the-asterisk-book.com/unstable/faxserver-mit-iaxmodem-und-hylafax.html
http://lynks.ru/blog/articles/iaxmodem-hylafax-i-ldap