UxFax2 Unix Fax Server

Version 3.x

Server Technical

Description


Table of Contents


INTRODUCTION
Interprocess Communications (IPC)
Spooler
Modem Driver
BMtransform
Preparation
Pagination
Notification
Reception Processing
Glossary File Structure
PI Interpretive Language

INTERPROCESS COMMUNICATIONS
Example IPC Structure

THE FAX SPOOLER
Startup
Runtime Environment
Configuration Files
License Verification
Master Validation
Go Into Background
Server Initiation
Open Fax Server Log
Enter Main Process Loop
Shutdown
Main Process Loop
Servicing Client Requests
Promoting Terminated Tasks
Spawning Due Tasks
Perform Fax History Archiving
Maintain Queue Statistics

THE MODEM DRIVER
Global Settings
debug
tia592
TxBitOrder
RxBitOrder
allow2d
maxspeed
termserv
binlock
date_fmt
Startup
Main Process Loop
Confirm the spooler is running
Check for a UUCP lock
Reset the modem (if necessary)
Service spooler commands
Answer incoming calls
Sending a Fax
rx_srv_sendfax()
GenericClass2_send()
send_g3()
Receiving a Fax
receive_fax()
BMtransform
Usage within UxFax2.local
NotifyPrint_Do
Epson8_graphics
Epson24_graphics
LjetII_graphics
LjetIIL_graphics
LjetIII_graphics
LjetIIIL_graphics
vi_Prepare
UniplexII_Prepare
WP51_Prepare
PCR_Prepare
PCF_Prepare
PCL_Prepare
PCX_Prepare
DCX_Prepare
TIFF_Prepare
ReceiveProcessFax
SendPrepareGroupIII
CreateDCXFile




INTRODUCTION

This document describes the UxFax2 fax server software and provides substantial detail on the spooling mechanism and the modem driver. The client application (faxcmd) is not discussed in detail. The fax server is described under the following four major headings, each of which is also briefly introduced next;
In addition, there are several common concepts in the structure and file usage of the UxFax2 fax server software. An understanding of these concepts assists in an overall understanding of the software;
These topics are also intoduced briefly here, but a complete description of the PI langauage and glossry files is available in the UxFax2 API Programmers Reference manual.

Interprocess Communications (IPC)

The UxFax2 fax server software exploits the IPC facilities which are built into all Unix kernels. This provides the simplest and most portable method of process to process communications without any reliance upon other software, such as RPC, which is often unbundled in commercial releases of Unix.

The UxFax2 client processes (faxcmd) communicate with the fax spooler through "named pipes" (or FIFOs) in the spooling directory. The fax spooler communicates with each attached modem driver through nterprocess pipes. All processes, including the modem driver, submit command requests to the spooler through a common FIFO, and each request is serviced in turn through this FIFO. And due to the efficient design of the spooler scheduling mechanism, all requests can be served rapidly.

Spooler

The UxFax2 spooler is a single executable program named faxsrv. The spooler accepts command requests, including documents submitted for transmission as faxes from the clients, and produces command responses in reply to the client processes. The spooler also maintains the various ISAM data tables which are used to store configuration and fax history data, along with a name and address data base. All requests to modify the data tables are handled by the spooler through the client request interface.

All scheduling of fax server tasks are controlled by the spooler. These tasks will include the preparation and pagination of documents submitted for transmission, plus processing and notification of received faxes. These various tasks are handled by child processes of the spooler. Each time a task needs to be performed the spooler will spawn a copy of itself to execute the particular task.

The spooler will also "spawn" a copy of itself for each defined modem. These child processes will execute as a modem driver. Faxes which are ready for transmission will be assigned to an available modem driver.

The spooler uses an efficient deterministic scheduling algorithm. And since most of the server tasks are handled by child processes, the main spooler process activity is confined within a very tight loop, which involves;
  1. Accepting incoming client request.
  2. Dispatching due or over-due tasks.
  3. Promoting and rescheduling completed tasks.
  4. Performing routine "house-keeping" tasks.
Wherever possible, the spooler uses editable shell scripts and other interpretive techniques for all major tasks. This allows the software to be easily customised if necessary, or extended. For example, it is possible to install support for additional document types without recompiling the code.

Modem Driver

The modem driver executes as a spawned child process of the spooler, except the entire modem driver is implemented in an interpretive language. This language is called PI and closely resemles the "C" language. The entire driver is visible as plain text and may be modified to suit custom site requirements if necessary.

But the modem driver attempts to provide a generic driver for any fax modem, and in most cases this is achieved. At most, redefinition of the modem "dialer prefix" is all that is necessary to customise the driver for particular modems.

Reception of incoming faxes is automatically handled by the modem driver without intervention by the fax spooler. As soon as "ring" indication is detected on a modem, the driver will notify the spooler, thus indicating that the modem is no longer available for transmission of scheduled faxes. When the entire fax has been recevied, the modem driver will again notify the spooler which will schedule the received fax for further processing and notification.

Faxes which are due for transmission are passed to the modem driver with a simple command. The modem driver then controls the modem through a dialogue of commands and expected responses. The modem driver provides "change of state" indication to the spooler, along with result codes after tranmission of faxes.

BMtransform

