The Palner Group, Inc.

Kamailio, Asterisk, VoIP, and IT Consulting

Integrating Fax for Asterisk

Asterisk provides an open-source solution for IP Telephony (aka VoIP). Customizing your telephone system to increase productivity remains one of Asterisk’s greatest features. Today, we will look at using Asterisk to replace your need for a fax machine.

Benefits

  • Store faxes electronically
  • Reduce printing costs
  • Share faxes via email

Requirements

  • Server running Asterisk (32 bit compatibility needed)
  • Fax for Asterisk Software Add-on

Step One: Get the Fax for Asterisk Software License

First, choose the licensing based on your needs. If you will only need to support 1 simultaneous fax “session,” you may be interested in the Free Fax For Asterisk License. Digium provides the Free Fax for Asterisk software at no cost, limited one per installation of Asterisk. You can combine the Free Fax for Asterisk license with the paid Fax for Asterisk licensing if you will need additional simultaneous fax sessions.

For example, you can download and install Free Fax for Asterisk providing your system one (1) fax session. If you find you need additional simultaneous sessions, simply purchase a paid license (currently $39.99 per session).

To get the Fax for Asterisk software, go to the Digium Store. Once “purchased” you will receive your license via email.

Step Two: Download and Install the Fax for Asterisk Software

Once you’ve received your license, there are many small steps needed to download, register, and install the software.

  • Download and run the registration software (outgoing network traffic to TCP port 443 (SSL) must be allowed)
cd /root
wget http://downloads.digium.com/pub/register/x86-32/register
chmod 500 /root/register
/root/register
  • Complete the registration
  • Go to http://www.digium.com/en/docs/FAX/faa-download.php and discover which files to download
  • Download both the res_fax and res_fax_digium files
  • Untar the res_fax file and copy it to the source file directory (example res_fax-1.6.0_1.0.3-x86_32.tar.gz)
tar xzvf res_fax-1.6.0_1.0.3-x86_32.tar.gz
cp /root/res_fax-1.6.0_1.0.3-x86_32/res_fax.so /usr/lib/asterisk/modules
  • Untar and install the res_fax_digium software (example res_fax_digium-1.6.0_1.0.3-pentium4m_32.tar.gz)
tar xzvf res_fax_digium-1.6.0_1.0.3-pentium4m_32.tar.gz
cp /root/res_fax_digium-1.6.0_1.0.3-pentium4m_32/res_fax_digium.so /usr/lib/asterisk/modules
  • Make a directory for your fax files
mkdir /var/spool/asterisk/fax

Step Three: Test if the Software Installed Correctly

Restart asterisk and test if that the fax module has loaded:

asterisk -rx "restart now"
asterisk -r
*CLI> fax show stats

If the software installed successfully, you should see something similar to:

Fax Statistics:
---------------

Current Sessions     : 0
Transmit Attempts    : 0
Receive Attempts     : 0
Completed Faxes      : 0
Failed Faxes         : 0
*CLI>
Digium T.38
Licensed Channels    : 1
Max Concurrent       : 0
Success              : 0
Canceled             : 0
No Fax               : 0
Partial              : 0
Negotiation Failed   : 0
Train Failure        : 0
Protocol Error       : 0
IO Partial           : 0
IO Fail              : 0
*CLI>
Digium G.711
Licensed Channels    : 1
Max Concurrent       : 1
Success              : 0
Switched to T.38     : 0
Canceled             : 0
No Fax               : 0
Partial              : 0
Negotiation Failed   : 0
Train Failure        : 0
Protocol Error       : 0
IO Partial           : 0
IO Fail              : 0

Step Four: Make a dialplan

Make a dialplan that fits your needs. Here’s an example for sending and receiving:

[inboundfax]
exten => s,1,NoOp(**** FAX RECEIVED from ${CALLERID(num)} ${STRFTIME(${EPOCH},,%c)} ****)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FILENAME=fax-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})
exten => s,n,Set(FAXFILE=${FILENAME}.tif)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=Received by MYCOMPANY ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M)})
exten => s,n,Set(FAXOPT(localstationid)=5555551212)
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => s,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => s,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => s,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => s,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => s,n,NoOp(**** RECEIVING FAX : ${FAXFILE} ****)
exten => s,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten => s,n,Hangup()
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})

[outboundfax]
exten => s,1,NoOp(send a fax)
exten => s,n,Set(FAXOPT(filename)=${FAXFILE})
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=Fax from MYCOMPANY +1 555 555 1212)
exten => s,n,Set(FAXOPT(localstationid)=15555551212)
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,SendFAX(/tmp/${FAXFILE},d)
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})

