Web Fax for Asterisk

Over the past few weeks, I have been working with the popular telephony software asterisk and all the stack that stands on top of it. I have (in coordination with a friend) setup asterisk, FreePBX, a2billing, fax for asterisk and vicidial on several production servers. Combined, these provide a complete telephony solution for a wide range of commercial organizations. As a side note, I might be writing tutorials about some of these things in the future.

One of most problematic of these technologies was getting fax to work with asterisk. We tried many variations and finally found out that Digium’s Fax for Asterisk, or Free Fax for Asterisk (FFA) is currently the most stable and easy to set up. However, it does not provide an easy way to let your end users send faxes if they don’t have SIP enabled fax machines. What’s more, there is no software available that would allow you to do that! So, in one of our projects, we had to come up with a custom interface and we decided to open it up so that many others who need it can benefit from our efforts and hopefully build on it.

We call this PHP-based script Web Fax for Asterisk and are releasing it under GPLv3. For those of you who just want to get the code, you can get it from sourceforge.net. You can also get it from the SF SVN repo if you want to contribute. (In that case, gimme a shout and I’ll allow you to commit.)

For those of you who want to learn how it’s made, please read on.

First you need to install asterisk and get FFA to work. Search for any asterisk installation tutorial (you’ll need to go with 1.6 if you want the more stable T.38 support) and then follow this guide to setup FFA. You should also setup FreePBX and get the Fax Configuration module from Schmoozecom. That would help you configure FFA so that your clients can receive faxes in their mailboxes. After that, you can begin with our Web Fax script to enable sending.

Web Fax for Asterisk

The rest of this post will first describe the code that has gone into Web Fax 0.1. At the end, we will cover the installation instructions to get your started. Let’s begin with the HTML form that the users see. It’s a fairly simple form which has some error checking. Web Fax currently supports DOC and PDF formats so you should include some instructions about this in your form. I’ll post the skeleton code here. The Web Fax archive contains a much better interface. So, the form:

[sourcecode lang=”html”]
<form action=”sendfax.php” method=”post” enctype=”multipart/form-data” name=”form1” id=”form1”>
<table>
<tr>
<td width=”188” class=”formLabel”>FAX Header</td>
<td width=”232”>
<input name=”faxHeader” type=”text” id=”faxHeader” value=”CSRDU” /></td>
</tr>
<tr>
<td class=”formLabel”>Local Station Identifier</td>
<td>
<input name=”localID” type=”text” id=”localID” value=”3239366136” /></td>
</tr>
<tr>
<td class=”formLabel”>Notification Email Address </td>
<td>
<input name=”email” type=”text” id=”email” value=”recluze@gmail.com” /></td>
</tr>
<tr>
<td class=”formLabel”>FAX Destination</td>
<td>
<input name=”dest” type=”text” id=”dest” value=”14809073626” /></td>
</tr>
<tr>
<td class=”formLabel”>Attach file</td>
<td>
<input type=”file” name=”faxFile” id=”faxFile” /></td>
</tr>
<tr>
<td> </td>
<td><input type=”submit” name=”sendFax” id=”sendFax” value=”Send FAX” /></td>
<td> </td>
</tr>
</table>
</form>
[/sourcecode]

The sendfax.php script does all the heavy lifting of communicating the information provided by the user to asterisk. It first uploads the document, converts it to tif format as required by Fax for Asterisk and then makes a call through asterisk. Let’s take a look at the salient parts of this script.

SendFax script

Uploading the document is easy. All we need to do is to check what format the document is in. We currently support .doc and .pdf formats. The strategy for .doc is to first convert it to .pdf. For that, we use the wvPDF command. (wvPDF requires tetex-latex or another package providing latex). We first save the uploaded .doc file with a temporary name in /tmp. Then we convert it.

[sourcecode lang=”php”]
$input_file_noext = unique_name(“/tmp”, “”);
$input_file = $input_file_noext . “.pdf”;
$input_file_tif = $input_file_noext . “.tif”;
$input_file_doc = $input_file_noext . “.doc”;

// needs the following in /etc/sudoers
// asterisk ALL=(ALL) NOPASSWD: /usr/bin/wvPDF
$wv_command = “sudo /usr/bin/wvPDF $input_file_doc $input_file” ;
$wv_command_output = system($wv_command, $retval);
[/sourcecode]

