ftp://ftp.metalab.unc.edu/pub/Linux/apps/serialcomm/fax/efax-0.9.tar.gz
[efax.git] / efax.c
1 #define Copyright         "Copyright 1999 Ed Casas"
2
3 #define Version           "efax v 0.9"
4
5 /*
6     Copyright (C) 1999  Ed Casas
7
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.
12
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.
17
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
21
22     Please contact the author if you wish to use efax or efix in
23     ways not covered by the GNU GPL.
24
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.
28
29 */
30
31 const char *Usage =
32   "Usage:\n"
33   "  %s [ option ]... [ -t num [ file... ] ]\n"
34   "Options:\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"
65   "Commands:\n"
66   "  -t      dial num and send fax image files file... \n"
67   ;
68
69 #include <ctype.h>              /* ANSI C */
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <time.h>
74
75 #include "efaxio.h"             /* EFAX */
76 #include "efaxlib.h"
77 #include "efaxmsg.h"
78 #include "efaxos.h"
79
80 /* constants... */
81
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 */
87
88 #define TMOD 55             /* T.30 pause between v.21&v.29, 75-20 ms */
89
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) */
98
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) */
104
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 */
130
131 typedef int cap [ NCAP ] ;              /* remote/local capabilities */
132
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 */
137
138                                         /* vertical resolution, dpi */
139 int vresolution [ 2 ] = { 98, 196 } ;
140
141                                         /* characters per second for br */
142 int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
143
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 } ;
147
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 } ;
151
152                                         /* minimum scan time in ms  */
153 int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
154
155                                         /* page width in pixels */
156 int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
157
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. */
160
161 typedef struct t30tabstruct
162
163   char *name ; 
164   uchar byte, shift, mask ; 
165   uchar safeval ;
166   uchar captodis[8], distocap[16], captodcs[8], dcstocap[16] ; 
167 } t30tabst ;
168
169 #define X 0xff                          /* invalid values */
170
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 } } 
189 } ;
190
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" }
201 } ;
202
203 /* T.30 control frames */
204
205 enum frametype {            
206  DIS=0x01, CSI, NSF=0x04,
207  CFR=0x21, FTT,
208  MCF=0x31, RTN, RTP, PIN, PIP,
209  DCS=0x41, TSI, NSS=0x44,
210  CRP=0x58, DCN=0x5f,
211  EOM=0x71, MPS, EOP=0x74, PRI_EOM=0x79, PRI_MPS, PRI_EOP=0x7c,
212  DTC=0x81, CIG, NSC=0x84
213  } ;
214
215 enum commanddtype { RCV=0, SND=1, DTA=0, TRN=1 } ;
216
217 /* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
218    [baud rate=BR]. */
219
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" } }
229 } ;
230
231 struct c2msgstruct
232
233   int min, max ;
234   char *msg ;
235 } c2msg [] = {
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" },
243
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" },
276
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" },
295   {  -1,  -1, "" }
296 } ;
297
298 /* meaning of efax return codes */
299
300 char *errormsg [] = {
301   "success",
302   "number busy or modem in use",
303   "unrecoverable error",
304   "invalid modem response",
305   "no response from modem",
306   "terminated by signal",
307   "internal error" } ;
308
309 /* Functions... */
310
311 /* Return name of frame of type 'fr'. */
312
313 char *frname ( int fr )
314 {
315   static struct framenamestruct {  int code ;  char *name ; } 
316   framenames [] = {
317
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"},
327
328     {CFR,"CFR - channel OK"},
329     {FTT,"FTT - channel not OK"},
330
331     {MPS,"MPS - not done"},
332     {EOM,"EOM - not done, new format"},
333     {EOP,"EOP - done"},
334
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"},
338
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"},
344
345     {CRP,"CRP - repeat command"},
346     {DCN,"DCN - disconnect"},
347     {0,0} },
348   *p ;
349   
350   for ( p=framenames ; p->code ; p++ )
351     if ( fr == p->code || ( fr & 0x7f ) == p->code) break ;
352   return p->code ? p->name : "UNKNOWN" ;
353 }
354
355 /* Range-check capability. */
356
357 int checkcap ( cap c )
358 {
359   int err=0, i ;
360
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] ) ;
364       c[i]=0 ;
365     }
366   return err ;
367 }
368
369
370 /* Print cap[ability] c using text values and prefix s. */
371
372 void printcap ( char *s , cap c )
373 {
374   int i ;
375   msg ( "N-+ %s" , s ) ;
376   checkcap ( c ) ;
377   for ( i=0 ; i<NCAP ; i++ ) 
378     msg ( "N-+  %s" , capvaluestr [ i ] [ c[i] ] ) ;
379   msg ( "N-" ) ;
380 }
381
382
383 /* Convert capability string to cap struct. Returns 0 or 2 on errors. */
384
385 int str2cap ( char *s, cap c )
386 {
387   int err=0, n ;
388
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 ) ;
391
392   if ( n < NCAP ) msg ( "Wmissing value(s) in \"%s\"", s ) ;
393
394   checkcap ( c ) ;
395
396   return err ;
397 }
398
399
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
402    DCS/DTC format. */
403
404 void mkdis ( cap c, uchar *fif, int len, int isdis, int t4tx ) 
405 {
406   int i, k ;
407   t30tabst *p ;
408
409   len = len > DCSLEN ? DCSLEN : len ;
410
411   fif[0] = 0 ;
412   fif[1] = ( isdis && t4tx ? 0x80 : 0 ) | 0x40 ;
413   for ( i=2 ; i<len-1 ; i++ ) fif[i] = 0x01 ;       /* add extension bits */
414   fif[i] = 0 ;
415
416   checkcap ( c ) ;
417
418   for ( i=0 ; i<NCAP ; i++ ) {
419     p = t30tab + 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 ;
423   }
424 }
425
426
427 /* Return length of DIS/DTC FIF (counts extension bits). */
428
429 int dislen ( uchar *fif )
430 {
431   int n ;
432   for ( n=3 ; fif [ n-1 ] & 0x01 && n < MAXFIFLEN ; n++ ) ;
433   return n ;
434 }
435
436
437 /* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 if bad DIS/DCS
438    field. */
439
440 int mkcap ( uchar *fif, cap c, int dis ) 
441 {
442   int err=0, i, j, k, len ;
443   t30tabst *p ;
444
445   len = dislen ( fif ) ;
446
447   for ( i=0 ; i<NCAP ; i++ ) {
448     p=t30tab+i ;
449     if ( p->byte >= len ) {
450       c [ i ] = 0 ;
451     } else {
452       j = ( fif [ p->byte ] >> p->shift ) & p->mask ;
453       k = ( dis ? p->distocap : p->dcstocap ) [ j ] ;
454       if ( k == X ) {
455         c [ i ] = p->safeval ;
456         err = msg("E3mkcap: bad %s field (%d) set to %d", 
457                   p->name, j, c [ i ] ) ;
458       } else { 
459         c [ i ] = k ;
460       }
461     }
462   }
463   return err ;
464 }
465
466
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. */
470
471 int mincap ( cap local, cap remote, cap session )
472 {
473   int err=0, i ;
474   int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ;
475
476   printcap ( "local  ", local ) ;
477   printcap ( "remote ", remote ) ;
478
479   for ( i=0 ; i<NCAP && i!=ST && i !=BR ; i++ )
480     session[i] = remote[i] < local[i] ? remote[i] : local[i] ;
481
482   session[BR] = brindex[ remote[BR] ] < brindex[ local[BR] ] ?
483     remote[BR] : local[BR] ;
484
485   session[ST] = msttab [ session[VR] ] [ remote[ST] ] ;
486
487   printcap ( "session", session ) ;
488
489   if ( local[WD] != session[WD] || local[LN] > session[LN] || 
490       local[DF] != session[DF] ) 
491     err = msg ("W3incompatible local and remote capabilities" ) ;
492
493   return err ;
494 }
495
496
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
504    file's y-resolution.
505
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
509    errors. */
510
511 int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
512 {
513   int err=0, m=EOP, yres, fVR, nVR  ;
514
515   if ( nextipage ( f, dp ) )
516     err = msg ( "E2 can't happen (rdpage: can't go to %s page)", 
517                dp ? "next" : "same" ) ;
518   
519   if ( ! err ) {
520
521     yres = f->page->yres ;
522     fVR = ( yres > (196+98)/2 ) ? 1 : 0 ;
523
524     if ( local && yres ) {
525       if ( local [ VR ] != fVR ) {
526         local [ VR ] = fVR ;
527         if ( changed ) *changed = 1 ;
528       } else {
529         if ( changed ) *changed = 0 ;
530       }
531     }
532
533     if ( lastpage ( f ) ) {
534       m = EOP ;
535     } else {
536       PAGE *p = f->page + 1 ;
537       nVR = ( p->yres > (196+98)/2 ) ? 1 : 0  ;
538       m = ( nVR != fVR ) ? EOM : MPS ;
539     }
540
541   }
542
543   if ( ppm ) {
544     *ppm = err ? EOP : m ;
545   }
546
547   return err ;
548 }
549
550
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
554    errors. */
555
556 int wrpage ( OFILE *f, int page )
557 {
558   int err=0 ;
559
560   err = nextopage ( f, page ) ;
561
562   if ( ! err && page == -1 ) {
563     if ( remove ( f->cfname ) ) {
564       err = msg ( "ES2can't delete file %s:", f->cfname ) ; 
565     } else {
566       msg ( "Fremoved %s", f->cfname ) ; 
567     }
568   }
569   
570   return err ;
571 }
572
573
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. */
581
582 int send_data ( TFILE *mf, IFILE *f, int page, int pages,
583                cap local, cap session, char *header, faxfont *font )
584 {
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 ] ;
590   ENCODER e ;
591
592   newENCODER ( &e ) ;
593
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] ;
598
599   msg ( "T padding to %d bytes/scan line.%s", minlen+1, 
600        decimate ? " reducing 196->98 lpi." : "" ) ;
601
602   if ( vfc ) 
603     msg ( "T limiting output to %d bps for %d byte modem buffer", 
604          dcecps*8, MAXDCEBUF + MINWRITE  ) ;
605
606   if ( ckfmt ( header, 6 ) )
607     msg ( "W too many %%d escapes in header format string \"%s\"", header ) ;
608   else
609     sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ;
610   msg ("I header:[%s]", headerbuf ) ;
611       
612   done = err = ttymode ( mf, SEND ) ; 
613
614   mf->start = time(0) ;
615   mf->mstart = proc_ms() ;
616   mf->bytes = mf->pad = mf->lines = 0 ;
617
618   /* start T.4 data with some FILL and an EOL */
619
620   for ( i=0 ; i<32 ; i++ )
621     p = putcode ( &e, 0, 8, buf ) ;
622   p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
623
624   if ( ! f || ! f->f ) 
625     err = msg ( "E2can't happen(send_data)" ) ; 
626
627   mf->lines=0 ;
628   for ( line=0 ; ! done && ! err ; line++ ) {
629
630     if ( line < HDRSPCE ) {     /* insert blank lines at the top */
631       runs[0] = pwidth ;
632       pixels = pwidth ;
633       nr = 1 ;
634     } else {
635       if ( ( nr = readline ( f, runs, &pixels ) ) < 0 ) {
636         done = 1 ;
637         continue ;
638       }
639     }
640                                 /* generate and OR in header pixels */
641     if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) {
642       int hnr ;
643       short hruns [ MAXRUNS ] ;
644       hnr = texttorun ( (uchar*) headerbuf, font, line-HDRSTRT, 
645                        HDRCHRW, HDRCHRH, HDRSHFT,
646                        hruns, 0 ) ;
647       nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ;
648     }
649     
650     inheader = line < HDRSTRT + HDRCHRH ;
651
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) ) ;
655         lastnr = nr ;
656         continue ;              /* get next line */
657       } else {                  /* OR previous line into current line */
658         nr = runor ( runs, nr, lastruns, lastnr, 0, &pixels ) ;
659       }
660     }
661
662     if ( nr > 0 ) {
663       if ( 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 ) ;
671           mf->pad ++ ;
672         }
673                                 /* add EOL */
674         p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
675         sendbuf ( mf, buf, p - buf, dcecps ) ;
676         mf->bytes += p - buf ;
677         mf->lines++ ;
678       } else {
679         /* probably read an EOL as part of RTC */
680       }
681       if ( tdata ( mf, 0 ) ) noise = 1 ;
682       p = buf ;
683     }
684   }
685
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 ;
691   
692   if ( noise ) msg ("W- characters received while sending" ) ;
693
694   return err ;
695 }
696
697
698 int end_data ( TFILE *mf, cap session, int ppm, int *good )
699 {
700   int err=0, c ;
701   uchar *p ;
702   long dt, draintime ;
703
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." ; 
708   else {
709     p = "" ;
710     err = msg ( "E2 can't happen (end_data)" ) ;
711   }
712
713   tput ( mf, p, 2 ) ;
714
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 ;
719
720   c = ckcmd ( mf, 0, 0, (int) draintime, OK ) ;
721
722   if ( good ) *good = ( c == OK ) ? 1 : 0 ;
723
724   dt = time(0) - mf->start ;
725
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 ) ;
729
730   if ( mf->bytes / (dt+1) > cps[session[BR]] )
731     msg ( "E flow control did not work" ) ;
732
733   if ( ! err ) err = ttymode ( mf, COMMAND ) ;
734
735   return err ;
736 }
737
738
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. */
742
743 int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels )
744 {
745   int err=0, c=EOF, x, n ;
746   dtab *tab, *t ;
747   short shift ;
748   short *p, *maxp, *q, len=0 ;
749   uchar rd_state ;
750
751   maxp = ( p = runs ) + MAXRUNS ;
752
753   x = d->x ; shift = d->shift ; tab = d->tab ; /* restore decoder state */
754   rd_state = f->rd_state ;
755
756   do {
757     do {
758       while ( shift < 0 ) { 
759         c = tgetd ( f, TO_CHAR ) ;
760
761         rd_state = ( rd_state & rd_allowed[c] ) ?
762           ( ( rd_state & rd_nexts[c] ) ? rd_state <<= 1 : rd_state ) : 
763           RD_BEGIN ;
764
765         if ( rd_state == RD_END )
766           msg ( "W+ modem response in data" ) ; 
767
768         if ( c < 0 )  {
769           x = ( x << 15 ) | 1 ; shift += 15 ;  /* EOL pad at EOF */
770         } else {
771           x = ( x <<  8 ) | c ; shift +=  8 ; 
772         }
773       }
774       t = tab + ( ( x >> shift ) & 0x1ff ) ;
775       tab = t->next ;
776       shift -= t->bits ;
777     } while ( ! t->code ) ;
778     if ( p < maxp ) *p++ = t->code ;
779   } while ( t->code != -1 ) ;
780
781   d->x = x ; d->shift = shift ; d->tab = tab ; /* save state */
782   f->rd_state = rd_state ;
783
784   if ( p >= maxp ) msg ( "Wrun length buffer overflow" ) ;
785
786   /* combine make-up and terminating codes and remove +1 offset
787      in run lengths */
788
789   n = p - runs - 1 ;
790   for ( p = q = runs ; n-- > 0 ; )
791     if ( *p > 64 && n-- > 0 ) {
792       len += *q++ = p[0] + p[1] - 2 ;
793       p+=2 ;
794     } else {
795       len += *q++ = *p++ - 1 ;
796     }
797   n = q - runs ;
798   
799   /* check for RTC and errors */
800
801   if ( len )
802     d->eolcnt = 0 ;
803   else
804     if ( ++(d->eolcnt) >= RTCEOL ) err = EOF ;
805
806   if ( c < 0 ) err = - 2 ;
807
808   if ( pels ) *pels = len ;
809   
810   return err ? err : n ;
811 }
812
813
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. */
819
820 int receive_data ( TFILE *mf, OFILE *f, cap session, int *nerr )
821 {
822   int err=0, line, lines, nr, len ;
823   int pwidth = pagewidth [ session [ WD ] ] ;
824   short runs [ MAXRUNS ] ;
825   DECODER d ;
826
827   if ( ! f || ! f->f ) {
828     msg ( "E2 can't happen (writeline)" ) ;
829   } 
830   
831   newDECODER ( &d ) ;
832   *nerr = 0 ;
833
834   lines=0 ; 
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 ) { 
838         (*nerr)++ ;
839         if ( *nerr <= MAXERRPRT ) msg ("R-+ (%d:%d)", line, len ) ;
840         nr = xpad ( runs, nr, pwidth - len ) ;
841       } 
842       writeline ( f, runs, nr, 1 ) ;
843       lines++ ;
844     }
845     if ( ferror ( f->f ) ) {
846       err = msg ("ES2file write:") ;
847       tput ( mf, CAN_STR, 1 ) ;
848       msg ("Wdata reception CANcelled") ;
849     } 
850   }
851   
852   if ( *nerr ) {
853     if ( *nerr > MAXERRPRT ) msg ("R-+ ....." ) ;
854     msg ("R-  : reception errors" ) ;
855     msg ("W- %d reception errors", *nerr ) ;
856   }
857
858   if ( nr == EOF )
859     while ( tgetd ( mf, TO_CHAR ) >= 0 ) ; /* got RTC, wait for DLE-ETX */
860
861   msg ( "I- received %d lines, %d errors", lines, *nerr ) ;
862
863   return err ;
864 }
865
866
867 /* Send training check sequence of n zeroes.  Returns 0 or 2 on error. */
868
869 int puttrain ( TFILE *f, char *s, int n  )
870 {
871   int i, m, err=0 ;
872   uchar buf [ MINWRITE ] = { 0 } ;
873
874   ckcmd ( f, &err, s, TO_FT, CONNECT ) ;
875   
876   if ( ! err ) {
877     ttymode ( f, SEND ) ;
878
879     for ( i=0 ; i < n ; i += m ) {
880       m = n-i < MINWRITE ? n-i : MINWRITE ;
881       sendbuf ( f, buf, m, 0 ) ;
882     }
883
884     buf[0] = 1 ;                /* make sure last byte is non-zero */
885     buf[1] = DLE ;
886     buf[2] = ETX ;
887     sendbuf ( f, buf, 3, 0 ) ;
888
889     ttymode ( f, COMMAND ) ;
890
891     ckcmd ( f, &err, 0, TO_DRAIN_D, OK ) ;
892     msg ( "I- sent TCF - channel check of %d bytes", n ) ;
893   }
894   
895   return err ;
896 }
897
898
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.  */
903
904 int gettrain ( TFILE *f, char *s, int n, int *good ) 
905
906   int err=0, c, i=0, maxrunl=0, runl=0 ;
907   
908   ckcmd ( f, &err, s, T2, CONNECT ) ;
909   
910   if ( ! err ) {
911
912     for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
913       if ( c ) {
914         if ( runl > maxrunl ) maxrunl = runl ;
915         runl = 0 ;
916       } else {
917         runl ++ ;
918       }
919     
920     if ( c == EOF )
921       err = msg ( "E3timed out during training check data" ) ;
922     else
923       ckcmd ( f, &err, 0, TO_RTCMD, NO ) ;
924     
925   }
926      
927   if ( runl > maxrunl ) maxrunl = runl ;
928      
929   if ( good ) *good = !err && maxrunl > n ;
930
931   if ( !err ) {
932     msg ( "I- received TCF - channel check (%sOK: run of %d in %d)", 
933          maxrunl > n ? "" : "not ", maxrunl, i ) ;
934   }
935
936   return err ;
937 }
938
939
940 /* Log a sent/received HDLC frame.  Display of these messages is delayed to
941    avoid possible timing problems. */
942
943 void logfr ( char *s , char *nm , uchar *p , int n )
944 {
945   int i=0 ;
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-" ) ;
950   }
951   msg ( "H-" ) ;
952   msg ( "I- %s %s", s, nm ) ;
953 }
954
955
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
962    error. */
963
964 #define MORE_FR  0x100 
965 #define SUB_FR   0x200 
966
967 int nframes = 0 ;               /* counts frames sent/received */
968
969 int putframe ( int type, uchar *buf, int len, TFILE *f, int t )
970 {
971   int err=0 ;
972
973   buf [ 0 ] = 0xff ;
974   buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ;
975   buf [ 2 ] = type & 0xff ;
976
977   if ( nframes++ && ! ( type & SUB_FR ) )
978     ckcmd ( f, &err, "+FTH=3" , TO_FT, CONNECT ) ;
979   
980   if ( ! err ) {
981
982     if ( ! buf[len+2] ) {
983       msg ( "Wlast byte of frame is NULL" ) ;
984     }
985
986     /* ttymode ( f, SEND ) ; */
987     sendbuf ( f, buf, len+3, 0 ) ;
988     tput ( f, DLE_ETX, 2 ) ; 
989     /* ttymode ( f, COMMAND ) ; */
990
991     logfr ( "sent", frname ( buf [ 2 ] ), buf, len+3 ) ;
992
993     ckcmd ( f, &err, 0, TO_DRAIN_H, ( type & MORE_FR ) ? CONNECT : OK ) ;
994   }
995
996   return err ;
997 }
998
999
1000 /* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */
1001
1002 void revcpy ( uchar *from , uchar *to )
1003 {
1004   int i, j ;
1005   for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- ) 
1006     to [ i ] = normalbits [ from [ j ] & 0xff ] ;
1007 }
1008
1009
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. */
1013
1014 int fixframe ( uchar *buf, int n, TFILE *f )
1015 {
1016   int i;
1017
1018   if ( *buf == 0xc0 || *buf == 0xc8 ) {
1019     for ( i=n; i >= 1 ; i-- ) 
1020       buf[i]=buf[i-1] ;
1021     buf[i] = 0xff ;
1022     msg ("W HDLC frame missing initial 0xff" ) ;
1023     n++ ;
1024   }
1025
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 ;
1031   }
1032
1033   return n ;
1034 }
1035
1036
1037 /* Read HDLC frame data.  Returns 0 if OK, 1 on frame error, 3 on
1038    timeout, invalid response or too-long frame. */
1039
1040 int receive_frame_data ( TFILE *f, uchar *buf, int n, int *len )
1041 {
1042   int err=0, c, i ;
1043
1044   for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0  ; i++ )
1045     if ( i < n ) buf[ i ] = c ;
1046   
1047   if ( c == EOF ) {
1048
1049     err = msg ( "E3timed out reading frame data" ) ;
1050
1051   } else {
1052     
1053     switch ( cmd ( f, 0, TO_RTCMD ) ) {
1054     case OK:
1055     case CONNECT:
1056       break ;
1057     case ERROR:
1058     case NO:
1059       err = msg ( "W1frame error" ) ;
1060       break ;
1061     case EOF:
1062       err = msg ( "E3no response after frame data" ) ;
1063       break ;
1064     default:
1065       err = msg ( "E3wrong response after frame data" ) ;
1066       break ;
1067     }
1068
1069   }
1070
1071   if ( i >= n ) 
1072     err = msg ( "E3frame too long (%d, > %d max bytes)", i, n ) ;
1073   
1074   if ( len ) *len = i ;
1075
1076   return err ;
1077 }
1078
1079
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.
1083
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.
1087
1088    When receiving responses returns on the first detected
1089    non-optional frame, after timeout T4, or on errors.
1090
1091    Returns immediately if gets a +FCERROR response so can retry
1092    as data carrier.  Returns DCN as a valid frame instead of
1093    hanging up.
1094
1095    Returns the command/response received, or EOF on timeout or
1096    error.
1097  
1098 */
1099
1100 int getfr ( TFILE *mf, uchar *buf, int getcmd )
1101 {
1102   int err=0, frame=0, frlen, c, t ;
1103   char remoteid [ IDLEN + 1 ] ;
1104   time_t start ;
1105   uchar *fif=buf+3 ;
1106   
1107   start = 10*time(0) ;
1108   
1109   t = getcmd ? ( getcmd > 1 ? getcmd : T2 ) : T4 ;
1110
1111  Enter:
1112
1113   err = 0 ;
1114
1115   if ( nframes++ ) {
1116     c = cmd ( mf, "+FRH=3", t ) ;
1117   } else {
1118     c = CONNECT ;               /* implied by ATA or ATD */
1119   }
1120   
1121   switch ( c ) {
1122   case EOF:                     /* time out */
1123     tput ( mf, CAN_STR, 1 ) ;
1124     ckcmd ( mf, 0, 0, TO_ABRT, OK ) ;
1125     err = 1 ;
1126     break ;
1127   case NO:                      /* S7 time out */
1128     err = 1 ;
1129     break ;
1130   case MODULATION:              /* data carrier (or DHS) */
1131     return -msg ( "W-2 wrong carrier" ) ;
1132     break ;
1133   case CONNECT:                 /* frame */
1134     break ;
1135   default:                      /* shouldn't happen */
1136     err = msg ( "E3wrong response to receive-frame command" ) ;
1137     break ;
1138   }
1139   
1140   if ( ! err ) 
1141     err = receive_frame_data ( mf, buf, MAXFRLEN, &frlen ) ;
1142   
1143   if ( ! err && frlen < 3 ) 
1144     err = msg ( "E3received short frame (%d bytes)", frlen ) ;
1145
1146   if ( ! err ) {
1147
1148     frlen = fixframe ( buf, frlen, mf ) ;
1149     logfr ( "received", frname ( buf [ 2 ] ), buf, frlen ) ;
1150     frame = buf [ 2 ] & 0x7f ;
1151
1152     switch ( frame ) {
1153     case CRP:
1154       err = 1 ;
1155     case NSF:
1156     case NSC:
1157     case NSS:
1158       goto Enter ;
1159     case CIG:
1160     case CSI:
1161     case TSI:
1162       revcpy ( fif , (uchar*) remoteid ) ;
1163       msg ( "I- remote ID -> %*.*s", IDLEN, IDLEN, remoteid ) ;
1164       goto Enter ;
1165     }
1166
1167   }
1168   
1169   if ( err && getcmd && ( t -= 10*time(0) - start ) > 0 ) 
1170     goto Enter ;
1171
1172   return err ? EOF : frame ;
1173 }
1174
1175
1176 /* Class 1 send/receive.  
1177
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.
1181
1182   */
1183
1184 int c1sndrcv ( 
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 )
1189
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 } ;
1194   char *fname=0 ;
1195   uchar buf [ MAXFRLEN ], *fif=buf+3 ;
1196
1197   if ( ! calling ) goto RX ;
1198
1199   /* Class 1 Transmitter: */
1200
1201  T:  /* Transmitter Phase B - wait for DIS or DTC */
1202
1203   pagetry = 0 ;
1204   
1205   frame = getfr ( mf, buf, T1 ) ;
1206   
1207   if ( frame <= 0 ) {
1208     err = msg ( "E3no answer from remote fax" ) ;
1209     goto B ;
1210   }
1211   
1212   if ( frame != DIS && frame != DTC ) {
1213     msg ( "W2 can't open page" ) ;
1214     goto C ;
1215   }
1216
1217   disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1218   try = 0 ;
1219
1220  A:                             /* decide to send or receive after DIS/DTC */
1221
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 ;
1227   }
1228
1229   msg ( "N remote has %sdocument(s) to send, and can %sreceive",
1230        remtx ? "" : "no ", remrx ? "" : "not " ) ;
1231
1232   if ( pages > 0 ) {
1233     if ( ! remrx ) msg ( "W remote cannot receive, trying anyways" ) ; 
1234     goto D ;
1235   } else {
1236     if ( ! remtx ) msg ( "W remote has nothing to send, trying anyways" )  ; 
1237     goto R ;
1238   }
1239
1240  D:                             /* send DCS */
1241
1242   if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1243     err = msg ( "E2can't open page" ) ;
1244     goto B ;
1245   }
1246
1247  D_2:
1248
1249   mincap ( local, remote, session ) ;
1250
1251   revcpy ( (uchar*) localid, fif ) ;
1252   if ( ! err ) 
1253     err = putframe ( TSI | MORE_FR | disbit, buf, IDLEN, mf, -1 ) ;  
1254
1255   mkdis ( session, fif, DCSLEN, 0, pages ) ;
1256   if ( ! err ) 
1257     err = putframe ( DCS | SUB_FR | disbit, buf, DCSLEN, mf, -1 ) ;
1258
1259   if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1260     msleep ( TMOD ) ;           /* if +FTS not supported */
1261
1262   if ( ! err ) 
1263     err = puttrain ( mf, c1cmd[SND][TRN][session[BR]], 
1264                     1.5*cps [ session[BR] ] ) ;
1265   try++ ;
1266
1267   if ( ! err ) {
1268     cmd ( mf, "+FRS=1", T3S ) ; /* wait for TCF carrier to drop */
1269     frame = getfr ( mf, buf, 0 ) ;
1270   }
1271
1272   if ( err || frame < 0 ) {
1273     if ( try >= 3 ) {
1274       goto C_timeout ;
1275     } else { 
1276       goto D_2 ;
1277     }
1278   }
1279   
1280   switch ( frame ) {
1281
1282   case DIS:
1283   case DTC:
1284     if ( try >= 3 ) goto C_timeout ;
1285     else goto A ;
1286
1287   case FTT:
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 ; }
1292
1293   case CFR:
1294     goto I_2 ;
1295
1296   default:
1297     err = msg ( "E3 invalid response to DCS (0x%02x)", frame ) ;
1298     goto C ;
1299   }    
1300
1301  I:                             /* send a page */
1302
1303   if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1304     err = msg ( "E2can't open page" ) ;
1305     goto B ;
1306   }
1307
1308  I_2:
1309
1310   ckcmd ( mf, &err, c1cmd [SND][DTA][session[BR]], TO_FT, CONNECT ) ;
1311   if ( !err )
1312     err = send_data ( mf, inf, page, pages, local, session, header, font ) ;
1313
1314   pagetry++ ;
1315
1316   if ( !err )
1317     err = end_data ( mf, session, 0, 0 ) ;
1318   
1319   if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1320     msleep ( TMOD ) ;           /* if +FTS not supported */
1321
1322                                 /* fix ppm if on last page of stdin */
1323   if ( lastpage ( inf ) ) ppm = EOP ;
1324
1325   try = 0 ;
1326  sendppm:
1327   if ( !err ) err = putframe ( ppm | disbit, buf, 0, mf, -1 ) ;
1328   try++ ;
1329   
1330   frame = getfr ( mf, buf, 0 ) ;
1331   if ( frame < 0 ) {
1332     if ( try >= 3 ) {
1333       goto C_timeout ;
1334     } else { 
1335       goto sendppm ;
1336     }
1337   }
1338
1339   fname = inf->page->fname ;
1340
1341   switch ( noretry ? MCF : frame ) { /* common retry logic */
1342   case MCF:
1343   case RTP:
1344   case PIP:
1345     fname = inf->page->fname ;
1346     if ( fname ) msg ( "Isent -> %s", fname ) ;
1347     pagetry=0 ;
1348     page++ ;
1349     dp = 1 ;
1350     break ;
1351   case PIN:
1352   case RTN:
1353     dp = 0 ;
1354     retry = pagetry < NTXRETRY ;
1355     break ;
1356   default:  
1357     err = msg ( "E3invalid post-page response (0x%02x)", frame ) ;
1358     goto C ;
1359   }
1360   
1361   switch ( ppm ) {
1362     
1363   case MPS:
1364     switch ( frame ) {
1365     case PIN: goto E ;
1366     case PIP: goto E ;
1367     case MCF: goto I ;
1368     case RTP: goto D ;
1369     case RTN: goto D ;
1370     }
1371
1372   case EOP:
1373     switch ( frame ) {
1374     case PIN: goto E ;
1375     case PIP: goto E ;
1376     case MCF: 
1377     case RTP: 
1378       nextipage ( inf, 1 ) ;    /* skip ahead to mark all files done */
1379       if ( remtx ) goto R ;     /* poll after sending */
1380       else goto C ;
1381     case RTN: 
1382       if ( retry ) goto D ;
1383       else goto C ;
1384     }
1385     
1386   case EOM:
1387     switch ( frame ) {
1388     case PIN: goto E ;
1389     case PIP: goto E ;
1390     case MCF: 
1391     case RTP: 
1392     case RTN: 
1393       cmd ( mf, "+FRS=20", T3S ) ; /* wait for ppr carrier to drop */
1394       if ( retry ) goto T ;
1395       else goto T ;
1396     }
1397     
1398   }  
1399
1400  E:                             /* ignore PIN and PIP */
1401   msg ( "W interrupt request ignored" ) ;
1402   try=0 ;
1403   goto A ;
1404
1405   /* Class 1 Receiver */
1406
1407  RX:
1408
1409  R:  /* Receiver Phase B */
1410
1411   if ( ! err ) err = wrpage ( outf, rxpage ) ;
1412
1413   disbit=0x00 ;
1414
1415   for ( t=0 ; !err && t<T1 ; t+=T2+10 ) {
1416
1417     revcpy ( (uchar*) localid, fif ) ;
1418     if ( !err ) 
1419       err = putframe ( CSI | disbit | MORE_FR, buf, IDLEN, mf, -1 ) ;
1420     
1421     mkdis ( local, fif, DEFDISLEN, 1, pages ) ;
1422     if ( !err ) 
1423       err = putframe ( DIS | disbit | SUB_FR, buf, DEFDISLEN, mf, -1 ) ;
1424
1425     frame = getfr ( mf, buf, 0 ) ;
1426
1427     if ( frame > 0 ) {
1428       disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1429       goto F_2 ;
1430     }
1431   }
1432   if ( err ) goto C ;
1433   else goto C_timeout ;
1434   
1435
1436  F:  /* get a command */
1437
1438   last = frame ;
1439   frame = getfr ( mf, buf, 1 ) ;
1440
1441   if ( writepending ) {         /* do postponed file close/open */
1442     writepending=0 ;
1443     err = wrpage ( outf, rxpage ) ;
1444     if ( err ) goto C ;
1445   }
1446
1447   if ( frame < 0 ) {
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 ; }
1451   }
1452   
1453  F_2:
1454
1455   switch ( frame ) {
1456
1457   case DTC:
1458     goto D ;
1459
1460   case DIS:
1461     try=0 ;
1462     goto A ;
1463     
1464   case DCS: 
1465     mkcap ( fif, session, 0 ) ;
1466     printcap ( "session", session ) ;
1467     
1468     cmd ( mf, "+FTS=1", T3S ) ; /* make sure DCS is over */
1469
1470     gettrain ( mf, c1cmd [RCV][TRN][session[BR]], cps[session[BR]], &good ) ;
1471
1472     if ( putframe ( ( good ? CFR : FTT ) | disbit, buf, 0, mf, -1 ) ||
1473         ! good ) goto F ;
1474
1475   getdata:
1476     
1477     outf->w=pagewidth[session[WD]];
1478     outf->h=0;
1479     outf->xres=204.0;
1480     outf->yres=vresolution[session[VR]];
1481     
1482     if ( cmd ( mf, c1cmd [RCV][DTA][session[BR]], TO_FT ) != CONNECT ) 
1483       goto F ;                  /* +FCERROR -> DCS resent */
1484     
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 */
1489       rxpage++ ;
1490     } else {
1491       good = 0 ;
1492     }
1493     ckcmd ( mf, 0, 0, TO_RTCMD, NO ) ;
1494     goto F ;
1495
1496     /* III: */
1497
1498   case PRI_EOM:
1499   case PRI_MPS:
1500   case PRI_EOP:
1501     frame &=0xf7 ;              /* ignore PRocedure Interrupt bit */
1502   case MPS:
1503   case EOP:
1504   case EOM:
1505     putframe ( ( good ? MCF : RTN ) | disbit, buf, 0, mf, -1 ) ;
1506     if ( good && frame == MPS ) goto getdata ;
1507     else goto F ;
1508     
1509   case DCN:
1510     goto B ;
1511     
1512   default:
1513     err = msg ( "E3 unrecognized command" ) ;
1514     goto B ;
1515
1516   }
1517
1518  C_timeout:
1519   err = msg ( "E3 no command/response from remote" ) ;
1520
1521  C:
1522   putframe ( DCN, buf, 0, mf, -1 ) ;
1523
1524  B:
1525   ckcmd ( mf, 0, "H", TO_RESET, OK ) ;  /* hang up */
1526
1527   if ( rxpage > 0 ) 
1528     wrpage ( outf, -1 ) ;       /* remove last file */
1529
1530   return err ;
1531 }
1532
1533
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). */
1538
1539 int gethsc ( int *hsc, int *perr )
1540 {
1541   int err=0, i ;
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 ) ;
1548         }
1549       }
1550       if ( perr && ! *perr ) {
1551         *perr = 2 ;
1552       }
1553     } else {
1554       err = 1 ;
1555     }
1556   }
1557   return err ;
1558 }
1559
1560
1561 /* Print remote ID and store DCS values in session as per
1562    responses since last command. */
1563
1564 void getc2dcs ( cap session )
1565 {
1566   char *p ;
1567   if ( ( p = sresponse ( "+FTI:",  0 ) ) != 0 ||  
1568        ( p =  sresponse ( "+FTSI:", 0 ) ) != 0 ) {
1569     msg ( "I- remote ID -> %s", p ) ;
1570   }
1571   if ( ( p = sresponse ( "+FCS:", 0 ) ) != 0 || 
1572       ( p = sresponse ( "+FDCS:", 0 ) ) != 0 ) {
1573     str2cap ( p, session ) ;
1574     printcap ( "session", session ) ;
1575   }
1576 }  
1577
1578 /* Wait for a starting character XON or DC2.  Display & ignore
1579    any other characters received. */
1580
1581 void getstartc ( TFILE *mf )
1582 {
1583   int c, noise ;
1584   
1585   for ( noise=0 ; ( c = tgetc ( mf, TO_C2X ) ) != XON && c != DC2 ; noise++ ) {
1586     if ( c == EOF ) {
1587       msg ( "Wno XON/DC2 received after CONNECT") ;
1588       break ;
1589     } else { 
1590       msg ( "W-+%s", cname ( c ) ) ; 
1591       noise++ ; 
1592     }
1593   }
1594   
1595   if ( noise )
1596     msg ( "W  : %d characters received while waiting to send", noise ) ;
1597 }  
1598
1599
1600 /* Class 2 send and receive.  
1601
1602    If calling, polls if no files to send, otherwise sends.  If
1603    not calling sends documents if files to send, else receives.
1604
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.
1609
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.
1613
1614    Returns 0 if OK or 2 on errors.  */
1615
1616
1617 int c2sndrcv (
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 )
1622 {
1623   int err=0, done=0, page, pagetry, nerr, c, dp=0 ;
1624   int ppm=0, good, hsc, changed ;
1625   int remtx=0 ;
1626   char *fname=0 ;
1627   cap session = { 0,0,0,0, 0,0,0,0 } ;
1628   char buf [ CMDBUFSIZE ] ;
1629
1630   hsc=-1 ;                      /* will be set >= 0 on hangup */
1631
1632   if ( sresponse ( "+FPO", 0 ) ) {
1633     remtx = 1 ;
1634     msg ( "N remote has document(s) to send." ) ;
1635   }
1636
1637   if ( calling ) {
1638     if ( pages ) goto send ;
1639     else goto poll ;
1640   } else {
1641     if ( pages ) goto pollserver ;
1642     else goto receive ;
1643   }
1644
1645   /* Class 2 Send */
1646
1647  pollserver:
1648
1649   /* with +FLP[L]=1 the modem should accept +FDT. */
1650
1651  send:
1652   
1653   page=1 ;
1654   
1655   pagetry=0 ;
1656   while ( ! err && ! done ) {
1657
1658     err = rdpage ( inf, dp, &ppm, local, &changed ) ;
1659
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 ) ) {
1665         continue ;
1666       }
1667     }
1668     
1669     ckcmd ( mf, &err, "+FDT", -TO_C2B, CONNECT ) ;
1670     if ( err || gethsc ( &hsc, &err ) ) { 
1671       done=1 ; 
1672       continue ; 
1673     }
1674
1675     getc2dcs ( session ) ; 
1676
1677     if ( ! c20 ) getstartc ( mf ) ;
1678
1679     send_data ( mf, inf, page, pages, local, session, header, font ) ;
1680     pagetry++ ;
1681
1682     if ( c20 ) {
1683       end_data ( mf, session, ppm, &good ) ;
1684     } else {
1685       end_data ( mf, session, 0, 0 ) ;
1686
1687       gethsc ( &hsc, &err ) ;
1688
1689       if ( ! err && hsc < 0 ) {
1690         ckcmd ( mf, &err, ppm == EOP ? "+FET=2" : 
1691                ppm == EOM ? "+FET=1" : "+FET=0" , TO_C2PP, OK ) ;
1692       }
1693
1694       gethsc ( &hsc, &err ) ;
1695
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" ) ;
1702         }
1703       }
1704
1705     }
1706     
1707     if ( noretry ) good = 1;
1708     
1709     if ( good ) {
1710       fname = inf->page->fname ;
1711       if ( fname ) msg ( "Isent -> %s", fname ) ;
1712       pagetry=0 ;
1713       page++ ;
1714       dp = 1 ;
1715       if ( ppm == EOP ) {
1716         nextipage ( inf, 1 ) ;  /* skip ahead to mark all files done */
1717         done = 1 ;
1718       }
1719     } else {
1720       dp = 0 ;
1721       if ( pagetry >= NTXRETRY )
1722         err = msg ( "E2too many page send retries" ) ;
1723     }
1724
1725     if ( gethsc ( &hsc, &err ) )  done=1 ;
1726
1727     if ( good && lastpage ( inf ) ) {
1728       done = 1 ;
1729     }
1730   }
1731
1732   goto done ;
1733
1734   /* Class 2 Receive */
1735
1736  poll:
1737
1738   /* with +FSP[L]=1 and +FPO[LL]: the modem should now accept +FDR. */
1739
1740  receive:
1741
1742   getc2dcs ( session ) ;        /* get ATA responses */
1743
1744   done=0 ;
1745   for ( page=0 ; ! err && ! done ; page++ ) {
1746
1747     if ( ! ( err = wrpage ( outf, page ) ) ) {
1748       c = cmd ( mf, "+FDR", -TO_C2R ) ;
1749
1750       switch ( c ) {
1751
1752       case CONNECT:
1753         getc2dcs ( session ) ; 
1754
1755         outf->w=pagewidth[session[WD]];
1756         outf->h=0;
1757         outf->xres=204.0;
1758         outf->yres=vresolution[session[VR]];
1759         
1760         tput ( mf, &startchar, 1 ) ;
1761
1762         if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1763           good = nerr < maxpgerr ;
1764           msg ( "I-received -> %s", outf->cfname ) ;
1765         } else { 
1766           good = 0 ;
1767         }
1768         
1769         ckcmd ( mf, &err, 0, TO_C2EOR, OK ) ;
1770
1771         if ( err || gethsc ( &hsc, &err ) )  { 
1772           wrpage ( outf, +1 ) ;
1773           wrpage ( outf, -1 ) ;
1774           done=1 ; 
1775           continue ; 
1776         }
1777         
1778         if ( ! good ) {
1779           msg ( "Wreception errors" ) ;
1780           ckcmd ( mf, 0, c20 ? "+FPS=2" : "+FPTS=2",  T3S, OK ) ;
1781           if ( gethsc ( &hsc, &err ) ) continue ;
1782         }
1783         break ;
1784
1785       case OK:
1786         wrpage ( outf, -1 ) ;   /* no more pages */
1787         done=1 ;
1788         if ( gethsc ( &hsc, &err ) ) continue ;
1789         break ;
1790
1791       default:
1792         wrpage ( outf, -1 ) ;   /* oops */
1793         err = msg ( "E3receive (+FDR) command failed") ;
1794         break ;
1795       }
1796     }
1797   } 
1798
1799   
1800  done:
1801   if ( hsc < 0 ) ckcmd ( mf, 0, c20 ? "+FKS" : "+FK", TO_RESET, OK ) ;
1802
1803   return err ;
1804 }
1805
1806
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
1812    on errors.  */
1813
1814 int dial ( TFILE *f, char *s, int nowait )
1815 {
1816   int err=0, hsc=-1 ;
1817   char c, dsbuf [ 128 ], *p ;
1818
1819   sprintf ( dsbuf, nowait ? "D%.126s;" : "D%.127s" , s ) ;
1820   msg ( "Idialing %s", dsbuf+1 ) ;
1821
1822   c = cmd ( f, dsbuf, TO_A ) ;
1823
1824   if ( ( p = sresponse ( "+FCSI:", 0 ) ) != 0 ||
1825        ( p =  sresponse ( "+FCI:", 0 ) ) != 0 ) {
1826     msg ( "I- remote ID -> %s", p ) ;
1827   }
1828
1829   if ( nowait && c == OK ) {
1830     msg ( "Icalled" ) ;
1831     nframes = 1 ;
1832   } else if ( c1 && c == CONNECT ) {
1833     msg ( "Iconnected" ) ; 
1834     nframes = 0 ;
1835   } else if ( !c1 && c == OK ) {
1836     msg ( "Iconnected" ) ; 
1837   } else if ( c ==  BUSY ) {
1838     err = msg ( "W1number is busy" ) ; 
1839   } else {
1840     err = msg ( "E2dial command failed" ) ;
1841   }
1842
1843   gethsc ( &hsc, err ? 0 : &err ) ;
1844
1845   return err ;
1846 }
1847
1848
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. */
1853
1854 enum connectmode { NONE, DATAMODE, FAXMODE, VOICEMODE } ; 
1855
1856 enum connectmode ansmode ( int *crate, int *hsc )
1857 {
1858   enum connectmode mode = NONE ;
1859   int x=0 ;
1860
1861   if ( c1 && sresponse ( "CONNECT", &x ) ) {
1862     mode = x ? DATAMODE : FAXMODE ;
1863   }
1864
1865   if ( !c1 && sresponse ( "OK", 0 ) ) {
1866     mode = FAXMODE ;
1867   } 
1868
1869   if ( !c1 && ( sresponse ( "CONNECT", &x ) || sresponse ( "+FDM", 0 ) ) ) {
1870     mode = DATAMODE ;
1871   } 
1872
1873   if ( sresponse ( "DATA", 0 ) || sresponse ( "CONNECT DATA", 0 ) ) {
1874     mode = DATAMODE ;
1875     sresponse ( "CONNECT", &x ) ;
1876   }
1877
1878   if ( sresponse ( "FAX", 0 ) || sresponse ( "+FCO", 0 ) ) {
1879     mode = FAXMODE ;
1880   }
1881
1882   if ( sresponse ( "VCON", 0 ) ) {
1883     mode = VOICEMODE ;
1884   }
1885   
1886   if ( gethsc ( hsc, 0 ) ) {
1887     mode = NONE ;
1888   }
1889
1890   if ( DATAMODE && x ) *crate = x ;
1891
1892   return mode ;
1893 }
1894
1895
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. */
1901
1902 int answer ( TFILE *f, char **lkfile, 
1903             int wait, int share, int softaa, 
1904             char *getty, char *vcmd, char *acmd )
1905 {
1906   int err=0, c ;
1907   int crate=19200, hsc=-1, i ;
1908   enum connectmode mode=NONE ;
1909
1910   if ( ! err && share ) {
1911     err = ttymode ( f, COMMAND ) ;
1912     if ( ! err ) 
1913       err = unlockall ( lkfile ) ;
1914   }
1915   
1916   if ( ! err && wait ) {
1917     msg ( "Iwaiting for activity") ;
1918     tdata ( f, -1 ) ;
1919     msg ( "Iactivity detected") ;
1920   }
1921   
1922   if ( ! err && share ) {
1923     msleep ( 500 ) ;            /* let other programs lock port  */
1924     err = lockall ( lkfile, 1 ) ;
1925     if ( err )
1926       err = msg ( "W1can't answer: can't lock device" ) ;
1927     else
1928       err = ttymode ( f, COMMAND ) ; /* in case it was changed silently */
1929   }
1930
1931   for ( i=0 ; ! err && mode == NONE && ( i==0 || ( i==1 && softaa ) ) ; i++ ) {
1932
1933     c = cmd ( f, wait ? 0 : acmd, ( i==0 && softaa ) ? TO_DATAF : TO_A ) ;
1934
1935     if ( c == DATA ) cmd ( f, c1 ? "O" : 0, TO_A ) ; /* +FAE=1 weirdness */
1936
1937     mode = ansmode ( &crate, &hsc ) ;
1938     
1939     switch ( mode ) {
1940     case DATAMODE :
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 ) ;
1946         } else {
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:" ) ;
1951         }
1952       } else {
1953         err = msg ( "E2no getty command defined for data call" ) ;
1954       }
1955       break ; 
1956     case FAXMODE :
1957       nframes = 0 ;
1958       msg ( "Ifax call answered") ;
1959       break ;
1960     case VOICEMODE :
1961       msg ( "Ivoice call answered") ;
1962       if ( vcmd && *vcmd ) {
1963         char buf [ MAXGETTY ] ;
1964         if ( ckfmt ( vcmd, 6 ) ) {
1965         } else {
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:" ) ;
1970         }
1971       } else {
1972         err = msg ( "E2no voice command defined for voice call" ) ;
1973       }
1974       break ; 
1975     case NONE:
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 ) 
1981               == OK ) break ; 
1982         wait = 0 ;
1983         acmd = ANSCMD ;
1984       } else {
1985         err = msg ( "E3unable to answer call") ;
1986       }
1987       break ;
1988     default:
1989       err = msg ( "E3can't happen(answer)" ) ;
1990       break ;
1991     }
1992     
1993   }
1994
1995   return err  ;
1996 }
1997
1998
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. */
2003
2004 int modem_init ( TFILE *mf, cap c, char *id, 
2005                  int calling, int poll, int capsset, int *preverse )
2006 {
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 } } ;
2011
2012
2013   /* diasable command echo and get firmware revision */
2014
2015   cmd ( mf, "E0", t ) ;
2016
2017   if ( cmd ( mf, "I3", t ) == OK ) {
2018     getresp ( "", model, CMDBUFSIZE-1 ) ;
2019     strcat ( model, " " ) ;
2020   }
2021
2022   /* if not already chosen, pick safest class; set it */
2023
2024   if ( ! err && ! c1 && !c2 && ! c20 ) {
2025     if ( cmd ( mf, "+FCLASS=?", t ) != OK ) {
2026       err = msg ("E3 modem does not support fax" ) ;
2027     } else {
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 */
2033         c1 = 1 ; 
2034         c2 = c20 = 0 ;
2035       }
2036     }
2037   }
2038
2039   ckcmd ( mf, &err, c1 ? "+FCLASS=1" : 
2040        ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), t, OK ) ;
2041
2042   /* get make & model if using Class 2 or 2.0 */
2043
2044   if ( ! c1 ) {
2045     for ( p = modelq [ c20 ] ; ! err && *p ; p++ ) {
2046       if ( cmd ( mf, *p, t ) == OK ) {
2047         getresp ( "", model, CMDBUFSIZE-1 ) ;
2048         strcat ( model, " " ) ;
2049       }
2050     }
2051   
2052     if ( ! c1 && strstr ( model, "Multi-Tech" ) ) {
2053       *preverse = 0 ;
2054       msg ("I Multi-Tech bit order set" ) ;
2055     }
2056   }
2057
2058   if ( ! err ) 
2059     msg ( "I using %sin class %s", model, c1 ? "1" : c20 ? "2.0" : "2" ) ;
2060
2061   /* get maximum modem speed if not already set (Class 1 only) */
2062
2063   if ( ! err && c1 && ! capsset ) {
2064     int i ;
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++ ) ;
2068     c[1]=i?i-1:0;
2069   }
2070
2071   /* issue essential commands and set/get modem capabilities (Class 2 only) */
2072
2073   if ( ! err && ! c1 ) {
2074
2075     if ( c20 ) {
2076       ckcmd ( mf, 0, "+FIP", t, OK ) ;
2077       ckcmd ( mf, 0, "+FNR=1,1,1,1", t, OK ) ;
2078     }
2079
2080     ckcmd ( mf, &err, "+FCR=1", t, OK ) ;
2081
2082     if ( ! capsset ) {
2083       if ( cmd ( mf, c20 ? "+FIS?" : "+FDIS?", -t ) == OK &&
2084            ( q = strinresp ( "," ) ) ) {
2085         str2cap ( q-1, c ) ;
2086       } else {
2087         msg ( "W can't get modem capabilities, set to default" ) ;
2088         capsset = 1 ;
2089       }
2090     }
2091
2092     if ( capsset ) {
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 ) ;
2097     }
2098     
2099     sprintf ( buf, c20 ? "+FLI=\"%.*s\"" : "+FLID=\"%.*s\"" , 
2100              CMDBUFSIZE-9, id ) ;
2101     ckcmd ( mf, 0, buf, -t, OK ) ;
2102
2103     if ( ! err && poll ) {
2104
2105       ckcmd ( mf, 0, c20 ? "+FSP=1" : "+FSPL=1", -t, OK ) ;
2106
2107       sprintf ( buf, c20 ? "+FPI=\"%.*s\"" : "+FCIG=\"%.*s\"" , 
2108                CMDBUFSIZE-9, id ) ;
2109       ckcmd ( mf, 0, buf, -t, OK ) ;
2110
2111     }
2112   }
2113
2114   return err ;
2115 }
2116
2117
2118 /* the following are global so can terminate properly on signal */
2119
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 */
2125
2126
2127 /* print names of files not sent and reset modem before
2128    exiting. */
2129
2130 int cleanup ( int err )
2131 {
2132                                 /* log names of files not sent */
2133   logifnames ( &ifile, "I failed -> %s" ) ;
2134
2135   if ( ! locked && faxdev.fd >= 0 )
2136     end_session ( &faxdev, icmd[2], lkfile, err != 4 ) ;
2137   
2138   msg ( "Idone, returning %d (%s)", err, 
2139         errormsg [ err >= 0 && err <= 5 ? err : 6 ] ) ;
2140
2141   return err ;
2142 }
2143
2144
2145 /* signal handler */
2146
2147 void onsig ( int sig ) 
2148
2149   msg ( "E terminating on signal %d", sig ) ; 
2150   exit ( cleanup ( 5 ) ) ;
2151 }
2152
2153
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. */
2158
2159 int main( int argc, char **argv)
2160 {
2161   int err=0, doneargs=0, c=0, i ;
2162   int testing=0, calling=0 ;
2163
2164   int nicmd[3]={0,0,0}, nlkfile=0, nverb=0 ;
2165
2166   char *faxfile = FAXFILE ;
2167
2168   int softaa=0, share=0, wait=0, reverse=1, ignerr=0, noretry=0, hwfc=0 ;
2169   int capsset=0 ;
2170   char *getty = "", *vcmd = "", *acmd=ANSCMD ;
2171
2172   cap local = { DEFCAP } ;
2173   char localid  [ IDLEN + 1 ] = DEFID ;
2174
2175   int maxpgerr = MAXPGERR ;
2176
2177   time_t now ;
2178   char *header = 0, headerbuf [ MAXLINELEN ] ; 
2179   char *fontname = 0 ;
2180   faxfont font ;
2181
2182   OFILE ofile ;
2183   int pages = 0 ;
2184   char *phnum="", *ansfname = DEFPAT ;
2185   char fnamepat [ EFAX_PATH_MAX ] ;
2186   
2187   /* print initial message to both stderr & stdout */
2188   argv0 = argv[0] ;
2189   verb[1] = "ewia" ;
2190   msg ( "I " Version " " Copyright ) ;
2191   argv0 = efaxbasename ( argv0 ) ;
2192   msg ( "A compiled "__DATE__ " " __TIME__ ) ;
2193   verb[1] = "" ;
2194
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 ) {
2198
2199     switch (c) {
2200     case 'a': 
2201       acmd = nxtoptarg ;
2202       break ;
2203     case 'c': 
2204       err = str2cap ( nxtoptarg, local ) ;
2205       capsset = 1 ;
2206       break ;
2207     case 'l': 
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 ) ;
2213       break ;
2214     case 'i': 
2215       if ( nicmd[0] < MAXICMD ) icmd[0][ nicmd[0]++ ] = nxtoptarg ;
2216       else err = msg ( "E2too many '-i' options"); 
2217       break ;
2218     case 'j': 
2219       if ( nicmd[1] < MAXICMD ) icmd[1][ nicmd[1]++ ] = nxtoptarg ;
2220       else err = msg ( "E2too many '-j' options"); 
2221       break ;
2222     case 'k': 
2223       if ( nicmd[2] < MAXICMD ) icmd[2][ nicmd[2]++ ] = nxtoptarg ;
2224       else err = msg ( "E2too many '-k' options"); 
2225       break ;
2226     case 'h': 
2227       header = nxtoptarg ; 
2228       break ;
2229     case 'f': 
2230       fontname = nxtoptarg ; 
2231       break ;
2232     case 'd': 
2233       faxfile = nxtoptarg ; 
2234       break ;
2235     case 'e': 
2236       vcmd = nxtoptarg ; 
2237       break ;
2238     case 'g': 
2239       getty = nxtoptarg ; 
2240       break ;
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 ) ; 
2257         }
2258       break ;
2259     case 'q':
2260       if ( sscanf ( nxtoptarg , "%d", &maxpgerr ) != 1 || maxpgerr < 0 )
2261         err=msg ("E2bad quality (-q) argument (%s)", nxtoptarg ) ;
2262       break;
2263     case 'r': 
2264       ansfname = nxtoptarg ;
2265       break;
2266     case 's': 
2267       share = 1 ; 
2268       break;
2269     case 't': 
2270       calling=1;
2271       /* fall through */
2272     case 'p':
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 ;
2277       phnum = nxtoptarg ;
2278       doneargs=1 ; 
2279       break;
2280     case 'v': 
2281       verb[nverb] = nxtoptarg ; 
2282       nverb=1;
2283       break ;
2284     case 'w': 
2285       wait = 1 ; 
2286       break ;
2287     case 'x': 
2288       if ( nlkfile < MAXLKFILE ) lkfile[ nlkfile++ ] = nxtoptarg ;
2289       else err = msg ( "E2too many lock files" ) ; 
2290       break ;
2291     case 'T':                   /* test: begin+end session */
2292       testing=1;
2293       doneargs=1 ; 
2294       break ;
2295     default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
2296     }
2297   }
2298
2299   for ( i=0 ; i<argc ; i++ ) 
2300     msg ( "Aargv[%d]=%s", i, argv[i]) ; 
2301
2302   if ( ! nicmd[2] ) icmd[2][nicmd[2]++] = "H" ; /* default -k command */
2303
2304   readfont ( fontname, &font ) ;
2305
2306   if ( ! header ) {
2307     char tmp [ MAXLINELEN ] ;
2308     now = time ( 0 ) ;
2309     strftime ( tmp, MAXLINELEN, "%c %%s   P. %%%%d", localtime ( &now ) ) ;
2310     sprintf ( header = headerbuf, tmp, localid ) ;
2311   }
2312
2313   if ( ! err ) {
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,
2320                                     &reverse ) ;
2321     if ( ! err ) err = setup ( &faxdev, icmd[1], ignerr ) ;
2322     if ( err == 1 ) locked = 1 ;
2323   }
2324
2325   if ( ! err && ! testing ) {
2326
2327     if ( calling ) {
2328       err = dial ( &faxdev, phnum, 0 ) ;
2329     } else {
2330       err = answer ( &faxdev, lkfile, wait, share, softaa, 
2331                     getty, vcmd, acmd ) ;
2332       if ( err == 1 ) locked = 1 ;
2333     }
2334
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 ) ;
2339     
2340     if ( ! err ) {
2341       if ( c1 ) {
2342         err = c1sndrcv ( &faxdev, local, localid,
2343                         &ofile, &ifile, pages, header, &font,
2344                         maxpgerr, noretry, calling ) ;
2345       } else {
2346         err = c2sndrcv ( &faxdev, local, localid,
2347                         &ofile, &ifile, pages, header, &font,
2348                         maxpgerr, noretry, calling ) ;
2349       }
2350     }
2351   }
2352
2353   return cleanup ( err ) ;
2354 }