The creation and manipulation of all documents and images is all done by a single executable program named BMtransform. This program is a bit-map transformation engine; hence it's name.

Internally, UxFax2 uses a custom group 3 file format since there is no standard or internationally recognised fax file format except for CCITT T.4. This internal file format comprises concatenated CCITT G3 images, each preceded by a 64 byte header. BMtransform is used in all stages of fax preparation, pagination, notification and reception processing to convert to or from this internal format.

Preparation. BMtransform acts as a PCL interpreter, and is able to emulate a Laserjet II or Laserjet III printer. To allow Uniplex or WP documents to be submitted for faxing, the applications Laserjet printer driver is called to generate a PCL image of the document. This PCL image is then converted by BMtransform into a group 3 image.

For ASCII files, the Laserjet emulation is also used. For other document and image formats, such as PCX, TIFF etc., BMtransform is called with specific options to handle these formats directly.

Pagination. BMtransform supports a variety of output formats and options. One of these options allows it to create individual files for each page of a composite image file. During "pagination", a prepared group 3 file is converted into discreet CCITT fax page images, ready for transmission.

Notification. BMtransform provides several output options to generate common printer formats such as Laserjet and Epson. This capability is used to generate notification printouts.

Reception Processing. Faxes are received in raw CCITT T.4 format as individual page image files. The reception process uses BMtransform to generate a composite image file. This is opposite to the pagination process.

Glossary File Structure

Most text files used by the software are "glossary files". This is a simple text file structure which allows otherwise unrelated information to be grouped together in one file, instead of having many individual files. For example, one of the major glossary files used by UxFax2 is called UxFax2.local. Amongst other things, this file includes many shell scripts which would otherwise have to be provided as individual executable files.

Discreet information within a glossary file is held within a "glossary entry". A glossary entry is delineated by a unique text heading preceded by a hash ("#") character in the left column, and finishes with double closing braces ("))") in the left column.

There are several extensions to the glossary file structure which provide "preprocessor" type facilities ordinarily associated with a programming language. These facilities are used extensively by the software, namely;

PI Interpretive Language

UxFax2 uses an inbuilt interpretive language extensively for several functions. This interpreter is modelled on the "C" language and is called "PI" (program interpreter). It is a typical procedural  language with sub-routine and argument passing. The major difference from "C" is that it is a loosely typed language which allows very flexible variable usage with automatic allocation of data and array storage. The code for a PI program is maintained in a glossary file.

The interpreter is used solely to implement the modem driver. Several custom functions are included to accommodate low level fax functions, or where speed is most important. But otherwise the entire logic of the modem driver is visible in the driver's PI code.

The interpreter is also used to generate the headers which appear on the top of notification print-outs.


INTERPROCESS COMMUNICATIONS

The UxFax2 fax server software exploits the IPC facilities which are common to all versions of Unix. The client processes (faxcmd) communicate with the fax spooler through "named pipes" (or FIFOs) in the spooling directory, and fax spooler communicates with each attached modem driver through interprocess pipes. All processes, including the modem driver, submit command requests to the spooler through a common FIFO, and each request is served in turn through this FIFO. The named pipes are all located in the spooling directory, within the "ipc" sub-directory, named $SpoolDir/ipc.

The main spooler process creates a FIFO called "Lock". Any process that wishes to issue a request to the spooler writes it's process ID into the file. (This includes the modem driver processes).

Each client process creates two FIFOs in the ipc directory which are named after the clients process ID. For example, if the process has PID 1234, one of the FIFOs is called the control FIFO and will be named "C01234", the other is called the data FIFO and will be called "D01234".

When a client issues a request, it writes it's PID to the Lock file, and writes it's request to it's named control FIFO. The server will read the PID from the Lock file and open the control FIFO for reading. After processing the request, the server will write it's response into the data FIFO and then close it. The client will read all data from the data FIFO until end-of-file.

For example, when the "status" request is issued to the fax spooler, as shown in the following command line extract, only the line starting with "Faxcmd:" is generated locally by the client. The remaining text (highlighted) is generated by the spooler and is all read from the data FIFO.

faxcmd> status
Faxcmd: Request 'status' sent Sun Aug 25 22:17:34 1995
Server: Command CMD_STATUS rcv'd from root@pjb
Spooler status: 1 modem(s) attached, 0 active task(s)
Modem      Mode                 Status
modem1     Send (no indial)     Initialising

Each attached modem driver is a spawned copy of the fax spooler (faxsrv). When the child process is created, the spooler will create two IPC pipes, and the child will re-open it's standard input and output streams so they are attached to these two same pipes.

The modem drivers use the same mechanism to issue requests to the spooler, by writing their PID to the "Lock" file. Except they issue their request through their stdin/stdout file stream, and consequently through the IPC pipes to the spooler, instead of through named pipes like other clients.

Example IPC Structure

  Client            Contents of         Spooler       IPC     Modem
  Processes        $SpoolDir/ipc        Process      pipes    Driver

                     +--------+        +----------+        +----------+
                     | Master |        | pid=1010 | -----> | pid=2233 |
                     +--------+        |          |        |          |
                     |  Lock  | -----> |  faxsrv  | <----- |  faxsrv  |
 +----------+        +--------+        +----------+        +----------+
 | pid=1234 | -----> | C01234 |
 |          |        +--------+
 |  faxcmd  | <----- | D01234 |
 +----------+        +--------+
 | pid=4444 | -----> | C04444 |
 |          |        +--------+
 |  faxcmd  | <----- | D04444 |
 +----------+        +--------+