Step Five: Test

How do you test? Simple point an incoming number to inboundfax,s,1 and watch the magic happen. Faxes will be saved to /var/spool/asterisk/fax/ in tiff format.

But Wait! There’s More!

Sure, you could stop there, but wouldn’t it be neat to automatically email the received fax in pdf format? Using an AGI script, you can simply convert the tiff file into pdf format, attach it to an email, and off it goes!

Now, there are literally a thousand ways to do this. You can write your AGI scripts in the programming language of your choice; every language has it’s pros and cons. In our example, we’re going to demonstrate this process using a Perl script.

Install the Pre-reqs

You will want to install ghostscript to help convert the graphic files. On a centos install, this is as easy as typing yum -y install ghostscript. If you are using a different build you can install how you like or download the code directly from http://www.ghostscript.com/.

For the Perl pre-reqs, you will want to install a few packages from CPAN (to send mail and use smtp authentication):

perl -MCPAN -e shell
install MIME::Lite
install MIME::Base64
install Authen::SASL

Next create your perl script. In this case, call it receivedfax.pl and place it in /var/lib/asterisk/agi-bin:

#!/usr/bin/perl
use strict;
use MIME::Lite;

my ($msg,$stdinresult);

# $ARGV[0] = msgfrom, $ARGV[1] = msgto, $ARGV[2] = cidnum, $ARGV[3] = filename,
chomp($stdinresult = );

if ($#ARGV != 3) {
	print qq(VERBOSE "FAIL: 4 Arguments needed" 2\n);
	chomp($stdinresult = );
	exit(0);
}

system("tiff2ps -a /var/spool/asterisk/fax/$ARGV[3].tif | ps2pdf13 -sPAPERSIZE=letter - > /var/spool/asterisk/fax/$ARGV[3].pdf");

$msg = MIME::Lite->new(
	From => "$ARGV[0]",
	To => "$ARGV[1]",
	Subject => "FAX from $ARGV[2]",
	Type => 'multipart/mixed'
);

$msg->attach(
	Type => 'TEXT',
	Data => "Greetings.\n\nYou have received a fax from $ARGV[2]. (attached)\n\nSincerely,\nCOMPANY NAME\n\n"
);

$msg->attach(
	Type => 'image/pdf',
	Path => "/var/spool/asterisk/fax/$ARGV[3].pdf",
	Filename => "$ARGV[3].pdf",
	Disposition => 'attachment'
);

MIME::Lite->send('smtp', 'SMTP.SERVER.COM', Timeout=>60,
	AuthUser=>'MAILUSER', AuthPass=>'PASSWORD');

$msg->send;

system("rm -f /var/spool/asterisk/fax/$ARGV[3].pdf");

#example: receivedfax.pl "asterisk@mydomain.com" "JohnDoe@mydomain.com" 55512345678 fax-20091115-170217

Then, modify your dialplan to run the AGI script:

[inboundfax]
exten => s,1,NoOp(**** FAX RECEIVED from ${CALLERID(num)} ${STRFTIME(${EPOCH},,%c)} ****)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FILENAME=fax-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})
exten => s,n,Set(FAXFILE=${FILENAME}.tif)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=Received by MYCOMPANY ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M)})
exten => s,n,Set(FAXOPT(localstationid)=5555551212)
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => s,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => s,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => s,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => s,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => s,n,NoOp(**** RECEIVING FAX : ${FAXFILE} ****)
exten => s,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten => s,n,Hangup()
exten => h,1,GotoIf($["${FAXOPT(ecm)}" = "no" ]?end)
exten => h,n,AGI(receivedfax.pl,from@domain.com,to@domain.com,${CALLERID(num)},${FILENAME})
exten => h,n(end),NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)}) 

You can even create a similar script to transform a pdf into a tiff file and send via outbound fax:

#!/usr/bin/perl -w
use strict;
use warnings;
sub random_name_generator($);

# usage: faxout.pl number filename
# example: faxout.pl 5555551212 myfax.pdf

if ($#ARGV != 1) {
	print qq(FAIL: 2 Arguments needed\n);
	exit(0);
}

my ($callto,$pdfname,$callfile,$filename);

$callto = $ARGV[0];
$pdfname = $ARGV[1];

my $tifname = $pdfname;
$tifname =~ s/.pdf/.tif/i;

system("gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sOutputFile=$tifname $pdfname");

