3 #define Copyright "Copyright 1999 Ed Casas"
5 #define Version "efax v 0.9"
8 Copyright (C) 1999 Ed Casas
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 Please contact the author if you wish to use efax or efix in
25 ways not covered by the GNU GPL.
27 You may contact the author by e-mail at: edc@cce.com, by mail
28 at: 2629 West 3rd Ave, Vancouver, BC, Canada, V6K 1M4, or by
29 fax at: +1 604 734 5291.
33 static const char *Usage =
35 " %s [ option ]... [ -t num [ file... ] ]\n"
37 " -a str use command ATstr to answer\n"
38 " -c cap set modem and receive capabilites to cap\n"
39 " -d dev use modem on device dev\n"
40 " -e cmd exec \"/bin/sh -c cmd\" for voice calls\n"
42 " -f fnt use (PBM) font file fnt for headers\n"
44 " -g cmd exec \"/bin/sh -c cmd\" for data calls\n"
45 " -h hdr use page header hdr (use %%d's for current page/total pages)\n"
46 " -i str send modem command ATstr at start\n"
47 " -j str send modem command ATstr after set fax mode\n"
48 " -k str send modem command ATstr when done\n"
49 " -l id set local identification to id\n"
50 " -o opt use protocol option opt:\n"
51 " 0 use class 2.0 instead of class 2 modem commands\n"
53 " 1 use class 1 modem commands\n"
55 " 2 use class 2 modem commands\n"
56 " a if first [data mode] answer attempt fails retry as fax\n"
57 " e ignore errors in modem initialization commands\n"
58 " f use virtual flow control\n"
59 " h use hardware flow control\n"
60 " l halve lock file polling interval\n"
61 " n ignore page retransmission requests\n"
62 " r do not reverse received bit order for Class 2 modems\n"
63 " x use XON instead of DC2 to trigger reception\n"
64 " z add 100 ms to pause before each modem comand (cumulative)\n"
65 " -q ne ask for retransmission if more than ne errors per page\n"
67 " -r pat save received pages into files pat.001, pat.002, ... \n"
69 " -s share (unlock) modem device while waiting for call\n"
70 " -v lvl print messages of type in string lvl (ewinchamr)\n"
71 " -w don't answer phone, wait for OK or CONNECT instead\n"
72 " -x fil use uucp-style lock file fil\n"
74 " -t dial num and send fax image files file... \n"
77 #include <ctype.h> /* ANSI C */
83 #include "efaxio.h" /* EFAX */
90 /* delays and timeouts (t/o), in deciseconds */
91 #define T1 350 /* T.30 T1 - waiting for DIS/DCS before Phase B */
92 #define T2 60 /* T.30 T2 - waiting for frame in Phase B */
93 #define T3S 30 /* T.30 response timeout (not T3) */
94 #define T4 30 /* T.30 T4 - between [re]transmissions of DIS */
96 #define TMOD 55 /* T.30 pause between v.21&v.29, 75-20 ms */
98 #define TO_A 1200 /* dial/answer (Phase A) - modem may t/o first */
99 #define TO_ABRT 20 /* max delay after sending abort sequence */
100 #define TO_CHAR 102 /* per data character (2x max FILL length) */
101 #define TO_DATAF 80 /* software adaptive answer data connect t/o */
102 #define TO_DRAIN_H 136 /* minimum HDLC buffer drain time (4k/300cps) */
103 #define TO_DRAIN_D 300 /* minimum data buffer drain time */
104 #define TO_FT 31 /* max delay after +F[TR][MH] command */
105 #define TO_RTCMD 20 /* return to command mode after DLE-ETX (rx) */
107 #define TO_C2B 450 /* Class 2 DIS to CONNECT:(DCS+TCF+CFR)xretries */
108 #define TO_C2X 20 /* Class 2 wait for XON: 2/5 of 5s timeout */
109 #define TO_C2PP 200 /* Class 2 wait for ppr: (ppm+ppr)x3retries + 2 */
110 #define TO_C2R 600 /* Class 2 receive: (TCF+FTT)x11 retrains + 5 */
111 #define TO_C2EOR 120 /* Class 2 end of data rx (4 retrans x 3 s) */
113 #define ANSCMD "A" /* default modem command to answer calls */
114 #define DCSLEN 3 /* length of FIF for DCS commands sent */
115 #define DEFDISLEN 3 /* length of DIS initially transmitted */
116 #define DEFCAP 1,3,0,2,0,0,0,0 /* default local capabilities */
117 #define DEFID " " /* default local ID */
118 #define DEFPAT "%m%d%H%M%S" /* default received file name pattern */
119 #define HDRSHFT 54 /* shift header right 6.7mm into image area */
120 #define HDRSPCE 20 /* number of scan lines inserted before image */
121 #define HDRSTRT 4 /* scan line where header is placed on image */
123 #define HDRCHRH 24 /* header character height (pels, at 196lpi) */
125 #define HDRCHRH 0 /* header character height (pels, at 196lpi) */
127 #define HDRCHRW 12 /* header character width (pels) */
128 #define IDLEN 20 /* length of T.30 ID strings, must be 20 */
129 #define MAXDIS 8 /* maximum DIS frames sent without response (T1) */
130 #define MAXERRPRT 32 /* maximum number of reception errors to report */
131 #define MAXFIFLEN 125 /* max FIF len = MAXFRLEN - (adx+ctl+FCF) - FCS */
132 #define MAXFRLEN 130 /* max frame length = 3.45s x 300 bps / 8 */
133 #define MAXGETTY 512 /* maximum length of exec'ed (-g, -e) commands */
134 #define MAXICMD 100 /* maximum # of modem setup/reset commands */
135 #define MAXLKFILE 16 /* maximum number of lock files */
136 #define MAXNULLS 2 /* maximum consecutive received nulls saved */
137 #define MAXPGERR 10 /* maximum received errors allowed per page */
138 #define MAXTRAIN 2 /* maximum training retries at lowest speed */
139 #define MAXRETRY 3 /* maximum retries of unacknowledged commands */
140 #define NCAP 8 /* number of fields in a capability string */
141 #define NTXRETRY 3 /* maximum re-sends per page */
143 typedef int cap [ NCAP ] ; /* remote/local capabilities */
145 /* capability fields... */
146 enum captype { VR, BR, WD, LN, DF, EC, BF, ST } ;
147 static int capmax [ NCAP ] = { 1, 7, 2, 2, 3, 2, 1, 7 } ;
148 /* & maximum values */
151 /* vertical resolution, dpi */
152 int vresolution [ 2 ] = { 98, 196 } ;
155 /* characters per second for br */
156 static int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
159 /* next br = fallback [ br ] */
160 /* 0, 1, 2, 3, 4, 5, 6, 7 */
161 int fallback [ 8 ] = {-1, 0, 1, 2, 7, 4, 3, 6 } ;
163 /* negotiation speed index */
164 /* 0, 1, 2, 3, 4, 5, 6, 7 */
165 int brindex [ 8 ] = { 0, 1, 2, 3, 4, 7, 5, 6 } ;
168 /* minimum scan time in ms */
169 static int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
171 /* page width in pixels */
172 static int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
174 /* Table to convert between T.30 DIS/DCS/DTC FIF and Class 2-like
175 capability codes. Uses br=6, 7 for V.17 at 7200, 9600. */
177 typedef struct t30tabstruct
180 uchar byte, shift, mask ;
182 uchar captodis[8], distocap[16], captodcs[8], dcstocap[16] ;
185 #define X 0xff /* invalid values */
187 static t30tabst t30tab [ NCAP ] = {
188 { "vr", 1, 1, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
189 { "br", 1, 2, 0x0f, 0,
190 { 0, 4, 12, 12, 13, 13 } ,
191 { 0, X, X, X, 1, X, X, X, 3, X, X, X, 3, 5, 3, X } ,
192 { 0, 4, 12, 8, 5, 1 } ,
193 { 0, 5, 5, X, 1, 4, 4, X, 3, 7, X, X, 2, 6, X, X } } ,
194 { "wd", 2, 6, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, 2 } ,
195 { 0, 2, 1 } , { 0, 2, 1, 2 } },
196 { "ln", 2, 4, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, X } ,
197 { 0, 2, 1 } , { 0, 2, 1, X } },
198 { "df", 1, 0, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
199 { "ec", 3, 4, 0x03, 0, { 0, 2, 2 } , { 0, X, 2, X } ,
200 { 0, 3, 2 } , { 0, 0, 2, 1 } },
201 { "bf", 5, 5, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
202 { "st", 2, 1, 0x07, 7,
203 { 7, 4, 3, 2, 6, 0, 5, 1 } , { 5, 7, 3, 2, 1, 6, 4, 0 } ,
204 { 7, 4, X, 2, X, 0, X, 1 } , { 5, 7, 3, 1, X, X, X, 0 } }
207 /* values of capability fields */
208 static char *capvaluestr [ NCAP ] [8] = {
209 { " 98lpi", "196lpi" } ,
210 { " 2400bps", " 4800bps", " 7200bps", " 9600bps", " 12kbps", "14.4kbps",
211 "7200V.17", "9600V.17" } ,
212 { "8.5\"/215mm", " 10\"/255mm", " 12\"/303mm",
213 " 6\"/151mm", "4.2\"/107mm" } ,
214 { "11\"/A4", "14\"/B4", " any " } ,
215 { "1D" , "2D" }, { " - ", "ECM-256", "ECM-64 " }, { " - ", "BFT" },
216 { "0ms", "5ms", "10/5ms", "10ms", "20/10ms", "20ms", "40/20ms", "40ms" }
219 /* T.30 control frames */
222 DIS=0x01, CSI, NSF=0x04,
224 MCF=0x31, RTN, RTP, PIN, PIP,
225 DCS=0x41, TSI, NSS=0x44,
227 EOM=0x71, MPS, EOP=0x74, PRI_EOM=0x79, PRI_MPS, PRI_EOP=0x7c,
228 DTC=0x81, CIG, NSC=0x84
231 enum commanddtype { RCV=0, SND=1, DTA=0, TRN=1 } ;
233 /* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
237 char *c1cmd [ 2 ] [ 2 ] [ 8 ] = {
238 { { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=122", "+FRM=146" ,
239 "+FRM=74", "+FRM=98" } ,
240 { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=121", "+FRM=145" ,
241 "+FRM=73", "+FRM=97" } } ,
242 { { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=122", "+FTM=146" ,
243 "+FTM=74", "+FTM=98", } ,
244 { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=121", "+FTM=145" ,
245 "+FTM=73", "+FTM=97" } }
249 static struct c2msgstruct
255 { 0, 9, "Call Placement and Termination:" },
256 { 0, 0, " Normal and proper end of connection" },
257 { 1, 1, " Ring Detect without successful handshake" },
258 { 2, 2, " Call aborted, from +FK[S] or CAN" },
259 { 3, 3, " No Loop Current" },
260 { 4, 4, " Ringback Detected, no answer" },
261 { 5, 5, " Ringback Detected, answer without CED" },
263 { 10, 19, "Transmit Phase A & Miscellaneous Errors:" },
264 { 10, 10, " Unspecified Phase A error" },
265 { 11, 11, " No Answer (T.30 T1 timeout)" },
266 { 20, 39, "Transmit Phase B Hangup Codes:" },
267 { 20, 20, " Unspecified Transmit Phase B error" },
268 { 21, 21, " Remote cannot receive or send" },
269 { 22, 22, " COMREC error in transmit Phase B" },
270 { 23, 23, " COMREC invalid command received" },
271 { 24, 24, " RSPREC error" },
272 { 25, 25, " DCS sent three times without response" },
273 { 26, 26, " DIS/DTC received 3 times; DCS not recognized" },
274 { 27, 27, " Failure to train at 2400 bps or +FMINSP value" },
275 { 28, 28, " RSPREC invalid response received" },
276 { 40, 49, "Transmit Phase C Hangup Codes:" },
277 { 40, 40, " Unspecified Transmit Phase C error" },
278 { 41, 41, " Unspecified image format error" },
279 { 42, 42, " Image conversion error" },
280 { 43, 43, " DTE to DCE data underflow" },
281 { 44, 44, " Unrecognized transparent data command" },
282 { 45, 45, " Image error, line length wrong" },
283 { 46, 46, " Image error, page length wrong" },
284 { 47, 47, " Image error, wrong compression code" },
285 { 50, 69, "Transmit Phase D Hangup Codes:" },
286 { 50, 50, " Unspecified Transmit Phase D error" },
287 { 51, 51, " RSPREC error" },
288 { 52, 52, " No response to MPS repeated 3 times" },
289 { 53, 53, " Invalid response to MPS" },
290 { 54, 54, " No response to EOP repeated 3 times" },
291 { 55, 55, " Invalid response to EOP" },
292 { 56, 56, " No response to EOM repeated 3 times" },
293 { 57, 57, " Invalid response to EOM" },
294 { 58, 58, " Unable to continue after PIN or PIP" },
296 { 70, 89, "Receive Phase B Hangup Codes:" },
297 { 70, 70, " Unspecified Receive Phase B error" },
298 { 71, 71, " RSPREC error" },
299 { 72, 72, " COMREC error" },
300 { 73, 73, " T.30 T2 timeout, expected page not received" },
301 { 74, 74, " T.30 T1 timeout, after EOM received" },
302 { 90, 99, "Receive Phase C Hangup Codes:" },
303 { 90, 90, " Unspecified Receive Phase C error" },
304 { 91, 91, " Missing EOL after 5 seconds" },
305 { 92, 92, " Unused code" },
306 { 93, 93, " DCE to DTE buffer overflow" },
307 { 94, 94, " Bad CRC or frame (ECM or BFT modes)" },
308 { 100, 119, "Receive Phase D Hangup Codes:" },
309 { 100, 100, " Unspecified Receive Phase D errors" },
310 { 101, 101, " RSPREC invalid response received" },
311 { 102, 102, " COMREC invalid response received" },
312 { 103, 103, " Unable to continue after PIN or PIP" },
313 { 120, 255, "Reserved Codes" },
318 /* meaning of efax return codes */
320 static char *errormsg [] = {
322 "number busy or modem in use",
323 "unrecoverable error",
324 "invalid modem response",
325 "no response from modem",
326 "terminated by signal",
331 /* Return name of frame of type 'fr'. */
334 char *frname ( int fr )
336 static struct framenamestruct { int code ; char *name ; }
339 {NSC,"NSC - poller features"}, /* these 3 frames must be first */
340 {CIG,"CIG - poller ID"},
341 {DTC,"DTC - poller capabilities"},
342 {NSF,"NSF - answering features"},
343 {CSI,"CSI - answering ID"},
344 {DIS,"DIS - answering capabilities"},
345 {NSS,"NSS - caller features"},
346 {TSI,"TSI - caller ID"},
347 {DCS,"DCS - session format"},
349 {CFR,"CFR - channel OK"},
350 {FTT,"FTT - channel not OK"},
352 {MPS,"MPS - not done"},
353 {EOM,"EOM - not done, new format"},
356 {PRI_MPS,"PRI-MPS - not done, call operator"},
357 {PRI_EOM,"PRI-EOM - not done, new format, call operator"},
358 {PRI_EOP,"PRI-EOP - done, call operator"},
360 {MCF,"MCF - page OK"},
361 {RTP,"RTP - page OK, check channel"},
362 {PIP,"PIP - page OK, call operator"},
363 {RTN,"RTN - page not OK, check channel"},
364 {PIN,"PIN - page not OK, call operator"},
366 {CRP,"CRP - repeat command"},
367 {DCN,"DCN - disconnect"},
371 for ( p=framenames ; p->code ; p++ )
372 if ( fr == p->code || ( fr & 0x7f ) == p->code) break ;
373 return p->code ? p->name : "UNKNOWN" ;
377 /* Range-check capability. */
379 static int checkcap ( cap c )
383 for ( i=0 ; i<NCAP ; i++ )
384 if ( c[i] > capmax[i] || c[i] < 0 ) {
385 err = msg ( "E3%s = %d out of range, set to 0", t30tab[i].name, c[i] ) ;
392 /* Print cap[ability] c using text values and prefix s. */
394 static void printcap ( char *s , cap c )
397 msg ( "N-+ %s" , s ) ;
399 for ( i=0 ; i<NCAP ; i++ )
400 msg ( "N-+ %s" , capvaluestr [ i ] [ c[i] ] ) ;
405 /* Convert capability string to cap struct. Returns 0 or 2 on errors. */
407 static int str2cap ( char *s, cap c )
412 for ( n=0 ; n<NCAP ; n++ ) {
415 c [ n ] = strtol ( s, &end, 10 );
416 if (end && *end && *end!=',')
421 if ( n < NCAP ) msg ( "Wmissing value(s) in \"%s\"", s ) ;
429 /* Convert a cap[ability] 'c' to a DIS/DCS/DTC FIF 'fif' of 'len'
430 bytes. Converts into DIS format if 'isdis' is true, else into
434 void mkdis ( cap c, uchar *fif, int len, int isdis, int t4tx )
439 len = len > DCSLEN ? DCSLEN : len ;
442 fif[1] = ( isdis && t4tx ? 0x80 : 0 ) | 0x40 ;
443 for ( i=2 ; i<len-1 ; i++ ) fif[i] = 0x01 ; /* add extension bits */
448 for ( i=0 ; i<NCAP ; i++ ) {
450 if ( ( k = ( isdis ? p->captodis : p->captodcs ) [ c [ i ] ] ) == X )
451 msg ( "E3mkdis: can't happen (invalid %s)", p->name ), k=0 ;
452 if ( p->byte < len ) fif [ p->byte ] |= k << p->shift ;
458 /* Return length of DIS/DTC FIF (counts extension bits). */
461 int dislen ( uchar *fif )
464 for ( n=3 ; fif [ n-1 ] & 0x01 && n < MAXFIFLEN ; n++ ) ;
470 /* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 if bad DIS/DCS
474 int mkcap ( uchar *fif, cap c, int dis )
476 int err=0, i, j, k, len ;
479 len = dislen ( fif ) ;
481 for ( i=0 ; i<NCAP ; i++ ) {
483 if ( p->byte >= len ) {
486 j = ( fif [ p->byte ] >> p->shift ) & p->mask ;
487 k = ( dis ? p->distocap : p->dcstocap ) [ j ] ;
489 c [ i ] = p->safeval ;
490 err = msg("E3mkcap: bad %s field (%d) set to %d",
491 p->name, j, c [ i ] ) ;
502 /* Compute compatible local/remote capabilities. Used by the
503 sending station only and only for Class 1. Returns 0 if OK or
504 3 if no compatible settings possible. */
507 int mincap ( cap local, cap remote, cap session )
510 int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ;
512 printcap ( "local ", local ) ;
513 printcap ( "remote ", remote ) ;
515 for ( i=0 ; i<NCAP && i!=ST && i !=BR ; i++ )
516 session[i] = remote[i] < local[i] ? remote[i] : local[i] ;
518 session[BR] = brindex[ remote[BR] ] < brindex[ local[BR] ] ?
519 remote[BR] : local[BR] ;
521 session[ST] = msttab [ session[VR] ] [ remote[ST] ] ;
523 printcap ( "session", session ) ;
525 if ( local[WD] != session[WD] || local[LN] > session[LN] ||
526 local[DF] != session[DF] )
527 err = msg ("W3incompatible local and remote capabilities" ) ;
534 /* Skip to start of first/next page (or to start of previous page
535 if dp is 0). If ppm in not null, it is then set to EOP if
536 there are no pages following this one, MPS if the next page
537 has the same format as `local' (assumed to be the format of
538 the previous page), EOM if the page has a different format.
539 If local is non-NULL its format fields are set according to
540 the format of the new page. Currently only considers the
543 This function is called before send_data() and obtains the ppm
544 for that page. It can be called again with dp=0 if a PIN or
545 RTN is received to restart the page. Returns 0 or 2 on
548 static int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
550 int err=0, m=EOP, yres, fVR, nVR ;
552 if ( nextipage ( f, dp ) )
553 err = msg ( "E2 can't happen (rdpage: can't go to %s page)",
554 dp ? "next" : "same" ) ;
558 yres = f->page->yres ;
559 fVR = ( yres > (196+98)/2 ) ? 1 : 0 ;
561 if ( local && yres ) {
562 if ( local [ VR ] != fVR ) {
564 if ( changed ) *changed = 1 ;
566 if ( changed ) *changed = 0 ;
570 if ( lastpage ( f ) ) {
573 PAGE *p = f->page + 1 ;
574 nVR = ( p->yres > (196+98)/2 ) ? 1 : 0 ;
575 m = ( nVR != fVR ) ? EOM : MPS ;
581 *ppm = err ? EOP : m ;
588 /* Terminate previous page if page number is non-zero and start
589 next output page if page number is non-negative. If page is -1
590 removes the most recently opened file. Returns 0 if OK, 2 on
594 int wrpage ( OFILE *f, int page )
598 err = nextopage ( f, page ) ;
600 if ( ! err && page == -1 ) {
601 if ( remove ( f->cfname ) ) {
602 err = msg ( "ES2can't delete file %s:", f->cfname ) ;
604 msg ( "Fremoved %s", f->cfname ) ;
613 /* Send data for one page. Figures out required padding and 196->98 lpi
614 decimation based on local and session capabilitites, substitutes page
615 numbers in header string and enables serial port flow control. Inserts
616 the page header before the input file data. Converts each scan line to
617 T.4 codes and adds padding (FILL) and EOL codes before writing out.
618 Sends RTC when done. Sends DLE-ETX and returns serial port to command
619 mode when done. Returns 0 if OK, non-0 on errors. */
621 static int send_data ( TFILE *mf, IFILE *f, int page, int pages,
622 cap local, cap session
624 , char *header, faxfont *font
628 int done=0, err=0, noise=0, nr=0, lastnr=0, line, pixels ;
629 int i, decimate, pwidth, minlen, dcecps, inheader, skip=0 ;
630 uchar buf [ MAXCODES + 2*EOLBITS/8 + 1 ], *p ;
631 short runs [ MAXRUNS ], lastruns [ MAXRUNS ] ;
633 char headerbuf [ MAXLINELEN ] ;
639 dcecps = cps[session[BR]] ;
640 minlen = ( (long)dcecps * mst[session[ST]] - 1500 + 500 ) / 1000 ;
641 pwidth = pagewidth [ session [ WD ] ] ;
642 decimate = local[VR] > session[VR] ;
644 msg ( "T padding to %d bytes/scan line.%s", minlen+1,
645 decimate ? " reducing 196->98 lpi." : "" ) ;
648 msg ( "T limiting output to %d bps for %d byte modem buffer",
649 dcecps*8, MAXDCEBUF + MINWRITE ) ;
652 if ( ckfmt ( header, 6 ) )
653 msg ( "W too many %%d escapes in header format string \"%s\"", header ) ;
655 sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ;
656 msg ("I header:[%s]", headerbuf ) ;
659 done = err = ttymode ( mf, SEND ) ;
661 mf->start = time(0) ;
662 mf->mstart = proc_ms() ;
663 mf->bytes = mf->pad = mf->lines = 0 ;
665 /* start T.4 data with some FILL and an EOL */
667 for ( i=0 ; i<32 ; i++ )
668 p = putcode ( &e, 0, 8, buf ) ;
669 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
672 err = msg ( "E2can't happen(send_data)" ) ;
675 for ( line=0 ; ! done && ! err ; line++ ) {
677 if ( line < HDRSPCE ) { /* insert blank lines at the top */
682 if ( ( nr = readline ( f, runs, &pixels ) ) < 0 ) {
688 /* generate and OR in header pixels */
689 if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) {
691 short hruns [ MAXRUNS ] ;
692 hnr = texttorun ( (uchar*) headerbuf, font, line-HDRSTRT,
693 HDRCHRW, HDRCHRH, HDRSHFT,
695 nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ;
699 inheader = line < HDRSTRT + HDRCHRH ;
701 if ( decimate || ( inheader && local[VR] == 0 ) ) {
702 if ( ++skip & 1 ) { /* save the first of every 2 lines */
703 memcpy ( lastruns, runs, nr * sizeof(short) ) ;
705 continue ; /* get next line */
706 } else { /* OR previous line into current line */
707 nr = runor ( runs, nr, lastruns, lastnr, 0, &pixels ) ;
713 /* make line the right width */
714 if ( pixels != pwidth ) nr = xpad ( runs, nr, pwidth - pixels ) ;
715 /* convert to MH coding */
716 p = runtocode ( &e, runs, nr, p ) ;
717 /* zero pad to minimum scan time */
718 while ( p - buf < minlen ) {
719 p = putcode ( &e, 0, 8, p ) ;
723 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
724 sendbuf ( mf, buf, p - buf, dcecps ) ;
725 mf->bytes += p - buf ;
728 /* probably read an EOL as part of RTC */
730 if ( tdata ( mf, 0 ) ) noise = 1 ;
735 for ( i=0 ; i < RTCEOL ; i++ )
736 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
737 p = putcode ( &e, 0, 0, p ) ;
738 sendbuf ( mf, buf, p - buf, dcecps ) ;
739 mf->bytes += p - buf ;
741 if ( noise ) msg ("W- characters received while sending" ) ;
747 static int end_data ( TFILE *mf, cap session, int ppm, int *good )
753 if ( ! ppm ) p = DLE_ETX ;
754 else if ( ppm == MPS ) p = "\020," ;
755 else if ( ppm == EOM ) p = "\020;" ;
756 else if ( ppm == EOP ) p = "\020." ;
759 err = msg ( "E2 can't happen (end_data)" ) ;
764 dt = time(0) - mf->start ;
765 /* time to drain buffers + 100% + 4s */
766 draintime = ( 2 * ( mf->bytes / cps[ session[BR] ] + 1 - dt ) + 4 ) * 10 ;
767 draintime = draintime < TO_DRAIN_D ? TO_DRAIN_D : draintime ;
769 c = ckcmd ( mf, 0, 0, (int) draintime, OK ) ;
771 if ( good ) *good = ( c == OK ) ? 1 : 0 ;
773 dt = time(0) - mf->start ;
775 msg ( "Isent %d+%d lines, %d+%d bytes, %d s %d bps" ,
776 HDRSPCE, mf->lines-HDRSPCE,
777 mf->bytes-mf->pad, mf->pad, (int) dt, (mf->bytes*8)/dt ) ;
779 if ( mf->bytes / (dt+1) > cps[session[BR]] )
780 msg ( "E flow control did not work" ) ;
782 if ( ! err ) err = ttymode ( mf, COMMAND ) ;
788 /* Read one scan line from fax device. If pointer pels is not
789 null it is used to save pixel count. Returns number of runs
790 stored, EOF on RTC, or -2 on EOF, DLE-ETX or other error. */
793 int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels )
795 int err=0, c=EOF, x, n ;
798 short *p, *maxp, *q, len=0 ;
801 maxp = ( p = runs ) + MAXRUNS ;
803 x = d->x ; shift = d->shift ; tab = d->tab ; /* restore decoder state */
804 rd_state = f->rd_state ;
808 while ( shift < 0 ) {
809 c = tgetd ( f, TO_CHAR ) ;
811 rd_state = ( rd_state & rd_allowed[c] ) ?
812 ( ( rd_state & rd_nexts[c] ) ? rd_state <<= 1 : rd_state ) :
815 if ( rd_state == RD_END )
816 msg ( "W+ modem response in data" ) ;
819 x = ( x << 15 ) | 1 ; shift += 15 ; /* EOL pad at EOF */
821 x = ( x << 8 ) | c ; shift += 8 ;
824 t = tab + ( ( x >> shift ) & 0x1ff ) ;
827 } while ( ! t->code ) ;
828 if ( p < maxp ) *p++ = t->code ;
829 } while ( t->code != -1 ) ;
831 d->x = x ; d->shift = shift ; d->tab = tab ; /* save state */
832 f->rd_state = rd_state ;
834 if ( p >= maxp ) msg ( "Wrun length buffer overflow" ) ;
836 /* combine make-up and terminating codes and remove +1 offset
840 for ( p = q = runs ; n-- > 0 ; )
841 if ( *p > 64 && n-- > 0 ) {
842 len += *q++ = p[0] + p[1] - 2 ;
845 len += *q++ = *p++ - 1 ;
849 /* check for RTC and errors */
854 if ( ++(d->eolcnt) >= RTCEOL ) err = EOF ;
856 if ( c < 0 ) err = - 2 ;
858 if ( pels ) *pels = len ;
860 return err ? err : n ;
864 /* Receive data. Reads scan lines from modem and writes to output
865 file. Checks for errors by comparing received line width and
866 session line width. Check that the output file is still OK
867 and if not, send one CANcel character and wait for protocol to
868 complete. Returns 0 if OK or 2 if there was a file write error. */
870 int receive_data ( TFILE *mf, OFILE *f, cap session, int *nerr )
872 int err=0, line, lines, nr, len ;
873 int pwidth = pagewidth [ session [ WD ] ] ;
874 short runs [ MAXRUNS ] ;
877 if ( ! f || ! f->f ) {
878 msg ( "E2 can't happen (writeline)" ) ;
885 for ( line=0 ; ( nr = readfaxruns ( mf, &d, runs, &len ) ) >= 0 ; line++ ) {
886 if ( nr > 0 && len > 0 && line ) { /* skip first line+EOL and RTC */
887 if ( len != pwidth ) {
889 if ( *nerr <= MAXERRPRT ) msg ("R-+ (%d:%d)", line, len ) ;
890 nr = xpad ( runs, nr, pwidth - len ) ;
892 writeline ( f, runs, nr, 1 ) ;
895 if ( ferror ( f->f ) ) {
896 err = msg ("ES2file write:") ;
897 tput ( mf, CAN_STR, 1 ) ;
898 msg ("Wdata reception CANcelled") ;
903 if ( *nerr > MAXERRPRT ) msg ("R-+ ....." ) ;
904 msg ("R- : reception errors" ) ;
905 msg ("W- %d reception errors", *nerr ) ;
909 while ( tgetd ( mf, TO_CHAR ) >= 0 ) ; /* got RTC, wait for DLE-ETX */
911 msg ( "I- received %d lines, %d errors", lines, *nerr ) ;
917 /* Send training check sequence of n zeroes. Returns 0 or 2 on error. */
919 int puttrain ( TFILE *f, char *s, int n )
922 uchar buf [ MINWRITE ] = { 0 } ;
924 ckcmd ( f, &err, s, TO_FT, CONNECT ) ;
927 ttymode ( f, SEND ) ;
929 for ( i=0 ; i < n ; i += m ) {
930 m = n-i < MINWRITE ? n-i : MINWRITE ;
931 sendbuf ( f, buf, m, 0 ) ;
934 buf[0] = 1 ; /* make sure last byte is non-zero */
937 sendbuf ( f, buf, 3, 0 ) ;
939 ttymode ( f, COMMAND ) ;
941 ckcmd ( f, &err, 0, TO_DRAIN_D, OK ) ;
942 msg ( "I- sent TCF - channel check of %d bytes", n ) ;
949 /* Checks for an error-free run of at least n bytes in the
950 received training check sequence. Sets good if it's not null,
951 the run was long enough and there were no errors. Returns 0 or
952 3 on other errors. */
954 int gettrain ( TFILE *f, char *s, int n, int *good )
956 int err=0, c, i=0, maxrunl=0, runl=0 ;
958 ckcmd ( f, &err, s, T2, CONNECT ) ;
962 for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
964 if ( runl > maxrunl ) maxrunl = runl ;
971 err = msg ( "E3timed out during training check data" ) ;
973 ckcmd ( f, &err, 0, TO_RTCMD, NO ) ;
977 if ( runl > maxrunl ) maxrunl = runl ;
979 if ( good ) *good = !err && maxrunl > n ;
982 msg ( "I- received TCF - channel check (%sOK: run of %d in %d)",
983 maxrunl > n ? "" : "not ", maxrunl, i ) ;
990 /* Log a sent/received HDLC frame. Display of these messages is delayed to
991 avoid possible timing problems. */
993 void logfr ( char *s , char *nm , uchar *p , int n )
996 msg ( n > 10 ? "H- %s %d bytes:" : "H-+ %s %d bytes:" , s, n ) ;
997 for ( i=0 ; i<n ; i++ ) {
998 msg ( "H-+ %02x" , p[i] & 0xff ) ;
999 if ( ( i&0xf ) == 0xf && i != n-1 ) msg ( "H-" ) ;
1002 msg ( "I- %s %s", s, nm ) ;
1004 #endif /* UCLINUX */
1007 /* Send HDLC control frame of type type. Extra bits can be OR'ed
1008 into the frame type (FCF) to indicate that this frame follows
1009 a previous one (no +FTH required) and/or that more frames will
1010 follow. Sets up flag, address, and fax control field bytes in
1011 `buf'. Sends these plus `len` additional bytes. Terminates
1012 with DLE-ETX and checks response. Returns 0 if OK, 2 or 3 on
1015 #define MORE_FR 0x100
1016 #define SUB_FR 0x200
1018 static int nframes = 0 ; /* counts frames sent/received */
1021 int putframe ( int type, uchar *buf, int len, TFILE *f, int t )
1026 buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ;
1027 buf [ 2 ] = type & 0xff ;
1029 if ( nframes++ && ! ( type & SUB_FR ) )
1030 ckcmd ( f, &err, "+FTH=3" , TO_FT, CONNECT ) ;
1034 if ( ! buf[len+2] ) {
1035 msg ( "Wlast byte of frame is NULL" ) ;
1038 /* ttymode ( f, SEND ) ; */
1039 sendbuf ( f, buf, len+3, 0 ) ;
1040 tput ( f, DLE_ETX, 2 ) ;
1041 /* ttymode ( f, COMMAND ) ; */
1043 logfr ( "sent", frname ( buf [ 2 ] ), buf, len+3 ) ;
1045 ckcmd ( f, &err, 0, TO_DRAIN_H, ( type & MORE_FR ) ? CONNECT : OK ) ;
1052 /* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */
1054 void revcpy ( uchar *from , uchar *to )
1057 for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- )
1058 to [ i ] = normalbits [ from [ j ] & 0xff ] ;
1062 /* Check for missing initial 0xFF in HDLC frame and insert it if
1063 missing. Ugly fix for a still-hidden bug. Also do bit
1064 inversion if required. */
1066 int fixframe ( uchar *buf, int n, TFILE *f )
1070 if ( *buf == 0xc0 || *buf == 0xc8 ) {
1071 for ( i=n; i >= 1 ; i-- )
1074 msg ("W HDLC frame missing initial 0xff" ) ;
1078 if ( buf[1] == 0x03 || buf[1] == 0x13 ) {
1079 for ( i=0 ; i < n ; i++ )
1080 buf[i]=normalbits[buf[i]] ;
1081 msg ("W bit-reversed HDLC frame, reversing bit order" ) ;
1082 f->ibitorder = f->ibitorder == normalbits ? reversebits : normalbits ;
1089 /* Read HDLC frame data. Returns 0 if OK, 1 on frame error, 3 on
1090 timeout, invalid response or too-long frame. */
1092 int receive_frame_data ( TFILE *f, uchar *buf, int n, int *len )
1096 for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
1097 if ( i < n ) buf[ i ] = c ;
1101 err = msg ( "E3timed out reading frame data" ) ;
1105 switch ( cmd ( f, 0, TO_RTCMD ) ) {
1111 err = msg ( "W1frame error" ) ;
1114 err = msg ( "E3no response after frame data" ) ;
1117 err = msg ( "E3wrong response after frame data" ) ;
1124 err = msg ( "E3frame too long (%d, > %d max bytes)", i, n ) ;
1126 if ( len ) *len = i ;
1130 #endif /* UCLINUX */
1133 /* Get a Class 1 command or response frame. An attempt to match
1134 and combine T.30 "Response Received?" and "Command Received?"
1135 protocol flowcharts.
1137 When receiving commands returns after first correct
1138 non-optional frame or after the time given by getcmd has
1139 elapsed. This is instead of looping through main flowchart.
1141 When receiving responses returns on the first detected
1142 non-optional frame, after timeout T4, or on errors.
1144 Returns immediately if gets a +FCERROR response so can retry
1145 as data carrier. Returns DCN as a valid frame instead of
1148 Returns the command/response received, or EOF on timeout or
1154 int getfr ( TFILE *mf, uchar *buf, int getcmd )
1156 int err=0, frame=0, frlen, c, t ;
1157 char remoteid [ IDLEN + 1 ] ;
1161 start = 10*time(0) ;
1163 t = getcmd ? ( getcmd > 1 ? getcmd : T2 ) : T4 ;
1170 c = cmd ( mf, "+FRH=3", t ) ;
1172 c = CONNECT ; /* implied by ATA or ATD */
1176 case EOF: /* time out */
1177 tput ( mf, CAN_STR, 1 ) ;
1178 ckcmd ( mf, 0, 0, TO_ABRT, OK ) ;
1181 case NO: /* S7 time out */
1184 case MODULATION: /* data carrier (or DHS) */
1185 return -msg ( "W-2 wrong carrier" ) ;
1187 case CONNECT: /* frame */
1189 default: /* shouldn't happen */
1190 err = msg ( "E3wrong response to receive-frame command" ) ;
1195 err = receive_frame_data ( mf, buf, MAXFRLEN, &frlen ) ;
1197 if ( ! err && frlen < 3 )
1198 err = msg ( "E3received short frame (%d bytes)", frlen ) ;
1202 frlen = fixframe ( buf, frlen, mf ) ;
1203 logfr ( "received", frname ( buf [ 2 ] ), buf, frlen ) ;
1204 frame = buf [ 2 ] & 0x7f ;
1216 revcpy ( fif , (uchar*) remoteid ) ;
1217 msg ( "I- remote ID -> %*.*s", IDLEN, IDLEN, remoteid ) ;
1223 if ( err && getcmd && ( t -= 10*time(0) - start ) > 0 )
1226 return err ? EOF : frame ;
1230 /* Class 1 send/receive.
1232 The logic in this function is a mess because it's meant to
1233 mirror the flowchart in ITU-T recommendation T.30 which is the
1234 protocol specification.
1239 TFILE *mf, cap local, char *localid,
1240 OFILE *outf, IFILE *inf,
1241 int pages, char *header, faxfont *font,
1242 int maxpgerr, int noretry, int calling )
1244 int err=0, rxpage=0, page=1, t, disbit, good, frame, last, nerr ;
1245 int rxdislen, ppm, try=0, pagetry=0, retry=0, remtx=0, remrx=0 ;
1246 int writepending=0, dp=0 ;
1247 cap remote = { DEFCAP }, session = { DEFCAP } ;
1249 uchar buf [ MAXFRLEN ], *fif=buf+3 ;
1251 if ( ! calling ) goto RX ;
1253 /* Class 1 Transmitter: */
1255 T: /* Transmitter Phase B - wait for DIS or DTC */
1259 frame = getfr ( mf, buf, T1 ) ;
1262 err = msg ( "E3no answer from remote fax" ) ;
1266 if ( frame != DIS && frame != DTC ) {
1267 msg ( "W2 can't open page" ) ;
1271 disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1274 A: /* decide to send or receive after DIS/DTC */
1276 if ( frame == DIS || frame == DTC ) {
1277 rxdislen = dislen ( fif ) ;
1278 mkcap ( fif, remote, 1 ) ;
1279 remtx = fif[1] & 0x80 ;
1280 remrx = fif[1] & 0x40 ;
1283 msg ( "N remote has %sdocument(s) to send, and can %sreceive",
1284 remtx ? "" : "no ", remrx ? "" : "not " ) ;
1287 if ( ! remrx ) msg ( "W remote cannot receive, trying anyways" ) ;
1290 if ( ! remtx ) msg ( "W remote has nothing to send, trying anyways" ) ;
1296 if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1297 err = msg ( "E2can't open page" ) ;
1303 mincap ( local, remote, session ) ;
1305 revcpy ( (uchar*) localid, fif ) ;
1307 err = putframe ( TSI | MORE_FR | disbit, buf, IDLEN, mf, -1 ) ;
1309 mkdis ( session, fif, DCSLEN, 0, pages ) ;
1311 err = putframe ( DCS | SUB_FR | disbit, buf, DCSLEN, mf, -1 ) ;
1313 if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1314 msleep ( TMOD ) ; /* if +FTS not supported */
1317 err = puttrain ( mf, c1cmd[SND][TRN][session[BR]],
1318 1.5*cps [ session[BR] ] ) ;
1322 cmd ( mf, "+FRS=1", T3S ) ; /* wait for TCF carrier to drop */
1323 frame = getfr ( mf, buf, 0 ) ;
1326 if ( err || frame < 0 ) {
1338 if ( try >= 3 ) goto C_timeout ;
1342 msg ( "I channel not usable at %d bps", 8*cps[session[BR]] ) ;
1343 remote[BR] = fallback[session[BR]] ;
1344 if ( remote[BR] >= 0 ) goto D_2 ;
1345 else { err = msg ( "E2 channel not usable at lowest speed" ) ; goto C ; }
1351 err = msg ( "E3 invalid response to DCS (0x%02x)", frame ) ;
1355 I: /* send a page */
1357 if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1358 err = msg ( "E2can't open page" ) ;
1364 ckcmd ( mf, &err, c1cmd [SND][DTA][session[BR]], TO_FT, CONNECT ) ;
1366 err = send_data ( mf, inf, page, pages, local, session, header, font ) ;
1371 err = end_data ( mf, session, 0, 0 ) ;
1373 if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1374 msleep ( TMOD ) ; /* if +FTS not supported */
1376 /* fix ppm if on last page of stdin */
1377 if ( lastpage ( inf ) ) ppm = EOP ;
1381 if ( !err ) err = putframe ( ppm | disbit, buf, 0, mf, -1 ) ;
1384 frame = getfr ( mf, buf, 0 ) ;
1393 fname = inf->page->fname ;
1395 switch ( noretry ? MCF : frame ) { /* common retry logic */
1399 fname = inf->page->fname ;
1400 if ( fname ) msg ( "Isent -> %s", fname ) ;
1408 retry = pagetry < NTXRETRY ;
1411 err = msg ( "E3invalid post-page response (0x%02x)", frame ) ;
1432 nextipage ( inf, 1 ) ; /* skip ahead to mark all files done */
1433 if ( remtx ) goto R ; /* poll after sending */
1436 if ( retry ) goto D ;
1447 cmd ( mf, "+FRS=20", T3S ) ; /* wait for ppr carrier to drop */
1448 if ( retry ) goto T ;
1454 E: /* ignore PIN and PIP */
1455 msg ( "W interrupt request ignored" ) ;
1459 /* Class 1 Receiver */
1463 R: /* Receiver Phase B */
1465 if ( ! err ) err = wrpage ( outf, rxpage ) ;
1469 for ( t=0 ; !err && t<T1 ; t+=T2+10 ) {
1471 revcpy ( (uchar*) localid, fif ) ;
1473 err = putframe ( CSI | disbit | MORE_FR, buf, IDLEN, mf, -1 ) ;
1475 mkdis ( local, fif, DEFDISLEN, 1, pages ) ;
1477 err = putframe ( DIS | disbit | SUB_FR, buf, DEFDISLEN, mf, -1 ) ;
1479 frame = getfr ( mf, buf, 0 ) ;
1482 disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1487 else goto C_timeout ;
1490 F: /* get a command */
1493 frame = getfr ( mf, buf, 1 ) ;
1495 if ( writepending ) { /* do postponed file close/open */
1497 err = wrpage ( outf, rxpage ) ;
1502 if ( frame == -2 ) goto getdata ; /* data carrier detected */
1503 if ( last == EOM ) goto R ;
1504 else { err = msg ("E3 timed out waiting for command" ) ; goto B ; }
1519 mkcap ( fif, session, 0 ) ;
1520 printcap ( "session", session ) ;
1522 cmd ( mf, "+FTS=1", T3S ) ; /* make sure DCS is over */
1524 gettrain ( mf, c1cmd [RCV][TRN][session[BR]], cps[session[BR]], &good ) ;
1526 if ( putframe ( ( good ? CFR : FTT ) | disbit, buf, 0, mf, -1 ) ||
1531 outf->w=pagewidth[session[WD]];
1534 outf->yres=vresolution[session[VR]];
1536 if ( cmd ( mf, c1cmd [RCV][DTA][session[BR]], TO_FT ) != CONNECT )
1537 goto F ; /* +FCERROR -> DCS resent */
1539 if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1540 good = nerr < maxpgerr ;
1541 msg ( "I-received -> %s", outf->cfname ) ;
1542 writepending=1 ; /* ppm follows immediately, don't write yet */
1547 ckcmd ( mf, 0, 0, TO_RTCMD, NO ) ;
1555 frame &=0xf7 ; /* ignore PRocedure Interrupt bit */
1559 putframe ( ( good ? MCF : RTN ) | disbit, buf, 0, mf, -1 ) ;
1560 if ( good && frame == MPS ) goto getdata ;
1567 err = msg ( "E3 unrecognized command" ) ;
1573 err = msg ( "E3 no command/response from remote" ) ;
1576 putframe ( DCN, buf, 0, mf, -1 ) ;
1579 ckcmd ( mf, 0, "H", TO_RESET, OK ) ; /* hang up */
1582 wrpage ( outf, -1 ) ; /* remove last file */
1586 #endif /* UCLINUX */
1589 /* Check for hangup message. Assumes hsc is initialized to a
1590 negative value. Returns 0 if no hangup message, 1 if there
1591 was one. If perr is not null, sets it to 2 if the hsc was
1592 non-zero (error). */
1594 static int gethsc ( int *hsc, int *perr )
1597 if ( sresponse ( "+FHNG:", hsc ) || sresponse ( "+FHS:", hsc ) ) {
1598 if ( hsc && *hsc > 0 ) {
1599 err = msg ( "E2abnormal termination (code %d)", *hsc ) ;
1600 for ( i=0 ; c2msg[i].min >= 0 ; i++ ) {
1601 if ( *hsc >= c2msg[i].min && *hsc <= c2msg[i].max ) {
1602 msg ( "E %s", c2msg[i].msg ) ;
1605 if ( perr && ! *perr ) {
1616 /* Print remote ID and store DCS values in session as per
1617 responses since last command. */
1619 static void getc2dcs ( cap session )
1622 if ( ( p = sresponse ( "+FTI:", 0 ) ) != 0 ||
1623 ( p = sresponse ( "+FTSI:", 0 ) ) != 0 ) {
1624 msg ( "I- remote ID -> %s", p ) ;
1626 if ( ( p = sresponse ( "+FCS:", 0 ) ) != 0 ||
1627 ( p = sresponse ( "+FDCS:", 0 ) ) != 0 ) {
1628 str2cap ( p, session ) ;
1629 printcap ( "session", session ) ;
1633 /* Wait for a starting character XON or DC2. Display & ignore
1634 any other characters received. */
1636 static void getstartc ( TFILE *mf )
1640 for ( noise=0 ; ( c = tgetc ( mf, TO_C2X ) ) != XON && c != DC2 ; noise++ ) {
1642 msg ( "Wno XON/DC2 received after CONNECT") ;
1645 msg ( "W-+%s", cname ( c ) ) ;
1651 msg ( "W : %d characters received while waiting to send", noise ) ;
1655 /* Class 2 send and receive.
1657 If calling, polls if no files to send, otherwise sends. If
1658 not calling sends documents if files to send, else receives.
1660 When sending, issues +FDIS to change session parameters if
1661 file format changes, then sends +FDT followed by data and a
1662 post-page message determined by format of next page, if any.
1663 Retransmits each page up to NTXRETRY times.
1665 When receiving extracts file format from responses to +FDR or
1666 ATA and saves them in the file. Receives data to a file and
1667 sets page transfer status if too many errors.
1669 Returns 0 if OK or 2 on errors. */
1672 static int c2sndrcv (
1673 TFILE *mf, cap local, char *localid,
1674 OFILE *outf, IFILE *inf,
1677 char *header, faxfont *font,
1678 #endif /* UCLINUX */
1679 int maxpgerr, int noretry, int calling )
1683 #endif /* UCLINUX */
1684 int err=0, done=0, page, pagetry, dp=0 ;
1685 int ppm=0, good, hsc, changed ;
1688 cap session = { 0,0,0,0, 0,0,0,0 } ;
1689 char buf [ CMDBUFSIZE ] ;
1691 hsc=-1 ; /* will be set >= 0 on hangup */
1693 if ( sresponse ( "+FPO", 0 ) ) {
1695 msg ( "N remote has document(s) to send." ) ;
1701 #endif /* UCLINUX */
1705 #endif /* UCLINUX */
1709 if ( pages ) goto pollserver ;
1712 #endif /* UCLINUX */
1718 #endif /* UCLINUX */
1720 /* with +FLP[L]=1 the modem should accept +FDT. */
1727 while ( ! err && ! done ) {
1729 err = rdpage ( inf, dp, &ppm, local, &changed ) ;
1731 if ( ! err && changed ) {
1732 sprintf ( buf, c20 ? "+FIS=%d,%d,%d,%d" : "+FDIS=%d,%d,%d,%d",
1733 local[0], local[1], local[2], local[3] ) ;
1734 ckcmd ( mf, 0, buf, TO_FT, OK ) ;
1735 if ( gethsc ( &hsc, &err ) ) {
1740 ckcmd ( mf, &err, "+FDT", -TO_C2B, CONNECT ) ;
1741 if ( err || gethsc ( &hsc, &err ) ) {
1746 getc2dcs ( session ) ;
1748 if ( ! c20 ) getstartc ( mf ) ;
1750 send_data ( mf, inf, page, pages, local, session
1753 #endif /* UCLINUX */
1758 end_data ( mf, session, ppm, &good ) ;
1760 end_data ( mf, session, 0, 0 ) ;
1762 gethsc ( &hsc, &err ) ;
1764 if ( ! err && hsc < 0 ) {
1765 ckcmd ( mf, &err, ppm == EOP ? "+FET=2" :
1766 ppm == EOM ? "+FET=1" : "+FET=0" , TO_C2PP, OK ) ;
1769 gethsc ( &hsc, &err ) ;
1771 if ( ! err && hsc < 0 ) {
1772 if ( sresponse ( "+FPTS:", &good ) ) {
1773 good &= 1 ; /* odd values mean received OK */
1774 } else { /* no +FPTS and +FHNG probably NG */
1775 good = gethsc ( 0, 0 ) ? 0 :
1776 msg ( "W1no +FPTS response, assumed received" ) ;
1782 if ( noretry ) good = 1;
1785 fname = inf->page->fname ;
1786 if ( fname ) msg ( "Isent -> %s", fname ) ;
1791 nextipage ( inf, 1 ) ; /* skip ahead to mark all files done */
1796 if ( pagetry >= NTXRETRY )
1797 err = msg ( "E2too many page send retries" ) ;
1800 if ( gethsc ( &hsc, &err ) ) done=1 ;
1802 if ( good && lastpage ( inf ) ) {
1810 /* Class 2 Receive */
1814 /* with +FSP[L]=1 and +FPO[LL]: the modem should now accept +FDR. */
1818 getc2dcs ( session ) ; /* get ATA responses */
1821 for ( page=0 ; ! err && ! done ; page++ ) {
1823 if ( ! ( err = wrpage ( outf, page ) ) ) {
1824 c = cmd ( mf, "+FDR", -TO_C2R ) ;
1829 getc2dcs ( session ) ;
1831 outf->w=pagewidth[session[WD]];
1834 outf->yres=vresolution[session[VR]];
1836 tput ( mf, &startchar, 1 ) ;
1838 if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1839 good = nerr < maxpgerr ;
1840 msg ( "I-received -> %s", outf->cfname ) ;
1845 ckcmd ( mf, &err, 0, TO_C2EOR, OK ) ;
1847 if ( err || gethsc ( &hsc, &err ) ) {
1848 wrpage ( outf, +1 ) ;
1849 wrpage ( outf, -1 ) ;
1855 msg ( "Wreception errors" ) ;
1856 ckcmd ( mf, 0, c20 ? "+FPS=2" : "+FPTS=2", T3S, OK ) ;
1857 if ( gethsc ( &hsc, &err ) ) continue ;
1862 wrpage ( outf, -1 ) ; /* no more pages */
1864 if ( gethsc ( &hsc, &err ) ) continue ;
1868 wrpage ( outf, -1 ) ; /* oops */
1869 err = msg ( "E3receive (+FDR) command failed") ;
1874 #endif /* UCLINUX */
1878 if ( hsc < 0 ) ckcmd ( mf, 0, c20 ? "+FKS" : "+FK", TO_RESET, OK ) ;
1884 /* Dial the phone number given by string s. If nowait is true
1885 adds a ';' to the dial string to avoid waiting for a
1886 CONNECTion (might allow ersatz polling). Also resets the
1887 global "nframes" if appropriate so getfr() and putframe() know
1888 not to issue +FRH/+FTH. Returns 0 if dialed OK, 1 if busy, 2
1891 static int dial ( TFILE *f, char *s, int nowait )
1894 char c, dsbuf [ 128 ], *p ;
1896 sprintf ( dsbuf, nowait ? "D%.126s;" : "D%.127s" , s ) ;
1897 msg ( "Idialing %s", dsbuf+1 ) ;
1899 c = cmd ( f, dsbuf, TO_A ) ;
1901 if ( ( p = sresponse ( "+FCSI:", 0 ) ) != 0 ||
1902 ( p = sresponse ( "+FCI:", 0 ) ) != 0 ) {
1903 msg ( "I- remote ID -> %s", p ) ;
1906 if ( nowait && c == OK ) {
1909 } else if ( c1 && c == CONNECT ) {
1910 msg ( "Iconnected" ) ;
1912 } else if ( !c1 && c == OK ) {
1913 msg ( "Iconnected" ) ;
1914 } else if ( c == BUSY ) {
1915 err = msg ( "W1number is busy" ) ;
1917 err = msg ( "E2dial command failed" ) ;
1920 gethsc ( &hsc, err ? 0 : &err ) ;
1926 /* Figure out which mode the modem answered in (fax, data, voice
1927 or none) based on modem class and responses to the previous
1928 command. Sets crate (connect rate) for DATAMODE and hsc
1929 (hangup status code) if detects a class 2 hangup message. */
1931 enum connectmode { NONE, DATAMODE, FAXMODE, VOICEMODE } ;
1934 enum connectmode ansmode ( int *crate, int *hsc )
1936 enum connectmode mode = NONE ;
1939 if ( c1 && sresponse ( "CONNECT", &x ) ) {
1940 mode = x ? DATAMODE : FAXMODE ;
1943 if ( !c1 && sresponse ( "OK", 0 ) ) {
1947 if ( !c1 && ( sresponse ( "CONNECT", &x ) || sresponse ( "+FDM", 0 ) ) ) {
1951 if ( sresponse ( "DATA", 0 ) || sresponse ( "CONNECT DATA", 0 ) ) {
1953 sresponse ( "CONNECT", &x ) ;
1956 if ( sresponse ( "FAX", 0 ) || sresponse ( "+FCO", 0 ) ) {
1960 if ( sresponse ( "VCON", 0 ) ) {
1964 if ( gethsc ( hsc, 0 ) ) {
1968 if ( DATAMODE && x ) *crate = x ;
1972 #endif /* UCLINUX */
1975 /* Answer the phone. Remove our lock if sharing device with
1976 outgoing calls. If waiting for call, wait for modem activity,
1977 else answer phone. Figure out what mode we answered in and
1978 handle call appropriately. Re-lock if necessary. Exec *getty
1979 or *vcmd for data or voice calls. */
1982 int answer ( TFILE *f, char **lkfile,
1983 int wait, int share, int softaa,
1984 char *getty, char *vcmd, char *acmd )
1987 int crate=19200, hsc=-1, i ;
1988 enum connectmode mode=NONE ;
1990 if ( ! err && share ) {
1991 err = ttymode ( f, COMMAND ) ;
1993 err = unlockall ( lkfile ) ;
1996 if ( ! err && wait ) {
1997 msg ( "Iwaiting for activity") ;
1999 msg ( "Iactivity detected") ;
2002 if ( ! err && share ) {
2003 msleep ( 500 ) ; /* let other programs lock port */
2004 err = lockall ( lkfile, 1 ) ;
2006 err = msg ( "W1can't answer: can't lock device" ) ;
2008 err = ttymode ( f, COMMAND ) ; /* in case it was changed silently */
2011 for ( i=0 ; ! err && mode == NONE && ( i==0 || ( i==1 && softaa ) ) ; i++ ) {
2013 c = cmd ( f, wait ? 0 : acmd, ( i==0 && softaa ) ? TO_DATAF : TO_A ) ;
2015 if ( c == DATA ) cmd ( f, c1 ? "O" : 0, TO_A ) ; /* +FAE=1 weirdness */
2017 mode = ansmode ( &crate, &hsc ) ;
2021 msg ( "Idata call answered") ;
2022 if ( getty && *getty ) {
2023 char buf [ MAXGETTY ] ;
2024 if ( ckfmt ( getty, 6 ) ) {
2025 err = msg ( "E3 too many %%d escapes in command (%s)", getty ) ;
2027 sprintf ( buf, getty, crate, crate, crate, crate, crate, crate ) ;
2028 msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
2029 execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ;
2030 err = msg ( "ES2exec failed:" ) ;
2033 err = msg ( "E2no getty command defined for data call" ) ;
2038 msg ( "Ifax call answered") ;
2041 msg ( "Ivoice call answered") ;
2042 if ( vcmd && *vcmd ) {
2043 char buf [ MAXGETTY ] ;
2044 if ( ckfmt ( vcmd, 6 ) ) {
2046 sprintf ( buf, vcmd, f->fd, f->fd, f->fd, f->fd, f->fd, f->fd ) ;
2047 msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
2048 execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ;
2049 err = msg ( "ES2exec failed:" ) ;
2052 err = msg ( "E2no voice command defined for voice call" ) ;
2056 if ( i==0 && softaa && hsc < 0 && getty && *getty ) {
2057 int j ; /* switch to fax for 2nd try */
2058 for ( j=0 ; j<3 ; j++ )
2059 if ( cmd ( f, c1 ? "+FCLASS=1" :
2060 ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), -TO_RESET )
2065 err = msg ( "E3unable to answer call") ;
2069 err = msg ( "E3can't happen(answer)" ) ;
2077 #endif /* UCLINUX */
2080 /* Initialize modem. Determine class to use and issue
2081 class-specific fax initialization commands. If poll is true,
2082 issues commands to enable polling also. Returns 0 or 3 if a
2083 mandatory setup command fails. */
2085 static int modem_init ( TFILE *mf, cap c, char *id,
2086 int calling, int poll, int capsset, int *preverse )
2088 int err=0, t=-TO_RESET ;
2089 char buf [ CMDBUFSIZE ], model [ CMDBUFSIZE ] = "" ;
2090 char **p, *q, *modelq [2][4] = { { "+FMFR?", "+FMDL?", 0 },
2091 { "+FMI?", "+FMM?", "+FMR?", 0 } } ;
2094 /* diasable command echo and get firmware revision */
2096 cmd ( mf, "E0", t ) ;
2098 if ( cmd ( mf, "I3", t ) == OK ) {
2099 getresp ( "", model, CMDBUFSIZE-1 ) ;
2100 strcat ( model, " " ) ;
2103 /* if not already chosen, pick safest class; set it */
2105 if ( ! err && ! c1 && !c2 && ! c20 ) {
2106 if ( cmd ( mf, "+FCLASS=?", t ) != OK ) {
2107 err = msg ("E3 modem does not support fax" ) ;
2109 if ( strinresp ( "2.0" ) ) c20 = 1 ;
2110 else if ( strinresp ( "2" ) ) ;
2112 else if ( strinresp ( "1" ) ) c1 = 1 ;
2113 #endif /* UCLINUX */
2114 else err = msg ("E3 can't determine fax modem class support" ) ;
2116 if ( strstr ( model, "Sportster" ) ) { /* USR Sporsters are buggy */
2120 #endif /* UCLINUX */
2124 ckcmd ( mf, &err, c1 ? "+FCLASS=1" :
2125 ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), t, OK ) ;
2127 /* get make & model if using Class 2 or 2.0 */
2130 for ( p = modelq [ c20 ] ; ! err && *p ; p++ ) {
2131 if ( cmd ( mf, *p, t ) == OK ) {
2132 getresp ( "", model, CMDBUFSIZE-1 ) ;
2133 strcat ( model, " " ) ;
2137 if ( ! c1 && strstr ( model, "Multi-Tech" ) ) {
2139 msg ("I Multi-Tech bit order set" ) ;
2144 msg ( "I using %sin class %s", model, c1 ? "1" : c20 ? "2.0" : "2" ) ;
2146 /* get maximum modem speed if not already set (Class 1 only) */
2148 if ( ! err && c1 && ! capsset ) {
2150 char *c1spstr [6] = { "24", "48", "72", "96", "121", "145" } ;
2151 ckcmd ( mf, &err, calling ? "+FTM=?" : "+FRM=?", t, OK ) ;
2152 for ( i=0 ; i < 6 && strinresp ( c1spstr[i] ) ; i++ ) ;
2156 /* issue essential commands and set/get modem capabilities (Class 2 only) */
2158 if ( ! err && ! c1 ) {
2161 ckcmd ( mf, 0, "+FIP", t, OK ) ;
2162 ckcmd ( mf, 0, "+FNR=1,1,1,1", t, OK ) ;
2165 ckcmd ( mf, &err, "+FCR=1", t, OK ) ;
2168 if ( cmd ( mf, c20 ? "+FIS?" : "+FDIS?", -t ) == OK &&
2169 ( q = strinresp ( "," ) ) ) {
2170 str2cap ( q-1, c ) ;
2172 msg ( "W can't get modem capabilities, set to default" ) ;
2178 sprintf ( buf, c20 ? "+FCC=%d,%d,%d,%d,%d,%d,%d,%d" :
2179 "+FDCC=%d,%d,%d,%d,%d,%d,%d,%d",
2180 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7] ) ;
2181 ckcmd ( mf, 0, buf, -t, OK ) ;
2184 sprintf ( buf, c20 ? "+FLI=\"%.*s\"" : "+FLID=\"%.*s\"" ,
2185 CMDBUFSIZE-9, id ) ;
2186 ckcmd ( mf, 0, buf, -t, OK ) ;
2188 if ( ! err && poll ) {
2190 ckcmd ( mf, 0, c20 ? "+FSP=1" : "+FSPL=1", -t, OK ) ;
2192 sprintf ( buf, c20 ? "+FPI=\"%.*s\"" : "+FCIG=\"%.*s\"" ,
2193 CMDBUFSIZE-9, id ) ;
2194 ckcmd ( mf, 0, buf, -t, OK ) ;
2203 /* the following are global so can terminate properly on signal */
2205 static char *icmd[3][ MAXICMD+1 ] = {{0},{0},{0}} ; /* initialization commands */
2206 static TFILE faxdev = { -1, 0,0, {0}, 0, 0 } ; /* modem */
2207 static char *lkfile [ MAXLKFILE+1 ] = {0} ; /* lock file names */
2208 static IFILE ifile = { 0 } ; /* files being sent */
2209 static int locked = 0 ; /* modem locked */
2212 /* print names of files not sent and reset modem before
2215 static int cleanup ( int err )
2217 /* log names of files not sent */
2218 logifnames ( &ifile, "I failed -> %s" ) ;
2220 if ( ! locked && faxdev.fd >= 0 )
2221 end_session ( &faxdev, icmd[2], lkfile, err != 4 ) ;
2223 msg ( "Idone, returning %d (%s)", err,
2224 errormsg [ err >= 0 && err <= 5 ? err : 6 ] ) ;
2230 /* signal handler */
2232 static void onsig ( int sig )
2234 msg ( "E terminating on signal %d", sig ) ;
2235 exit ( cleanup ( 5 ) ) ;
2239 /* Fax send/receive program for Class 1, 2 and 2.0 fax
2240 modems. Returns 0 on success, 1 if number busy or device
2241 locked, 2 for errors, 3 for protocol errors, 4 if no modem
2242 response, 5 on signal. */
2244 int main( int argc, char **argv)
2246 int err=0, doneargs=0, c=0, i ;
2252 #endif /* UCLINUX */
2254 int nicmd[3]={0,0,0}, nlkfile=0, nverb=0 ;
2256 char *faxfile = FAXFILE ;
2258 int softaa=0, share=0, wait=0, reverse=1, ignerr=0, noretry=0, hwfc=0 ;
2260 char *getty = "", *vcmd = "", *acmd=ANSCMD ;
2262 cap local = { DEFCAP } ;
2263 char localid [ IDLEN + 1 ] = DEFID ;
2265 int maxpgerr = MAXPGERR ;
2269 char *header = 0, headerbuf [ MAXLINELEN ] ;
2270 char *fontname = 0 ;
2272 #endif /* UCLINUX */
2278 char *ansfname = DEFPAT ;
2279 char fnamepat [ EFAX_PATH_MAX ] ;
2280 #endif /* UCLINUX */
2282 /* print initial message to both stderr & stdout */
2285 msg ( "I " Version " " Copyright ) ;
2286 argv0 = efaxbasename ( argv0 ) ;
2287 msg ( "A compiled "__DATE__ " " __TIME__ ) ;
2290 while ( ! err && ! doneargs &&
2291 ( c = nextopt ( argc,argv,
2292 "a:c:d:e:f:g:h:i:j:k:l:o:p:q:r:st:v:wx:T" ) ) != -1 ) {
2299 err = str2cap ( nxtoptarg, local ) ;
2303 if ( strlen ( nxtoptarg ) > IDLEN )
2304 msg("Wlocal ID (%s) truncated to %d characters", nxtoptarg, IDLEN ) ;
2305 if ( strspn ( nxtoptarg, " +0123456789" ) != strlen ( nxtoptarg ) )
2306 msg("Wlocal ID (%s) has non-standard characters", nxtoptarg ) ;
2307 sprintf ( localid, "%*.*s", IDLEN, IDLEN, nxtoptarg ) ;
2310 if ( nicmd[0] < MAXICMD ) icmd[0][ nicmd[0]++ ] = nxtoptarg ;
2311 else err = msg ( "E2too many '-i' options");
2314 if ( nicmd[1] < MAXICMD ) icmd[1][ nicmd[1]++ ] = nxtoptarg ;
2315 else err = msg ( "E2too many '-j' options");
2318 if ( nicmd[2] < MAXICMD ) icmd[2][ nicmd[2]++ ] = nxtoptarg ;
2319 else err = msg ( "E2too many '-k' options");
2323 header = nxtoptarg ;
2326 fontname = nxtoptarg ;
2328 #endif /* UCLINUX */
2330 faxfile = nxtoptarg ;
2338 case 'o': /* most protocol options are globals */
2339 for ( ; *nxtoptarg ; nxtoptarg++ )
2340 switch ( *nxtoptarg ) {
2341 case '0' : c20 = 1 ; break ;
2343 case '1' : c1 = 1 ; break ;
2344 #endif /* UCLINUX */
2345 case '2' : c2 = 1 ; break ;
2346 case 'a' : softaa = 1 ; break ;
2347 case 'e' : ignerr = 1 ; break ;
2348 case 'f' : vfc = 1 ; break ;
2349 case 'h' : hwfc = 1 ; break ;
2350 case 'l' : lockpolldelay /= 2 ; break ;
2351 case 'n' : noretry = 1 ; break ;
2352 case 'r' : reverse = 0 ; break ;
2353 case 'x' : startchar = XON ; break ;
2354 case 'z' : cmdpause += T_CMD ; break ;
2355 default : msg ( "Wunrecognized protocol option (%c)", *nxtoptarg ) ;
2359 maxpgerr = atoi( nxtoptarg );
2361 err=msg ("E2bad quality (-q) argument (%s)", nxtoptarg ) ;
2365 ansfname = nxtoptarg ;
2367 #endif /* UCLINUX */
2374 #endif /* UCLINUX */
2377 if ( argv [ argc ] ) err = msg ("E2can't happen(unterminated argv)") ;
2378 if ( ! err ) err = newIFILE ( &ifile, argv + nxtoptind ) ;
2379 pages = argc - nxtoptind - ( c == 'p' ? 1 : 0 ) ;
2380 pages = pages < 0 ? 0 : pages ;
2385 verb[nverb] = nxtoptarg ;
2392 if ( nlkfile < MAXLKFILE ) lkfile[ nlkfile++ ] = nxtoptarg ;
2393 else err = msg ( "E2too many lock files" ) ;
2395 case 'T': /* test: begin+end session */
2399 default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
2403 for ( i=0 ; i<argc ; i++ )
2404 msg ( "Aargv[%d]=%s", i, argv[i]) ;
2406 if ( ! nicmd[2] ) icmd[2][nicmd[2]++] = "H" ; /* default -k command */
2409 readfont ( fontname, &font ) ;
2412 char tmp [ MAXLINELEN ] ;
2414 strftime ( tmp, MAXLINELEN, "%c %%s P. %%%%d", localtime ( &now ) ) ;
2415 sprintf ( header = headerbuf, tmp, localid ) ;
2417 #endif /* UCLINUX */
2420 err = begin_session ( &faxdev, faxfile,
2421 !c1 && !c20 && reverse, /* Class 2 rx bit reversal */
2422 hwfc, lkfile, COMMAND, onsig ) ;
2423 if ( ! err ) err = setup ( &faxdev, icmd[0], ignerr ) ;
2424 if ( ! err ) err = modem_init ( &faxdev, local, localid,
2425 calling, calling && !pages, capsset,
2427 if ( ! err ) err = setup ( &faxdev, icmd[1], ignerr ) ;
2428 if ( err == 1 ) locked = 1 ;
2431 if ( ! err && ! testing ) {
2434 err = dial ( &faxdev, phnum, 0 ) ;
2438 err = answer ( &faxdev, lkfile, wait, share, softaa,
2439 getty, vcmd, acmd ) ;
2440 if ( err == 1 ) locked = 1 ;
2442 #endif /* UCLINUX */
2444 now = time(0) ; /* do it here so use reception time */
2446 strftime ( fnamepat, EFAX_PATH_MAX, ansfname, localtime ( &now ) ) ;
2447 strncat ( fnamepat, ".%03d", EFAX_PATH_MAX - strlen ( fnamepat ) ) ;
2448 newOFILE ( &ofile, O_TIFF_FAX, fnamepat, 0, 0, 0, 0 ) ;
2449 #endif /* UCLINUX */
2454 err = c1sndrcv ( &faxdev, local, localid,
2455 &ofile, &ifile, pages, header, &font,
2456 maxpgerr, noretry, calling ) ;
2458 #endif /* UCLINUX */
2460 err = c2sndrcv ( &faxdev, local, localid,
2461 &ofile, &ifile, pages,
2464 #endif /* UCLINUX */
2465 maxpgerr, noretry, calling ) ;
2470 return cleanup ( err ) ;