This diagram shows an example sitution where the fax spooler is running (pid 1010) with one modem driver attached (pid 2233), and there are two client process running (pid 1234 and 4444). This diagram also shows the contents of the ipc subdirectory in the spool directory.

Master
This is a regular file. When the spooler process starts up, it checks the PID in the Master file to determine if another copy of the spooler is running. Otherwise it writes its own PID into this file.

Lock
This is a named pipe (FIFO) file. The spooler creates this file at startup. Whenever any client process wishes to submit a command or request to the server, it will write it's process ID into this FIFO. Ordinarily this file will have a size of zero bytes, but if there is a backlog of requests, it's size will be an multiple of four bytes, since the client PIDs are written into this FIFO as binary words.

Cnnnnn and Dnnnnn
There are two named pipes created by each client process. These are referred to as the Control and Data FIFOs. The files are named after the PID of the client. When the client wishes to submit a command or request, after writing its PID into the Lock file, it will write the request into the Control file, and then wait for a reply from the Data FIFO.

When the spooler reads the client PID from the Lock file, it will open the corresponding Control FIFO to read the client request. After processing the request, the spooler writes the response to the Data FIFO.

Modem Driver Each modem driver also communicates with the spooler in a similar fashion, by writing its PID to the Lock file. But when the modem driver is spawned by the spooler, the spooler creates an interprocess channel between them which is used instead of name pipes. The Control IPC channel will be the modem driver's standard output file descriptor. The Data IPC channel will be the modem driver's standard input.


THE FAX SPOOLER

The fax spooler operates as a background daemon process. Ordinarily it will be added to the system startup files so it starts automatically whenever the system is rebooted. At any time there should be more than one copy of it running. The parent copy will be the actual spooler process, and there should be at least one child process operating as the modem driver. These two copies will be operating with super-user privilege.

At other times there may be more copies running as the spooler spawns additional copies of itself to perform the various tasks involved in the preparation and processing of faxes. These copies will be operating under the priveleges of the owner of the fax task (the user who submitted the fax).

Startup

The spooler is either started from the client process, or it may be called directly from the command line. Both methods are identical, since even the client process simply calls the spooler by name, i.e.;

${FaxBin:={Utools:=/usr}/Utools/bin}/faxsrv

Prior to entering the main process loop, there are many steps performed during the initiation of the spooler. Besides reading the common configuration files, the spooler must validate the license and then verify that there are no other copies of the spooler running. It will then put itself into background and spawn copies of itself for each defined modem driver.

Runtime Environment
The fax spooler process, faxsrv runs with "root" priveleges. This is necessary because it will spawn tasks on behalf of users who submit or receive faxes. Therefore, the actual executable file has the "set UID" and "set GID" bits set as below;

chmod 6555 $Utools/Utools/bin/faxsrv
chown root $Utools/Utools/bin/faxsrv
chgrp bin $Utools/Utools/bin/faxsrv

Any user is able to start the fax spooler simply by calling it by name, but the process will change it's ownership to "root".

Configuration Files
Startup is controlled by the configuration file which is found in the same location as the executable. This file is named UxFax2.cfg. The spooler will examine it's own command line. If the program was called with a relative or absolute path, the spooler will look in that location for the configuration file. Otherwise it will examine the
paths in the "PATH" environment variable. The configuration file sets various environment variables which are used extensively by the program, these are;

FaxBin - Location of binary executables.
FaxLib - Location of UxFax2.* library files.
SpoolDir - Location of the spool directory.
FaxInitFile - Master glossary/configuration file.
FontDir - Location of fonts.

This configuration also names the main message catalogue;

$FaxLib/UxFax2.msg - Message catalogue.

After finding this file, the remaining startup configuration is directed by the file nominated by the environment variable "FaxInitFile". This is usually $FaxLib/UxFax2.ua.glos. This glossary file contains various "#include", "#open" and "#define" directives naming other files which are opened at startup. These files will include;

$FaxLib/UxFax2.local - Scripts and printer drivers.
$FaxLib/UxFax2.modem - Modem drivers.

License Verification
The fax spooler will only run if there is a valid license or evaluation key installed. Only the server looks for licenses; the client processes do not, but they will not be usable if the spooler cannot run.

The license key limits the number of modems that may be attached to the spooler. An evaluation key will allow an unlimited number of modems to be attached. The other optional license keys for receive and networking are examined by the spooler. The network option also enables the receive option.

Master Validation
To prohibit multiple copies of the fax spooler from running, the spooler will write it's process ID (PID) into a "Master" file in the spool directory named $SpoolDir/ipc/Master. At stratup, the spooler will look for this file to determine if a copy of the spooler is already running. If so, the spooler will exit with an error message (server error 4).

Go Into Background
After the spooler has validated the Master file, it will also recreate the "Lock" file. This is the main client request FIFO used for inter-process communication between clients and the spooler. This file is named $SpoolDir/ipc/Lock.

