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