UxFax2 Unix Fax Server
Version 3.x
Server Technical
Description
Table of Contents
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;
- Accepting incoming client request.
- Dispatching due or over-due tasks.
- Promoting and rescheduling completed tasks.
- 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;
- Included files
- Defined variable substitution
- Environment variable substitution
- Inline shell command substitution
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.
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;
- Possible linked ISAM address data base.
- Custom environment.
- Data dase permissions.
- Address data base display format.
- Achive settings.
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;
- Servicing client requests.
- Promoting tasks when they terminate.
- Spawning tasks which are due.
- Performing archiving of the fax history DB.
- Maintain queue statistics.
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;
- If this record is complete and older than the spooler archive date,
and the "archive old records" option is enabled, it will be archived.
- 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;
- debug = 0 : Write nothing except session parameters
- debug = 1 : Write out exception errors (unexpected responses)
- debug = 2 : Write out all modem dialog (commands & responses)
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;
- 0 = 2.4K
- 1 = 4.8K
- 2 = 7.2K
- 3 = 9.6K
- 4 = 12K
- 5 = 14.4K.
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;
- 0 = ASCII encoding
- 1 = Binary encoding
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.