The spooler will then execute a fork() and exit(). This puts the server into the background. It then executes setpgrp() to create it's own process group. The spooler is now a "daemon" process. The process ID of this new daemon process is written into the "Master" file.

The spooler reopens it's standard input and output streams to the null device /dev/null to disassociate itself from any controlling terminals. It also sets it's signal trapping to ignore SIGHUP and SIGQUIT. A special signal trap is set for SIGTERM, since this signal is ordinarily used to terminate processes, and the trap will allow graceful exit of the spooler and any of it's child processes.

Server Initiation
After opening the fax data table, which the spooler will keep open until it exits, the spooler will spawn copies of itself to execute as modem drivers. The spooler will spawn a copy for each modem defined in the modem data table, limited by the number allowed in the license limit.

In case the spooler previously stopped while any server tasks were active, the fax history data table will still record these tasks as being active, so the spooler will reset these fax history records to a "Waiting" state.

Open Fax Server Log
The spooler will close it's standard error stream, which is originally open to the startup controlling terminal. It will then reopen this stream to the server log file, $SpoolDir/log/faxsrv. The file is opened in "append" mode, so the file will not be truncated each time the spooler starts.

Enter Main Process Loop
Prior to entering the main spooler process loop, the spooler will read the configuration file named $SpoolDir/db/alias.cfg. This file contains local custom configuration including;

The spooler then opens a new entry in the server log. The server log is written as a glossary file, and this new entry is a new glossary header, consisting of the date, time and process ID which will unique identify this new glossary entry. e.g.;

pid.00671.03/06/96.15:46:34 Fax server start-up

The spooler will open the lock FIFO it previously created when going into background. This FIFO is opened for reading by the spooler to read the PID of clients processes who wish to submit a request.

Lastly, the spooler reads each of the command names from the main message catalogue, $FaxLib/UxFax2.msg, messages 300 through 349. These messages are used by the spooler in response to client requests.

The spooler now enters the main process loop. This is described in detail under a separate heading.

Shutdown

The spooler will remain in the main process loop until it receives a "shutdown" request from a client, or if it receives a SIGTERM signal from another process. Either method will allow the spooler to shutdown gracefully.

If the spooler receives a shutdown request, it will attempt to detach each attached modem using the standard detach method. If the spooler recieves the SIGTERM signal, the modem drivers will also receive these signals and exit gracefully.

After exiting from the main process loop, the spooler will close the fax history data table it opened during server initiation. It will also close the fax server log by writing closing braces "))" to close the current glossary entry.

The Lock and Master files created when the spooler went into background will be removed. And lastly, it will close each of the configuration files it opened during startup.

Main Process Loop

The spooler operates within a tight process loop. Most spooler activity is performed by child processes of the spooler. This improves performance and responsiveness of the spooler. The activities performed by the spooler within this main process loop are limited to;
The spooler will remain within this process loop until it receives a "shutdown" client request, which will force it to break from this loop, or it is interupted by a SIGTERM signal.

Servicing Client Requests
Clients indicate that they have a request by writing their process ID (PID) into the common lock file FIFO, $SpoolDir/ipc/Lock. The spooler will perform a blocking read from this FIFO for up to two seconds. If any requests are pending, this read will return the PID of the requesting client.

Whenever a client runs, it creates two additional FIFOs in the "ipc" spool sub-directory. These FIFOs are named after the clients PID. After a client writes it's PID into the lock file, it writes the request into the named "control" pipe, and then reads the response through the named "data" pipe.

This mechanism is also used by a modem driver when it wishes to inform the server of a change of state, so the server will first compare the PID to that of all the modem drivers to determine if the request is being originated by a modem driver.

If the request is from a modem driver, the spooler will read the request from the IPC pipe created when the child process was spawned. Otherwise it will read the request from the named pipe, determined by the PID of the requesting client.

Client (and modem driver) requests are identified by a command constant which provides an index into an array of indirect pointers to the request handler functions. After receiving a request, the spooler will scan this array for a matching handler function. If a matching function is found, it will write a brief summary of the request event into the server log (except for command DRV_STATUS), such as;

03/06/95 15:46:52: Command CMD_ENQUEUE rcv'd from pjb@alcatraz

The handler function is then called indirectly, and the PID of the requesting client, along with a copy of the request is passed to the handler function.

Promoting Terminated Tasks
If no client requests are received, the spooler will look to see if any child task it has previously spawned has terminated. This is achieved by a blocking call to wait() which will return the PID and exit code (or reason for termination) of any child process which has terminated. The spooler will wait for up to one second.

Background Information

Tasks are uniquely identified by the request and sequence number, which are usually represented as two four digit numbers such as 0552.0001. The first part, the request number, is the number which identifies a client fax request or a received fax. The second part, the sequence number, is incremented for each task performed during the sending or receiving of a fax.

Each task is recorded in the fax history data table in the order that it occurs. When you obtain the history of a fax by issuing a client "history" command, the result is sequential listing of all fax records for a particular request.

Promoting a task involves analysing the result of a task, and generating the next sequential record for a request, depending upon the last result. It does not involve actually initiating the next task. Instead, the "next due" time for the task is determined, depending upon whether the fax is to be sent off-peak or is to be rescheduled for retry. The "next due" time is simply written into the new record, and the state of the record is set to waiting.

