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