unstrip-downed Class 2 error messages table
[efax.git] / efax.c
1 #include "config.h"
2
3 #define Copyright         "Copyright 1999 Ed Casas"
4
5 #define Version           "efax v 0.9"
6
7 /*
8     Copyright (C) 1999  Ed Casas
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24     Please contact the author if you wish to use efax or efix in
25     ways not covered by the GNU GPL.
26
27     You may contact the author by e-mail at: edc@cce.com, by mail
28     at: 2629 West 3rd Ave, Vancouver, BC, Canada, V6K 1M4, or by
29     fax at: +1 604 734 5291.
30
31 */
32
33 static const char *Usage =
34   "Usage:\n"
35   "  %s [ option ]... [ -t num [ file... ] ]\n"
36   "Options:\n"
37   "  -a str  use command ATstr to answer\n"
38   "  -c cap  set modem and receive capabilites to cap\n"
39   "  -d dev  use modem on device dev\n"
40   "  -e cmd  exec \"/bin/sh -c cmd\" for voice calls\n"
41 #ifndef UCLINUX
42   "  -f fnt  use (PBM) font file fnt for headers\n"
43 #endif /* UCLINUX */
44   "  -g cmd  exec \"/bin/sh -c cmd\" for data calls\n"
45   "  -h hdr  use page header hdr (use %%d's for current page/total pages)\n"
46   "  -i str  send modem command ATstr at start\n"
47   "  -j str  send modem command ATstr after set fax mode\n"
48   "  -k str  send modem command ATstr when done\n"
49   "  -l id   set local identification to id\n"
50   "  -o opt  use protocol option opt:\n"
51   "      0     use class 2.0 instead of class 2 modem commands\n"
52 #ifndef UCLINUX
53   "      1     use class 1 modem commands\n"
54 #endif /* UCLINUX */
55   "      2     use class 2 modem commands\n"
56   "      a     if first [data mode] answer attempt fails retry as fax\n"
57   "      e     ignore errors in modem initialization commands\n"
58   "      f     use virtual flow control\n"
59   "      h     use hardware flow control\n"
60   "      l     halve lock file polling interval\n"
61   "      n     ignore page retransmission requests\n"
62   "      r     do not reverse received bit order for Class 2 modems\n"  
63   "      x     use XON instead of DC2 to trigger reception\n"
64   "      z     add 100 ms to pause before each modem comand (cumulative)\n"
65   "  -q ne   ask for retransmission if more than ne errors per page\n"
66 #ifndef UCLINUX
67   "  -r pat  save received pages into files pat.001, pat.002, ... \n"
68 #endif /* UCLINUX */
69   "  -s      share (unlock) modem device while waiting for call\n"
70   "  -v lvl  print messages of type in string lvl (ewinchamr)\n"
71   "  -w      don't answer phone, wait for OK or CONNECT instead\n"
72   "  -x fil  use uucp-style lock file fil\n"
73   "Commands:\n"
74   "  -t      dial num and send fax image files file... \n"
75   ;
76
77 #include <ctype.h>              /* ANSI C */
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <time.h>
82
83 #include "efaxio.h"             /* EFAX */
84 #include "efaxlib.h"
85 #include "efaxmsg.h"
86 #include "efaxos.h"
87
88 /* constants... */
89
90                             /* delays and timeouts (t/o), in deciseconds */
91 #define T1 350              /* T.30 T1 - waiting for DIS/DCS before Phase B */
92 #define T2 60               /* T.30 T2 - waiting for frame in Phase B */
93 #define T3S 30              /* T.30 response timeout (not T3) */
94 #define T4 30               /* T.30 T4 - between [re]transmissions of DIS */
95
96 #define TMOD 55             /* T.30 pause between v.21&v.29, 75-20 ms */
97
98 #define TO_A     1200       /* dial/answer (Phase A) - modem may t/o first */
99 #define TO_ABRT  20         /* max delay after sending abort sequence */
100 #define TO_CHAR  102        /* per data character (2x max FILL length) */
101 #define TO_DATAF 80         /* software adaptive answer data connect t/o */
102 #define TO_DRAIN_H 136      /* minimum HDLC buffer drain time (4k/300cps) */
103 #define TO_DRAIN_D 300      /* minimum data buffer drain time */
104 #define TO_FT    31         /* max delay after +F[TR][MH] command */
105 #define TO_RTCMD 20         /* return to command mode after DLE-ETX (rx) */
106
107 #define TO_C2B    450       /* Class 2 DIS to CONNECT:(DCS+TCF+CFR)xretries */
108 #define TO_C2X    20        /* Class 2 wait for XON: 2/5 of 5s timeout */
109 #define TO_C2PP   200       /* Class 2 wait for ppr: (ppm+ppr)x3retries + 2 */
110 #define TO_C2R    600       /* Class 2 receive: (TCF+FTT)x11 retrains + 5 */
111 #define TO_C2EOR  120       /* Class 2 end of data rx (4 retrans x 3 s) */
112
113 #define ANSCMD  "A"         /* default modem command to answer calls */
114 #define DCSLEN 3            /* length of FIF for DCS commands sent */
115 #define DEFDISLEN 3         /* length of DIS initially transmitted */
116 #define DEFCAP 1,3,0,2,0,0,0,0  /* default local capabilities */
117 #define DEFID "                    " /* default local ID */
118 #define DEFPAT "%m%d%H%M%S" /* default received file name pattern */
119 #define HDRSHFT 54          /* shift header right 6.7mm into image area */
120 #define HDRSPCE 20          /* number of scan lines inserted before image */
121 #define HDRSTRT  4          /* scan line where header is placed on image */
122 #ifndef UCLINUX
123 #define HDRCHRH 24          /* header character height (pels, at 196lpi) */
124 #else /* UCLINUX */
125 #define HDRCHRH 0           /* header character height (pels, at 196lpi) */
126 #endif /* UCLINUX */
127 #define HDRCHRW 12          /* header character width (pels) */
128 #define IDLEN 20            /* length of T.30 ID strings, must be 20 */
129 #define MAXDIS 8            /* maximum DIS frames sent without response (T1) */
130 #define MAXERRPRT 32        /* maximum number of reception errors to report */
131 #define MAXFIFLEN 125       /* max FIF len = MAXFRLEN - (adx+ctl+FCF) - FCS */
132 #define MAXFRLEN 130        /* max frame length = 3.45s x 300 bps / 8 */
133 #define MAXGETTY 512        /* maximum length of exec'ed (-g, -e) commands */
134 #define MAXICMD  100        /* maximum # of modem setup/reset commands */
135 #define MAXLKFILE 16        /* maximum number of lock files */
136 #define MAXNULLS 2          /* maximum consecutive received nulls saved */
137 #define MAXPGERR 10         /* maximum received errors allowed per page */
138 #define MAXTRAIN 2          /* maximum training retries at lowest speed */
139 #define MAXRETRY 3          /* maximum retries of unacknowledged commands */
140 #define NCAP 8              /* number of fields in a capability string */
141 #define NTXRETRY 3          /* maximum re-sends per page */
142
143 typedef int cap [ NCAP ] ;              /* remote/local capabilities */
144
145                                         /* capability fields... */
146 enum  captype {          VR, BR, WD, LN, DF, EC, BF, ST } ;
147 static int capmax [ NCAP ] = {   1,  7,  2,  2,  3,  2,  1,  7 } ;
148                                         /* & maximum values */
149
150 #ifndef UCLINUX
151                                         /* vertical resolution, dpi */
152 int vresolution [ 2 ] = { 98, 196 } ;
153 #endif /* UCLINUX */
154
155                                         /* characters per second for br */
156 static int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
157
158 #ifndef UCLINUX
159                                         /* next br = fallback [ br ] */
160                     /* 0, 1, 2, 3, 4, 5, 6, 7 */
161 int fallback [ 8 ] = {-1, 0, 1, 2, 7, 4, 3, 6 } ;
162
163                                         /* negotiation speed index */
164                          /* 0, 1, 2, 3, 4, 5, 6, 7 */
165 int brindex [ 8 ] = { 0, 1, 2, 3, 4, 7, 5, 6 } ;
166 #endif /* UCLINUX */
167
168                                         /* minimum scan time in ms  */
169 static int mst [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
170
171                                         /* page width in pixels */
172 static int pagewidth [ 5 ] = { 1728, 2048, 2432, 1216, 864 } ;
173
174 /* Table to convert between T.30 DIS/DCS/DTC FIF and Class 2-like
175    capability codes. Uses br=6, 7 for V.17 at 7200, 9600. */
176
177 typedef struct t30tabstruct
178
179   char *name ; 
180   uchar byte, shift, mask ; 
181   uchar safeval ;
182   uchar captodis[8], distocap[16], captodcs[8], dcstocap[16] ; 
183 } t30tabst ;
184
185 #define X 0xff                          /* invalid values */
186
187 static t30tabst t30tab [ NCAP ] = {
188   { "vr", 1, 1, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },    
189   { "br", 1, 2, 0x0f, 0,
190       { 0, 4, 12, 12, 13, 13 } ,
191       { 0, X, X, X, 1, X, X, X, 3, X, X, X, 3, 5, 3, X } ,
192       { 0, 4, 12, 8, 5, 1 } ,
193       { 0, 5, 5, X, 1, 4, 4, X, 3, 7, X, X, 2, 6, X, X } } ,
194   { "wd", 2, 6, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, 2 } ,
195       { 0, 2, 1 } , { 0, 2, 1, 2 } },
196   { "ln", 2, 4, 0x03, 0, { 0, 2, 1 } , { 0, 2, 1, X } ,
197       { 0, 2, 1 } , { 0, 2, 1, X } },
198   { "df", 1, 0, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
199   { "ec", 3, 4, 0x03, 0, { 0, 2, 2 } , { 0, X, 2, X } , 
200       { 0, 3, 2 } , { 0, 0, 2, 1 } }, 
201   { "bf", 5, 5, 0x01, 0, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
202   { "st", 2, 1, 0x07, 7,
203       { 7, 4, 3, 2, 6, 0, 5, 1 } , { 5, 7, 3, 2, 1, 6, 4, 0 } ,
204       { 7, 4, X, 2, X, 0, X, 1 } , { 5, 7, 3, 1, X, X, X, 0 } } 
205 } ;
206
207                                         /* values of capability fields */
208 static char *capvaluestr [ NCAP ] [8] = {
209   { " 98lpi", "196lpi" } , 
210   { " 2400bps", " 4800bps", " 7200bps", " 9600bps", "  12kbps", "14.4kbps",
211     "7200V.17", "9600V.17" } ,
212   { "8.5\"/215mm", " 10\"/255mm", " 12\"/303mm",
213     "  6\"/151mm", "4.2\"/107mm" } ,
214   { "11\"/A4", "14\"/B4", " any  " } ,
215   { "1D" , "2D" }, { "   -   ", "ECM-256", "ECM-64 " }, { " - ", "BFT" },
216   { "0ms", "5ms", "10/5ms", "10ms", "20/10ms", "20ms", "40/20ms", "40ms" }
217 } ;
218
219 /* T.30 control frames */
220
221 enum frametype {            
222  DIS=0x01, CSI, NSF=0x04,
223  CFR=0x21, FTT,
224  MCF=0x31, RTN, RTP, PIN, PIP,
225  DCS=0x41, TSI, NSS=0x44,
226  CRP=0x58, DCN=0x5f,
227  EOM=0x71, MPS, EOP=0x74, PRI_EOM=0x79, PRI_MPS, PRI_EOP=0x7c,
228  DTC=0x81, CIG, NSC=0x84
229  } ;
230
231 enum commanddtype { RCV=0, SND=1, DTA=0, TRN=1 } ;
232
233 /* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
234    [baud rate=BR]. */
235
236 #ifndef UCLINUX
237 char *c1cmd [ 2 ]  [ 2 ] [ 8 ] = { 
238 { { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=122", "+FRM=146" ,
239     "+FRM=74", "+FRM=98" } ,
240   { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=121", "+FRM=145" ,
241     "+FRM=73", "+FRM=97" } } ,
242 { { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=122", "+FTM=146" ,
243     "+FTM=74", "+FTM=98", } ,
244   { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=121", "+FTM=145" ,
245     "+FTM=73", "+FTM=97" } }
246 } ;
247 #endif /* UCLINUX */
248
249 static struct c2msgstruct
250
251   int min, max ;
252   char *msg ;
253 } c2msg [] = {
254   {   0,   9, "Call Placement and Termination:" },
255   {   0,   0, "  Normal and proper end of connection" },
256   {   1,   1, "  Ring Detect without successful handshake" },
257   {   2,   2, "  Call aborted, from +FK[S] or CAN" },
258   {   3,   3, "  No Loop Current" },
259   {   4,   4, "  Ringback Detected, no answer" },
260   {   5,   5, "  Ringback Detected, answer without CED" },
261
262   {  10,  19, "Transmit Phase A & Miscellaneous Errors:" },
263   {  10,  10, "  Unspecified Phase A error" },
264   {  11,  11, "  No Answer (T.30 T1 timeout)" },
265   {  20,  39, "Transmit Phase B Hangup Codes:" },
266   {  20,  20, "  Unspecified Transmit Phase B error" },
267   {  21,  21, "  Remote cannot receive or send" },
268   {  22,  22, "  COMREC error in transmit Phase B" },
269   {  23,  23, "  COMREC invalid command received" },
270   {  24,  24, "  RSPREC error" },
271   {  25,  25, "  DCS sent three times without response" },
272   {  26,  26, "  DIS/DTC received 3 times; DCS not recognized" },
273   {  27,  27, "  Failure to train at 2400 bps or +FMINSP value" },
274   {  28,  28, "  RSPREC invalid response received" },
275   {  40,  49, "Transmit Phase C Hangup Codes:" },
276   {  40,  40, "  Unspecified Transmit Phase C error" },
277   {  41,  41, "  Unspecified image format error"  },
278   {  42,  42, "  Image conversion error" },
279   {  43,  43, "  DTE to DCE data underflow" },
280   {  44,  44, "  Unrecognized transparent data command" },
281   {  45,  45, "  Image error, line length wrong" },
282   {  46,  46, "  Image error, page length wrong" },
283   {  47,  47, "  Image error, wrong compression code" },
284   {  50,  69, "Transmit Phase D Hangup Codes:" },
285   {  50,  50, "  Unspecified Transmit Phase D error" },
286   {  51,  51, "  RSPREC error" },
287   {  52,  52, "  No response to MPS repeated 3 times" },
288   {  53,  53, "  Invalid response to MPS" },
289   {  54,  54, "  No response to EOP repeated 3 times" },
290   {  55,  55, "  Invalid response to EOP" },
291   {  56,  56, "  No response to EOM repeated 3 times" },
292   {  57,  57, "  Invalid response to EOM" },
293   {  58,  58, "  Unable to continue after PIN or PIP" },
294
295   {  70,  89, "Receive Phase B Hangup Codes:" },
296   {  70,  70, "  Unspecified Receive Phase B error" },
297   {  71,  71, "  RSPREC error" },
298   {  72,  72, "  COMREC error" },
299   {  73,  73, "  T.30 T2 timeout, expected page not received" },
300   {  74,  74, "  T.30 T1 timeout, after EOM received" },
301   {  90,  99, "Receive Phase C Hangup Codes:" },
302   {  90,  90, "  Unspecified Receive Phase C error" },
303   {  91,  91, "  Missing EOL after 5 seconds" },
304   {  92,  92, "  Unused code" },
305   {  93,  93, "  DCE to DTE buffer overflow" },
306   {  94,  94, "  Bad CRC or frame (ECM or BFT modes)" },
307   { 100, 119, "Receive Phase D Hangup Codes:" },
308   { 100, 100, "  Unspecified Receive Phase D errors" },
309   { 101, 101, "  RSPREC invalid response received" },
310   { 102, 102, "  COMREC invalid response received" },
311   { 103, 103, "  Unable to continue after PIN or PIP" },
312   { 120, 255, "Reserved Codes" },
313   {  -1,  -1, "" }
314 } ;
315
316 /* meaning of efax return codes */
317
318 static char *errormsg [] = {
319   "success",
320   "number busy or modem in use",
321   "unrecoverable error",
322   "invalid modem response",
323   "no response from modem",
324   "terminated by signal",
325   "internal error" } ;
326
327 /* Functions... */
328
329 /* Return name of frame of type 'fr'. */
330
331 #ifndef UCLINUX
332 char *frname ( int fr )
333 {
334   static struct framenamestruct {  int code ;  char *name ; } 
335   framenames [] = {
336
337     {NSC,"NSC - poller features"}, /* these 3 frames must be first */
338     {CIG,"CIG - poller ID"}, 
339     {DTC,"DTC - poller capabilities"},
340     {NSF,"NSF - answering features"},
341     {CSI,"CSI - answering ID"},
342     {DIS,"DIS - answering capabilities"},
343     {NSS,"NSS - caller features"},
344     {TSI,"TSI - caller ID"},
345     {DCS,"DCS - session format"},
346
347     {CFR,"CFR - channel OK"},
348     {FTT,"FTT - channel not OK"},
349
350     {MPS,"MPS - not done"},
351     {EOM,"EOM - not done, new format"},
352     {EOP,"EOP - done"},
353
354     {PRI_MPS,"PRI-MPS - not done, call operator"},
355     {PRI_EOM,"PRI-EOM - not done, new format, call operator"},
356     {PRI_EOP,"PRI-EOP - done, call operator"},
357
358     {MCF,"MCF - page OK"},
359     {RTP,"RTP - page OK, check channel"},
360     {PIP,"PIP - page OK, call operator"},
361     {RTN,"RTN - page not OK, check channel"},
362     {PIN,"PIN - page not OK, call operator"},
363
364     {CRP,"CRP - repeat command"},
365     {DCN,"DCN - disconnect"},
366     {0,0} },
367   *p ;
368   
369   for ( p=framenames ; p->code ; p++ )
370     if ( fr == p->code || ( fr & 0x7f ) == p->code) break ;
371   return p->code ? p->name : "UNKNOWN" ;
372 }
373 #endif /* UCLINUX */
374
375 /* Range-check capability. */
376
377 static int checkcap ( cap c )
378 {
379   int err=0, i ;
380
381   for ( i=0 ; i<NCAP ; i++ )
382     if ( c[i] > capmax[i] || c[i] < 0 ) {
383       err = msg ( "E3%s = %d out of range, set to 0", t30tab[i].name, c[i] ) ;
384       c[i]=0 ;
385     }
386   return err ;
387 }
388
389
390 /* Print cap[ability] c using text values and prefix s. */
391
392 static void printcap ( char *s , cap c )
393 {
394   int i ;
395   msg ( "N-+ %s" , s ) ;
396   checkcap ( c ) ;
397   for ( i=0 ; i<NCAP ; i++ ) 
398     msg ( "N-+  %s" , capvaluestr [ i ] [ c[i] ] ) ;
399   msg ( "N-" ) ;
400 }
401
402
403 /* Convert capability string to cap struct. Returns 0 or 2 on errors. */
404
405 static int str2cap ( char *s, cap c )
406 {
407   int err=0, n ;
408         char *end ;
409
410         for ( n=0 ; n<NCAP ; n++ ) {
411                 if (!s)
412                         break;
413                 c [ n ] = strtol ( s, &end, 10 );
414                 if (end && *end && *end!=',')
415                         break;
416                 s = end;
417   }
418         
419   if ( n < NCAP ) msg ( "Wmissing value(s) in \"%s\"", s ) ;
420
421   checkcap ( c ) ;
422
423   return err ;
424 }
425
426
427 /* Convert a cap[ability] 'c' to a DIS/DCS/DTC FIF 'fif' of 'len'
428    bytes.  Converts into DIS format if 'isdis' is true, else into
429    DCS/DTC format. */
430
431 #ifndef UCLINUX
432 void mkdis ( cap c, uchar *fif, int len, int isdis, int t4tx ) 
433 {
434   int i, k ;
435   t30tabst *p ;
436
437   len = len > DCSLEN ? DCSLEN : len ;
438
439   fif[0] = 0 ;
440   fif[1] = ( isdis && t4tx ? 0x80 : 0 ) | 0x40 ;
441   for ( i=2 ; i<len-1 ; i++ ) fif[i] = 0x01 ;       /* add extension bits */
442   fif[i] = 0 ;
443
444   checkcap ( c ) ;
445
446   for ( i=0 ; i<NCAP ; i++ ) {
447     p = t30tab + i ;
448     if ( ( k = ( isdis ? p->captodis : p->captodcs ) [ c [ i ] ] ) == X )
449       msg ( "E3mkdis: can't happen (invalid %s)", p->name ), k=0 ;
450     if ( p->byte < len ) fif [ p->byte ] |= k << p->shift ;
451   }
452 }
453 #endif /* UCLINUX */
454
455
456 /* Return length of DIS/DTC FIF (counts extension bits). */
457
458 #ifndef UCLINUX
459 int dislen ( uchar *fif )
460 {
461   int n ;
462   for ( n=3 ; fif [ n-1 ] & 0x01 && n < MAXFIFLEN ; n++ ) ;
463   return n ;
464 }
465 #endif /* UCLINUX */
466
467
468 /* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 if bad DIS/DCS
469    field. */
470
471 #ifndef UCLINUX
472 int mkcap ( uchar *fif, cap c, int dis ) 
473 {
474   int err=0, i, j, k, len ;
475   t30tabst *p ;
476
477   len = dislen ( fif ) ;
478
479   for ( i=0 ; i<NCAP ; i++ ) {
480     p=t30tab+i ;
481     if ( p->byte >= len ) {
482       c [ i ] = 0 ;
483     } else {
484       j = ( fif [ p->byte ] >> p->shift ) & p->mask ;
485       k = ( dis ? p->distocap : p->dcstocap ) [ j ] ;
486       if ( k == X ) {
487         c [ i ] = p->safeval ;
488         err = msg("E3mkcap: bad %s field (%d) set to %d", 
489                   p->name, j, c [ i ] ) ;
490       } else { 
491         c [ i ] = k ;
492       }
493     }
494   }
495   return err ;
496 }
497 #endif /* UCLINUX */
498
499
500 /* Compute compatible local/remote capabilities. Used by the
501    sending station only and only for Class 1. Returns 0 if OK or
502    3 if no compatible settings possible. */
503
504 #ifndef UCLINUX
505 int mincap ( cap local, cap remote, cap session )
506 {
507   int err=0, i ;
508   int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ;
509
510   printcap ( "local  ", local ) ;
511   printcap ( "remote ", remote ) ;
512
513   for ( i=0 ; i<NCAP && i!=ST && i !=BR ; i++ )
514     session[i] = remote[i] < local[i] ? remote[i] : local[i] ;
515
516   session[BR] = brindex[ remote[BR] ] < brindex[ local[BR] ] ?
517     remote[BR] : local[BR] ;
518
519   session[ST] = msttab [ session[VR] ] [ remote[ST] ] ;
520
521   printcap ( "session", session ) ;
522
523   if ( local[WD] != session[WD] || local[LN] > session[LN] || 
524       local[DF] != session[DF] ) 
525     err = msg ("W3incompatible local and remote capabilities" ) ;
526
527   return err ;
528 }
529 #endif /* UCLINUX */
530
531
532 /* Skip to start of first/next page (or to start of previous page
533    if dp is 0).  If ppm in not null, it is then set to EOP if
534    there are no pages following this one, MPS if the next page
535    has the same format as `local' (assumed to be the format of
536    the previous page), EOM if the page has a different format.
537    If local is non-NULL its format fields are set according to
538    the format of the new page.  Currently only considers the
539    file's y-resolution.
540
541    This function is called before send_data() and obtains the ppm
542    for that page.  It can be called again with dp=0 if a PIN or
543    RTN is received to restart the page.  Returns 0 or 2 on
544    errors. */
545
546 static int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed )
547 {
548   int err=0, m=EOP, yres, fVR, nVR  ;
549
550   if ( nextipage ( f, dp ) )
551     err = msg ( "E2 can't happen (rdpage: can't go to %s page)", 
552                dp ? "next" : "same" ) ;
553   
554   if ( ! err ) {
555
556     yres = f->page->yres ;
557     fVR = ( yres > (196+98)/2 ) ? 1 : 0 ;
558
559     if ( local && yres ) {
560       if ( local [ VR ] != fVR ) {
561         local [ VR ] = fVR ;
562         if ( changed ) *changed = 1 ;
563       } else {
564         if ( changed ) *changed = 0 ;
565       }
566     }
567
568     if ( lastpage ( f ) ) {
569       m = EOP ;
570     } else {
571       PAGE *p = f->page + 1 ;
572       nVR = ( p->yres > (196+98)/2 ) ? 1 : 0  ;
573       m = ( nVR != fVR ) ? EOM : MPS ;
574     }
575
576   }
577
578   if ( ppm ) {
579     *ppm = err ? EOP : m ;
580   }
581
582   return err ;
583 }
584
585
586 /* Terminate previous page if page number is non-zero and start
587    next output page if page number is non-negative. If page is -1
588    removes the most recently opened file. Returns 0 if OK, 2 on
589    errors. */
590
591 #ifndef UCLINUX
592 int wrpage ( OFILE *f, int page )
593 {
594   int err=0 ;
595
596   err = nextopage ( f, page ) ;
597
598   if ( ! err && page == -1 ) {
599     if ( remove ( f->cfname ) ) {
600       err = msg ( "ES2can't delete file %s:", f->cfname ) ; 
601     } else {
602       msg ( "Fremoved %s", f->cfname ) ; 
603     }
604   }
605   
606   return err ;
607 }
608 #endif /* UCLINUX */
609
610
611 /* Send data for one page.  Figures out required padding and 196->98 lpi
612    decimation based on local and session capabilitites, substitutes page
613    numbers in header string and enables serial port flow control.  Inserts
614    the page header before the input file data.  Converts each scan line to
615    T.4 codes and adds padding (FILL) and EOL codes before writing out.
616    Sends RTC when done.  Sends DLE-ETX and returns serial port to command
617    mode when done. Returns 0 if OK, non-0 on errors. */
618
619 static int send_data ( TFILE *mf, IFILE *f, int page, int pages,
620                cap local, cap session
621 #ifndef UCLINUX
622                                  , char *header, faxfont *font
623 #endif /* UCLINUX */
624                                  )
625 {
626   int done=0, err=0, noise=0, nr=0, lastnr=0, line, pixels ;
627   int i, decimate, pwidth, minlen, dcecps, inheader, skip=0 ;
628   uchar buf [ MAXCODES + 2*EOLBITS/8 + 1 ], *p ;
629   short runs [ MAXRUNS ], lastruns [ MAXRUNS ] ;
630 #ifndef UCLINUX
631   char headerbuf [ MAXLINELEN ] ;
632 #endif /* UCLINUX */
633   ENCODER e ;
634
635   newENCODER ( &e ) ;
636
637   dcecps = cps[session[BR]] ;
638   minlen = ( (long)dcecps * mst[session[ST]] - 1500 + 500 ) / 1000 ;
639   pwidth = pagewidth [ session [ WD ] ] ;
640   decimate = local[VR] > session[VR] ;
641
642   msg ( "T padding to %d bytes/scan line.%s", minlen+1, 
643        decimate ? " reducing 196->98 lpi." : "" ) ;
644
645   if ( vfc ) 
646     msg ( "T limiting output to %d bps for %d byte modem buffer", 
647          dcecps*8, MAXDCEBUF + MINWRITE  ) ;
648
649 #ifndef UCLINUX
650   if ( ckfmt ( header, 6 ) )
651     msg ( "W too many %%d escapes in header format string \"%s\"", header ) ;
652   else
653     sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ;
654   msg ("I header:[%s]", headerbuf ) ;
655 #endif /* UCLINUX */
656       
657   done = err = ttymode ( mf, SEND ) ; 
658
659   mf->start = time(0) ;
660   mf->mstart = proc_ms() ;
661   mf->bytes = mf->pad = mf->lines = 0 ;
662
663   /* start T.4 data with some FILL and an EOL */
664
665   for ( i=0 ; i<32 ; i++ )
666     p = putcode ( &e, 0, 8, buf ) ;
667   p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
668
669   if ( ! f || ! f->f ) 
670     err = msg ( "E2can't happen(send_data)" ) ; 
671
672   mf->lines=0 ;
673   for ( line=0 ; ! done && ! err ; line++ ) {
674
675     if ( line < HDRSPCE ) {     /* insert blank lines at the top */
676       runs[0] = pwidth ;
677       pixels = pwidth ;
678       nr = 1 ;
679     } else {
680       if ( ( nr = readline ( f, runs, &pixels ) ) < 0 ) {
681         done = 1 ;
682         continue ;
683       }
684     }
685 #ifndef UCLINUX
686                                 /* generate and OR in header pixels */
687     if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) {
688       int hnr ;
689       short hruns [ MAXRUNS ] ;
690       hnr = texttorun ( (uchar*) headerbuf, font, line-HDRSTRT, 
691                        HDRCHRW, HDRCHRH, HDRSHFT,
692                        hruns, 0 ) ;
693       nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ;
694     }
695 #endif /* UCLINUX */
696     
697     inheader = line < HDRSTRT + HDRCHRH ;
698
699     if ( decimate || ( inheader && local[VR] == 0 ) ) {
700       if ( ++skip & 1 ) {       /* save the first of every 2 lines */
701         memcpy ( lastruns, runs, nr * sizeof(short) ) ;
702         lastnr = nr ;
703         continue ;              /* get next line */
704       } else {                  /* OR previous line into current line */
705         nr = runor ( runs, nr, lastruns, lastnr, 0, &pixels ) ;
706       }
707     }
708
709     if ( nr > 0 ) {
710       if ( pixels ) {
711                                 /* make line the right width */
712         if ( pixels != pwidth ) nr = xpad ( runs, nr, pwidth - pixels ) ;
713                                 /* convert to MH coding */
714         p = runtocode ( &e, runs, nr, p ) ;
715                                 /* zero pad to minimum scan time */
716         while ( p - buf < minlen ) { 
717           p = putcode ( &e, 0, 8, p ) ;
718           mf->pad ++ ;
719         }
720                                 /* add EOL */
721         p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
722         sendbuf ( mf, buf, p - buf, dcecps ) ;
723         mf->bytes += p - buf ;
724         mf->lines++ ;
725       } else {
726         /* probably read an EOL as part of RTC */
727       }
728       if ( tdata ( mf, 0 ) ) noise = 1 ;
729       p = buf ;
730     }
731   }
732
733   for ( i=0 ; i < RTCEOL ; i++ )
734     p = putcode ( &e, EOLCODE, EOLBITS, p ) ;
735   p = putcode ( &e, 0, 0, p ) ;
736   sendbuf ( mf, buf, p - buf, dcecps ) ;
737   mf->bytes += p - buf ;
738   
739   if ( noise ) msg ("W- characters received while sending" ) ;
740
741   return err ;
742 }
743
744
745 static int end_data ( TFILE *mf, cap session, int ppm, int *good )
746 {
747   int err=0, c ;
748   uchar *p ;
749   long dt, draintime ;
750
751   if ( ! ppm ) p = DLE_ETX ;
752   else if ( ppm == MPS ) p = "\020," ; 
753   else if ( ppm == EOM ) p = "\020;" ; 
754   else if ( ppm == EOP ) p = "\020." ; 
755   else {
756     p = "" ;
757     err = msg ( "E2 can't happen (end_data)" ) ;
758   }
759
760   tput ( mf, p, 2 ) ;
761
762   dt = time(0) - mf->start ;
763                                 /* time to drain buffers + 100% + 4s */
764   draintime = ( 2 * ( mf->bytes / cps[ session[BR] ] + 1 - dt ) + 4 ) * 10 ;
765   draintime = draintime < TO_DRAIN_D ? TO_DRAIN_D : draintime ;
766
767   c = ckcmd ( mf, 0, 0, (int) draintime, OK ) ;
768
769   if ( good ) *good = ( c == OK ) ? 1 : 0 ;
770
771   dt = time(0) - mf->start ;
772
773   msg ( "Isent %d+%d lines, %d+%d bytes, %d s  %d bps" , 
774        HDRSPCE, mf->lines-HDRSPCE, 
775        mf->bytes-mf->pad, mf->pad, (int) dt, (mf->bytes*8)/dt ) ;
776
777   if ( mf->bytes / (dt+1) > cps[session[BR]] )
778     msg ( "E flow control did not work" ) ;
779
780   if ( ! err ) err = ttymode ( mf, COMMAND ) ;
781
782   return err ;
783 }
784
785
786 /* Read one scan line from fax device. If pointer pels is not
787    null it is used to save pixel count.  Returns number of runs
788    stored, EOF on RTC, or -2 on EOF, DLE-ETX or other error. */
789
790 #ifndef UCLINUX
791 int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels )
792 {
793   int err=0, c=EOF, x, n ;
794   dtab *tab, *t ;
795   short shift ;
796   short *p, *maxp, *q, len=0 ;
797   uchar rd_state ;
798
799   maxp = ( p = runs ) + MAXRUNS ;
800
801   x = d->x ; shift = d->shift ; tab = d->tab ; /* restore decoder state */
802   rd_state = f->rd_state ;
803
804   do {
805     do {
806       while ( shift < 0 ) { 
807         c = tgetd ( f, TO_CHAR ) ;
808
809         rd_state = ( rd_state & rd_allowed[c] ) ?
810           ( ( rd_state & rd_nexts[c] ) ? rd_state <<= 1 : rd_state ) : 
811           RD_BEGIN ;
812
813         if ( rd_state == RD_END )
814           msg ( "W+ modem response in data" ) ; 
815
816         if ( c < 0 )  {
817           x = ( x << 15 ) | 1 ; shift += 15 ;  /* EOL pad at EOF */
818         } else {
819           x = ( x <<  8 ) | c ; shift +=  8 ; 
820         }
821       }
822       t = tab + ( ( x >> shift ) & 0x1ff ) ;
823       tab = t->next ;
824       shift -= t->bits ;
825     } while ( ! t->code ) ;
826     if ( p < maxp ) *p++ = t->code ;
827   } while ( t->code != -1 ) ;
828
829   d->x = x ; d->shift = shift ; d->tab = tab ; /* save state */
830   f->rd_state = rd_state ;
831
832   if ( p >= maxp ) msg ( "Wrun length buffer overflow" ) ;
833
834   /* combine make-up and terminating codes and remove +1 offset
835      in run lengths */
836
837   n = p - runs - 1 ;
838   for ( p = q = runs ; n-- > 0 ; )
839     if ( *p > 64 && n-- > 0 ) {
840       len += *q++ = p[0] + p[1] - 2 ;
841       p+=2 ;
842     } else {
843       len += *q++ = *p++ - 1 ;
844     }
845   n = q - runs ;
846   
847   /* check for RTC and errors */
848
849   if ( len )
850     d->eolcnt = 0 ;
851   else
852     if ( ++(d->eolcnt) >= RTCEOL ) err = EOF ;
853
854   if ( c < 0 ) err = - 2 ;
855
856   if ( pels ) *pels = len ;
857   
858   return err ? err : n ;
859 }
860
861
862 /* Receive data. Reads scan lines from modem and writes to output
863    file.  Checks for errors by comparing received line width and
864    session line width.  Check that the output file is still OK
865    and if not, send one CANcel character and wait for protocol to
866    complete. Returns 0 if OK or 2 if there was a file write error. */
867
868 int receive_data ( TFILE *mf, OFILE *f, cap session, int *nerr )
869 {
870   int err=0, line, lines, nr, len ;
871   int pwidth = pagewidth [ session [ WD ] ] ;
872   short runs [ MAXRUNS ] ;
873   DECODER d ;
874
875   if ( ! f || ! f->f ) {
876     msg ( "E2 can't happen (writeline)" ) ;
877   } 
878   
879   newDECODER ( &d ) ;
880   *nerr = 0 ;
881
882   lines=0 ; 
883   for ( line=0 ; ( nr = readfaxruns ( mf, &d, runs, &len ) ) >= 0 ; line++ ) {
884     if ( nr > 0 && len > 0 && line ) { /* skip first line+EOL and RTC */
885       if ( len != pwidth ) { 
886         (*nerr)++ ;
887         if ( *nerr <= MAXERRPRT ) msg ("R-+ (%d:%d)", line, len ) ;
888         nr = xpad ( runs, nr, pwidth - len ) ;
889       } 
890       writeline ( f, runs, nr, 1 ) ;
891       lines++ ;
892     }
893     if ( ferror ( f->f ) ) {
894       err = msg ("ES2file write:") ;
895       tput ( mf, CAN_STR, 1 ) ;
896       msg ("Wdata reception CANcelled") ;
897     } 
898   }
899   
900   if ( *nerr ) {
901     if ( *nerr > MAXERRPRT ) msg ("R-+ ....." ) ;
902     msg ("R-  : reception errors" ) ;
903     msg ("W- %d reception errors", *nerr ) ;
904   }
905
906   if ( nr == EOF )
907     while ( tgetd ( mf, TO_CHAR ) >= 0 ) ; /* got RTC, wait for DLE-ETX */
908
909   msg ( "I- received %d lines, %d errors", lines, *nerr ) ;
910
911   return err ;
912 }
913
914
915 /* Send training check sequence of n zeroes.  Returns 0 or 2 on error. */
916
917 int puttrain ( TFILE *f, char *s, int n  )
918 {
919   int i, m, err=0 ;
920   uchar buf [ MINWRITE ] = { 0 } ;
921
922   ckcmd ( f, &err, s, TO_FT, CONNECT ) ;
923   
924   if ( ! err ) {
925     ttymode ( f, SEND ) ;
926
927     for ( i=0 ; i < n ; i += m ) {
928       m = n-i < MINWRITE ? n-i : MINWRITE ;
929       sendbuf ( f, buf, m, 0 ) ;
930     }
931
932     buf[0] = 1 ;                /* make sure last byte is non-zero */
933     buf[1] = DLE ;
934     buf[2] = ETX ;
935     sendbuf ( f, buf, 3, 0 ) ;
936
937     ttymode ( f, COMMAND ) ;
938
939     ckcmd ( f, &err, 0, TO_DRAIN_D, OK ) ;
940     msg ( "I- sent TCF - channel check of %d bytes", n ) ;
941   }
942   
943   return err ;
944 }
945
946
947 /* Checks for an error-free run of at least n bytes in the
948    received training check sequence. Sets good if it's not null,
949    the run was long enough and there were no errors. Returns 0 or
950    3 on other errors.  */
951
952 int gettrain ( TFILE *f, char *s, int n, int *good ) 
953
954   int err=0, c, i=0, maxrunl=0, runl=0 ;
955   
956   ckcmd ( f, &err, s, T2, CONNECT ) ;
957   
958   if ( ! err ) {
959
960     for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ )
961       if ( c ) {
962         if ( runl > maxrunl ) maxrunl = runl ;
963         runl = 0 ;
964       } else {
965         runl ++ ;
966       }
967     
968     if ( c == EOF )
969       err = msg ( "E3timed out during training check data" ) ;
970     else
971       ckcmd ( f, &err, 0, TO_RTCMD, NO ) ;
972     
973   }
974      
975   if ( runl > maxrunl ) maxrunl = runl ;
976      
977   if ( good ) *good = !err && maxrunl > n ;
978
979   if ( !err ) {
980     msg ( "I- received TCF - channel check (%sOK: run of %d in %d)", 
981          maxrunl > n ? "" : "not ", maxrunl, i ) ;
982   }
983
984   return err ;
985 }
986
987
988 /* Log a sent/received HDLC frame.  Display of these messages is delayed to
989    avoid possible timing problems. */
990
991 void logfr ( char *s , char *nm , uchar *p , int n )
992 {
993   int i=0 ;
994   msg ( n > 10 ? "H- %s %d bytes:" : "H-+ %s %d bytes:" , s, n ) ;
995   for ( i=0 ; i<n ; i++ ) {
996     msg ( "H-+  %02x" , p[i] & 0xff ) ;
997     if ( ( i&0xf ) == 0xf && i != n-1 ) msg ( "H-" ) ;
998   }
999   msg ( "H-" ) ;
1000   msg ( "I- %s %s", s, nm ) ;
1001 }
1002 #endif /* UCLINUX */
1003
1004
1005 /* Send HDLC control frame of type type.  Extra bits can be OR'ed
1006    into the frame type (FCF) to indicate that this frame follows
1007    a previous one (no +FTH required) and/or that more frames will
1008    follow.  Sets up flag, address, and fax control field bytes in
1009    `buf'.  Sends these plus `len` additional bytes.  Terminates
1010    with DLE-ETX and checks response.  Returns 0 if OK, 2 or 3 on
1011    error. */
1012
1013 #define MORE_FR  0x100 
1014 #define SUB_FR   0x200 
1015
1016 static int nframes = 0 ;                /* counts frames sent/received */
1017
1018 #ifndef UCLINUX
1019 int putframe ( int type, uchar *buf, int len, TFILE *f, int t )
1020 {
1021   int err=0 ;
1022
1023   buf [ 0 ] = 0xff ;
1024   buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ;
1025   buf [ 2 ] = type & 0xff ;
1026
1027   if ( nframes++ && ! ( type & SUB_FR ) )
1028     ckcmd ( f, &err, "+FTH=3" , TO_FT, CONNECT ) ;
1029   
1030   if ( ! err ) {
1031
1032     if ( ! buf[len+2] ) {
1033       msg ( "Wlast byte of frame is NULL" ) ;
1034     }
1035
1036     /* ttymode ( f, SEND ) ; */
1037     sendbuf ( f, buf, len+3, 0 ) ;
1038     tput ( f, DLE_ETX, 2 ) ; 
1039     /* ttymode ( f, COMMAND ) ; */
1040
1041     logfr ( "sent", frname ( buf [ 2 ] ), buf, len+3 ) ;
1042
1043     ckcmd ( f, &err, 0, TO_DRAIN_H, ( type & MORE_FR ) ? CONNECT : OK ) ;
1044   }
1045
1046   return err ;
1047 }
1048
1049
1050 /* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */
1051
1052 void revcpy ( uchar *from , uchar *to )
1053 {
1054   int i, j ;
1055   for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- ) 
1056     to [ i ] = normalbits [ from [ j ] & 0xff ] ;
1057 }
1058
1059
1060 /* Check for missing initial 0xFF in HDLC frame and insert it if
1061    missing.  Ugly fix for a still-hidden bug.  Also do bit
1062    inversion if required. */
1063
1064 int fixframe ( uchar *buf, int n, TFILE *f )
1065 {
1066   int i;
1067
1068   if ( *buf == 0xc0 || *buf == 0xc8 ) {
1069     for ( i=n; i >= 1 ; i-- ) 
1070       buf[i]=buf[i-1] ;
1071     buf[i] = 0xff ;
1072     msg ("W HDLC frame missing initial 0xff" ) ;
1073     n++ ;
1074   }
1075
1076   if ( buf[1] == 0x03 || buf[1] == 0x13 ) {
1077     for ( i=0 ; i < n ; i++ ) 
1078       buf[i]=normalbits[buf[i]] ;
1079     msg ("W bit-reversed HDLC frame, reversing bit order" ) ;
1080     f->ibitorder = f->ibitorder == normalbits ? reversebits : normalbits ;
1081   }
1082
1083   return n ;
1084 }
1085
1086
1087 /* Read HDLC frame data.  Returns 0 if OK, 1 on frame error, 3 on
1088    timeout, invalid response or too-long frame. */
1089
1090 int receive_frame_data ( TFILE *f, uchar *buf, int n, int *len )
1091 {
1092   int err=0, c, i ;
1093
1094   for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0  ; i++ )
1095     if ( i < n ) buf[ i ] = c ;
1096   
1097   if ( c == EOF ) {
1098
1099     err = msg ( "E3timed out reading frame data" ) ;
1100
1101   } else {
1102     
1103     switch ( cmd ( f, 0, TO_RTCMD ) ) {
1104     case OK:
1105     case CONNECT:
1106       break ;
1107     case ERROR:
1108     case NO:
1109       err = msg ( "W1frame error" ) ;
1110       break ;
1111     case EOF:
1112       err = msg ( "E3no response after frame data" ) ;
1113       break ;
1114     default:
1115       err = msg ( "E3wrong response after frame data" ) ;
1116       break ;
1117     }
1118
1119   }
1120
1121   if ( i >= n ) 
1122     err = msg ( "E3frame too long (%d, > %d max bytes)", i, n ) ;
1123   
1124   if ( len ) *len = i ;
1125
1126   return err ;
1127 }
1128 #endif /* UCLINUX */
1129
1130
1131 /* Get a Class 1 command or response frame.  An attempt to match
1132    and combine T.30 "Response Received?" and "Command Received?"
1133    protocol flowcharts.
1134
1135    When receiving commands returns after first correct
1136    non-optional frame or after the time given by getcmd has
1137    elapsed.  This is instead of looping through main flowchart.
1138
1139    When receiving responses returns on the first detected
1140    non-optional frame, after timeout T4, or on errors.
1141
1142    Returns immediately if gets a +FCERROR response so can retry
1143    as data carrier.  Returns DCN as a valid frame instead of
1144    hanging up.
1145
1146    Returns the command/response received, or EOF on timeout or
1147    error.
1148  
1149 */
1150
1151 #ifndef UCLINUX
1152 int getfr ( TFILE *mf, uchar *buf, int getcmd )
1153 {
1154   int err=0, frame=0, frlen, c, t ;
1155   char remoteid [ IDLEN + 1 ] ;
1156   time_t start ;
1157   uchar *fif=buf+3 ;
1158   
1159   start = 10*time(0) ;
1160   
1161   t = getcmd ? ( getcmd > 1 ? getcmd : T2 ) : T4 ;
1162
1163  Enter:
1164
1165   err = 0 ;
1166
1167   if ( nframes++ ) {
1168     c = cmd ( mf, "+FRH=3", t ) ;
1169   } else {
1170     c = CONNECT ;               /* implied by ATA or ATD */
1171   }
1172   
1173   switch ( c ) {
1174   case EOF:                     /* time out */
1175     tput ( mf, CAN_STR, 1 ) ;
1176     ckcmd ( mf, 0, 0, TO_ABRT, OK ) ;
1177     err = 1 ;
1178     break ;
1179   case NO:                      /* S7 time out */
1180     err = 1 ;
1181     break ;
1182   case MODULATION:              /* data carrier (or DHS) */
1183     return -msg ( "W-2 wrong carrier" ) ;
1184     break ;
1185   case CONNECT:                 /* frame */
1186     break ;
1187   default:                      /* shouldn't happen */
1188     err = msg ( "E3wrong response to receive-frame command" ) ;
1189     break ;
1190   }
1191   
1192   if ( ! err ) 
1193     err = receive_frame_data ( mf, buf, MAXFRLEN, &frlen ) ;
1194   
1195   if ( ! err && frlen < 3 ) 
1196     err = msg ( "E3received short frame (%d bytes)", frlen ) ;
1197
1198   if ( ! err ) {
1199
1200     frlen = fixframe ( buf, frlen, mf ) ;
1201     logfr ( "received", frname ( buf [ 2 ] ), buf, frlen ) ;
1202     frame = buf [ 2 ] & 0x7f ;
1203
1204     switch ( frame ) {
1205     case CRP:
1206       err = 1 ;
1207     case NSF:
1208     case NSC:
1209     case NSS:
1210       goto Enter ;
1211     case CIG:
1212     case CSI:
1213     case TSI:
1214       revcpy ( fif , (uchar*) remoteid ) ;
1215       msg ( "I- remote ID -> %*.*s", IDLEN, IDLEN, remoteid ) ;
1216       goto Enter ;
1217     }
1218
1219   }
1220   
1221   if ( err && getcmd && ( t -= 10*time(0) - start ) > 0 ) 
1222     goto Enter ;
1223
1224   return err ? EOF : frame ;
1225 }
1226
1227
1228 /* Class 1 send/receive.  
1229
1230   The logic in this function is a mess because it's meant to
1231   mirror the flowchart in ITU-T recommendation T.30 which is the
1232   protocol specification.
1233
1234   */
1235
1236 int c1sndrcv ( 
1237               TFILE *mf, cap local, char *localid, 
1238               OFILE *outf, IFILE *inf, 
1239               int pages, char *header, faxfont *font, 
1240               int maxpgerr, int noretry, int calling )
1241
1242   int err=0, rxpage=0, page=1, t, disbit, good, frame, last, nerr ;
1243   int rxdislen, ppm, try=0, pagetry=0, retry=0, remtx=0, remrx=0 ;
1244   int writepending=0, dp=0 ;
1245   cap remote = { DEFCAP }, session = { DEFCAP } ;
1246   char *fname=0 ;
1247   uchar buf [ MAXFRLEN ], *fif=buf+3 ;
1248
1249   if ( ! calling ) goto RX ;
1250
1251   /* Class 1 Transmitter: */
1252
1253  T:  /* Transmitter Phase B - wait for DIS or DTC */
1254
1255   pagetry = 0 ;
1256   
1257   frame = getfr ( mf, buf, T1 ) ;
1258   
1259   if ( frame <= 0 ) {
1260     err = msg ( "E3no answer from remote fax" ) ;
1261     goto B ;
1262   }
1263   
1264   if ( frame != DIS && frame != DTC ) {
1265     msg ( "W2 can't open page" ) ;
1266     goto C ;
1267   }
1268
1269   disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1270   try = 0 ;
1271
1272  A:                             /* decide to send or receive after DIS/DTC */
1273
1274   if ( frame == DIS || frame == DTC ) {
1275     rxdislen = dislen ( fif ) ;
1276     mkcap ( fif, remote, 1 ) ;
1277     remtx = fif[1] & 0x80 ;
1278     remrx = fif[1] & 0x40 ;
1279   }
1280
1281   msg ( "N remote has %sdocument(s) to send, and can %sreceive",
1282        remtx ? "" : "no ", remrx ? "" : "not " ) ;
1283
1284   if ( pages > 0 ) {
1285     if ( ! remrx ) msg ( "W remote cannot receive, trying anyways" ) ; 
1286     goto D ;
1287   } else {
1288     if ( ! remtx ) msg ( "W remote has nothing to send, trying anyways" )  ; 
1289     goto R ;
1290   }
1291
1292  D:                             /* send DCS */
1293
1294   if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1295     err = msg ( "E2can't open page" ) ;
1296     goto B ;
1297   }
1298
1299  D_2:
1300
1301   mincap ( local, remote, session ) ;
1302
1303   revcpy ( (uchar*) localid, fif ) ;
1304   if ( ! err ) 
1305     err = putframe ( TSI | MORE_FR | disbit, buf, IDLEN, mf, -1 ) ;  
1306
1307   mkdis ( session, fif, DCSLEN, 0, pages ) ;
1308   if ( ! err ) 
1309     err = putframe ( DCS | SUB_FR | disbit, buf, DCSLEN, mf, -1 ) ;
1310
1311   if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1312     msleep ( TMOD ) ;           /* if +FTS not supported */
1313
1314   if ( ! err ) 
1315     err = puttrain ( mf, c1cmd[SND][TRN][session[BR]], 
1316                     1.5*cps [ session[BR] ] ) ;
1317   try++ ;
1318
1319   if ( ! err ) {
1320     cmd ( mf, "+FRS=1", T3S ) ; /* wait for TCF carrier to drop */
1321     frame = getfr ( mf, buf, 0 ) ;
1322   }
1323
1324   if ( err || frame < 0 ) {
1325     if ( try >= 3 ) {
1326       goto C_timeout ;
1327     } else { 
1328       goto D_2 ;
1329     }
1330   }
1331   
1332   switch ( frame ) {
1333
1334   case DIS:
1335   case DTC:
1336     if ( try >= 3 ) goto C_timeout ;
1337     else goto A ;
1338
1339   case FTT:
1340     msg ( "I channel not usable at %d bps", 8*cps[session[BR]] ) ;
1341     remote[BR] = fallback[session[BR]] ;
1342     if ( remote[BR] >= 0 ) goto D_2 ;
1343     else { err = msg ( "E2 channel not usable at lowest speed" ) ; goto C ; }
1344
1345   case CFR:
1346     goto I_2 ;
1347
1348   default:
1349     err = msg ( "E3 invalid response to DCS (0x%02x)", frame ) ;
1350     goto C ;
1351   }    
1352
1353  I:                             /* send a page */
1354
1355   if ( rdpage ( inf, dp, &ppm, local, 0 ) ) {
1356     err = msg ( "E2can't open page" ) ;
1357     goto B ;
1358   }
1359
1360  I_2:
1361
1362   ckcmd ( mf, &err, c1cmd [SND][DTA][session[BR]], TO_FT, CONNECT ) ;
1363   if ( !err )
1364     err = send_data ( mf, inf, page, pages, local, session, header, font ) ;
1365
1366   pagetry++ ;
1367
1368   if ( !err )
1369     err = end_data ( mf, session, 0, 0 ) ;
1370   
1371   if ( cmd ( mf, "+FTS=8", T3S ) != OK )
1372     msleep ( TMOD ) ;           /* if +FTS not supported */
1373
1374                                 /* fix ppm if on last page of stdin */
1375   if ( lastpage ( inf ) ) ppm = EOP ;
1376
1377   try = 0 ;
1378  sendppm:
1379   if ( !err ) err = putframe ( ppm | disbit, buf, 0, mf, -1 ) ;
1380   try++ ;
1381   
1382   frame = getfr ( mf, buf, 0 ) ;
1383   if ( frame < 0 ) {
1384     if ( try >= 3 ) {
1385       goto C_timeout ;
1386     } else { 
1387       goto sendppm ;
1388     }
1389   }
1390
1391   fname = inf->page->fname ;
1392
1393   switch ( noretry ? MCF : frame ) { /* common retry logic */
1394   case MCF:
1395   case RTP:
1396   case PIP:
1397     fname = inf->page->fname ;
1398     if ( fname ) msg ( "Isent -> %s", fname ) ;
1399     pagetry=0 ;
1400     page++ ;
1401     dp = 1 ;
1402     break ;
1403   case PIN:
1404   case RTN:
1405     dp = 0 ;
1406     retry = pagetry < NTXRETRY ;
1407     break ;
1408   default:  
1409     err = msg ( "E3invalid post-page response (0x%02x)", frame ) ;
1410     goto C ;
1411   }
1412   
1413   switch ( ppm ) {
1414     
1415   case MPS:
1416     switch ( frame ) {
1417     case PIN: goto E ;
1418     case PIP: goto E ;
1419     case MCF: goto I ;
1420     case RTP: goto D ;
1421     case RTN: goto D ;
1422     }
1423
1424   case EOP:
1425     switch ( frame ) {
1426     case PIN: goto E ;
1427     case PIP: goto E ;
1428     case MCF: 
1429     case RTP: 
1430       nextipage ( inf, 1 ) ;    /* skip ahead to mark all files done */
1431       if ( remtx ) goto R ;     /* poll after sending */
1432       else goto C ;
1433     case RTN: 
1434       if ( retry ) goto D ;
1435       else goto C ;
1436     }
1437     
1438   case EOM:
1439     switch ( frame ) {
1440     case PIN: goto E ;
1441     case PIP: goto E ;
1442     case MCF: 
1443     case RTP: 
1444     case RTN: 
1445       cmd ( mf, "+FRS=20", T3S ) ; /* wait for ppr carrier to drop */
1446       if ( retry ) goto T ;
1447       else goto T ;
1448     }
1449     
1450   }  
1451
1452  E:                             /* ignore PIN and PIP */
1453   msg ( "W interrupt request ignored" ) ;
1454   try=0 ;
1455   goto A ;
1456
1457   /* Class 1 Receiver */
1458
1459  RX:
1460
1461  R:  /* Receiver Phase B */
1462
1463   if ( ! err ) err = wrpage ( outf, rxpage ) ;
1464
1465   disbit=0x00 ;
1466
1467   for ( t=0 ; !err && t<T1 ; t+=T2+10 ) {
1468
1469     revcpy ( (uchar*) localid, fif ) ;
1470     if ( !err ) 
1471       err = putframe ( CSI | disbit | MORE_FR, buf, IDLEN, mf, -1 ) ;
1472     
1473     mkdis ( local, fif, DEFDISLEN, 1, pages ) ;
1474     if ( !err ) 
1475       err = putframe ( DIS | disbit | SUB_FR, buf, DEFDISLEN, mf, -1 ) ;
1476
1477     frame = getfr ( mf, buf, 0 ) ;
1478
1479     if ( frame > 0 ) {
1480       disbit = ( frame == DIS ) ? 0x80 : 0x00 ;
1481       goto F_2 ;
1482     }
1483   }
1484   if ( err ) goto C ;
1485   else goto C_timeout ;
1486   
1487
1488  F:  /* get a command */
1489
1490   last = frame ;
1491   frame = getfr ( mf, buf, 1 ) ;
1492
1493   if ( writepending ) {         /* do postponed file close/open */
1494     writepending=0 ;
1495     err = wrpage ( outf, rxpage ) ;
1496     if ( err ) goto C ;
1497   }
1498
1499   if ( frame < 0 ) {
1500     if ( frame == -2 ) goto getdata ; /* data carrier detected */
1501     if ( last == EOM ) goto R ; 
1502     else { err = msg ("E3 timed out waiting for command" ) ; goto B ; }
1503   }
1504   
1505  F_2:
1506
1507   switch ( frame ) {
1508
1509   case DTC:
1510     goto D ;
1511
1512   case DIS:
1513     try=0 ;
1514     goto A ;
1515     
1516   case DCS: 
1517     mkcap ( fif, session, 0 ) ;
1518     printcap ( "session", session ) ;
1519     
1520     cmd ( mf, "+FTS=1", T3S ) ; /* make sure DCS is over */
1521
1522     gettrain ( mf, c1cmd [RCV][TRN][session[BR]], cps[session[BR]], &good ) ;
1523
1524     if ( putframe ( ( good ? CFR : FTT ) | disbit, buf, 0, mf, -1 ) ||
1525         ! good ) goto F ;
1526
1527   getdata:
1528     
1529     outf->w=pagewidth[session[WD]];
1530     outf->h=0;
1531     outf->xres=204.0;
1532     outf->yres=vresolution[session[VR]];
1533     
1534     if ( cmd ( mf, c1cmd [RCV][DTA][session[BR]], TO_FT ) != CONNECT ) 
1535       goto F ;                  /* +FCERROR -> DCS resent */
1536     
1537     if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1538       good = nerr < maxpgerr ;
1539       msg ( "I-received -> %s", outf->cfname ) ;
1540       writepending=1 ;          /* ppm follows immediately, don't write yet */
1541       rxpage++ ;
1542     } else {
1543       good = 0 ;
1544     }
1545     ckcmd ( mf, 0, 0, TO_RTCMD, NO ) ;
1546     goto F ;
1547
1548     /* III: */
1549
1550   case PRI_EOM:
1551   case PRI_MPS:
1552   case PRI_EOP:
1553     frame &=0xf7 ;              /* ignore PRocedure Interrupt bit */
1554   case MPS:
1555   case EOP:
1556   case EOM:
1557     putframe ( ( good ? MCF : RTN ) | disbit, buf, 0, mf, -1 ) ;
1558     if ( good && frame == MPS ) goto getdata ;
1559     else goto F ;
1560     
1561   case DCN:
1562     goto B ;
1563     
1564   default:
1565     err = msg ( "E3 unrecognized command" ) ;
1566     goto B ;
1567
1568   }
1569
1570  C_timeout:
1571   err = msg ( "E3 no command/response from remote" ) ;
1572
1573  C:
1574   putframe ( DCN, buf, 0, mf, -1 ) ;
1575
1576  B:
1577   ckcmd ( mf, 0, "H", TO_RESET, OK ) ;  /* hang up */
1578
1579   if ( rxpage > 0 ) 
1580     wrpage ( outf, -1 ) ;       /* remove last file */
1581
1582   return err ;
1583 }
1584 #endif /* UCLINUX */
1585
1586
1587 /* Check for hangup message.  Assumes hsc is initialized to a
1588    negative value.  Returns 0 if no hangup message, 1 if there
1589    was one.  If perr is not null, sets it to 2 if the hsc was
1590    non-zero (error). */
1591
1592 static int gethsc ( int *hsc, int *perr )
1593 {
1594   int err=0, i ;
1595   if ( sresponse ( "+FHNG:", hsc ) || sresponse ( "+FHS:", hsc ) ) {
1596     if ( hsc && *hsc > 0 ) {
1597       err = msg ( "E2abnormal termination (code %d)", *hsc ) ;
1598       for ( i=0 ; c2msg[i].min >= 0 ; i++ ) {
1599         if ( *hsc >= c2msg[i].min && *hsc <= c2msg[i].max ) {
1600           msg ( "E %s", c2msg[i].msg ) ;
1601         }
1602       }
1603       if ( perr && ! *perr ) {
1604         *perr = 2 ;
1605       }
1606     } else {
1607       err = 1 ;
1608     }
1609   }
1610   return err ;
1611 }
1612
1613
1614 /* Print remote ID and store DCS values in session as per
1615    responses since last command. */
1616
1617 static void getc2dcs ( cap session )
1618 {
1619   char *p ;
1620   if ( ( p = sresponse ( "+FTI:",  0 ) ) != 0 ||  
1621        ( p =  sresponse ( "+FTSI:", 0 ) ) != 0 ) {
1622     msg ( "I- remote ID -> %s", p ) ;
1623   }
1624   if ( ( p = sresponse ( "+FCS:", 0 ) ) != 0 || 
1625       ( p = sresponse ( "+FDCS:", 0 ) ) != 0 ) {
1626     str2cap ( p, session ) ;
1627     printcap ( "session", session ) ;
1628   }
1629 }  
1630
1631 /* Wait for a starting character XON or DC2.  Display & ignore
1632    any other characters received. */
1633
1634 static void getstartc ( TFILE *mf )
1635 {
1636   int c, noise ;
1637   
1638   for ( noise=0 ; ( c = tgetc ( mf, TO_C2X ) ) != XON && c != DC2 ; noise++ ) {
1639     if ( c == EOF ) {
1640       msg ( "Wno XON/DC2 received after CONNECT") ;
1641       break ;
1642     } else { 
1643       msg ( "W-+%s", cname ( c ) ) ; 
1644       noise++ ; 
1645     }
1646   }
1647   
1648   if ( noise )
1649     msg ( "W  : %d characters received while waiting to send", noise ) ;
1650 }  
1651
1652
1653 /* Class 2 send and receive.  
1654
1655    If calling, polls if no files to send, otherwise sends.  If
1656    not calling sends documents if files to send, else receives.
1657
1658    When sending, issues +FDIS to change session parameters if
1659    file format changes, then sends +FDT followed by data and a
1660    post-page message determined by format of next page, if any.
1661    Retransmits each page up to NTXRETRY times.
1662
1663    When receiving extracts file format from responses to +FDR or
1664    ATA and saves them in the file. Receives data to a file and
1665    sets page transfer status if too many errors.
1666
1667    Returns 0 if OK or 2 on errors.  */
1668
1669
1670 static int c2sndrcv (
1671               TFILE *mf, cap local, char *localid, 
1672               OFILE *outf, IFILE *inf, 
1673               int pages,
1674 #ifndef UCLINUX
1675                                 char *header, faxfont *font, 
1676 #endif /* UCLINUX */
1677               int maxpgerr, int noretry, int calling )
1678 {
1679 #ifndef UCLINUX
1680   int c, nerr;
1681 #endif /* UCLINUX */
1682   int err=0, done=0, page, pagetry, dp=0 ;
1683   int ppm=0, good, hsc, changed ;
1684   int remtx=0 ;
1685   char *fname=0 ;
1686   cap session = { 0,0,0,0, 0,0,0,0 } ;
1687   char buf [ CMDBUFSIZE ] ;
1688
1689   hsc=-1 ;                      /* will be set >= 0 on hangup */
1690
1691   if ( sresponse ( "+FPO", 0 ) ) {
1692     remtx = 1 ;
1693     msg ( "N remote has document(s) to send." ) ;
1694   }
1695
1696   if ( calling ) {
1697 #ifndef UCLINUX
1698     if ( pages )
1699 #endif /* UCLINUX */
1700       goto send ;
1701 #ifndef UCLINUX
1702     else goto poll ;
1703 #endif /* UCLINUX */
1704   }
1705 #ifndef UCLINUX
1706   else {
1707     if ( pages ) goto pollserver ;
1708     else goto receive ;
1709   }
1710 #endif /* UCLINUX */
1711
1712   /* Class 2 Send */
1713
1714 #ifndef UCLINUX
1715  pollserver:
1716 #endif /* UCLINUX */
1717
1718   /* with +FLP[L]=1 the modem should accept +FDT. */
1719
1720  send:
1721   
1722   page=1 ;
1723   
1724   pagetry=0 ;
1725   while ( ! err && ! done ) {
1726
1727     err = rdpage ( inf, dp, &ppm, local, &changed ) ;
1728
1729     if ( ! err && changed ) {
1730       sprintf ( buf, c20 ? "+FIS=%d,%d,%d,%d" : "+FDIS=%d,%d,%d,%d", 
1731                local[0], local[1], local[2], local[3] ) ;
1732       ckcmd ( mf, 0, buf, TO_FT, OK ) ;
1733       if ( gethsc ( &hsc, &err ) ) {
1734         continue ;
1735       }
1736     }
1737     
1738     ckcmd ( mf, &err, "+FDT", -TO_C2B, CONNECT ) ;
1739     if ( err || gethsc ( &hsc, &err ) ) { 
1740       done=1 ; 
1741       continue ; 
1742     }
1743
1744     getc2dcs ( session ) ; 
1745
1746     if ( ! c20 ) getstartc ( mf ) ;
1747
1748     send_data ( mf, inf, page, pages, local, session
1749 #ifndef UCLINUX
1750                                 , header, font
1751 #endif /* UCLINUX */
1752                                 ) ;
1753     pagetry++ ;
1754
1755     if ( c20 ) {
1756       end_data ( mf, session, ppm, &good ) ;
1757     } else {
1758       end_data ( mf, session, 0, 0 ) ;
1759
1760       gethsc ( &hsc, &err ) ;
1761
1762       if ( ! err && hsc < 0 ) {
1763         ckcmd ( mf, &err, ppm == EOP ? "+FET=2" : 
1764                ppm == EOM ? "+FET=1" : "+FET=0" , TO_C2PP, OK ) ;
1765       }
1766
1767       gethsc ( &hsc, &err ) ;
1768
1769       if ( ! err && hsc < 0 ) {
1770         if ( sresponse ( "+FPTS:", &good ) ) {
1771           good &= 1 ;           /* odd values mean received OK */
1772         } else {                        /* no +FPTS and +FHNG probably NG */
1773           good = gethsc ( 0, 0 ) ? 0 :  
1774             msg ( "W1no +FPTS response, assumed received" ) ;
1775         }
1776       }
1777
1778     }
1779     
1780     if ( noretry ) good = 1;
1781     
1782     if ( good ) {
1783       fname = inf->page->fname ;
1784       if ( fname ) msg ( "Isent -> %s", fname ) ;
1785       pagetry=0 ;
1786       page++ ;
1787       dp = 1 ;
1788       if ( ppm == EOP ) {
1789         nextipage ( inf, 1 ) ;  /* skip ahead to mark all files done */
1790         done = 1 ;
1791       }
1792     } else {
1793       dp = 0 ;
1794       if ( pagetry >= NTXRETRY )
1795         err = msg ( "E2too many page send retries" ) ;
1796     }
1797
1798     if ( gethsc ( &hsc, &err ) )  done=1 ;
1799
1800     if ( good && lastpage ( inf ) ) {
1801       done = 1 ;
1802     }
1803   }
1804
1805   goto done ;
1806
1807 #ifndef UCLINUX
1808   /* Class 2 Receive */
1809
1810  poll:
1811
1812   /* with +FSP[L]=1 and +FPO[LL]: the modem should now accept +FDR. */
1813
1814  receive:
1815
1816   getc2dcs ( session ) ;        /* get ATA responses */
1817
1818   done=0 ;
1819   for ( page=0 ; ! err && ! done ; page++ ) {
1820
1821     if ( ! ( err = wrpage ( outf, page ) ) ) {
1822       c = cmd ( mf, "+FDR", -TO_C2R ) ;
1823
1824       switch ( c ) {
1825
1826       case CONNECT:
1827         getc2dcs ( session ) ; 
1828
1829         outf->w=pagewidth[session[WD]];
1830         outf->h=0;
1831         outf->xres=204.0;
1832         outf->yres=vresolution[session[VR]];
1833         
1834         tput ( mf, &startchar, 1 ) ;
1835
1836         if ( receive_data ( mf, outf, session, &nerr ) == 0 ) {
1837           good = nerr < maxpgerr ;
1838           msg ( "I-received -> %s", outf->cfname ) ;
1839         } else { 
1840           good = 0 ;
1841         }
1842         
1843         ckcmd ( mf, &err, 0, TO_C2EOR, OK ) ;
1844
1845         if ( err || gethsc ( &hsc, &err ) )  { 
1846           wrpage ( outf, +1 ) ;
1847           wrpage ( outf, -1 ) ;
1848           done=1 ; 
1849           continue ; 
1850         }
1851         
1852         if ( ! good ) {
1853           msg ( "Wreception errors" ) ;
1854           ckcmd ( mf, 0, c20 ? "+FPS=2" : "+FPTS=2",  T3S, OK ) ;
1855           if ( gethsc ( &hsc, &err ) ) continue ;
1856         }
1857         break ;
1858
1859       case OK:
1860         wrpage ( outf, -1 ) ;   /* no more pages */
1861         done=1 ;
1862         if ( gethsc ( &hsc, &err ) ) continue ;
1863         break ;
1864
1865       default:
1866         wrpage ( outf, -1 ) ;   /* oops */
1867         err = msg ( "E3receive (+FDR) command failed") ;
1868         break ;
1869       }
1870     }
1871   } 
1872 #endif /* UCLINUX */
1873
1874   
1875  done:
1876   if ( hsc < 0 ) ckcmd ( mf, 0, c20 ? "+FKS" : "+FK", TO_RESET, OK ) ;
1877
1878   return err ;
1879 }
1880
1881
1882 /* Dial the phone number given by string s.  If nowait is true
1883    adds a ';' to the dial string to avoid waiting for a
1884    CONNECTion (might allow ersatz polling).  Also resets the
1885    global "nframes" if appropriate so getfr() and putframe() know
1886    not to issue +FRH/+FTH. Returns 0 if dialed OK, 1 if busy, 2
1887    on errors.  */
1888
1889 static int dial ( TFILE *f, char *s, int nowait )
1890 {
1891   int err=0, hsc=-1 ;
1892   char c, dsbuf [ 128 ], *p ;
1893
1894   sprintf ( dsbuf, nowait ? "D%.126s;" : "D%.127s" , s ) ;
1895   msg ( "Idialing %s", dsbuf+1 ) ;
1896
1897   c = cmd ( f, dsbuf, TO_A ) ;
1898
1899   if ( ( p = sresponse ( "+FCSI:", 0 ) ) != 0 ||
1900        ( p =  sresponse ( "+FCI:", 0 ) ) != 0 ) {
1901     msg ( "I- remote ID -> %s", p ) ;
1902   }
1903
1904   if ( nowait && c == OK ) {
1905     msg ( "Icalled" ) ;
1906     nframes = 1 ;
1907   } else if ( c1 && c == CONNECT ) {
1908     msg ( "Iconnected" ) ; 
1909     nframes = 0 ;
1910   } else if ( !c1 && c == OK ) {
1911     msg ( "Iconnected" ) ; 
1912   } else if ( c ==  BUSY ) {
1913     err = msg ( "W1number is busy" ) ; 
1914   } else {
1915     err = msg ( "E2dial command failed" ) ;
1916   }
1917
1918   gethsc ( &hsc, err ? 0 : &err ) ;
1919
1920   return err ;
1921 }
1922
1923
1924 /* Figure out which mode the modem answered in (fax, data, voice
1925    or none) based on modem class and responses to the previous
1926    command.  Sets crate (connect rate) for DATAMODE and hsc
1927    (hangup status code) if detects a class 2 hangup message. */
1928
1929 enum connectmode { NONE, DATAMODE, FAXMODE, VOICEMODE } ; 
1930
1931 #ifndef UCLINUX
1932 enum connectmode ansmode ( int *crate, int *hsc )
1933 {
1934   enum connectmode mode = NONE ;
1935   int x=0 ;
1936
1937   if ( c1 && sresponse ( "CONNECT", &x ) ) {
1938     mode = x ? DATAMODE : FAXMODE ;
1939   }
1940
1941   if ( !c1 && sresponse ( "OK", 0 ) ) {
1942     mode = FAXMODE ;
1943   } 
1944
1945   if ( !c1 && ( sresponse ( "CONNECT", &x ) || sresponse ( "+FDM", 0 ) ) ) {
1946     mode = DATAMODE ;
1947   } 
1948
1949   if ( sresponse ( "DATA", 0 ) || sresponse ( "CONNECT DATA", 0 ) ) {
1950     mode = DATAMODE ;
1951     sresponse ( "CONNECT", &x ) ;
1952   }
1953
1954   if ( sresponse ( "FAX", 0 ) || sresponse ( "+FCO", 0 ) ) {
1955     mode = FAXMODE ;
1956   }
1957
1958   if ( sresponse ( "VCON", 0 ) ) {
1959     mode = VOICEMODE ;
1960   }
1961   
1962   if ( gethsc ( hsc, 0 ) ) {
1963     mode = NONE ;
1964   }
1965
1966   if ( DATAMODE && x ) *crate = x ;
1967
1968   return mode ;
1969 }
1970 #endif /* UCLINUX */
1971
1972
1973 /* Answer the phone.  Remove our lock if sharing device with
1974    outgoing calls.  If waiting for call, wait for modem activity,
1975    else answer phone.  Figure out what mode we answered in and
1976    handle call appropriately.  Re-lock if necessary. Exec *getty
1977    or *vcmd for data or voice calls. */
1978
1979 #ifndef UCLINUX
1980 int answer ( TFILE *f, char **lkfile, 
1981             int wait, int share, int softaa, 
1982             char *getty, char *vcmd, char *acmd )
1983 {
1984   int err=0, c ;
1985   int crate=19200, hsc=-1, i ;
1986   enum connectmode mode=NONE ;
1987
1988   if ( ! err && share ) {
1989     err = ttymode ( f, COMMAND ) ;
1990     if ( ! err ) 
1991       err = unlockall ( lkfile ) ;
1992   }
1993   
1994   if ( ! err && wait ) {
1995     msg ( "Iwaiting for activity") ;
1996     tdata ( f, -1 ) ;
1997     msg ( "Iactivity detected") ;
1998   }
1999   
2000   if ( ! err && share ) {
2001     msleep ( 500 ) ;            /* let other programs lock port  */
2002     err = lockall ( lkfile, 1 ) ;
2003     if ( err )
2004       err = msg ( "W1can't answer: can't lock device" ) ;
2005     else
2006       err = ttymode ( f, COMMAND ) ; /* in case it was changed silently */
2007   }
2008
2009   for ( i=0 ; ! err && mode == NONE && ( i==0 || ( i==1 && softaa ) ) ; i++ ) {
2010
2011     c = cmd ( f, wait ? 0 : acmd, ( i==0 && softaa ) ? TO_DATAF : TO_A ) ;
2012
2013     if ( c == DATA ) cmd ( f, c1 ? "O" : 0, TO_A ) ; /* +FAE=1 weirdness */
2014
2015     mode = ansmode ( &crate, &hsc ) ;
2016     
2017     switch ( mode ) {
2018     case DATAMODE :
2019       msg ( "Idata call answered") ;
2020       if ( getty && *getty ) {
2021         char buf [ MAXGETTY ] ;
2022         if ( ckfmt ( getty, 6 ) ) {
2023           err = msg ( "E3 too many %%d escapes in command (%s)", getty ) ;
2024         } else {
2025           sprintf ( buf, getty, crate, crate, crate, crate, crate, crate ) ;
2026           msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
2027           execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ; 
2028           err = msg ( "ES2exec failed:" ) ;
2029         }
2030       } else {
2031         err = msg ( "E2no getty command defined for data call" ) ;
2032       }
2033       break ; 
2034     case FAXMODE :
2035       nframes = 0 ;
2036       msg ( "Ifax call answered") ;
2037       break ;
2038     case VOICEMODE :
2039       msg ( "Ivoice call answered") ;
2040       if ( vcmd && *vcmd ) {
2041         char buf [ MAXGETTY ] ;
2042         if ( ckfmt ( vcmd, 6 ) ) {
2043         } else {
2044           sprintf ( buf, vcmd, f->fd, f->fd, f->fd, f->fd, f->fd, f->fd ) ;
2045           msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
2046           execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ; 
2047           err = msg ( "ES2exec failed:" ) ;
2048         }
2049       } else {
2050         err = msg ( "E2no voice command defined for voice call" ) ;
2051       }
2052       break ; 
2053     case NONE:
2054       if ( i==0 && softaa && hsc < 0 && getty && *getty ) {
2055         int j ;                 /* switch to fax for 2nd try */
2056         for ( j=0 ; j<3 ; j++ ) 
2057           if ( cmd ( f, c1 ? "+FCLASS=1" : 
2058                     ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), -TO_RESET ) 
2059               == OK ) break ; 
2060         wait = 0 ;
2061         acmd = ANSCMD ;
2062       } else {
2063         err = msg ( "E3unable to answer call") ;
2064       }
2065       break ;
2066     default:
2067       err = msg ( "E3can't happen(answer)" ) ;
2068       break ;
2069     }
2070     
2071   }
2072
2073   return err  ;
2074 }
2075 #endif /* UCLINUX */
2076
2077
2078 /* Initialize modem.  Determine class to use and issue
2079    class-specific fax initialization commands. If poll is true,
2080    issues commands to enable polling also.  Returns 0 or 3 if a
2081    mandatory setup command fails. */
2082
2083 static int modem_init ( TFILE *mf, cap c, char *id, 
2084                  int calling, int poll, int capsset, int *preverse )
2085 {
2086   int err=0, t=-TO_RESET ;
2087   char buf [ CMDBUFSIZE ], model [ CMDBUFSIZE ] = "" ;
2088   char **p, *q, *modelq [2][4] = { { "+FMFR?", "+FMDL?", 0 }, 
2089                                    { "+FMI?", "+FMM?", "+FMR?", 0 } } ;
2090
2091
2092   /* diasable command echo and get firmware revision */
2093
2094   cmd ( mf, "E0", t ) ;
2095
2096   if ( cmd ( mf, "I3", t ) == OK ) {
2097     getresp ( "", model, CMDBUFSIZE-1 ) ;
2098     strcat ( model, " " ) ;
2099   }
2100
2101   /* if not already chosen, pick safest class; set it */
2102
2103   if ( ! err && ! c1 && !c2 && ! c20 ) {
2104     if ( cmd ( mf, "+FCLASS=?", t ) != OK ) {
2105       err = msg ("E3 modem does not support fax" ) ;
2106     } else {
2107       if ( strinresp ( "2.0" ) ) c20 = 1 ;
2108       else if ( strinresp ( "2" ) ) ;
2109 #ifndef UCLINUX
2110       else if ( strinresp ( "1" ) ) c1 = 1 ;
2111 #endif /* UCLINUX */
2112       else err = msg ("E3 can't determine fax modem class support" ) ;
2113 #ifndef UCLINUX
2114       if ( strstr ( model, "Sportster" ) ) { /* USR Sporsters are buggy */
2115         c1 = 1 ; 
2116         c2 = c20 = 0 ;
2117       }
2118 #endif /* UCLINUX */
2119     }
2120   }
2121
2122   ckcmd ( mf, &err, c1 ? "+FCLASS=1" : 
2123        ( c20 ? "+FCLASS=2.0" : "+FCLASS=2" ), t, OK ) ;
2124
2125   /* get make & model if using Class 2 or 2.0 */
2126
2127   if ( ! c1 ) {
2128     for ( p = modelq [ c20 ] ; ! err && *p ; p++ ) {
2129       if ( cmd ( mf, *p, t ) == OK ) {
2130         getresp ( "", model, CMDBUFSIZE-1 ) ;
2131         strcat ( model, " " ) ;
2132       }
2133     }
2134   
2135     if ( ! c1 && strstr ( model, "Multi-Tech" ) ) {
2136       *preverse = 0 ;
2137       msg ("I Multi-Tech bit order set" ) ;
2138     }
2139   }
2140
2141   if ( ! err ) 
2142     msg ( "I using %sin class %s", model, c1 ? "1" : c20 ? "2.0" : "2" ) ;
2143
2144   /* get maximum modem speed if not already set (Class 1 only) */
2145
2146   if ( ! err && c1 && ! capsset ) {
2147     int i ;
2148     char *c1spstr [6] = { "24", "48", "72", "96", "121", "145" } ;
2149     ckcmd ( mf, &err, calling ? "+FTM=?" : "+FRM=?", t, OK ) ;
2150     for ( i=0 ; i < 6 && strinresp ( c1spstr[i] ) ; i++ ) ;
2151     c[1]=i?i-1:0;
2152   }
2153
2154   /* issue essential commands and set/get modem capabilities (Class 2 only) */
2155
2156   if ( ! err && ! c1 ) {
2157
2158     if ( c20 ) {
2159       ckcmd ( mf, 0, "+FIP", t, OK ) ;
2160       ckcmd ( mf, 0, "+FNR=1,1,1,1", t, OK ) ;
2161     }
2162
2163     ckcmd ( mf, &err, "+FCR=1", t, OK ) ;
2164
2165     if ( ! capsset ) {
2166       if ( cmd ( mf, c20 ? "+FIS?" : "+FDIS?", -t ) == OK &&
2167            ( q = strinresp ( "," ) ) ) {
2168         str2cap ( q-1, c ) ;
2169       } else {
2170         msg ( "W can't get modem capabilities, set to default" ) ;
2171         capsset = 1 ;
2172       }
2173     }
2174
2175     if ( capsset ) {
2176       sprintf ( buf, c20 ? "+FCC=%d,%d,%d,%d,%d,%d,%d,%d" : 
2177                 "+FDCC=%d,%d,%d,%d,%d,%d,%d,%d", 
2178                 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7] ) ;
2179       ckcmd ( mf, 0, buf, -t, OK ) ;
2180     }
2181     
2182     sprintf ( buf, c20 ? "+FLI=\"%.*s\"" : "+FLID=\"%.*s\"" , 
2183              CMDBUFSIZE-9, id ) ;
2184     ckcmd ( mf, 0, buf, -t, OK ) ;
2185
2186     if ( ! err && poll ) {
2187
2188       ckcmd ( mf, 0, c20 ? "+FSP=1" : "+FSPL=1", -t, OK ) ;
2189
2190       sprintf ( buf, c20 ? "+FPI=\"%.*s\"" : "+FCIG=\"%.*s\"" , 
2191                CMDBUFSIZE-9, id ) ;
2192       ckcmd ( mf, 0, buf, -t, OK ) ;
2193
2194     }
2195   }
2196
2197   return err ;
2198 }
2199
2200
2201 /* the following are global so can terminate properly on signal */
2202
2203 static char *icmd[3][ MAXICMD+1 ] = {{0},{0},{0}} ; /* initialization commands */
2204 static TFILE faxdev = { -1, 0,0, {0}, 0, 0 } ;  /* modem */
2205 static char *lkfile [ MAXLKFILE+1 ] = {0} ; /* lock file names */
2206 static IFILE ifile = { 0 } ;            /* files being sent */
2207 static int locked = 0 ;         /* modem locked */
2208
2209
2210 /* print names of files not sent and reset modem before
2211    exiting. */
2212
2213 static int cleanup ( int err )
2214 {
2215                                 /* log names of files not sent */
2216   logifnames ( &ifile, "I failed -> %s" ) ;
2217
2218   if ( ! locked && faxdev.fd >= 0 )
2219     end_session ( &faxdev, icmd[2], lkfile, err != 4 ) ;
2220   
2221   msg ( "Idone, returning %d (%s)", err, 
2222         errormsg [ err >= 0 && err <= 5 ? err : 6 ] ) ;
2223
2224   return err ;
2225 }
2226
2227
2228 /* signal handler */
2229
2230 static void onsig ( int sig ) 
2231
2232   msg ( "E terminating on signal %d", sig ) ; 
2233   exit ( cleanup ( 5 ) ) ;
2234 }
2235
2236
2237 /* Fax send/receive program for Class 1, 2 and 2.0 fax
2238    modems. Returns 0 on success, 1 if number busy or device
2239    locked, 2 for errors, 3 for protocol errors, 4 if no modem
2240    response, 5 on signal. */
2241
2242 int main( int argc, char **argv)
2243 {
2244   int err=0, doneargs=0, c=0, i ;
2245   int testing=0;
2246 #ifndef UCLINUX
2247         int calling=0 ;
2248 #else /* UCLINUX */
2249 #define calling (1)
2250 #endif /* UCLINUX */
2251
2252   int nicmd[3]={0,0,0}, nlkfile=0, nverb=0 ;
2253
2254   char *faxfile = FAXFILE ;
2255
2256   int softaa=0, share=0, wait=0, reverse=1, ignerr=0, noretry=0, hwfc=0 ;
2257   int capsset=0 ;
2258   char *getty = "", *vcmd = "", *acmd=ANSCMD ;
2259
2260   cap local = { DEFCAP } ;
2261   char localid  [ IDLEN + 1 ] = DEFID ;
2262
2263   int maxpgerr = MAXPGERR ;
2264
2265   time_t now ;
2266 #ifndef UCLINUX
2267   char *header = 0, headerbuf [ MAXLINELEN ] ; 
2268   char *fontname = 0 ;
2269   faxfont font ;
2270 #endif /* UCLINUX */
2271
2272   OFILE ofile ;
2273   int pages = 0 ;
2274   char *phnum="";
2275 #ifndef UCLINUX
2276         char *ansfname = DEFPAT ;
2277   char fnamepat [ EFAX_PATH_MAX ] ;
2278 #endif /* UCLINUX */
2279   
2280   /* print initial message to both stderr & stdout */
2281   argv0 = argv[0] ;
2282   verb[1] = "ewia" ;
2283   msg ( "I " Version " " Copyright ) ;
2284   argv0 = efaxbasename ( argv0 ) ;
2285   msg ( "A compiled "__DATE__ " " __TIME__ ) ;
2286   verb[1] = "" ;
2287
2288   while ( ! err && ! doneargs &&
2289          ( c = nextopt ( argc,argv,
2290                         "a:c:d:e:f:g:h:i:j:k:l:o:p:q:r:st:v:wx:T" ) ) != -1 ) {
2291
2292     switch (c) {
2293     case 'a': 
2294       acmd = nxtoptarg ;
2295       break ;
2296     case 'c': 
2297       err = str2cap ( nxtoptarg, local ) ;
2298       capsset = 1 ;
2299       break ;
2300     case 'l': 
2301       if ( strlen ( nxtoptarg ) > IDLEN ) 
2302         msg("Wlocal ID (%s) truncated to %d characters", nxtoptarg, IDLEN ) ;
2303       if ( strspn ( nxtoptarg, " +0123456789" ) != strlen ( nxtoptarg ) )
2304         msg("Wlocal ID (%s) has non-standard characters", nxtoptarg ) ;
2305       sprintf ( localid, "%*.*s", IDLEN, IDLEN, nxtoptarg ) ;
2306       break ;
2307     case 'i': 
2308       if ( nicmd[0] < MAXICMD ) icmd[0][ nicmd[0]++ ] = nxtoptarg ;
2309       else err = msg ( "E2too many '-i' options"); 
2310       break ;
2311     case 'j': 
2312       if ( nicmd[1] < MAXICMD ) icmd[1][ nicmd[1]++ ] = nxtoptarg ;
2313       else err = msg ( "E2too many '-j' options"); 
2314       break ;
2315     case 'k': 
2316       if ( nicmd[2] < MAXICMD ) icmd[2][ nicmd[2]++ ] = nxtoptarg ;
2317       else err = msg ( "E2too many '-k' options"); 
2318       break ;
2319 #ifndef UCLINUX
2320     case 'h': 
2321       header = nxtoptarg ; 
2322       break ;
2323     case 'f': 
2324       fontname = nxtoptarg ; 
2325       break ;
2326 #endif /* UCLINUX */
2327     case 'd': 
2328       faxfile = nxtoptarg ; 
2329       break ;
2330     case 'e': 
2331       vcmd = nxtoptarg ; 
2332       break ;
2333     case 'g': 
2334       getty = nxtoptarg ; 
2335       break ;
2336     case 'o':                   /* most protocol options are globals */
2337       for ( ; *nxtoptarg ; nxtoptarg++ ) 
2338         switch ( *nxtoptarg ) {
2339         case '0' : c20 = 1 ; break ;
2340 #ifndef UCLINUX
2341         case '1' : c1 = 1 ; break ;
2342 #endif /* UCLINUX */
2343         case '2' : c2 = 1 ; break ;
2344         case 'a' : softaa = 1 ;  break ;
2345         case 'e' : ignerr = 1 ;  break ;
2346         case 'f' : vfc = 1 ;  break ;
2347         case 'h' : hwfc = 1 ;  break ;
2348         case 'l' : lockpolldelay /= 2 ;  break ;
2349         case 'n' : noretry = 1 ;  break ;
2350         case 'r' : reverse = 0 ; break ;
2351         case 'x' : startchar = XON ; break ;
2352         case 'z' : cmdpause += T_CMD ; break ;
2353          default : msg ( "Wunrecognized protocol option (%c)", *nxtoptarg ) ; 
2354         }
2355       break ;
2356     case 'q':
2357                         maxpgerr = atoi( nxtoptarg );
2358       if ( maxpgerr < 0 )
2359         err=msg ("E2bad quality (-q) argument (%s)", nxtoptarg ) ;
2360       break;
2361 #ifndef UCLINUX
2362     case 'r': 
2363       ansfname = nxtoptarg ;
2364       break;
2365 #endif /* UCLINUX */
2366     case 's': 
2367       share = 1 ; 
2368       break;
2369     case 't': 
2370 #ifndef UCLINUX
2371       calling=1;
2372 #endif /* UCLINUX */
2373       /* fall through */
2374     case 'p':
2375       if ( argv [ argc ] ) err = msg ("E2can't happen(unterminated argv)") ;
2376       if ( ! err ) err = newIFILE ( &ifile, argv + nxtoptind ) ;
2377       pages = argc - nxtoptind - ( c == 'p' ? 1 : 0 )  ;
2378       pages = pages < 0 ? 0 : pages ;
2379       phnum = nxtoptarg ;
2380       doneargs=1 ; 
2381       break;
2382     case 'v': 
2383       verb[nverb] = nxtoptarg ; 
2384       nverb=1;
2385       break ;
2386     case 'w': 
2387       wait = 1 ; 
2388       break ;
2389     case 'x': 
2390       if ( nlkfile < MAXLKFILE ) lkfile[ nlkfile++ ] = nxtoptarg ;
2391       else err = msg ( "E2too many lock files" ) ; 
2392       break ;
2393     case 'T':                   /* test: begin+end session */
2394       testing=1;
2395       doneargs=1 ; 
2396       break ;
2397     default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
2398     }
2399   }
2400
2401   for ( i=0 ; i<argc ; i++ ) 
2402     msg ( "Aargv[%d]=%s", i, argv[i]) ; 
2403
2404   if ( ! nicmd[2] ) icmd[2][nicmd[2]++] = "H" ; /* default -k command */
2405
2406 #ifndef UCLINUX
2407   readfont ( fontname, &font ) ;
2408
2409   if ( ! header ) {
2410     char tmp [ MAXLINELEN ] ;
2411     now = time ( 0 ) ;
2412     strftime ( tmp, MAXLINELEN, "%c %%s   P. %%%%d", localtime ( &now ) ) ;
2413     sprintf ( header = headerbuf, tmp, localid ) ;
2414   }
2415 #endif /* UCLINUX */
2416
2417   if ( ! err ) {
2418     err = begin_session ( &faxdev, faxfile, 
2419                          !c1 && !c20 && reverse, /* Class 2 rx bit reversal */
2420                          hwfc, lkfile, COMMAND, onsig ) ;
2421     if ( ! err ) err = setup ( &faxdev, icmd[0], ignerr ) ;
2422     if ( ! err ) err = modem_init ( &faxdev, local, localid, 
2423                                     calling, calling && !pages, capsset,
2424                                     &reverse ) ;
2425     if ( ! err ) err = setup ( &faxdev, icmd[1], ignerr ) ;
2426     if ( err == 1 ) locked = 1 ;
2427   }
2428
2429   if ( ! err && ! testing ) {
2430
2431     if ( calling ) {
2432       err = dial ( &faxdev, phnum, 0 ) ;
2433     }
2434 #ifndef UCLINUX
2435                 else {
2436       err = answer ( &faxdev, lkfile, wait, share, softaa, 
2437                     getty, vcmd, acmd ) ;
2438       if ( err == 1 ) locked = 1 ;
2439     }
2440 #endif /* UCLINUX */
2441
2442     now = time(0) ;             /* do it here so use reception time */
2443 #ifndef UCLINUX
2444     strftime ( fnamepat, EFAX_PATH_MAX, ansfname, localtime ( &now ) ) ;
2445     strncat ( fnamepat, ".%03d", EFAX_PATH_MAX - strlen ( fnamepat ) ) ;
2446     newOFILE ( &ofile, O_TIFF_FAX, fnamepat, 0, 0, 0, 0 ) ;
2447 #endif /* UCLINUX */
2448     
2449     if ( ! err ) {
2450 #ifndef UCLINUX
2451       if ( c1 ) {
2452         err = c1sndrcv ( &faxdev, local, localid,
2453                         &ofile, &ifile, pages, header, &font,
2454                         maxpgerr, noretry, calling ) ;
2455       } else
2456 #endif /* UCLINUX */
2457       {
2458         err = c2sndrcv ( &faxdev, local, localid,
2459                         &ofile, &ifile, pages,
2460 #ifndef UCLINUX
2461                         header, &font,
2462 #endif /* UCLINUX */
2463                         maxpgerr, noretry, calling ) ;
2464       }
2465     }
2466   }
2467
2468   return cleanup ( err ) ;
2469 }