+#include "config.h"
+
#define Copyright "Copyright 1999 Ed Casas"
#define Version "efax v 0.9"
*/
-const char *Usage =
+static const char *Usage =
"Usage:\n"
" %s [ option ]... [ -t num [ file... ] ]\n"
"Options:\n"
" -c cap set modem and receive capabilites to cap\n"
" -d dev use modem on device dev\n"
" -e cmd exec \"/bin/sh -c cmd\" for voice calls\n"
+#ifndef UCLINUX
" -f fnt use (PBM) font file fnt for headers\n"
+#endif /* UCLINUX */
" -g cmd exec \"/bin/sh -c cmd\" for data calls\n"
" -h hdr use page header hdr (use %%d's for current page/total pages)\n"
" -i str send modem command ATstr at start\n"
" -l id set local identification to id\n"
" -o opt use protocol option opt:\n"
" 0 use class 2.0 instead of class 2 modem commands\n"
+#ifndef UCLINUX
" 1 use class 1 modem commands\n"
+#endif /* UCLINUX */
" 2 use class 2 modem commands\n"
" a if first [data mode] answer attempt fails retry as fax\n"
" e ignore errors in modem initialization commands\n"
" x use XON instead of DC2 to trigger reception\n"
" z add 100 ms to pause before each modem comand (cumulative)\n"
" -q ne ask for retransmission if more than ne errors per page\n"
+#ifndef UCLINUX
" -r pat save received pages into files pat.001, pat.002, ... \n"
+#endif /* UCLINUX */
" -s share (unlock) modem device while waiting for call\n"
" -v lvl print messages of type in string lvl (ewinchamr)\n"
" -w don't answer phone, wait for OK or CONNECT instead\n"
#define HDRSHFT 54 /* shift header right 6.7mm into image area */
#define HDRSPCE 20 /* number of scan lines inserted before image */
#define HDRSTRT 4 /* scan line where header is placed on image */
+#ifndef UCLINUX
#define HDRCHRH 24 /* header character height (pels, at 196lpi) */
+#else /* UCLINUX */
+#define HDRCHRH 0 /* header character height (pels, at 196lpi) */
+#endif /* UCLINUX */
#define HDRCHRW 12 /* header character width (pels) */
#define IDLEN 20 /* length of T.30 ID strings, must be 20 */
#define MAXDIS 8 /* maximum DIS frames sent without response (T1) */
/* capability fields... */
enum captype { VR, BR, WD, LN, DF, EC, BF, ST } ;
-int capmax [ NCAP ] = { 1, 7, 2, 2, 3, 2, 1, 7 } ;
+static int capmax [ NCAP ] = { 1, 7, 2, 2, 3, 2, 1, 7 } ;
/* & maximum values */
+#ifndef UCLINUX
/* vertical resolution, dpi */
int vresolution [ 2 ] = { 98, 196 } ;
+#endif /* UCLINUX */
/* characters per second for br */
-int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
+static int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
+#ifndef UCLINUX
/* next br = fallback [ br ] */
/* 0, 1, 2, 3, 4, 5, 6, 7 */
int fallback [ 8 ] = {-1, 0, 1, 2, 7, 4, 3, 6 } ;
/* negotiation speed index */
/* 0, 1, 2, 3, 4, 5, 6, 7 */
int brindex [ 8 ] = { 0, 1, 2, 3, 4, 7, 5, 6 } ;
+#endif /* UCLINUX */
/* minimum scan time in ms */
-int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
+static int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
/* page width in pixels */
-int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
+static int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
/* Table to convert between T.30 DIS/DCS/DTC FIF and Class 2-like
capability codes. Uses br=6, 7 for V.17 at 7200, 9600. */
#define X 0xff /* invalid values */
-t30tabst t30tab [ NCAP ] = {
+static t30tabst t30tab [ NCAP ] = {
{ "vr", 1, 1, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
{ "br", 1, 2, 0x0f, 0,
{ 0, 4, 12, 12, 13, 13 } ,
} ;
/* values of capability fields */
-char *capvaluestr [ NCAP ] [8] = {
+static char *capvaluestr [ NCAP ] [8] = {
{ " 98lpi", "196lpi" } ,
{ " 2400bps", " 4800bps", " 7200bps", " 9600bps", " 12kbps", "14.4kbps",
"7200V.17", "9600V.17" } ,
/* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
[baud rate=BR]. */
+#ifndef UCLINUX
char *c1cmd [ 2 ] [ 2 ] [ 8 ] = {
{ { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=122", "+FRM=146" ,
"+FRM=74", "+FRM=98" } ,
{ "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=121", "+FTM=145" ,
"+FTM=73", "+FTM=97" } }
} ;
+#endif /* UCLINUX */
-struct c2msgstruct
+static struct c2msgstruct
{
int min, max ;
char *msg ;
/* meaning of efax return codes */
-char *errormsg [] = {
+static char *errormsg [] = {
"success",
"number busy or modem in use",
"unrecoverable error",
/* Return name of frame of type 'fr'. */
+#ifndef UCLINUX
char *frname ( int fr )
{
static struct framenamestruct { int code ; char *name ; }
if ( fr == p->code || ( fr & 0x7f ) == p->code) break ;
return p->code ? p->name : "UNKNOWN" ;
}
+#endif /* UCLINUX */
/* Range-check capability. */
-int checkcap ( cap c )
+static int checkcap ( cap c )
{
int err=0, i ;
/* Print cap[ability] c using text values and prefix s. */
-void printcap ( char *s , cap c )
+static void printcap ( char *s , cap c )
{
int i ;
msg ( "N-+ %s" , s ) ;
/* Convert capability string to cap struct. Returns 0 or 2 on errors. */
-int str2cap ( char *s, cap c )
+static int str2cap ( char *s, cap c )
{
int err=0, n ;
-
- n = sscanf ( s, "%d,%d,%d,%d,%d,%d,%d,%d",
- c+0, c+1, c+2, c+3, c+4, c+5, c+6, c+7 ) ;
-
+ char *end ;
+
+ for ( n=0 ; n<NCAP ; n++ ) {
+ if (!s)
+ break;
+ c [ n ] = strtol ( s, &end, 10 );
+ if (end && *end && *end!=',')
+ break;
+ s = end;
+ }
+
if ( n < NCAP ) msg ( "Wmissing value(s) in \"%s\"", s ) ;
checkcap ( c ) ;
bytes. Converts into DIS format if 'isdis' is true, else into
DCS/DTC format. */
+#ifndef UCLINUX
void mkdis ( cap c, uchar *fif, int len, int isdis, int t4tx )
{
int i, k ;
if ( p->byte < len ) fif [ p->byte ] |= k << p->shift ;
}
}
+#endif /* UCLINUX */
/* Return length of DIS/DTC FIF (counts extension bits). */
+#ifndef UCLINUX
int dislen ( uchar *fif )
{
int n ;
for ( n=3 ; fif [ n-1 ] & 0x01 && n < MAXFIFLEN ; n++ ) ;
return n ;
}
+#endif /* UCLINUX */
/* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 if bad DIS/DCS
field. */
+#ifndef UCLINUX
int mkcap ( uchar *fif, cap c, int dis )
{
int err=0, i, j, k, len ;
}
return err ;
}
+#endif /* UCLINUX */
/* Compute compatible local/remote capabilities. Used by the
sending station only and only for Class 1. Returns 0 if OK or
3 if no compatible settings possible. */
+#ifndef UCLINUX
int mincap ( cap local, cap remote, cap session )
{
int err=0, i ;
return err ;
}
+#endif /* UCLINUX */
/* Skip to start of first/next page (or to start of previous page
RTN is received to restart the page. Returns 0 or 2 on
errors. */
-int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
+static int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
{
int err=0, m=EOP, yres, fVR, nVR ;
removes the most recently opened file. Returns 0 if OK, 2 on
errors. */
+#ifndef UCLINUX
int wrpage ( OFILE *f, int page )
{
int err=0 ;
return err ;
}
+#endif /* UCLINUX */
/* Send data for one page. Figures out required padding and 196->98 lpi
Sends RTC when done. Sends DLE-ETX and returns serial port to command
mode when done. Returns 0 if OK, non-0 on errors. */
-int send_data ( TFILE *mf, IFILE *f, int page, int pages,
- cap local, cap session, char *header, faxfont *font )
+static int send_data ( TFILE *mf, IFILE *f, int page, int pages,
+ cap local, cap session
+#ifndef UCLINUX
+ , char *header, faxfont *font
+#endif /* UCLINUX */
+ )
{
int done=0, err=0, noise=0, nr=0, lastnr=0, line, pixels ;
int i, decimate, pwidth, minlen, dcecps, inheader, skip=0 ;
uchar buf [ MAXCODES + 2*EOLBITS/8 + 1 ], *p ;
short runs [ MAXRUNS ], lastruns [ MAXRUNS ] ;
+#ifndef UCLINUX
char headerbuf [ MAXLINELEN ] ;
+#endif /* UCLINUX */
ENCODER e ;
newENCODER ( &e ) ;
msg ( "T limiting output to %d bps for %d byte modem buffer",
dcecps*8, MAXDCEBUF + MINWRITE ) ;
+#ifndef UCLINUX
if ( ckfmt ( header, 6 ) )
msg ( "W too many %%d escapes in header format string \"%s\"", header ) ;
else
sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ;
msg ("I header:[%s]", headerbuf ) ;
+#endif /* UCLINUX */
done = err = ttymode ( mf, SEND ) ;
continue ;
}
}
+#ifndef UCLINUX
/* generate and OR in header pixels */
if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) {
int hnr ;
hruns, 0 ) ;
nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ;
}
+#endif /* UCLINUX */
inheader = line < HDRSTRT + HDRCHRH ;
}
-int end_data ( TFILE *mf, cap session, int ppm, int *good )
+static int end_data ( TFILE *mf, cap session, int ppm, int *good )
{
int err=0, c ;
uchar *p ;
null it is used to save pixel count. Returns number of runs
stored, EOF on RTC, or -2 on EOF, DLE-ETX or other error. */
+#ifndef UCLINUX
int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels )
{
int err=0, c=EOF, x, n ;
msg ( "H-" ) ;
msg ( "I- %s %s", s, nm ) ;
}
+#endif /* UCLINUX */
/* Send HDLC control frame of type type. Extra bits can be OR'ed
#define MORE_FR 0x100
#define SUB_FR 0x200
-int nframes = 0 ; /* counts frames sent/received */
+static int nframes = 0 ; /* counts frames sent/received */
+#ifndef UCLINUX
int putframe ( int type, uchar *buf, int len, TFILE *f, int t )
{
int err=0 ;
return err ;
}
+#endif /* UCLINUX */
/* Get a Class 1 command or response frame. An attempt to match
*/
+#ifndef UCLINUX
int getfr ( TFILE *mf, uchar *buf, int getcmd )
{
int err=0, frame=0, frlen, c, t ;
return err ;
}
+#endif /* UCLINUX */
/* Check for hangup message. Assumes hsc is initialized to a
was one. If perr is not null, sets it to 2 if the hsc was
non-zero (error). */
-int gethsc ( int *hsc, int *perr )
+static int gethsc ( int *hsc, int *perr )
{
int err=0, i ;
if ( sresponse ( "+FHNG:", hsc ) || sresponse ( "+FHS:", hsc ) ) {
/* Print remote ID and store DCS values in session as per
responses since last command. */
-void getc2dcs ( cap session )
+static void getc2dcs ( cap session )
{
char *p ;
if ( ( p = sresponse ( "+FTI:", 0 ) ) != 0 ||
/* Wait for a starting character XON or DC2. Display & ignore
any other characters received. */
-void getstartc ( TFILE *mf )
+static void getstartc ( TFILE *mf )
{
int c, noise ;
Returns 0 if OK or 2 on errors. */
-int c2sndrcv (
+static int c2sndrcv (
TFILE *mf, cap local, char *localid,
OFILE *outf, IFILE *inf,
- int pages, char *header, faxfont *font,
+ int pages,
+#ifndef UCLINUX
+ char *header, faxfont *font,
+#endif /* UCLINUX */
int maxpgerr, int noretry, int calling )
{
- int err=0, done=0, page, pagetry, nerr, c, dp=0 ;
+#ifndef UCLINUX
+ int c, nerr;
+#endif /* UCLINUX */
+ int err=0, done=0, page, pagetry, dp=0 ;
int ppm=0, good, hsc, changed ;
int remtx=0 ;
char *fname=0 ;
}
if ( calling ) {
- if ( pages ) goto send ;
+#ifndef UCLINUX
+ if ( pages )
+#endif /* UCLINUX */
+ goto send ;
+#ifndef UCLINUX
else goto poll ;
- } else {
+#endif /* UCLINUX */
+ }
+#ifndef UCLINUX
+ else {
if ( pages ) goto pollserver ;
else goto receive ;
}
+#endif /* UCLINUX */
/* Class 2 Send */
+#ifndef UCLINUX
pollserver:
+#endif /* UCLINUX */
/* with +FLP[L]=1 the modem should accept +FDT. */
if ( ! c20 ) getstartc ( mf ) ;
- send_data ( mf, inf, page, pages, local, session, header, font ) ;
+ send_data ( mf, inf, page, pages, local, session
+#ifndef UCLINUX
+ , header, font
+#endif /* UCLINUX */
+ ) ;
pagetry++ ;
if ( c20 ) {
goto done ;
+#ifndef UCLINUX
/* Class 2 Receive */
poll:
}
}
}
+#endif /* UCLINUX */
done:
not to issue +FRH/+FTH. Returns 0 if dialed OK, 1 if busy, 2
on errors. */
-int dial ( TFILE *f, char *s, int nowait )
+static int dial ( TFILE *f, char *s, int nowait )
{
int err=0, hsc=-1 ;
char c, dsbuf [ 128 ], *p ;
enum connectmode { NONE, DATAMODE, FAXMODE, VOICEMODE } ;
+#ifndef UCLINUX
enum connectmode ansmode ( int *crate, int *hsc )
{
enum connectmode mode = NONE ;
return mode ;
}
+#endif /* UCLINUX */
/* Answer the phone. Remove our lock if sharing device with
handle call appropriately. Re-lock if necessary. Exec *getty
or *vcmd for data or voice calls. */
+#ifndef UCLINUX
int answer ( TFILE *f, char **lkfile,
int wait, int share, int softaa,
char *getty, char *vcmd, char *acmd )
return err ;
}
+#endif /* UCLINUX */
/* Initialize modem. Determine class to use and issue
issues commands to enable polling also. Returns 0 or 3 if a
mandatory setup command fails. */
-int modem_init ( TFILE *mf, cap c, char *id,
+static int modem_init ( TFILE *mf, cap c, char *id,
int calling, int poll, int capsset, int *preverse )
{
int err=0, t=-TO_RESET ;
} else {
if ( strinresp ( "2.0" ) ) c20 = 1 ;
else if ( strinresp ( "2" ) ) ;
+#ifndef UCLINUX
else if ( strinresp ( "1" ) ) c1 = 1 ;
+#endif /* UCLINUX */
else err = msg ("E3 can't determine fax modem class support" ) ;
+#ifndef UCLINUX
if ( strstr ( model, "Sportster" ) ) { /* USR Sporsters are buggy */
c1 = 1 ;
c2 = c20 = 0 ;
}
+#endif /* UCLINUX */
}
}
/* the following are global so can terminate properly on signal */
-char *icmd[3][ MAXICMD+1 ] = {{0},{0},{0}} ; /* initialization commands */
-TFILE faxdev = { -1, 0,0, {0}, 0, 0 } ; /* modem */
-char *lkfile [ MAXLKFILE+1 ] = {0} ; /* lock file names */
-IFILE ifile = { 0 } ; /* files being sent */
-int locked = 0 ; /* modem locked */
+static char *icmd[3][ MAXICMD+1 ] = {{0},{0},{0}} ; /* initialization commands */
+static TFILE faxdev = { -1, 0,0, {0}, 0, 0 } ; /* modem */
+static char *lkfile [ MAXLKFILE+1 ] = {0} ; /* lock file names */
+static IFILE ifile = { 0 } ; /* files being sent */
+static int locked = 0 ; /* modem locked */
/* print names of files not sent and reset modem before
exiting. */
-int cleanup ( int err )
+static int cleanup ( int err )
{
/* log names of files not sent */
logifnames ( &ifile, "I failed -> %s" ) ;
/* signal handler */
-void onsig ( int sig )
+static void onsig ( int sig )
{
msg ( "E terminating on signal %d", sig ) ;
exit ( cleanup ( 5 ) ) ;
int main( int argc, char **argv)
{
int err=0, doneargs=0, c=0, i ;
- int testing=0, calling=0 ;
+ int testing=0;
+#ifndef UCLINUX
+ int calling=0 ;
+#else /* UCLINUX */
+#define calling (1)
+#endif /* UCLINUX */
int nicmd[3]={0,0,0}, nlkfile=0, nverb=0 ;
int maxpgerr = MAXPGERR ;
time_t now ;
+#ifndef UCLINUX
char *header = 0, headerbuf [ MAXLINELEN ] ;
char *fontname = 0 ;
faxfont font ;
+#endif /* UCLINUX */
OFILE ofile ;
int pages = 0 ;
- char *phnum="", *ansfname = DEFPAT ;
+ char *phnum="";
+#ifndef UCLINUX
+ char *ansfname = DEFPAT ;
char fnamepat [ EFAX_PATH_MAX ] ;
+#endif /* UCLINUX */
/* print initial message to both stderr & stdout */
argv0 = argv[0] ;
if ( nicmd[2] < MAXICMD ) icmd[2][ nicmd[2]++ ] = nxtoptarg ;
else err = msg ( "E2too many '-k' options");
break ;
+#ifndef UCLINUX
case 'h':
header = nxtoptarg ;
break ;
case 'f':
fontname = nxtoptarg ;
break ;
+#endif /* UCLINUX */
case 'd':
faxfile = nxtoptarg ;
break ;
for ( ; *nxtoptarg ; nxtoptarg++ )
switch ( *nxtoptarg ) {
case '0' : c20 = 1 ; break ;
+#ifndef UCLINUX
case '1' : c1 = 1 ; break ;
+#endif /* UCLINUX */
case '2' : c2 = 1 ; break ;
case 'a' : softaa = 1 ; break ;
case 'e' : ignerr = 1 ; break ;
}
break ;
case 'q':
- if ( sscanf ( nxtoptarg , "%d", &maxpgerr ) != 1 || maxpgerr < 0 )
+ maxpgerr = atoi( nxtoptarg );
+ if ( maxpgerr < 0 )
err=msg ("E2bad quality (-q) argument (%s)", nxtoptarg ) ;
break;
+#ifndef UCLINUX
case 'r':
ansfname = nxtoptarg ;
break;
+#endif /* UCLINUX */
case 's':
share = 1 ;
break;
case 't':
+#ifndef UCLINUX
calling=1;
+#endif /* UCLINUX */
/* fall through */
case 'p':
if ( argv [ argc ] ) err = msg ("E2can't happen(unterminated argv)") ;
if ( ! nicmd[2] ) icmd[2][nicmd[2]++] = "H" ; /* default -k command */
+#ifndef UCLINUX
readfont ( fontname, &font ) ;
if ( ! header ) {
strftime ( tmp, MAXLINELEN, "%c %%s P. %%%%d", localtime ( &now ) ) ;
sprintf ( header = headerbuf, tmp, localid ) ;
}
+#endif /* UCLINUX */
if ( ! err ) {
err = begin_session ( &faxdev, faxfile,
if ( calling ) {
err = dial ( &faxdev, phnum, 0 ) ;
- } else {
+ }
+#ifndef UCLINUX
+ else {
err = answer ( &faxdev, lkfile, wait, share, softaa,
getty, vcmd, acmd ) ;
if ( err == 1 ) locked = 1 ;
}
+#endif /* UCLINUX */
now = time(0) ; /* do it here so use reception time */
+#ifndef UCLINUX
strftime ( fnamepat, EFAX_PATH_MAX, ansfname, localtime ( &now ) ) ;
strncat ( fnamepat, ".%03d", EFAX_PATH_MAX - strlen ( fnamepat ) ) ;
newOFILE ( &ofile, O_TIFF_FAX, fnamepat, 0, 0, 0, 0 ) ;
+#endif /* UCLINUX */
if ( ! err ) {
+#ifndef UCLINUX
if ( c1 ) {
err = c1sndrcv ( &faxdev, local, localid,
&ofile, &ifile, pages, header, &font,
maxpgerr, noretry, calling ) ;
- } else {
+ } else
+#endif /* UCLINUX */
+ {
err = c2sndrcv ( &faxdev, local, localid,
- &ofile, &ifile, pages, header, &font,
+ &ofile, &ifile, pages,
+#ifndef UCLINUX
+ header, &font,
+#endif /* UCLINUX */
maxpgerr, noretry, calling ) ;
}
}