If a child has terminated, the spooler will first check whether the PID is from one of the modem drivers, indicating that a modem driver has terminated abnormally. If so, the spooler will write an error message to the server log (server error 24), and then free up resources used by the modem driver. The spooler does not perfom any recovery in case of modem driver dying.

The spooler will also check if PID matches one of the server tasks it has previously spawned to perform a task such as preparing or processing a fax. If so, the server will obtain the exit status which will be used as the result code for that task. In most cases a zero exit code indicates success. But for a pagination task, the result code should be non-zero, indicating the number of pages to be sent.

The spooler will then read the corresponding record from the fax history data table matching this request/sequence. The record will be modified with the task exit code, and the state will be updated from "Active" to "Complete". This record is then passed to the major scheduling function called promote_task().

Spawning Due Tasks
When a fax is prepared or processed, etc., the spooler will spawn a child process to perform the task. There is a limit on the number of tasks which may run concurrently to avoid overloading the system. This limit is based on the number of attached modems, plus five. This limit assumes that a system with multiple modems will have the extra processing capacity for the additional concurrent tasks. If the spooler has not spawned more than the maximum number of tasks, it will determine if there are any other tasks which are overdue.

To find the next due task, the spooler reads the fax history data table using a secondary key which sorts it by "state" and "due time". This will find all faxes which are in a "waiting" state. The spooler will then read all "waiting" fax records and if the "next due" time is earlier than the current time. The spooler will spawn a task to perform the required action which is recorded in the "next_op" field of the record.

The spooler will first look for any faxes which are overdue to be sent. These records have the value of FAX_NEXTOP_SEND in their "next_op" field. This ensures that any faxes which are due to be sent have priority over faxes which are still being prepared. This ensures that all modems are active if necessary.

After checking for faxes overdue for sending, the spooler will re-read the fax history data table using the secondary key. This time it will look for faxes, other than those which are overdue for sending. All fax records which are overdue are passed to the major scheduling function called spawn_task().

Perform Fax History Archiving
If no are tasks are being performed, the spooler will check whether any fax records need to be archived. The last record read by the previous check for overdue tasks will return the oldest record in the fax history data table. This record will be examined for the following conditions;
  1. If this record is complete and older than the spooler archive date, and the "archive old records" option is enabled, it will be archived.
  2. If the "delete old records" option is enabled, the record will be deleted.
Each hour, the spooler will also check whether any archives need to be compressed or deleted.

Maintain Queue Statistics
The server maintains the statistics which are returned by the client command, qstatus. Whenever the server alters the fax history data table, it sets the global flag fax_db_write. This flag is examined as the last step of the main process loop, and if it has changed, the queue statistics will be updated. These statistics are maintained in the file $SpoolDir/tmp/qstatus.


THE MODEM DRIVER

The modem driver executes as a duplicate copy of the fax spooler process. But the entire modem driver is implemented in an interpretive laguage, and the entire source is visible within the modem driver file;

${FaxLib:={Utools:=/usr}/Utools/lib}/UxFax2.modem

The modem driver acquires the same run-time environment as the fax spooler, since it is a child of the spooler. This will include all the spoolers environment, but the spooler will have closed and re-opened all the configuration, message and glossary files before handing execution across to the interpreter so the file descriptors are not shared.

Global Settings

The modem driver starts execution at the driver_main() sub-routine entry in UxFax2.modem driver source. There are a couple of global variables which are initially defined with default values. These are;

debug
The level of debugging information written to the log file. There are three levels of debug. The default setting is one. The options are;
The debug level is defined in the modem data base definition, and the final setting will be determined from there.

tia592
Most fax modems conform to the draft class 2 standard SP-2388 and this variable should be set to "0". But some more recent models are fully compliant with the ratified standard TIA592, and these modems should have this variable set to "1". This value is determined from the modem during modem reset within the subroutine modem_reset().

The other global settings are established within the GlobalSettings() subroutine. This subroutine includes an array called fcmd which defines all the different commands, depending upon whther the modem is a TIA592 (Class 2.0) compliant modem,oor not. The global tia592 will provide the first dimension index into this array.

TxBitOrder/RxBitOrder
Most manufacturers of Class2 modems (SP-2388) appear to use direct bit ordering for send and reverse bit ordering for receive regardless of the setting of "+FBOR" which defaults to "0" (direct bit order). These parameters need to be set manually to suit the modem. They should be "0" or "1". In general, TIA592 compliant modems appear to use this setting properly, and should have TxBitOrder="0" and RxBitOrder="1". (Tested with USRobotic Courier modem). Multitech modems also use this parameter correctly and should be set like TIA592.

allow2d
Allows 2D (Modified Read) compression when sending. This is sometimes called 2DMR compression. The options are, 1=allow, 0=deny. If this is set to zero, all faxes will be sent uncompressed in 1D huffman. The default setting is zero since most modems do not support 2D.

maxspeed
Sets the maximum modem transmission speed. The options are;
The default setting is 3 (9.6Kb), but it may be set to 5 if the modem supports 14.4Kb transmission speed.

termserv
On systems where the fax modem is connected to a terminal server, this variable should be set to non-zero. This may also be done by setting TermSever=1 in the Custom Environment.