if ($callto) {
	$filename = &random_name_generator(12).".call";
	open (MYFILE, ">>/tmp/$filename") or die $!;
	$callfile = "Channel: Local/$callto\@outboundialcontext\n";
	$callfile = $callfile . "MaxRetries: 1\n";
	$callfile = $callfile . "RetryTime: 60\n";
	$callfile = $callfile . "WaitTime: 60\n";
	$callfile = $callfile . "Archive: yes\n";
	$callfile = $callfile . "Context: outboundfax\n";
	$callfile = $callfile . "Extension: s\n";
	$callfile = $callfile . "Priority: 1\n";
	$callfile = $callfile . "Set: FAXFILE=$tifname\n";
	print MYFILE $callfile;
	close (MYFILE);
	system("mv /tmp/$filename /var/spool/asterisk/outgoing");
}

sub random_name_generator($) {
	my ($namelength, $randomstring, @chars);
	$namelength = shift;
	@chars = ('a'..'z','A'..'Z','0'..'9');
	foreach (1..$namelength) {
		$randomstring .= $chars[rand @chars];
	}
	return $randomstring;
}

Happy Coding!

13 Comments

  1. Just a note: if you are using a repo-based distribution of Linux, please search for the required perl modules in yum/apt/other before using CPAN.

    I’ve seen (and experienced) messed up installs as a result from using more then one package manager on a system.

    Ubuntu:
    libmime-base64-perl
    libmime-lite-perl
    libauthen-sasl-perl

    Centos:
    http://dag.wieers.com/rpm/packages/perl-MIME-Base64/
    http://dag.wieers.com/rpm/packages/perl-MIME-Lite/
    http://dag.wieers.com/rpm/packages/perl-Authen-SASL/

  2. Just finished following all instructions from team forrest guide —> get error cannot load module

    [Dec 18 14:31:26] WARNING[11002]: loader.c:359 load_dynamic_module: Error loadin ile: No such file or directory
    [Dec 18 14:31:26] WARNING[11002]: loader.c:653 load_resource: Module ‘res_fax.so

    Verified the files exist:

    astbh00*CLI> module load res_f
    res_fax.so res_features.so res_fax_digium.so
    astbh00*CLI> module load res_f

    Help would be appreciated:

  3. Ok… we’d love to help!

    First, we need to know a little bit more info, such as: What OS are you running? What build of Asterisk?

  4. First, thanks for the guide!

    I am having some issues getting things to work, however. I’ve got the Fax for Asterisk add-ons installed (“fax show stats” shows the expected output), and I copied the incoming section of your dialplan essentially wholesale (only changed the tif location to /tmp instead of /var/…..). The inbound calls are coming in via SIP, and the context for it has t38pt_udptl=yes.

    When I try to fax, I get a couple lines on the Asterisk console that say “Using SIP RTP CoS mark 5” and “Using UDPTL CoS mark 5”, but nothing else happens.

    Is there anything obvious that I’m missing?

  5. Thank you Pat,

    Normally I see that when you’re making a call from either a bad sip user or to an extension that’s not in the dialplan. If you want to contact us, we can take a look at your configs and how you’re dialing.

  6. Thanks for the guide. I’m a complete newbie to PBX software. I’ve successfully (I think) implemented the free 1 channel version of Fax for Asterisk on an install of AsteriskNOW. Is there a way to send a fax from the command line? For example, if I wanted to create a shell script (running as a cron job) that would automatically fax a file?

    Thanks in advance!!!

  7. You can do this with an originate command, but you might find it better to make a call file if you’re using cron.

  8. Hi, works great. Any idea how we can get a decent and complete CDR for an outbound fax using the callfile? The stored CDR is table cdr has always 0 seconds billtime.
    Thaaanks..

  9. @Kenneth—

    Normally we would do custom CDR for all calls… this way we can tie in rates, etc. in real time.

  10. Hi,

    I would appreciate a guide on how I can fend faxes from my PC without connecting to the asterisk server directly to send.

    Thanks

  11. I’av got a error when loading the res_fax.so module.
    Like shis:
    WARNING[1764]:Loader.c:386 load_dynamic_module:error loading module ‘res_fax.so’:/usr/lib/asterisk/modules/res_fax.so: undefined symbol: ao2_ref

    I’m a beginner,mybe shis question is so stupid. But it disturb me. thank you vvvvvery much!

  12. additional:
    My system is Ubuntu10.04 , kernel is linux2.6.32-22-generic. Asterisk version is 1.6.2.7 .

  13. Hi,

    Thanks a lot for this great tutorial. It was a great help. Just one (rather newbie) question:

    You mention in the faxout.pl script the channel to have the context outboundialcontext …. can’t figure out what that is for the life of me!

    Can you please provide any hint on that? Thanks.

Comments are closed.