Notice the commented out lines. For some reason, latex won’t run from PHP. So, we add the wvPDF to /etc/sudoers file for user asterisk – we’re running apache as the user asterisk.

Now that we have a .pdf file – whether through conversion from .doc or originally from the user – we can convert it to .tif through ghostscript. (Make sure it’s installed.)

[sourcecode lang=”php”]
$gs_command = “gs -q -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=${input_file_tif} -f $input_file “ ;
$gs_command_output = system($gs_command, $retval);
$doc_convert_output = $gs_command_output;
[/sourcecode]

Finally, we need to create a .call file that will automate asterisk making a call. We set some parameters, create the file and move it to asterisk’s outgoing directory.

[sourcecode lang=”php”]
$faxHeader = $_POST[“faxHeader”];
$localID = $_POST[“localID”];
$email = $_POST[“email”];
$dest = $_POST[“dest”];

$outbound_route = “@outbound-allroutes”;
$outboundfax_context = “outboundfax”;

$callfile = “Channel: Local/$dest$outbound_routen” .
“MaxRetries: 1n” .
“RetryTime: 60n” .
“WaitTime: 60n” .
“Archive: yesn” .
“Context: $outboundfax_context n” .
“Extension: sn” .
“Priority: 1n” .
“Set: FAXFILE=$input_file_tifn” .
“Set: FAXHEADER=$faxHeadern” .
“Set: TIMESTAMP=” . date(“d/m/y : H:i:s”,time()) . “n” .
“Set: DESTINATION=$destn”.
“Set: LOCALID=$localIDn” .
“Set: EMAIL=$emailn”;

// create the call file in /tmp
$callfilename = unique_name(“/tmp”, “.call”);
$f = fopen($callfilename, “w”);
fwrite($f, $callfile);
fclose($f);

// $asterisk_spool_folder is usually /var/spool/asterisk/outgoing
rename($callfilename, $asterisk_spool_folder . “/” . substr($callfilename,4));
[/sourcecode]

Notice the channel and context fields in the call file. The channel will depend on your outbound route. I found that outboud-allroutes worked for my settings. You might want to try that if you’re not sure of the route. The last thing we need to do is to create a context for sending fax within asterisk conf files.

Outbout Fax Context

The context should ideally be created in /etc/asterisk/extensions_additional.conf. You should also make sure that this file is ‘included’ in extensions.conf. The content of the context follow:

[sourcecode]
[outboundfax]
exten => s,1,Set(FAXOPT(filename)=${FAXFILE})
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=${FAXHEADER})
exten => s,n,Set(FAXOPT(localstationid)=${LOCALID})
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,SendFAX(${FAXFILE},d)
exten => s,n,System(${ASTVARLIBDIR}/bin/faxnotify.php INIT “${EMAIL}” “${DESTINATION}” “${TIMESTAMP}” “NO_STATUS” “NO_PAGES”)
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => h,n,NoOp(FaxStatus : ${FAXSTATUS})
exten => h,n,NoOp(FaxStatusString : ${FAXSTATUSSTRING})
exten => h,n,NoOp(FaxError : ${FAXERROR})
exten => h,n,NoOp(RemoteStationID : ${REMOTESTATIONID})
exten => h,n,NoOp(FaxPages : ${FAXPAGES})
exten => h,n,NoOp(FaxBitRate : ${FAXBITRATE})
exten => h,n,NoOp(FaxResolution : ${FAXRESOLUTION})
exten => h,n,System(${ASTVARLIBDIR}/bin/faxnotify.php NOTIFY “${EMAIL}” “${DESTINATION}” “${TIMESTAMP}” “${FAXSTATUSSTRING}” “${FAXPAGES}”)
; end of outboundfax context
[/sourcecode]

The important lines are the ones with ‘SendFax’ and ‘System’ calls. SendFax sends the fax (duh!) and system calls out notification script that sends an email to the user describing the status of the transmission. The notification script is essentially a mailer. You can refer to the Web Fax source for the complete script.

And that is how we implemented the Web Fax for Asterisk script.