binlock
Most systems use ASCII encoding in UUCP lock files. But some store the PID as a binary integer. Set the variable "binlock" to suit the
machine. The options are;
On HP systems, this should be set to one. Most other systems use the default setting of zero.

date_fmt
Format specification for the date string in a sent fax header. This uses the same syntax as the unix command. Refer to date(1) in your Unix reference manuals. This variable defaults to the value of environment variable CFTIME which may be set in the custom environment of UxFax2

Startup

The modem driver is called with it's own name passed as the only argument to the entry routine driver_main(). The driver uses this name to search for it's own record in the modem data table. The record is read into the variable modem which is used in argument to most other subroutines. The global variable debug (described previously) is set from the "debug" field of the modem record.

The driver then reads the Master file contained in the ipc spool subdirectory to determine the process ID of the spooler process. During the main process loop, the modem driver will use this PID to continually monitor whether it's parent is still running.

The driver then enters the main process loop.

Main Process Loop

The driver operates within a loop which performs the following functions;

Confirm the spooler is running.
Check for a UUCP lock.
Reset the modem, if necessary.
Service spooler commands.
Answer incoming calls.

The driver will remain in this loop until it receives a CMD_SHUTDOWN command from the spooler, or it is interrupted by a SIGTERM signal, which may is issued by the spooler when modem drivers are detached.

Confirm the spooler is running
The process ID of the spooler which was obtained during startup is used as an argument to the function kill() to determine if the spooler is still running. If not, the driver will write an appropriate message to the log file and then terminate. This inhibits the driver from continuing to operate if the spooler has terminated abnormally.

Check for a UUCP lock
UxFax2 can share a modem with UUCP, provided that the UUCP lock file named in the modem definition is correct. If a lock file exists, indicating that another UUCP process is using the modem, the driver will enter a loop that it will remain in until the UUCP lock can be removed.

Reset the modem (if necessary)
On each iteration of the main process loop, the driver checks if the status has changed from S_WAIT, which would happen after sending or receiving a fax, or if the modem was locked-out or otherwise uninitialised. If so, the driver will attempt to obtain a UUCP lock and reset the modem.

If it fails to obtain a UUCP lock, the driver will enter a loop until the UUCP lock can be obtained.

When a UUCP is successfully obtained, the driver will open the device and then call modem_reset() to reset the modem. This subroutine will conduct a dialog with the modem, sending "ATZ" and several other strings to reset the modem and determine its capabilites.

The driver will then inform the spooler of an change of status. If the modem driver is operating in receive mode, the device file opened during reset will remain open, otherwise it will be closed.

Service spooler commands
The driver checks if there are any commands from the spooler. The two possible commands are CMD_SHUTDOWN and DRV_SENDFAX. These commands and the handler functions are declared in the array varaible cmd. Only the DRV_SENDFAX command has a handler function. The other command would cause exit from the main process loop. After scanning the cmd array for a matching command, the driver will call the handler function indirectly. This only occurs when the server instructs the driver to send a fax. The handler function is rx_srv_sendfax().

Before calling the handler, the driver will attempt to obtain a UUCP lockfile and re-open the device file if it is not already open.

Answer incoming calls
When the driver is operating in receive mode, it will constantly monitor the modem for ring indication. This is done by reading any string from the modem and examining it for the "RING". This is generated by the modem when it receives ring tone and auto-answer is disabled.

Auto-answer is disabled when the driver is operating in receive mode. If ring indication is obtained, the driver will send "ATA" to answer the in coming call. If a "+FCON" response is obtained, the incoming call is a fax transmission, and the receive_fax() subroutine is called.

Otherwise it may be an incoming data call, in which case the driver releases the modem and enters a sleep. This gives UUCP the opportunity to take the call.

Sending a Fax

UxFax2 uses a generic modem driver, which is suitable for all class 2 and class 2.0 (TIA592) modems. This is achieved by use only the most common and necessary class 2 commands. In most cases, the only local configuraton necessary may be applied in the dialer prefix setting of the modem definition. This usually involves adding a command to enable software flow control.

The sending of faxes is directed by the routine rx_srv_sendfax(), and the send_g3() and GenericClass2_send() subroutines. The rx_srv_sendfax() handler is called when a DRV_SENDFAX command is received from the spooler,

rx_srv_sendfax()
The handler is called with arguments including the opened file streams for the modem device; a copy of the spooler command, which includes the request and sequence number of the fax to be transmitted; plus the modem drivers own data record.

The handler will open the fax history data table and read the corresponding record for the request/sequence number of this fax request. It then writes the glossary header into the modem log file for this request before calling the main subroutine, GenericClass2_send() which conducts the session dialog.

GenericClass2_send()
The routine handles the majority of the modem dialog involved when sending a fax. The sessions starts with initial settings being entered nto the modem before the recipient phone number is dialled.

The routine examines the dial response, expecting a "+FCON" response, indicating that a fax machine has answered the call. Other possible response at this stage include "NO DIALTONE" and "BUSY". These responses will cause return from the routine, and the spooler will be notified of this so the fax may be rescheduled.

During the spooler pagination task for this request, two copies of the paginated group 3 image will have been created. One will be compressed, the other will be uncompressed. These files will be named;

