1 #define Copyright "Copyright 1999 Ed Casas"
3 #define Version "efax v 0.9"
6 Copyright (C) 1999 Ed Casas
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 Please contact the author if you wish to use efax or efix in
23 ways not covered by the GNU GPL.
25 You may contact the author by e-mail at: edc@cce.com, by mail
26 at: 2629 West 3rd Ave, Vancouver, BC, Canada, V6K 1M4, or by
27 fax at: +1 604 734 5291.
33 " %s [ option ]... [ -t num [ file... ] ]\n"
35 " -a str use command ATstr to answer\n"
36 " -c cap set modem and receive capabilites to cap\n"
37 " -d dev use modem on device dev\n"
38 " -e cmd exec \"/bin/sh -c cmd\" for voice calls\n"
39 " -f fnt use (PBM) font file fnt for headers\n"
40 " -g cmd exec \"/bin/sh -c cmd\" for data calls\n"
41 " -h hdr use page header hdr (use %%d's for current page/total pages)\n"
42 " -i str send modem command ATstr at start\n"
43 " -j str send modem command ATstr after set fax mode\n"
44 " -k str send modem command ATstr when done\n"
45 " -l id set local identification to id\n"
46 " -o opt use protocol option opt:\n"
47 " 0 use class 2.0 instead of class 2 modem commands\n"
48 " 1 use class 1 modem commands\n"
49 " 2 use class 2 modem commands\n"
50 " a if first [data mode] answer attempt fails retry as fax\n"
51 " e ignore errors in modem initialization commands\n"
52 " f use virtual flow control\n"
53 " h use hardware flow control\n"
54 " l halve lock file polling interval\n"
55 " n ignore page retransmission requests\n"
56 " r do not reverse received bit order for Class 2 modems\n"
57 " x use XON instead of DC2 to trigger reception\n"
58 " z add 100 ms to pause before each modem comand (cumulative)\n"
59 " -q ne ask for retransmission if more than ne errors per page\n"
60 " -r pat save received pages into files pat.001, pat.002, ... \n"
61 " -s share (unlock) modem device while waiting for call\n"
62 " -v lvl print messages of type in string lvl (ewinchamr)\n"
63 " -w don't answer phone, wait for OK or CONNECT instead\n"
64 " -x fil use uucp-style lock file fil\n"
66 " -t dial num and send fax image files file... \n"
69 #include <ctype.h> /* ANSI C */
75 #include "efaxio.h" /* EFAX */
82 /* delays and timeouts (t/o), in deciseconds */
83 #define T1 350 /* T.30 T1 - waiting for DIS/DCS before Phase B */
84 #define T2 60 /* T.30 T2 - waiting for frame in Phase B */
85 #define T3S 30 /* T.30 response timeout (not T3) */
86 #define T4 30 /* T.30 T4 - between [re]transmissions of DIS */
88 #define TMOD 55 /* T.30 pause between v.21&v.29, 75-20 ms */
90 #define TO_A 1200 /* dial/answer (Phase A) - modem may t/o first */
91 #define TO_ABRT 20 /* max delay after sending abort sequence */
92 #define TO_CHAR 102 /* per data character (2x max FILL length) */
93 #define TO_DATAF 80 /* software adaptive answer data connect t/o */
94 #define TO_DRAIN_H 136 /* minimum HDLC buffer drain time (4k/300cps) */
95 #define TO_DRAIN_D 300 /* minimum data buffer drain time */
96 #define TO_FT 31 /* max delay after +F[TR][MH] command */
97 #define TO_RTCMD 20 /* return to command mode after DLE-ETX (rx) */
99 #define TO_C2B 450 /* Class 2 DIS to CONNECT:(DCS+TCF+CFR)xretries */
100 #define TO_C2X 20 /* Class 2 wait for XON: 2/5 of 5s timeout */
101 #define TO_C2PP 200 /* Class 2 wait for ppr: (ppm+ppr)x3retries + 2 */
102 #define TO_C2R 600 /* Class 2 receive: (TCF+FTT)x11 retrains + 5 */
103 #define TO_C2EOR 120 /* Class 2 end of data rx (4 retrans x 3 s) */
105 #define ANSCMD "A" /* default modem command to answer calls */
106 #define DCSLEN 3 /* length of FIF for DCS commands sent */
107 #define DEFDISLEN 3 /* length of DIS initially transmitted */
108 #define DEFCAP 1,3,0,2,0,0,0,0 /* default local capabilities */
109 #define DEFID " " /* default local ID */
110 #define DEFPAT "%m%d%H%M%S" /* default received file name pattern */
111 #define HDRSHFT 54 /* shift header right 6.7mm into image area */
112 #define HDRSPCE 20 /* number of scan lines inserted before image */
113 #define HDRSTRT 4 /* scan line where header is placed on image */
114 #define HDRCHRH 24 /* header character height (pels, at 196lpi) */
115 #define HDRCHRW 12 /* header character width (pels) */
116 #define IDLEN 20 /* length of T.30 ID strings, must be 20 */
117 #define MAXDIS 8 /* maximum DIS frames sent without response (T1) */
118 #define MAXERRPRT 32 /* maximum number of reception errors to report */
119 #define MAXFIFLEN 125 /* max FIF len = MAXFRLEN - (adx+ctl+FCF) - FCS */
120 #define MAXFRLEN 130 /* max frame length = 3.45s x 300 bps / 8 */
121 #define MAXGETTY 512 /* maximum length of exec'ed (-g, -e) commands */
122 #define MAXICMD 100 /* maximum # of modem setup/reset commands */
123 #define MAXLKFILE 16 /* maximum number of lock files */
124 #define MAXNULLS 2 /* maximum consecutive received nulls saved */
125 #define MAXPGERR 10 /* maximum received errors allowed per page */
126 #define MAXTRAIN 2 /* maximum training retries at lowest speed */
127 #define MAXRETRY 3 /* maximum retries of unacknowledged commands */
128 #define NCAP 8 /* number of fields in a capability string */
129 #define NTXRETRY 3 /* maximum re-sends per page */
131 typedef int cap [ NCAP ] ; /* remote/local capabilities */
133 /* capability fields... */
134 enum captype { VR, BR, WD, LN, DF, EC, BF, ST } ;
135 int capmax [ NCAP ] = { 1, 7, 2, 2, 3, 2, 1, 7 } ;
136 /* & maximum values */
138 /* vertical resolution, dpi */
139 int vresolution [ 2 ] = { 98, 196 } ;
141 /* characters per second for br */
142 int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
144 /* next br = fallback [ br ] */
145 /* 0, 1, 2, 3, 4, 5, 6, 7 */
146 int fallback [ 8 ] = {-1, 0, 1, 2, 7, 4, 3, 6 } ;
148 /* negotiation speed index */
149 /* 0, 1, 2, 3, 4, 5, 6, 7 */
150 int brindex [ 8 ] = { 0, 1, 2, 3, 4, 7, 5, 6 } ;
152 /* minimum scan time in ms */
153 int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
155 /* page width in pixels */
156 int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
158 /* Table to convert between T.30 DIS/DCS/DTC FIF and Class 2-like
159 capability codes. Uses br=6, 7 for V.17 at 7200, 9600. */
161 typedef struct t30tabstruct
164 uchar byte, shift, mask ;
166 uchar captodis[8], distocap[16], captodcs[8], dcstocap[16] ;
169 #define X 0xff /* invalid values */
171 t30tabst t30tab [ NCAP ] = {
172 { "vr", 1, 1, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
173 { "br", 1, 2, 0x0f, 0,
174 { 0, 4, 12, 12, 13, 13 } ,
175 { 0, X, X, X, 1, X, X, X, 3, X, X, X, 3, 5, 3, X } ,
176 { 0, 4, 12, 8, 5, 1 } ,
177 { 0, 5, 5, X, 1, 4, 4, X, 3, 7, X, X, 2, 6, X, X } } ,
178 { "wd", 2, 6, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, 2 } ,
179 { 0, 2, 1 } , { 0, 2, 1, 2 } },
180 { "ln", 2, 4, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, X } ,
181 { 0, 2, 1 } , { 0, 2, 1, X } },
182 { "df", 1, 0, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
183 { "ec", 3, 4, 0x03, 0, { 0, 2, 2 } , { 0, X, 2, X } ,
184 { 0, 3, 2 } , { 0, 0, 2, 1 } },
185 { "bf", 5, 5, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
186 { "st", 2, 1, 0x07, 7,
187 { 7, 4, 3, 2, 6, 0, 5, 1 } , { 5, 7, 3, 2, 1, 6, 4, 0 } ,
188 { 7, 4, X, 2, X, 0, X, 1 } , { 5, 7, 3, 1, X, X, X, 0 } }
191 /* values of capability fields */
192 char *capvaluestr [ NCAP ] [8] = {
193 { " 98lpi", "196lpi" } ,
194 { " 2400bps", " 4800bps", " 7200bps", " 9600bps", " 12kbps", "14.4kbps",
195 "7200V.17", "9600V.17" } ,
196 { "8.5\"/215mm", " 10\"/255mm", " 12\"/303mm",
197 " 6\"/151mm", "4.2\"/107mm" } ,
198 { "11\"/A4", "14\"/B4", " any " } ,
199 { "1D" , "2D" }, { " - ", "ECM-256", "ECM-64 " }, { " - ", "BFT" },
200 { "0ms", "5ms", "10/5ms", "10ms", "20/10ms", "20ms", "40/20ms", "40ms" }
203 /* T.30 control frames */
206 DIS=0x01, CSI, NSF=0x04,
208 MCF=0x31, RTN, RTP, PIN, PIP,
209 DCS=0x41, TSI, NSS=0x44,
211 EOM=0x71, MPS, EOP=0x74, PRI_EOM=0x79, PRI_MPS, PRI_EOP=0x7c,
212 DTC=0x81, CIG, NSC=0x84
215 enum commanddtype { RCV=0, SND=1, DTA=0, TRN=1 } ;
217 /* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
220 char *c1cmd [ 2 ] [ 2 ] [ 8 ] = {
221 { { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=122", "+FRM=146" ,
222 "+FRM=74", "+FRM=98" } ,
223 { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=121", "+FRM=145" ,
224 "+FRM=73", "+FRM=97" } } ,
225 { { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=122", "+FTM=146" ,
226 "+FTM=74", "+FTM=98", } ,
227 { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=121", "+FTM=145" ,
228 "+FTM=73", "+FTM=97" } }
236 { 0, 9, "Call Placement and Termination:" },
237 { 0, 0, " Normal and proper end of connection" },
238 { 1, 1, " Ring Detect without successful handshake" },
239 { 2, 2, " Call aborted, from +FK[S] or CAN" },
240 { 3, 3, " No Loop Current" },
241 { 4, 4, " Ringback Detected, no answer" },
242 { 5, 5, " Ringback Detected, answer without CED" },
244 { 10, 19, "Transmit Phase A & Miscellaneous Errors:" },
245 { 10, 10, " Unspecified Phase A error" },
246 { 11, 11, " No Answer (T.30 T1 timeout)" },
247 { 20, 39, "Transmit Phase B Hangup Codes:" },
248 { 20, 20, " Unspecified Transmit Phase B error" },
249 { 21, 21, " Remote cannot receive or send" },
250 { 22, 22, " COMREC error in transmit Phase B" },
251 { 23, 23, " COMREC invalid command received" },
252 { 24, 24, " RSPREC error" },
253 { 25, 25, " DCS sent three times without response" },
254 { 26, 26, " DIS/DTC received 3 times; DCS not recognized" },
255 { 27, 27, " Failure to train at 2400 bps or +FMINSP value" },
256 { 28, 28, " RSPREC invalid response received" },
257 { 40, 49, "Transmit Phase C Hangup Codes:" },
258 { 40, 40, " Unspecified Transmit Phase C error" },
259 { 41, 41, " Unspecified image format error" },
260 { 42, 42, " Image conversion error" },
261 { 43, 43, " DTE to DCE data underflow" },
262 { 44, 44, " Unrecognized transparent data command" },
263 { 45, 45, " Image error, line length wrong" },
264 { 46, 46, " Image error, page length wrong" },
265 { 47, 47, " Image error, wrong compression code" },
266 { 50, 69, "Transmit Phase D Hangup Codes:" },
267 { 50, 50, " Unspecified Transmit Phase D error" },
268 { 51, 51, " RSPREC error" },
269 { 52, 52, " No response to MPS repeated 3 times" },
270 { 53, 53, " Invalid response to MPS" },
271 { 54, 54, " No response to EOP repeated 3 times" },
272 { 55, 55, " Invalid response to EOP" },
273 { 56, 56, " No response to EOM repeated 3 times" },
274 { 57, 57, " Invalid response to EOM" },
275 { 58, 58, " Unable to continue after PIN or PIP" },
277 { 70, 89, "Receive Phase B Hangup Codes:" },
278 { 70, 70, " Unspecified Receive Phase B error" },
279 { 71, 71, " RSPREC error" },
280 { 72, 72, " COMREC error" },
281 { 73, 73, " T.30 T2 timeout, expected page not received" },
282 { 74, 74, " T.30 T1 timeout, after EOM received" },
283 { 90, 99, "Receive Phase C Hangup Codes:" },
284 { 90, 90, " Unspecified Receive Phase C error" },
285 { 91, 91, " Missing EOL after 5 seconds" },
286 { 92, 92, " Unused code" },
287 { 93, 93, " DCE to DTE buffer overflow" },
288 { 94, 94, " Bad CRC or frame (ECM or BFT modes)" },
289 { 100, 119, "Receive Phase D Hangup Codes:" },
290 { 100, 100, " Unspecified Receive Phase D errors" },
291 { 101, 101, " RSPREC invalid response received" },
292 { 102, 102, " COMREC invalid response received" },
293 { 103, 103, " Unable to continue after PIN or PIP" },
294 { 120, 255, "Reserved Codes" },
298 /* meaning of efax return codes */
300 char *errormsg [] = {
302 "number busy or modem in use",
303 "unrecoverable error",
304 "invalid modem response",
305 "no response from modem",
306 "terminated by signal",
311 /* Return name of frame of type 'fr'. */
313 char *frname ( int fr )
315 static struct framenamestruct { int code ; char *name ; }
318 {NSC,"NSC - poller features"}, /* these 3 frames must be first */
319 {CIG,"CIG - poller ID"},
320 {DTC,"DTC - poller capabilities"},
321 {NSF,"NSF - answering features"},
322 {CSI,"CSI - answering ID"},
323 {DIS,"DIS - answering capabilities"},
324 {NSS,"NSS - caller features"},
325 {TSI,"TSI - caller ID"},
326 {DCS,"DCS - session format"},
328 {CFR,"CFR - channel OK"},
329 {FTT,"FTT - channel not OK"},
331 {MPS,"MPS - not done"},
332 {EOM,"EOM - not done, new format"},
335 {PRI_MPS,"PRI-MPS - not done, call operator"},
336 {PRI_EOM,"PRI-EOM - not done, new format, call operator"},
337 {PRI_EOP,"PRI-EOP - done, call operator"},
339 {MCF,"MCF - page OK"},
340 {RTP,"RTP - page OK, check channel"},
341 {PIP,"PIP - page OK, call operator"},
342 {RTN,"RTN - page not OK, check channel"},
343 {PIN,"PIN - page not OK, call operator"},
345 {CRP,"CRP - repeat command"},
346 {DCN,"DCN - disconnect"},
350 for ( p=framenames ; p->code ; p++ )
351 if ( fr == p->code || ( fr & 0x7f ) == p->code) break ;
352 return p->code ? p->name : "UNKNOWN" ;
355 /* Range-check capability. */
357 int checkcap ( cap c )
361 for ( i=0 ; i<NCAP ; i++ )
362 if ( c[i] > capmax[i] || c[i] < 0 ) {
363 err = msg ( "E3%s = %d out of range, set to 0", t30tab[i].name, c[i] ) ;
370 /* Print cap[ability] c using text values and prefix s. */
372 void printcap ( char *s , cap c )
375 msg ( "N-+ %s" , s ) ;
377 for ( i=0 ; i<NCAP ; i++ )
378 msg ( "N-+ %s" , capvaluestr [ i ] [ c[i] ] ) ;
383 /* Convert capability string to cap struct. Returns 0 or 2 on errors. */
385 int str2cap ( char *s, cap c )
389 n = sscanf ( s, "%d,%d,%d,%d,%d,%d,%d,%d",
390 c+0, c+1, c+2, c+3, c+4, c+5, c+6, c+7 ) ;
392 if ( n < NCAP ) msg ( "Wmissing value(s) in \"%s\"", s ) ;
400 /* Convert a cap[ability] 'c' to a DIS/DCS/DTC FIF 'fif' of 'len'
401 bytes. Converts into DIS format if 'isdis' is true, else into
404 void mkdis ( cap c, uchar *fif, int len, int isdis, int t4tx )
409 len = len > DCSLEN ? DCSLEN : len ;
412 fif[1] = ( isdis && t4tx ? 0x80 : 0 ) | 0x40 ;
413 for ( i=2 ; i<len-1 ; i++ ) fif[i] = 0x01 ; /* add extension bits */
418 for ( i=0 ; i<NCAP ; i++ ) {
420 if ( ( k = ( isdis ? p->captodis : p->captodcs ) [ c [ i ] ] ) == X )
421 msg ( "E3mkdis: can't happen (invalid %s)", p->name ), k=0 ;
422 if ( p->byte < len ) fif [ p->byte ] |= k << p->shift ;
427 /* Return length of DIS/DTC FIF (counts extension bits). */
429 int dislen ( uchar *fif )
432 for ( n=3 ; fif [ n-1 ] & 0x01 && n < MAXFIFLEN ; n++ ) ;
437 /* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 if bad DIS/DCS
440 int mkcap ( uchar *fif, cap c, int dis )
442 int err=0, i, j, k, len ;
445 len = dislen ( fif ) ;
447 for ( i=0 ; i<NCAP ; i++ ) {
449 if ( p->byte >= len ) {
452 j = ( fif [ p->byte ] >> p->shift ) & p->mask ;
453 k = ( dis ? p->distocap : p->dcstocap ) [ j ] ;
455 c [ i ] = p->safeval ;
456 err = msg("E3mkcap: bad %s field (%d) set to %d",
457 p->name, j, c [ i ] ) ;
467 /* Compute compatible local/remote capabilities. Used by the
468 sending station only and only for Class 1. Returns 0 if OK or
469 3 if no compatible settings possible. */
471 int mincap ( cap local, cap remote, cap session )
474 int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ;
476 printcap ( "local ", local ) ;
477 printcap ( "remote ", remote ) ;
479 for ( i=0 ; i<NCAP && i!=ST && i !=BR ; i++ )
480 session[i] = remote[i] < local[i] ? remote[i] : local[i] ;
482 session[BR] = brindex[ remote[BR] ] < brindex[ local[BR] ] ?
483 remote[BR] : local[BR] ;
485 session[ST] = msttab [ session[VR] ] [ remote[ST] ] ;
487 printcap ( "session", session ) ;
489 if ( local[WD] != session[WD] || local[LN] > session[LN] ||
490 local[DF] != session[DF] )
491 err = msg ("W3incompatible local and remote capabilities" ) ;
497 /* Skip to start of first/next page (or to start of previous page
498 if dp is 0). If ppm in not null, it is then set to EOP if
499 there are no pages following this one, MPS if the next page
500 has the same format as `local' (assumed to be the format of
501 the previous page), EOM if the page has a different format.
502 If local is non-NULL its format fields are set according to
503 the format of the new page. Currently only considers the
506 This function is called before send_data() and obtains the ppm
507 for that page. It can be called again with dp=0 if a PIN or
508 RTN is received to restart the page. Returns 0 or 2 on
511 int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
513 int err=0, m=EOP, yres, fVR, nVR ;
515 if ( nextipage ( f, dp ) )
516 err = msg ( "E2 can't happen (rdpage: can't go to %s page)",
517 dp ? "next" : "same" ) ;
521 yres = f->page->yres ;
522 fVR = ( yres > (196+98)/2 ) ? 1 : 0 ;
524 if ( local && yres ) {
525 if ( local [ VR ] != fVR ) {
527 if ( changed ) *changed = 1 ;
529 if ( changed ) *changed = 0 ;
533 if ( lastpage ( f ) ) {
536 PAGE *p = f->page + 1 ;
537 nVR = ( p->yres > (196+98)/2 ) ? 1 : 0 ;
538 m = ( nVR != fVR ) ? EOM : MPS ;
544 *ppm = err ? EOP : m ;
551 /* Terminate previous page if page number is non-zero and start
552 next output page if page number is non-negative. If page is -1
553 removes the most recently opened file. Returns 0 if OK, 2 on
556 int wrpage ( OFILE *f, int page )
560 err = nextopage ( f, page ) ;
562 if ( ! err && page == -1 ) {
563 if ( remove ( f->cfname ) ) {
564 err = msg ( "ES2can't delete file %s:", f->cfname ) ;
566 msg ( "Fremoved %s", f->cfname ) ;
574 /* Send data for one page. Figures out required padding and 196->98 lpi
575 decimation based on local and session capabilitites, substitutes page
576 numbers in header string and enables serial port flow control. Inserts
577 the page header before the input file data. Converts each scan line to
578 T.4 codes and adds padding (FILL) and EOL codes before writing out.
579 Sends RTC when done. Sends DLE-ETX and returns serial port to command
580 mode when done. Returns 0 if OK, non-0 on errors. */
582 int send_data ( TFILE *mf, IFILE *f, int page, int pages,
583 cap local, cap session, char *header, faxfont *font )
585 int done=0, err=0, noise=0, nr=0, lastnr=0, line, pixels ;
586 int i, decimate, pwidth, minlen, dcecps, inheader, skip=0 ;
587 uchar buf [ MAXCODES + 2*EOLBITS/8 + 1 ], *p ;
588 short runs [ MAXRUNS ], lastruns [ MAXRUNS ] ;
589 char headerbuf [ MAXLINELEN ] ;
594 dcecps = cps[session[BR]] ;
595 minlen = ( (long)dcecps * mst[session[ST]] - 1500 + 500 ) / 1000 ;
596 pwidth = pagewidth [ session [ WD ] ] ;
597 decimate = local[VR] > session[VR] ;
599 msg ( "T padding to %d bytes/scan line.%s", minlen+1,
600 decimate ? " reducing 196->98 lpi." : "" ) ;
603 msg ( "T limiting output to %d bps for %d byte modem buffer",
604 dcecps*8, MAXDCEBUF + MINWRITE ) ;
606 if ( ckfmt ( header, 6 ) )
607 msg ( "W too many %%d escapes in header format string \"%s\"", header ) ;
609 sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ;
610 msg ("I header:[%s]", headerbuf ) ;
612 done = err = ttymode ( mf, SEND ) ;
614 mf->start = time(0) ;
615 mf->mstart = proc_ms() ;
616 mf->bytes = mf->pad = mf->lines = 0 ;
618 /* start T.4 data with some FILL and an EOL */
620 for ( i=0 ; i<32 ; i++ )
621 p = putcode ( &e, 0, 8, buf ) ;
622 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
625 err = msg ( "E2can't happen(send_data)" ) ;
628 for ( line=0 ; ! done && ! err ; line++ ) {
630 if ( line < HDRSPCE ) { /* insert blank lines at the top */
635 if ( ( nr = readline ( f, runs, &pixels ) ) < 0 ) {
640 /* generate and OR in header pixels */
641 if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) {
643 short hruns [ MAXRUNS ] ;
644 hnr = texttorun ( (uchar*) headerbuf, font, line-HDRSTRT,
645 HDRCHRW, HDRCHRH, HDRSHFT,
647 nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ;
650 inheader = line < HDRSTRT + HDRCHRH ;
652 if ( decimate || ( inheader && local[VR] == 0 ) ) {
653 if ( ++skip & 1 ) { /* save the first of every 2 lines */
654 memcpy ( lastruns, runs, nr * sizeof(short) ) ;
656 continue ; /* get next line */
657 } else { /* OR previous line into current line */
658 nr = runor ( runs, nr, lastruns, lastnr, 0, &pixels ) ;
664 /* make line the right width */
665 if ( pixels != pwidth ) nr = xpad ( runs, nr, pwidth - pixels ) ;
666 /* convert to MH coding */
667 p = runtocode ( &e, runs, nr, p ) ;
668 /* zero pad to minimum scan time */
669 while ( p - buf < minlen ) {
670 p = putcode ( &e, 0, 8, p ) ;
674 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
675 sendbuf ( mf, buf, p - buf, dcecps ) ;
676 mf->bytes += p - buf ;
679 /* probably read an EOL as part of RTC */
681 if ( tdata ( mf, 0 ) ) noise = 1 ;
686 for ( i=0 ; i < RTCEOL ; i++ )
687 p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
688 p = putcode ( &e, 0, 0, p ) ;
689 sendbuf ( mf, buf, p - buf, dcecps ) ;
690 mf->bytes += p - buf ;
692 if ( noise ) msg ("W- characters received while sending" ) ;
698 int end_data ( TFILE *mf, cap session, int ppm, int *good )
704 if ( ! ppm ) p = DLE_ETX ;
705 else if ( ppm == MPS ) p = "\020," ;
706 else if ( ppm == EOM ) p = "\020;" ;
707 else if ( ppm == EOP ) p = "\020." ;
710 err = msg ( "E2 can't happen (end_data)" ) ;
715 dt = time(0) - mf->start ;
716 /* time to drain buffers + 100% + 4s */
717 draintime = ( 2 * ( mf->bytes / cps[ session[BR] ] + 1 - dt ) + 4 ) * 10 ;
718 draintime = draintime < TO_DRAIN_D ? TO_DRAIN_D : draintime ;
720 c = ckcmd ( mf, 0, 0, (int) draintime, OK ) ;
722 if ( good ) *good = ( c == OK ) ? 1 : 0 ;
724 dt = time(0) - mf->start ;
726 msg ( "Isent %d+%d lines, %d+%d bytes, %d s %d bps" ,
727 HDRSPCE, mf->lines-HDRSPCE,
728 mf->bytes-mf->pad, mf->pad, (int) dt, (mf->bytes*8)/dt ) ;
730 if ( mf->bytes / (dt+1) > cps[session[BR]] )
731 msg ( "E flow control did not work" ) ;
733 if ( ! err ) err = ttymode ( mf, COMMAND ) ;
739 /* Read one scan line from fax device. If pointer pels is not
740 null it is used to save pixel count. Returns number of runs
741 stored, EOF on RTC, or -2 on EOF, DLE-ETX or other error. */
743 int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels )
745 int err=0, c=EOF, x, n ;
748 short *p, *maxp, *q, len=0 ;
751 maxp = ( p = runs ) + MAXRUNS ;
753 x = d->x ; shift = d->shift ; tab = d->tab ; /* restore decoder state */
754 rd_state = f->rd_state ;
758 while ( shift < 0 ) {
759 c = tgetd ( f, TO_CHAR ) ;
761 rd_state = ( rd_state & rd_allowed[c] ) ?
762 ( ( rd_state & rd_nexts[c] ) ? rd_state <<= 1 : rd_state ) :
765 if ( rd_state == RD_END )
766 msg ( "W+ modem response in data" ) ;
769 x = ( x << 15 ) | 1 ; shift += 15 ; /* EOL pad at EOF */
771 x = ( x << 8 ) | c ; shift += 8 ;
774 t = tab + ( ( x >> shift ) & 0x1ff ) ;
777 } while ( ! t->code ) ;
778 if ( p < maxp ) *p++ = t->code ;
779 } while ( t->code != -1 ) ;
781 d->x = x ; d->shift = shift ; d->tab = tab ; /* save state */
782 f->rd_state = rd_state ;
784 if ( p >= maxp ) msg ( "Wrun length buffer overflow" ) ;
786 /* combine make-up and terminating codes and remove +1 offset
790 for ( p = q = runs ; n-- > 0 ; )
791 if ( *p > 64 && n-- > 0 ) {
792 len += *q++ = p[0] + p[1] - 2 ;
795 len += *q++ = *p++ - 1 ;
799 /* check for RTC and errors */
804 if ( ++(d->eolcnt) >= RTCEOL ) err = EOF ;
806 if ( c < 0 ) err = - 2 ;
808 if ( pels ) *pels = len ;
810 return err ? err : n ;
814 /* Receive data. Reads scan lines from modem and writes to output
815 file. Checks for errors by comparing received line width and
816 session line width. Check that the output file is still OK
817 and if not, send one CANcel character and wait for protocol to
818 complete. Returns 0 if OK or 2 if there was a file write error. */
820 int receive_data ( TFILE *mf, OFILE *f, cap session, int *nerr )
822 int err=0, line, lines, nr, len ;
823 int pwidth = pagewidth [ session [ WD ] ] ;
824 short runs [ MAXRUNS ] ;
827 if ( ! f || ! f->f ) {
828 msg ( "E2 can't happen (writeline)" ) ;
835 for ( line=0 ; ( nr = readfaxruns ( mf, &d, runs, &len ) ) >= 0 ; line++ ) {
836 if ( nr > 0 && len > 0 && line ) { /* skip first line+EOL and RTC */
837 if ( len != pwidth ) {
839 if ( *nerr <= MAXERRPRT ) msg ("R-+ (%d:%d)", line, len ) ;
840 nr = xpad ( runs, nr, pwidth - len ) ;
842 writeline ( f, runs, nr, 1 ) ;
845 if ( ferror ( f->f ) ) {
846 err = msg ("ES2file write:") ;
847 tput ( mf, CAN_STR, 1 ) ;
848 msg ("Wdata reception CANcelled") ;
853 if ( *nerr > MAXERRPRT ) msg ("R-+ ....." ) ;
854 msg ("R- : reception errors" ) ;
855 msg ("W- %d reception errors", *nerr ) ;
859 while ( tgetd ( mf, TO_CHAR ) >= 0 ) ; /* got RTC, wait for DLE-ETX */
861 msg ( "I- received %d lines, %d errors", lines, *nerr ) ;
867 /* Send training check sequence of n zeroes. Returns 0 or 2 on error. */
869 int puttrain ( TFILE *f, char *s, int n )
872 uchar buf [ MINWRITE ] = { 0 } ;
874 ckcmd ( f, &err, s, TO_FT, CONNECT ) ;
877 ttymode ( f, SEND ) ;
879 for ( i=0 ; i < n ; i += m ) {
880 m = n-i < MINWRITE ? n-i : MINWRITE ;
881 sendbuf ( f, buf, m, 0 ) ;
884 buf[0] = 1 ; /* make sure last byte is non-zero */
887 sendbuf ( f, buf, 3, 0 ) ;
889 ttymode ( f, COMMAND ) ;
891 ckcmd ( f, &err, 0, TO_DRAIN_D, OK ) ;
892 msg ( "I- sent TCF - channel check of %d bytes", n ) ;
899 /* Checks for an error-free run of at least n bytes in the
900 received training check sequence. Sets good if it's not null,
901 the run was long enough and there were no errors. Returns 0 or
902 3 on other errors. */
904 int gettrain ( TFILE *f, char *s, int n, int *good )
906 int err=0, c, i=0, maxrunl=0, runl=0 ;
908 ckcmd ( f, &err, s, T2, CONNECT ) ;
912 for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
914 if ( runl > maxrunl ) maxrunl = runl ;
921 err = msg ( "E3timed out during training check data" ) ;
923 ckcmd ( f, &err, 0, TO_RTCMD, NO ) ;
927 if ( runl > maxrunl ) maxrunl = runl ;
929 if ( good ) *good = !err && maxrunl > n ;
932 msg ( "I- received TCF - channel check (%sOK: run of %d in %d)",
933 maxrunl > n ? "" : "not ", maxrunl, i ) ;
940 /* Log a sent/received HDLC frame. Display of these messages is delayed to
941 avoid possible timing problems. */
943 void logfr ( char *s , char *nm , uchar *p , int n )
946 msg ( n > 10 ? "H- %s %d bytes:" : "H-+ %s %d bytes:" , s, n ) ;
947 for ( i=0 ; i<n ; i++ ) {
948 msg ( "H-+ %02x" , p[i] & 0xff ) ;
949 if ( ( i&0xf ) == 0xf && i != n-1 ) msg ( "H-" ) ;
952 msg ( "I- %s %s", s, nm ) ;
956 /* Send HDLC control frame of type type. Extra bits can be OR'ed
957 into the frame type (FCF) to indicate that this frame follows
958 a previous one (no +FTH required) and/or that more frames will
959 follow. Sets up flag, address, and fax control field bytes in
960 `buf'. Sends these plus `len` additional bytes. Terminates
961 with DLE-ETX and checks response. Returns 0 if OK, 2 or 3 on
964 #define MORE_FR 0x100
967 int nframes = 0 ; /* counts frames sent/received */
969 int putframe ( int type, uchar *buf, int len, TFILE *f, int t )
974 buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ;
975 buf [ 2 ] = type & 0xff ;
977 if ( nframes++ && ! ( type & SUB_FR ) )
978 ckcmd ( f, &err, "+FTH=3" , TO_FT, CONNECT ) ;
982 if ( ! buf[len+2] ) {
983 msg ( "Wlast byte of frame is NULL" ) ;
986 /* ttymode ( f, SEND ) ; */
987 sendbuf ( f, buf, len+3, 0 ) ;
988 tput ( f, DLE_ETX, 2 ) ;
989 /* ttymode ( f, COMMAND ) ; */
991 logfr ( "sent", frname ( buf [ 2 ] ), buf, len+3 ) ;
993 ckcmd ( f, &err, 0, TO_DRAIN_H, ( type & MORE_FR ) ? CONNECT : OK ) ;
1000 /* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */
1002 void revcpy ( uchar *from , uchar *to )
1005 for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- )
1006 to [ i ] = normalbits [ from [ j ] & 0xff ] ;
1010 /* Check for missing initial 0xFF in HDLC frame and insert it if
1011 missing. Ugly fix for a still-hidden bug. Also do bit
1012 inversion if required. */
1014 int fixframe ( uchar *buf, int n, TFILE *f )
1018 if ( *buf == 0xc0 || *buf == 0xc8 ) {
1019 for ( i=n; i >= 1 ; i-- )
1022 msg ("W HDLC frame missing initial 0xff" ) ;
1026 if ( buf[1] == 0x03 || buf[1] == 0x13 ) {
1027 for ( i=0 ; i < n ; i++ )
1028 buf[i]=normalbits[buf[i]] ;
1029 msg ("W bit-reversed HDLC frame, reversing bit order" ) ;
1030 f->ibitorder = f->ibitorder == normalbits ? reversebits : normalbits ;
1037 /* Read HDLC frame data. Returns 0 if OK, 1 on frame error, 3 on
1038 timeout, invalid response or too-long frame. */
1040 int receive_frame_data ( TFILE *f, uchar *buf, int n, int *len )
1044 for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
1045 if ( i < n ) buf[ i ] = c ;
1049 err = msg ( "E3timed out reading frame data" ) ;
1053 switch ( cmd ( f, 0, TO_RTCMD ) ) {
1059 err = msg ( "W1frame error" ) ;
1062 err = msg ( "E3no response after frame data" ) ;
1065 err = msg ( "E3wrong response after frame data" ) ;
1072 err = msg ( "E3frame too long (%d, > %d max bytes)", i, n ) ;
1074 if ( len ) *len = i ;
1080 /* Get a Class 1 command or response frame. An attempt to match
1081 and combine T.30 "Response Received?" and "Command Received?"
1082 protocol flowcharts.
1084 When receiving commands returns after first correct
1085 non-optional frame or after the time given by getcmd has
1086 elapsed. This is instead of looping through main flowchart.
1088 When receiving responses returns on the first detected
1089 non-optional frame, after timeout T4, or on errors.
1091 Returns immediately if gets a +FCERROR response so can retry
1092 as data carrier. Returns DCN as a valid frame instead of
1095 Returns the command/response received, or EOF on timeout or
1100 int getfr ( TFILE *mf, uchar *buf, int getcmd )
1102 int err=0, frame=0, frlen, c, t ;
1103 char remoteid [ IDLEN + 1 ] ;
1107 start = 10*time(0) ;
1109 t = getcmd ? ( getcmd > 1 ? getcmd : T2 ) : T4 ;
1116 c = cmd ( mf, "+FRH=3", t ) ;
1118 c = CONNECT ; /* implied by ATA or ATD */
1122 case EOF: /* time out */
1123 tput ( mf, CAN_STR, 1 ) ;
1124 ckcmd ( mf, 0, 0, TO_ABRT, OK ) ;
1127 case NO: /* S7 time out */
1130 case MODULATION: /* data carrier (or DHS) */
1131 return -msg ( "W-2 wrong carrier" ) ;
1133 case CONNECT: /* frame */
1135 default: /* shouldn't happen */
1136 err = msg ( "E3wrong response to receive-frame command" ) ;
1141 err = receive_frame_data ( mf, buf, MAXFRLEN, &frlen ) ;
1143 if ( ! err && frlen < 3 )
1144 err = msg ( "E3received short frame (%d bytes)", frlen ) ;
1148 frlen = fixframe ( buf, frlen, mf ) ;
1149 logfr ( "received", frname ( buf [ 2 ] ), buf, frlen ) ;
1150 frame = buf [ 2 ] & 0x7f ;
1162 revcpy ( fif , (uchar*) remoteid ) ;
1163 msg ( "I- remote ID -> %*.*s", IDLEN, IDLEN, remoteid ) ;
1169 if ( err && getcmd && ( t -= 10*time(0) - start ) > 0 )
1172 return err ? EOF : frame ;
1176 /* Class 1 send/receive.
1178 The logic in this function is a mess because it's meant to
1179 mirror the flowchart in ITU-T recommendation T.30 which is the
1180 protocol specification.
1185 TFILE *mf, cap local, char *localid,
1186 OFILE *outf, IFILE *inf,
1187 int pages, char *header, faxfont *font,
1188 int maxpgerr, int noretry, int calling )
1190 int err=0, rxpage=0, page=1, t, disbit, good, frame, last, nerr ;
1191 int rxdislen, ppm, try=0, pagetry=0, retry=0, remtx=0, remrx=0 ;
1192 int writepending=0, dp=0 ;
1193 cap remote = { DEFCAP }, session = { DEFCAP } ;
1195 uchar buf [ MAXFRLEN ], *fif=buf+3 ;
1197 if ( ! calling ) goto RX ;
1199 /* Class 1 Transmitter: */
1201 T: /* Transmitter Phase B - wait for DIS or DTC */
1205 frame = getfr ( mf, buf, T1 ) ;
1208 err = msg ( "E3no answer from remote fax" ) ;
1212 if ( frame != DIS && frame != DTC ) {
1213 msg ( "W2 can't open page" ) ;
1217 disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1220 A: /* decide to send or receive after DIS/DTC */
1222 if ( frame == DIS || frame == DTC ) {
1223 rxdislen = dislen ( fif ) ;
1224 mkcap ( fif, remote, 1 ) ;
1225 remtx = fif[1] & 0x80 ;
1226 remrx = fif[1] & 0x40 ;
1229 msg ( "N remote has %sdocument(s) to send, and can %sreceive",
1230 remtx ? "" : "no ", remrx ? "" : "not " ) ;
1233 if ( ! remrx ) msg ( "W remote cannot receive, trying anyways" ) ;
1236 if ( ! remtx ) msg ( "W remote has nothing to send, trying anyways" ) ;
1242 if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1243 err = msg ( "E2can't open page" ) ;
1249 mincap ( local, remote, session ) ;
1251 revcpy ( (uchar*) localid, fif ) ;
1253 err = putframe ( TSI | MORE_FR | disbit, buf, IDLEN, mf, -1 ) ;
1255 mkdis ( session, fif, DCSLEN, 0, pages ) ;
1257 err = putframe ( DCS | SUB_FR | disbit, buf, DCSLEN, mf, -1 ) ;
1259 if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1260 msleep ( TMOD ) ; /* if +FTS not supported */
1263 err = puttrain ( mf, c1cmd[SND][TRN][session[BR]],
1264 1.5*cps [ session[BR] ] ) ;
1268 cmd ( mf, "+FRS=1", T3S ) ; /* wait for TCF carrier to drop */
1269 frame = getfr ( mf, buf, 0 ) ;
1272 if ( err || frame < 0 ) {
1284 if ( try >= 3 ) goto C_timeout ;
1288 msg ( "I channel not usable at %d bps", 8*cps[session[BR]] ) ;
1289 remote[BR] = fallback[session[BR]] ;
1290 if ( remote[BR] >= 0 ) goto D_2 ;
1291 else { err = msg ( "E2 channel not usable at lowest speed" ) ; goto C ; }
1297 err = msg ( "E3 invalid response to DCS (0x%02x)", frame ) ;
1301 I: /* send a page */
1303 if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1304 err = msg ( "E2can't open page" ) ;
1310 ckcmd ( mf, &err, c1cmd [SND][DTA][session[BR]], TO_FT, CONNECT ) ;
1312 err = send_data ( mf, inf, page, pages, local, session, header, font ) ;
1317 err = end_data ( mf, session, 0, 0 ) ;
1319 if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1320 msleep ( TMOD ) ; /* if +FTS not supported */
1322 /* fix ppm if on last page of stdin */
1323 if ( lastpage ( inf ) ) ppm = EOP ;
1327 if ( !err ) err = putframe ( ppm | disbit, buf, 0, mf, -1 ) ;
1330 frame = getfr ( mf, buf, 0 ) ;
1339 fname = inf->page->fname ;
1341 switch ( noretry ? MCF : frame ) { /* common retry logic */
1345 fname = inf->page->fname ;
1346 if ( fname ) msg ( "Isent -> %s", fname ) ;
1354 retry = pagetry < NTXRETRY ;
1357 err = msg ( "E3invalid post-page response (0x%02x)", frame ) ;
1378 nextipage ( inf, 1 ) ; /* skip ahead to mark all files done */
1379 if ( remtx ) goto R ; /* poll after sending */
1382 if ( retry ) goto D ;
1393 cmd ( mf, "+FRS=20", T3S ) ; /* wait for ppr carrier to drop */
1394 if ( retry ) goto T ;
1400 E: /* ignore PIN and PIP */
1401 msg ( "W interrupt request ignored" ) ;
1405 /* Class 1 Receiver */
1409 R: /* Receiver Phase B */
1411 if ( ! err ) err = wrpage ( outf, rxpage ) ;
1415 for ( t=0 ; !err && t<T1 ; t+=T2+10 ) {
1417 revcpy ( (uchar*) localid, fif ) ;
1419 err = putframe ( CSI | disbit | MORE_FR, buf, IDLEN, mf, -1 ) ;
1421 mkdis ( local, fif, DEFDISLEN, 1, pages ) ;
1423 err = putframe ( DIS | disbit | SUB_FR, buf, DEFDISLEN, mf, -1 ) ;
1425 frame = getfr ( mf, buf, 0 ) ;
1428 disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1433 else goto C_timeout ;
1436 F: /* get a command */
1439 frame = getfr ( mf, buf, 1 ) ;
1441 if ( writepending ) { /* do postponed file close/open */
1443 err = wrpage ( outf, rxpage ) ;
1448 if ( frame == -2 ) goto getdata ; /* data carrier detected */
1449 if ( last == EOM ) goto R ;
1450 else { err = msg ("E3 timed out waiting for command" ) ; goto B ; }
1465 mkcap ( fif, session, 0 ) ;
1466 printcap ( "session", session ) ;
1468 cmd ( mf, "+FTS=1", T3S ) ; /* make sure DCS is over */
1470 gettrain ( mf, c1cmd [RCV][TRN][session[BR]], cps[session[BR]], &good ) ;
1472 if ( putframe ( ( good ? CFR : FTT ) | disbit, buf, 0, mf, -1 ) ||
1477 outf->w=pagewidth[session[WD]];
1480 outf->yres=vresolution[session[VR]];
1482 if ( cmd ( mf, c1cmd [RCV][DTA][session[BR]], TO_FT ) != CONNECT )
1483 goto F ; /* +FCERROR -> DCS resent */
1485 if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1486 good = nerr < maxpgerr ;
1487 msg ( "I-received -> %s", outf->cfname ) ;
1488 writepending=1 ; /* ppm follows immediately, don't write yet */
1493 ckcmd ( mf, 0, 0, TO_RTCMD, NO ) ;
1501 frame &=0xf7 ; /* ignore PRocedure Interrupt bit */
1505 putframe ( ( good ? MCF : RTN ) | disbit, buf, 0, mf, -1 ) ;
1506 if ( good && frame == MPS ) goto getdata ;
1513 err = msg ( "E3 unrecognized command" ) ;
1519 err = msg ( "E3 no command/response from remote" ) ;
1522 putframe ( DCN, buf, 0, mf, -1 ) ;
1525 ckcmd ( mf, 0, "H", TO_RESET, OK ) ; /* hang up */
1528 wrpage ( outf, -1 ) ; /* remove last file */
1534 /* Check for hangup message. Assumes hsc is initialized to a
1535 negative value. Returns 0 if no hangup message, 1 if there
1536 was one. If perr is not null, sets it to 2 if the hsc was
1537 non-zero (error). */
1539 int gethsc ( int *hsc, int *perr )
1542 if ( sresponse ( "+FHNG:", hsc ) || sresponse ( "+FHS:", hsc ) ) {
1543 if ( hsc && *hsc > 0 ) {
1544 err = msg ( "E2abnormal termination (code %d)", *hsc ) ;
1545 for ( i=0 ; c2msg[i].min >= 0 ; i++ ) {
1546 if ( *hsc >= c2msg[i].min && *hsc <= c2msg[i].max ) {
1547 msg ( "E %s", c2msg[i].msg ) ;
1550 if ( perr && ! *perr ) {
1561 /* Print remote ID and store DCS values in session as per
1562 responses since last command. */
1564 void getc2dcs ( cap session )
1567 if ( ( p = sresponse ( "+FTI:", 0 ) ) != 0 ||
1568 ( p = sresponse ( "+FTSI:", 0 ) ) != 0 ) {
1569 msg ( "I- remote ID -> %s", p ) ;
1571 if ( ( p = sresponse ( "+FCS:", 0 ) ) != 0 ||
1572 ( p = sresponse ( "+FDCS:", 0 ) ) != 0 ) {
1573 str2cap ( p, session ) ;
1574 printcap ( "session", session ) ;
1578 /* Wait for a starting character XON or DC2. Display & ignore
1579 any other characters received. */
1581 void getstartc ( TFILE *mf )
1585 for ( noise=0 ; ( c = tgetc ( mf, TO_C2X ) ) != XON && c != DC2 ; noise++ ) {
1587 msg ( "Wno XON/DC2 received after CONNECT") ;
1590 msg ( "W-+%s", cname ( c ) ) ;
1596 msg ( "W : %d characters received while waiting to send", noise ) ;
1600 /* Class 2 send and receive.
1602 If calling, polls if no files to send, otherwise sends. If
1603 not calling sends documents if files to send, else receives.
1605 When sending, issues +FDIS to change session parameters if
1606 file format changes, then sends +FDT followed by data and a
1607 post-page message determined by format of next page, if any.
1608 Retransmits each page up to NTXRETRY times.
1610 When receiving extracts file format from responses to +FDR or
1611 ATA and saves them in the file. Receives data to a file and
1612 sets page transfer status if too many errors.
1614 Returns 0 if OK or 2 on errors. */
1618 TFILE *mf, cap local, char *localid,
1619 OFILE *outf, IFILE *inf,
1620 int pages, char *header, faxfont *font,
1621 int maxpgerr, int noretry, int calling )
1623 int err=0, done=0, page, pagetry, nerr, c, dp=0 ;
1624 int ppm=0, good, hsc, changed ;
1627 cap session = { 0,0,0,0, 0,0,0,0 } ;
1628 char buf [ CMDBUFSIZE ] ;
1630 hsc=-1 ; /* will be set >= 0 on hangup */
1632 if ( sresponse ( "+FPO", 0 ) ) {
1634 msg ( "N remote has document(s) to send." ) ;
1638 if ( pages ) goto send ;
1641 if ( pages ) goto pollserver ;
1649 /* with +FLP[L]=1 the modem should accept +FDT. */
1656 while ( ! err && ! done ) {
1658 err = rdpage ( inf, dp, &ppm, local, &changed ) ;
1660 if ( ! err && changed ) {
1661 sprintf ( buf, c20 ? "+FIS=%d,%d,%d,%d" : "+FDIS=%d,%d,%d,%d",
1662 local[0], local[1], local[2], local[3] ) ;
1663 ckcmd ( mf, 0, buf, TO_FT, OK ) ;
1664 if ( gethsc ( &hsc, &err ) ) {
1669 ckcmd ( mf, &err, "+FDT", -TO_C2B, CONNECT ) ;
1670 if ( err || gethsc ( &hsc, &err ) ) {
1675 getc2dcs ( session ) ;
1677 if ( ! c20 ) getstartc ( mf ) ;
1679 send_data ( mf, inf, page, pages, local, session, header, font ) ;
1683 end_data ( mf, session, ppm, &good ) ;
1685 end_data ( mf, session, 0, 0 ) ;
1687 gethsc ( &hsc, &err ) ;
1689 if ( ! err && hsc < 0 ) {
1690 ckcmd ( mf, &err, ppm == EOP ? "+FET=2" :
1691 ppm == EOM ? "+FET=1" : "+FET=0" , TO_C2PP, OK ) ;
1694 gethsc ( &hsc, &err ) ;
1696 if ( ! err && hsc < 0 ) {
1697 if ( sresponse ( "+FPTS:", &good ) ) {
1698 good &= 1 ; /* odd values mean received OK */
1699 } else { /* no +FPTS and +FHNG probably NG */
1700 good = gethsc ( 0, 0 ) ? 0 :
1701 msg ( "W1no +FPTS response, assumed received" ) ;
1707 if ( noretry ) good = 1;
1710 fname = inf->page->fname ;
1711 if ( fname ) msg ( "Isent -> %s", fname ) ;
1716 nextipage ( inf, 1 ) ; /* skip ahead to mark all files done */
1721 if ( pagetry >= NTXRETRY )
1722 err = msg ( "E2too many page send retries" ) ;
1725 if ( gethsc ( &hsc, &err ) ) done=1 ;
1727 if ( good && lastpage ( inf ) ) {
1734 /* Class 2 Receive */
1738 /* with +FSP[L]=1 and +FPO[LL]: the modem should now accept +FDR. */
1742 getc2dcs ( session ) ; /* get ATA responses */
1745 for ( page=0 ; ! err && ! done ; page++ ) {
1747 if ( ! ( err = wrpage ( outf, page ) ) ) {
1748 c = cmd ( mf, "+FDR", -TO_C2R ) ;
1753 getc2dcs ( session ) ;
1755 outf->w=pagewidth[session[WD]];
1758 outf->yres=vresolution[session[VR]];
1760 tput ( mf, &startchar, 1 ) ;
1762 if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1763 good = nerr < maxpgerr ;
1764 msg ( "I-received -> %s", outf->cfname ) ;
1769 ckcmd ( mf, &err, 0, TO_C2EOR, OK ) ;
1771 if ( err || gethsc ( &hsc, &err ) ) {
1772 wrpage ( outf, +1 ) ;
1773 wrpage ( outf, -1 ) ;
1779 msg ( "Wreception errors" ) ;
1780 ckcmd ( mf, 0, c20 ? "+FPS=2" : "+FPTS=2", T3S, OK ) ;
1781 if ( gethsc ( &hsc, &err ) ) continue ;
1786 wrpage ( outf, -1 ) ; /* no more pages */
1788 if ( gethsc ( &hsc, &err ) ) continue ;
1792 wrpage ( outf, -1 ) ; /* oops */
1793 err = msg ( "E3receive (+FDR) command failed") ;
1801 if ( hsc < 0 ) ckcmd ( mf, 0, c20 ? "+FKS" : "+FK", TO_RESET, OK ) ;
1807 /* Dial the phone number given by string s. If nowait is true
1808 adds a ';' to the dial string to avoid waiting for a
1809 CONNECTion (might allow ersatz polling). Also resets the
1810 global "nframes" if appropriate so getfr() and putframe() know
1811 not to issue +FRH/+FTH. Returns 0 if dialed OK, 1 if busy, 2
1814 int dial ( TFILE *f, char *s, int nowait )
1817 char c, dsbuf [ 128 ], *p ;
1819 sprintf ( dsbuf, nowait ? "D%.126s;" : "D%.127s" , s ) ;
1820 msg ( "Idialing %s", dsbuf+1 ) ;
1822 c = cmd ( f, dsbuf, TO_A ) ;
1824 if ( ( p = sresponse ( "+FCSI:", 0 ) ) != 0 ||
1825 ( p = sresponse ( "+FCI:", 0 ) ) != 0 ) {
1826 msg ( "I- remote ID -> %s", p ) ;
1829 if ( nowait && c == OK ) {
1832 } else if ( c1 && c == CONNECT ) {
1833 msg ( "Iconnected" ) ;
1835 } else if ( !c1 && c == OK ) {
1836 msg ( "Iconnected" ) ;
1837 } else if ( c == BUSY ) {
1838 err = msg ( "W1number is busy" ) ;
1840 err = msg ( "E2dial command failed" ) ;
1843 gethsc ( &hsc, err ? 0 : &err ) ;
1849 /* Figure out which mode the modem answered in (fax, data, voice
1850 or none) based on modem class and responses to the previous
1851 command. Sets crate (connect rate) for DATAMODE and hsc
1852 (hangup status code) if detects a class 2 hangup message. */
1854 enum connectmode { NONE, DATAMODE, FAXMODE, VOICEMODE } ;
1856 enum connectmode ansmode ( int *crate, int *hsc )
1858 enum connectmode mode = NONE ;
1861 if ( c1 && sresponse ( "CONNECT", &x ) ) {
1862 mode = x ? DATAMODE : FAXMODE ;
1865 if ( !c1 && sresponse ( "OK", 0 ) ) {
1869 if ( !c1 && ( sresponse ( "CONNECT", &x ) || sresponse ( "+FDM", 0 ) ) ) {
1873 if ( sresponse ( "DATA", 0 ) || sresponse ( "CONNECT DATA", 0 ) ) {
1875 sresponse ( "CONNECT", &x ) ;
1878 if ( sresponse ( "FAX", 0 ) || sresponse ( "+FCO", 0 ) ) {
1882 if ( sresponse ( "VCON", 0 ) ) {
1886 if ( gethsc ( hsc, 0 ) ) {
1890 if ( DATAMODE && x ) *crate = x ;
1896 /* Answer the phone. Remove our lock if sharing device with
1897 outgoing calls. If waiting for call, wait for modem activity,
1898 else answer phone. Figure out what mode we answered in and
1899 handle call appropriately. Re-lock if necessary. Exec *getty
1900 or *vcmd for data or voice calls. */
1902 int answer ( TFILE *f, char **lkfile,
1903 int wait, int share, int softaa,
1904 char *getty, char *vcmd, char *acmd )
1907 int crate=19200, hsc=-1, i ;
1908 enum connectmode mode=NONE ;
1910 if ( ! err && share ) {
1911 err = ttymode ( f, COMMAND ) ;
1913 err = unlockall ( lkfile ) ;
1916 if ( ! err && wait ) {
1917 msg ( "Iwaiting for activity") ;
1919 msg ( "Iactivity detected") ;
1922 if ( ! err && share ) {
1923 msleep ( 500 ) ; /* let other programs lock port */
1924 err = lockall ( lkfile, 1 ) ;
1926 err = msg ( "W1can't answer: can't lock device" ) ;
1928 err = ttymode ( f, COMMAND ) ; /* in case it was changed silently */
1931 for ( i=0 ; ! err && mode == NONE && ( i==0 || ( i==1 && softaa ) ) ; i++ ) {
1933 c = cmd ( f, wait ? 0 : acmd, ( i==0 && softaa ) ? TO_DATAF : TO_A ) ;
1935 if ( c == DATA ) cmd ( f, c1 ? "O" : 0, TO_A ) ; /* +FAE=1 weirdness */
1937 mode = ansmode ( &crate, &hsc ) ;
1941 msg ( "Idata call answered") ;
1942 if ( getty && *getty ) {
1943 char buf [ MAXGETTY ] ;
1944 if ( ckfmt ( getty, 6 ) ) {
1945 err = msg ( "E3 too many %%d escapes in command (%s)", getty ) ;
1947 sprintf ( buf, getty, crate, crate, crate, crate, crate, crate ) ;
1948 msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
1949 execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ;
1950 err = msg ( "ES2exec failed:" ) ;
1953 err = msg ( "E2no getty command defined for data call" ) ;
1958 msg ( "Ifax call answered") ;
1961 msg ( "Ivoice call answered") ;
1962 if ( vcmd && *vcmd ) {
1963 char buf [ MAXGETTY ] ;
1964 if ( ckfmt ( vcmd, 6 ) ) {
1966 sprintf ( buf, vcmd, f->fd, f->fd, f->fd, f->fd, f->fd, f->fd ) ;
1967 msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
1968 execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ;
1969 err = msg ( "ES2exec failed:" ) ;
1972 err = msg ( "E2no voice command defined for voice call" ) ;
1976 if ( i==0 && softaa && hsc < 0 && getty && *getty ) {
1977 int j ; /* switch to fax for 2nd try */
1978 for ( j=0 ; j<3 ; j++ )
1979 if ( cmd ( f, c1 ? "+FCLASS=1" :
1980 ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), -TO_RESET )
1985 err = msg ( "E3unable to answer call") ;
1989 err = msg ( "E3can't happen(answer)" ) ;
1999 /* Initialize modem. Determine class to use and issue
2000 class-specific fax initialization commands. If poll is true,
2001 issues commands to enable polling also. Returns 0 or 3 if a
2002 mandatory setup command fails. */
2004 int modem_init ( TFILE *mf, cap c, char *id,
2005 int calling, int poll, int capsset, int *preverse )
2007 int err=0, t=-TO_RESET ;
2008 char buf [ CMDBUFSIZE ], model [ CMDBUFSIZE ] = "" ;
2009 char **p, *q, *modelq [2][4] = { { "+FMFR?", "+FMDL?", 0 },
2010 { "+FMI?", "+FMM?", "+FMR?", 0 } } ;
2013 /* diasable command echo and get firmware revision */
2015 cmd ( mf, "E0", t ) ;
2017 if ( cmd ( mf, "I3", t ) == OK ) {
2018 getresp ( "", model, CMDBUFSIZE-1 ) ;
2019 strcat ( model, " " ) ;
2022 /* if not already chosen, pick safest class; set it */
2024 if ( ! err && ! c1 && !c2 && ! c20 ) {
2025 if ( cmd ( mf, "+FCLASS=?", t ) != OK ) {
2026 err = msg ("E3 modem does not support fax" ) ;
2028 if ( strinresp ( "2.0" ) ) c20 = 1 ;
2029 else if ( strinresp ( "2" ) ) ;
2030 else if ( strinresp ( "1" ) ) c1 = 1 ;
2031 else err = msg ("E3 can't determine fax modem class support" ) ;
2032 if ( strstr ( model, "Sportster" ) ) { /* USR Sporsters are buggy */
2039 ckcmd ( mf, &err, c1 ? "+FCLASS=1" :
2040 ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), t, OK ) ;
2042 /* get make & model if using Class 2 or 2.0 */
2045 for ( p = modelq [ c20 ] ; ! err && *p ; p++ ) {
2046 if ( cmd ( mf, *p, t ) == OK ) {
2047 getresp ( "", model, CMDBUFSIZE-1 ) ;
2048 strcat ( model, " " ) ;
2052 if ( ! c1 && strstr ( model, "Multi-Tech" ) ) {
2054 msg ("I Multi-Tech bit order set" ) ;
2059 msg ( "I using %sin class %s", model, c1 ? "1" : c20 ? "2.0" : "2" ) ;
2061 /* get maximum modem speed if not already set (Class 1 only) */
2063 if ( ! err && c1 && ! capsset ) {
2065 char *c1spstr [6] = { "24", "48", "72", "96", "121", "145" } ;
2066 ckcmd ( mf, &err, calling ? "+FTM=?" : "+FRM=?", t, OK ) ;
2067 for ( i=0 ; i < 6 && strinresp ( c1spstr[i] ) ; i++ ) ;
2071 /* issue essential commands and set/get modem capabilities (Class 2 only) */
2073 if ( ! err && ! c1 ) {
2076 ckcmd ( mf, 0, "+FIP", t, OK ) ;
2077 ckcmd ( mf, 0, "+FNR=1,1,1,1", t, OK ) ;
2080 ckcmd ( mf, &err, "+FCR=1", t, OK ) ;
2083 if ( cmd ( mf, c20 ? "+FIS?" : "+FDIS?", -t ) == OK &&
2084 ( q = strinresp ( "," ) ) ) {
2085 str2cap ( q-1, c ) ;
2087 msg ( "W can't get modem capabilities, set to default" ) ;
2093 sprintf ( buf, c20 ? "+FCC=%d,%d,%d,%d,%d,%d,%d,%d" :
2094 "+FDCC=%d,%d,%d,%d,%d,%d,%d,%d",
2095 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7] ) ;
2096 ckcmd ( mf, 0, buf, -t, OK ) ;
2099 sprintf ( buf, c20 ? "+FLI=\"%.*s\"" : "+FLID=\"%.*s\"" ,
2100 CMDBUFSIZE-9, id ) ;
2101 ckcmd ( mf, 0, buf, -t, OK ) ;
2103 if ( ! err && poll ) {
2105 ckcmd ( mf, 0, c20 ? "+FSP=1" : "+FSPL=1", -t, OK ) ;
2107 sprintf ( buf, c20 ? "+FPI=\"%.*s\"" : "+FCIG=\"%.*s\"" ,
2108 CMDBUFSIZE-9, id ) ;
2109 ckcmd ( mf, 0, buf, -t, OK ) ;
2118 /* the following are global so can terminate properly on signal */
2120 char *icmd[3][ MAXICMD+1 ] = {{0},{0},{0}} ; /* initialization commands */
2121 TFILE faxdev = { -1, 0,0, {0}, 0, 0 } ; /* modem */
2122 char *lkfile [ MAXLKFILE+1 ] = {0} ; /* lock file names */
2123 IFILE ifile = { 0 } ; /* files being sent */
2124 int locked = 0 ; /* modem locked */
2127 /* print names of files not sent and reset modem before
2130 int cleanup ( int err )
2132 /* log names of files not sent */
2133 logifnames ( &ifile, "I failed -> %s" ) ;
2135 if ( ! locked && faxdev.fd >= 0 )
2136 end_session ( &faxdev, icmd[2], lkfile, err != 4 ) ;
2138 msg ( "Idone, returning %d (%s)", err,
2139 errormsg [ err >= 0 && err <= 5 ? err : 6 ] ) ;
2145 /* signal handler */
2147 void onsig ( int sig )
2149 msg ( "E terminating on signal %d", sig ) ;
2150 exit ( cleanup ( 5 ) ) ;
2154 /* Fax send/receive program for Class 1, 2 and 2.0 fax
2155 modems. Returns 0 on success, 1 if number busy or device
2156 locked, 2 for errors, 3 for protocol errors, 4 if no modem
2157 response, 5 on signal. */
2159 int main( int argc, char **argv)
2161 int err=0, doneargs=0, c=0, i ;
2162 int testing=0, calling=0 ;
2164 int nicmd[3]={0,0,0}, nlkfile=0, nverb=0 ;
2166 char *faxfile = FAXFILE ;
2168 int softaa=0, share=0, wait=0, reverse=1, ignerr=0, noretry=0, hwfc=0 ;
2170 char *getty = "", *vcmd = "", *acmd=ANSCMD ;
2172 cap local = { DEFCAP } ;
2173 char localid [ IDLEN + 1 ] = DEFID ;
2175 int maxpgerr = MAXPGERR ;
2178 char *header = 0, headerbuf [ MAXLINELEN ] ;
2179 char *fontname = 0 ;
2184 char *phnum="", *ansfname = DEFPAT ;
2185 char fnamepat [ EFAX_PATH_MAX ] ;
2187 /* print initial message to both stderr & stdout */
2190 msg ( "I " Version " " Copyright ) ;
2191 argv0 = efaxbasename ( argv0 ) ;
2192 msg ( "A compiled "__DATE__ " " __TIME__ ) ;
2195 while ( ! err && ! doneargs &&
2196 ( c = nextopt ( argc,argv,
2197 "a:c:d:e:f:g:h:i:j:k:l:o:p:q:r:st:v:wx:T" ) ) != -1 ) {
2204 err = str2cap ( nxtoptarg, local ) ;
2208 if ( strlen ( nxtoptarg ) > IDLEN )
2209 msg("Wlocal ID (%s) truncated to %d characters", nxtoptarg, IDLEN ) ;
2210 if ( strspn ( nxtoptarg, " +0123456789" ) != strlen ( nxtoptarg ) )
2211 msg("Wlocal ID (%s) has non-standard characters", nxtoptarg ) ;
2212 sprintf ( localid, "%*.*s", IDLEN, IDLEN, nxtoptarg ) ;
2215 if ( nicmd[0] < MAXICMD ) icmd[0][ nicmd[0]++ ] = nxtoptarg ;
2216 else err = msg ( "E2too many '-i' options");
2219 if ( nicmd[1] < MAXICMD ) icmd[1][ nicmd[1]++ ] = nxtoptarg ;
2220 else err = msg ( "E2too many '-j' options");
2223 if ( nicmd[2] < MAXICMD ) icmd[2][ nicmd[2]++ ] = nxtoptarg ;
2224 else err = msg ( "E2too many '-k' options");
2227 header = nxtoptarg ;
2230 fontname = nxtoptarg ;
2233 faxfile = nxtoptarg ;
2241 case 'o': /* most protocol options are globals */
2242 for ( ; *nxtoptarg ; nxtoptarg++ )
2243 switch ( *nxtoptarg ) {
2244 case '0' : c20 = 1 ; break ;
2245 case '1' : c1 = 1 ; break ;
2246 case '2' : c2 = 1 ; break ;
2247 case 'a' : softaa = 1 ; break ;
2248 case 'e' : ignerr = 1 ; break ;
2249 case 'f' : vfc = 1 ; break ;
2250 case 'h' : hwfc = 1 ; break ;
2251 case 'l' : lockpolldelay /= 2 ; break ;
2252 case 'n' : noretry = 1 ; break ;
2253 case 'r' : reverse = 0 ; break ;
2254 case 'x' : startchar = XON ; break ;
2255 case 'z' : cmdpause += T_CMD ; break ;
2256 default : msg ( "Wunrecognized protocol option (%c)", *nxtoptarg ) ;
2260 if ( sscanf ( nxtoptarg , "%d", &maxpgerr ) != 1 || maxpgerr < 0 )
2261 err=msg ("E2bad quality (-q) argument (%s)", nxtoptarg ) ;
2264 ansfname = nxtoptarg ;
2273 if ( argv [ argc ] ) err = msg ("E2can't happen(unterminated argv)") ;
2274 if ( ! err ) err = newIFILE ( &ifile, argv + nxtoptind ) ;
2275 pages = argc - nxtoptind - ( c == 'p' ? 1 : 0 ) ;
2276 pages = pages < 0 ? 0 : pages ;
2281 verb[nverb] = nxtoptarg ;
2288 if ( nlkfile < MAXLKFILE ) lkfile[ nlkfile++ ] = nxtoptarg ;
2289 else err = msg ( "E2too many lock files" ) ;
2291 case 'T': /* test: begin+end session */
2295 default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
2299 for ( i=0 ; i<argc ; i++ )
2300 msg ( "Aargv[%d]=%s", i, argv[i]) ;
2302 if ( ! nicmd[2] ) icmd[2][nicmd[2]++] = "H" ; /* default -k command */
2304 readfont ( fontname, &font ) ;
2307 char tmp [ MAXLINELEN ] ;
2309 strftime ( tmp, MAXLINELEN, "%c %%s P. %%%%d", localtime ( &now ) ) ;
2310 sprintf ( header = headerbuf, tmp, localid ) ;
2314 err = begin_session ( &faxdev, faxfile,
2315 !c1 && !c20 && reverse, /* Class 2 rx bit reversal */
2316 hwfc, lkfile, COMMAND, onsig ) ;
2317 if ( ! err ) err = setup ( &faxdev, icmd[0], ignerr ) ;
2318 if ( ! err ) err = modem_init ( &faxdev, local, localid,
2319 calling, calling && !pages, capsset,
2321 if ( ! err ) err = setup ( &faxdev, icmd[1], ignerr ) ;
2322 if ( err == 1 ) locked = 1 ;
2325 if ( ! err && ! testing ) {
2328 err = dial ( &faxdev, phnum, 0 ) ;
2330 err = answer ( &faxdev, lkfile, wait, share, softaa,
2331 getty, vcmd, acmd ) ;
2332 if ( err == 1 ) locked = 1 ;
2335 now = time(0) ; /* do it here so use reception time */
2336 strftime ( fnamepat, EFAX_PATH_MAX, ansfname, localtime ( &now ) ) ;
2337 strncat ( fnamepat, ".%03d", EFAX_PATH_MAX - strlen ( fnamepat ) ) ;
2338 newOFILE ( &ofile, O_TIFF_FAX, fnamepat, 0, 0, 0, 0 ) ;
2342 err = c1sndrcv ( &faxdev, local, localid,
2343 &ofile, &ifile, pages, header, &font,
2344 maxpgerr, noretry, calling ) ;
2346 err = c2sndrcv ( &faxdev, local, localid,
2347 &ofile, &ifile, pages, header, &font,
2348 maxpgerr, noretry, calling ) ;
2353 return cleanup ( err ) ;