"hello world"
article in Tech linux-unix-and-friends

Asterisk faxing - Setup a complete faxing solution!

Faxing within Asterisk

Faxing with Asterisk can be problematic.  Right now all (Oct-2005) most Asterisk hardware doesn't support faxing directly.  So, you have to actually implement a soft fax modem.  Asterisk uses spandsp for implementing the actual modem.

I'm not writing to document how to actually use the fax applications within Asterisk.  For that look at Faxing With Asterisk I think it does a pretty good job of detailing how to use it.

However, I would like to comment on how to preprocess the tiffs that you want to send.  Many times you've got tiffs that aren't fax compliant.  I created a quick perl script that concats multiple tiff files together and makes sure they are fax compliant.  In fact, much of this code was developed by looking at how HylaFax preprocessed their tiffs.

Of course you'll want to modify this script for your own purposes it.  It requires perl, tiffcp, ghostscript, tiff2ps, and the Asterisk::Outgoing module for perl. 

Again, this script is used to insure that the tiffs you want to send are fax compliant.  It creates a temporary tiff for sending and creates a call file for Asterisk to process the fax file.

#!/usr/bin/perl

# Author: David A horner (DAH) http://dave.thehorners.com
# License: Public Domain

use Getopt::Std;
use Asterisk::Outgoing;
require File::Temp;
use File::Temp ();
use strict;

# handle args
my %opts;
getopts('a:l:p:r:u:', \%opts );

my $faxnumber=shift(@ARGV);
usage('Missing faxnumber') unless $faxnumber;
print "Fax number: $faxnumber\n";

#my $tmpp=pop(@ARGV);
#push(@ARGV, "/tmp/fax.tif");
#push(@ARGV, $tmpp);
usage('You must have at least one tiff file to send') unless $ARGV[0];
print "Sending fax files:\n";
foreach (@ARGV) {
   print "$_\n";
}
my $tmpfile = new File::Temp(UNLINK => 0, SUFFIX => ".tfax");
my $faxfile = new File::Temp(UNLINK => 0, SUFFIX => ".fax");
print "Filename is $tmpfile\n";
#-c g3:2d:fill
print "Running: tiffcp -i -c g3:1d:fill -f lsb2msb -r 9999 @ARGV $tmpfile\n";
###system("tiffcp -c g3:2d:fill -f lsb2msb -s @ARGV $tmpfile");
system("tiffcp -i -c g3:1d:fill -f lsb2msb -r 9999 @ARGV $tmpfile");
print "DONE WITH TIFFCP!\n";
my $vres=98;
my $hres=203.29;
my $paper='letter';
print "RUNNING: /usr/bin/tiff2ps -a $tmpfile | /usr/bin/gs -q -sDEVICE=tiffg3 -dNOPAUSE -dSAFER=true -sPAPERSIZE=$paper -dFIXEDMEDIA -r".$hres."x".$vres." \"-sOutputFile=$faxfile\"  -\n";
system("/usr/bin/tiff2ps -a  $tmpfile | /usr/bin/gs -q -sDEVICE=tiffg3 -dNOPAUSE -dSAFER=true -sPAPERSIZE=$paper -dFIXEDMEDIA -r".$hres."x".$vres." \"-sOutputFile=$faxfile\"  -") ;
print "DONE WITH GS!\n";
#usage('Missing faxnumber') unless $opts{'r'};
#usage('pages of the tiff file')  unless $opts{'l'};

my $out = new Asterisk::Outgoing;
$out->setvariable("Channel","ZAP/G1/$faxnumber");
$out->setvariable("MaxRetries","30");
$out->setvariable("WaitTime","100");
$out->setvariable("Application","txfax");
$out->setvariable("Data","$tmpfile|caller");
foreach my $var (keys %{$out->{OUTVARS}}) {
   print "$var: " . $out->{OUTVARS}{$var} . "\n";
}

$out->create_outgoing;
print "DONE WITH OUTGOING!\n";
exit;

sub usage {
    print "\n!! ", @_, " !!\n";
    print <<USAGE;
Usage: $0 [options] <fax-number> <page(s) in g3-format>
USAGE
    exit 1;
}

In the future I'll post some other scripts for processing faxes when they come in.  These scripts save off the tiff and email the user with the tiff that came in.
----
Now these scripts assume that you've already installed the app_rxfax and app_txfax that are included with the spandsp.