$SpoolDir/tx/xxxx.Cyyy
$SpoolDir/tx/xxxx.Uyyy

where xxxx is the request number, yyy is the page number, and "C" identifies the compressed image and "U" identifies the uncompressed image.

The routine then enters a loop for all pages of the fax. On each iteration, the modem driver will generate the header which appears on the top of the sent faxes. This is done dynamically so the date which appears on the top of the faxes is true. It is also necessary to create both compresses and uncompressed versions of the header. These will be named;

$SpoolDir/tx/xxxx.Chdr
$SpoolDir/tx/xxxx.Uhdr

These headers are made during the interval between the driver sending the command "AT+FDT", and receiving the expected response of "CONNECT", by the subroutine MakeHeader(). After this, the actual group 3 image will be sent by the send_g3() subroutine, and the loop will be repeated for any remaining pages.

The routine examines the response to the last page command "AT+FET=2" looking for a hang-up code which is preceded by "+FHNG". This should normally be zero. If not, a "phase D" error may be generated.

Before exiting the routine, the header images will be removed, and the routine will notify the spooler of the result of the fax transmission by calling subroutine TxRxFinished().

send_g3()
Sends the facsimile phase C data (the group 3 page image) to the modem. This routine is called from the main GenericClass2_send() function. Dev is the opened I/O stream file pointers. Hdr is a 2D array naming the two header string images created by MakeHeader(). File is a 2D array naming the standard and compressed page images. Dcs contains the negotiated session parameter string which is used by Class2Begin() which will return the negotiated mode, either 0 for 1D (standard) or 1 for 2D (compressed). Lastpg is used to indicate if this is the last page to be transmitted. This is significant for TIA592 protocol. The routine returns zero on success, or non-zero for an invalid response.

The Class2Modem() functions send the group 3 images to the modem and added appropriate padding to the data as determined by the negotiated session parameters.

Receiving a Fax

Faxes are received automatically by the modem driver with minimal intervention by the server. After receiving ring indication and confirming that the incoming call is from a fax machine, the main process loop will call the receive_fax() subroutine to perform the modem dialog required to receive a fax.

receive_fax()
The routine will initially open the fax history data table and call the function next_request_id() which will generate a new request number for this fax. The routine then writes a new glossary header into the modem log, and send change of state notification to the spooler, including the newly generated request number.

The fax reception dialog is relatively simple in comparison with sending a fax. The driver will send a "AT+FDR" command and wait for a "CONNECT" response, after which it will send a 'DC2' character to tell the modem to start transferring the page data.

The actual reception of page data is handled directly by an inbuilt unction called Class2rx(). This function is able to detect the end-of-page sequence which will be embedded in the data. And it allows the data to be received in block mode instead of character mode, which is far more efficient on a multi-user system. So, before it is called, the terminal interface is put into a block mode with a minimum 240 characters or 100msec intercharacter timeout.

After all pages are received, the routine will notify the spooler of the result of the fax reception by calling subroutine TxRxFinished().


BMtransform

BMtransform is used extensively by UxFax2 for all the graphics manipulation performed during the creation, sending and reception of faxes. The program is a general purpose bitmap transformation engine which supports various raster graphic file formats. Within UxFax2 it is generally converting to or from the "fax" format used internally by the program. This "fax" format comprises CCITT T.4 images concatenated together with 64 byte headers, this allows a multi-page fax image to
be maintained in a single file.

Usage within UxFax2.local

The glossary script file, $Utools/Utools/lib/UxFax2.local makes many references to BMtransform, since it is these scripts which do all the graphics manipulation. Below is a explanation of how it is used with it's various options within this file;

NotifyPrint_Do
This script converts a stored fax file into individual pages, and then prepends to each page a header. These individual page images (with headers) will each be a fax image, which are then passed to the printer driver. This script is used during print notification and hardcopy printouts. There are two references to BMtransform in the script. Firstly, it is called to split the stored fax file into the individual pages, using;

BMtransform -ifax -og3 -rfine -V1 -O filename.###

This will produce raw G3 images for each page. The "-O" option determines the filename which will be produced for each page. The "-V" option writes the name of each page to standard output, so the number of pages produced can be counted.

BMtransform is called again to create headers for each page. The header data is produced by the command faxcmd header. This produces a small PCL imgage which is then piped into the following command;

BMtransform -nortc -iljet -clip -rfine -ofax

The resultant image is prepended to each individual page image produced by the prior call to BMtransform. The "-nortc" flag stops the "fax" output including a "return to control" (T.4 end of page) sequence , but it does include a standard 64 byte header, so when the raw G3 page image is appended to it, the resultant file is a complete fax image which will be recognisable by BMtransform with a "-ifax" option within the printer driver.

The "-iljet" is used since the output from faxcmd header is effectively a small PCL print file. And the "-clip" option is used to remove any white space surrounding the image, so only the header remains in the image.

Epson8_graphics and Epson24_graphics
These scripts receive the image files produced by NotifyPrint_Do which is effectively a fully formed "fax" format image. BMtransform will be called with a "-oepson 8" or "-oepson 24" option, depending upon which printer driver is being invoked. It will also be called with the following options;

