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