You should add a file named "faxextensions" to your /etc/asterisk/ directory and include this file in your asterisk extensions.
; Author: David A horner (DAH) http://dave.thehorners.com
; License: Public Domain
;
; (#include <extensions/fax>)
; Recieve faxes and email em!
; Make sure that /usr/local/sbin/mailfax exists and works!
;

; If you want fax detection(asterisk to put faxes into the fax ext)
; Edit zapata.conf and add faxdetect=incoming,outgoing,or both

; Used for debuging
; exten => s,1,rxfax(/path_to_test_tiff/incoming.tif)

; To define email address, use following in asterisk console
; *CLI> database put extensionemail companyname bob@example.com
; Check if the email is correct by using
; *CLI> database show

; Macro for recieving faxes
[macro-faxreceive]
exten => s,1,SetVar(FAXFILE=/var/spool/asterisk/faxes/${UNIQUEID}.tif)
exten => s,2,DBGet(EMAILADDR=extensionemail/${ARG1})
exten => s,3,rxfax(${FAXFILE})
exten => s,103,SetVar(EMAILADDR=daveydave1234@yahoo.com)
exten => s,104,Goto(3)

[faxsend]
exten => h,1,System(/usr/local/sbin/mailfax ${FAXFILE} ${EMAILADDR} "${CALLERIDNUM} ${CALLERIDNAME}")
exten => h,2,Hangup
exten => i,1,Hangup     ;invalid event
exten => t,1,Hangup     ;timeout event

[incomingfax]
exten => s,1,Macro(faxreceive,pbxsolutions)
include => faxsend

Here is the mailfax script that I wrote to process the actual tiff fax file and email it. The script requires mime-construct as well as tiff2ps (for pdf emails).
#!/bin/sh

# Author: David A horner (DAH) http://dave.thehorners.com
# License: Public Domain

FAXFILE=$1
FILENAME=${FAXFILE:0:${#FAXFILE}-4}
PDFFILE=${FILENAME}".pdf"
RECIPIENT=$2
FAXSENDER=$3

FROMADDR=FaxServer@FAXSERVERNAME.com
FROMNAME="FAXSERVERNAME Faxserver"
BODY="Attached is your fax.  Thank you for using FAXSERVERNAME!"

if [ "${#@}" -ne "3" ]; then
  echo "$0 tifpath emailaddress faxsentfrom"
  echo "  tifpath - path of tif to send"
  echo "  emailaddress - email address's of recipients"
  echo "  faxsentfrom - fax sender, put in subject line"
  exit
fi

if [ -f $FAXFILE ]; then
  # Send file as plain tiff
  mime-construct --to $RECIPIENT --subject "Fax from $FAXSENDER" \
    --header "From: \"$FROMNAME\" <$FROMADDR>$nl" \
    --string "$BODY"\
    --attachment fax.tif --type application/tiff --file $FAXFILE

  # Send file as a pdf
#  tiff2ps -2eaz -w 8.5 -h 11 $FAXFILE | ps2pdf - | \
#  tiff2ps -2eaz $FAXFILE | ps2pdf - | \
  tiff2ps -2eaz -w 8.5 -h 11 $FAXFILE | ps2pdf - $PDFFILE
  mime-construct --to $RECIPIENT --subject "Fax from $FAXSENDER" \
    --header "From: \"$FROMNAME\" <$FROMADDR>$nl" \
    --string "$BODY"\
    --attachment fax.pdf --type application/pdf --file $PDFFILE
else
  mime-construct --to $RECIPIENT --subject "Fax error from $FAXSENDER" \
    --header "From: \"$FROMNAME\" <$FROMADDR>$nl" \
    --string "Fax not recieved correctly!"
fi
Note: This script does not delete the resulting tif and pdf files.  You can add an rm to the script yourself... or simply create a cron job to delete files that are older than X days.

To use these script you now simply create a context like so:
#include <faxextensions>

;Faxline
exten => XXXXXXX,1,Goto(faxlinecontext,100,1)
exten => XXXXXXX,2,Congestion

[faxlinecontext]
exten => 100,1,Macro(faxreceive,companyname)
include => faxsend

Also just for easy access, here is a call file for sending a fax:
Channel: Zap/g1/XXXXXXXXXX
Callerid: "faxing" <XXXXXXXXXX>
MaxRetries: 0
Application: txfax
Data: /var/spool/asterisk/faxes/sometiff.tif|caller
Context: default
Extension: s
RetryTime: 60
WaitTime: 60

Until Asterisk supports T.38 relay of fax you'll want to do uncompressed ulaw between you and your PSTN connection.  In fact, I wouldn't even try it without a direct PSTN connection, all my testing showed bad results when trying to do VOIP faxing.

-----
Update
-----
I've yet to try it...but here is a script to do email to fax conversions.  This is software for doing a email to fax gateway that accepts both tiff and pdf.
email2fax


Another software solution that looks good is AsterFax
Created: 2005-03-26 15:38:39 Modified: 2009-12-06 19:36:35
/root sections/
>peach custard pie
>linux
>windows
>programming
>random tech
>science
>research


moon and stars



My brain

Visible Dave Project


$$\cos x = \sum\limits_{n = 0}^\infty {\frac{{\left( { - 1} \right)^n x^{2n} }}{{\left( {2n} \right)!}}}$$