BMtransform -cut 5 -F '^L' $Resolution $PaperSize

The "-cut" option nominates that a left margin, comprising 5% of the image will be cut out. This effectively shifts the entire image left. The "-F" option adds a formfeed to the end of each page

The Resolution environment variable will use the corresponding setting in the printer definition. This variable will contain the horizontal and vertical resolutions in the options "-vr" and "-hr". Similarly the PaperSize environment variable is also obtained from the printer definition. It will contain the paper size as negative value using the "-hs" and "-vs" options.

LjetII_graphics and LjetIIL_graphics
These scripts also receive the image files produced by NotifyPrint_Do as a fully formed "fax" format image. BMtransform is called with a -opcl min" option which produces the smallest possible raster image for a laserjet II printer, and "-r300" or "-r100" resolution option, depending whether the high or log resolution driver is invoked. The other options are;

BMtransform -cut 5 -H '^[&l0E^[&a200V' -F '^[E'

The "-cut" and "-F" options are described in the "epson" driver. In a laserjet printer, the sequence "^[E" will force any unprinted data to be printed. The header option ("-H") sets the top margin to zero and adjusts the vertical registration.

LjetIII_graphics and LjetIIIL_graphics
These scripts receive the image files produced by NotifyPrint_Do as a fully formed "fax" format image. BMtransform is called with a "-opcl tiff" option which produces a compressed raster image for a laserjet III printer, and "-r300" or "-r100" resolution option, depending whether the high or log resolution driver is invoked. The other options are;

BMtransform -H '^[&l0e-288u60Z'-F '^[E' $PaperSize

This is mostly identical to the laserjet II driver, except for the header option ("-H"). The laserjet III provides different options to adjust the vertical and horizontal registration, which are used here. And so the "-cut" option isn't used here either.

vi_Prepare
This script will convert an ASCII file into a stored fax image, and it is used when preparing plain text (ASCII or vi) files. This employs the PCL printer emulator built into BMtransform. The input file ($Ifile) is prepended with an escape sequence which turns on 'newline' to 'newline/carriage return' translation, and BMtransform is called with the "-iljet" option;

( echo '\033&k3G'; cat $Ifile ) | \
BMtransform -iljet -rfine -ofax -f font_table

This method is redundant. The same effect can be achieved by calling BMtransform with a "-iascii" option which simply invokes the PCL interpreter but turns on NL/NLCR translation. The "-f" option names an alternative font table. The default font table is;

$Utools/Utools/font/font.table

The font table describes fonts by the characteristics which are used for font selection with the PCL language. This table names the soft font files which are used by BMtransform. In UxFax2, a set of helvetica and times fonts are supplied along with an alternate font table named;

$Utools/Utools/font/font.table.fax

UniplexII_Prepare and WP51_Prepare
These scripts convert the native word processor document into a stored fax format. Both employ the word processors laserjet printer driver to generate a PCL print file. This print file is then passed to BMtransform with "-iljet" and "-ofax" options. The other options are;

BMtransform -iljet -rfine -ofax -f font_table

PCL/PCF/PCR_Prepare
All of these scripts employ the laserjet emulation of BMtransform, and so each simply creates a PCL print file using the native application and passes this print file to BMtransform with the same option which were also used with UniplexII_Rrepare and WP51_Prepare.

PCX/DCX/TIFF_Prepare
Each of these scripts is identical except for the input option. BMtransform has inbuilt support for these formats, so the input options on each are "-ipcx", "-idcx" and "-itiff". All other options are the same.

ReceiveProcessFax
When receiving faxes, UxFax2 writes each page into an individual file. This script will process all these received fax pages and produced a single stored fax file. The command used is;

BMtransform -ofax -ig3 $Resolution -I filename.###

The input files are raw G3 ("-ig3") and the output will be a single fax file ("-ofax"). The resolution will be set in the environment according to what it was when the fax was received; either "-rfine" or "-rstd". And the input will be taken from the individual files named after the "-I" option.

SendPrepareGroupIII
This script is called during the "pagination" phase. This will create the individual pages from a single stored fax file. In addition, it will also create a compressed and uncompressed copy of each page. So BMtransform is called twice;

BMtransform -ifax -og32d $Resolution -O reqn.C###
BMtransform -ifax -og3 -V1 $Resolution -O reqn.U###

The first call will create the compressed images ("-og32d"), the second will create the uncompressed page images ("-og3"). The Resolution is set according to the chosen resolution when the fax was submitted, and will be either "-rfine" or "-rstd".

The second call includes the "-V" option which will cause it to write the file name of each page to be written to standard output. These are counted and the number is returned by the script. This is how UxFax2 determines the number of pages in a fax.

CreateDCXFile
This script creates a DCX format file suitable for displaying a fax using the fax viewer bundled with Windows operating systems. The input file will be a stored fax file ("-ifax"), and the output will be a DCX format file ("-odcx");

BMtransform -ifax -odcx -I $Ifile -O $Ofile

The "-O" option must be used when writing DCX files. A DCX file includes a header which contains all the offsets to the individual pages. This header can only be written after the entire file is generated, so the "-O" option is given which allows BMtransform to rewrite the header after if has completed generating the file. This cannot be done when the file is simply written to standard output.