📄 efax.c
字号:
return err ;}/* Log a sent/received HDLC frame. Display of these messages is delayed to avoid possible timing problems. */void logfr ( char *s , char *nm , uchar *p , int n ){ int i=0 ; msg ( n > 10 ? "H- %s %d bytes:" : "H-+ %s %d bytes:" , s, n ) ; for ( i=0 ; i<n ; i++ ) { msg ( "H-+ %02x" , p[i] & 0xff ) ; if ( ( i&0xf ) == 0xf && i != n-1 ) msg ( "H-" ) ; } msg ( "H-" ) ; msg ( "I- %s %s", s, nm ) ;}/* Send HDLC control frame of type type. Extra bits can be OR'ed into the frame type (FCF) to indicate that this frame follows a previous one (no +FTH required) and/or that more frames will follow. Sets up flag, address, and fax control field bytes in `buf'. Sends these plus `len` additional bytes. Terminates with DLE-ETX and checks response. Returns 0 if OK, 2 or 3 on error. */#define MORE_FR 0x100 #define SUB_FR 0x200 int nframes = 0 ; /* counts frames sent/received */int putframe ( int type, uchar *buf, int len, TFILE *f, int t ){ int err=0 ; buf [ 0 ] = 0xff ; buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ; buf [ 2 ] = type & 0xff ; if ( nframes++ && ! ( type & SUB_FR ) ) ckcmd ( f, &err, "+FTH=3" , TO_FT, CONNECT ) ; if ( ! err ) { if ( ! buf[len+2] ) { msg ( "Wlast byte of frame is NULL" ) ; } /* ttymode ( f, SEND ) ; */ sendbuf ( f, buf, len+3, 0 ) ; tput ( f, DLE_ETX, 2 ) ; /* ttymode ( f, COMMAND ) ; */ logfr ( "sent", frname ( buf [ 2 ] ), buf, len+3 ) ; ckcmd ( f, &err, 0, TO_DRAIN_H, ( type & MORE_FR ) ? CONNECT : OK ) ; } return err ;}/* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */void revcpy ( uchar *from , uchar *to ){ int i, j ; for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- ) to [ i ] = normalbits [ from [ j ] & 0xff ] ;}/* Check for missing initial 0xFF in HDLC frame and insert it if missing. Ugly fix for a still-hidden bug. Also do bit inversion if required. */int fixframe ( uchar *buf, int n, TFILE *f ){ int i; if ( *buf == 0xc0 || *buf == 0xc8 ) { for ( i=n; i >= 1 ; i-- ) buf[i]=buf[i-1] ; buf[i] = 0xff ; msg ("W HDLC frame missing initial 0xff" ) ; n++ ; } if ( buf[1] == 0x03 || buf[1] == 0x13 ) { for ( i=0 ; i < n ; i++ ) buf[i]=normalbits[buf[i]] ; msg ("W bit-reversed HDLC frame, reversing bit order" ) ; f->ibitorder = f->ibitorder == normalbits ? reversebits : normalbits ; } return n ;}/* Read HDLC frame data. Returns 0 if OK, 1 on frame error, 3 on timeout, invalid response or too-long frame. */int receive_frame_data ( TFILE *f, uchar *buf, int n, int *len ){ int err=0, c, i ; for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ ) if ( i < n ) buf[ i ] = c ; if ( c == EOF ) { err = msg ( "E3timed out reading frame data" ) ; } else { switch ( cmd ( f, 0, TO_RTCMD ) ) { case OK: case CONNECT: break ; case ERROR: case NO: err = msg ( "W1frame error" ) ; break ; case EOF: err = msg ( "E3no response after frame data" ) ; break ; default: err = msg ( "E3wrong response after frame data" ) ; break ; } } if ( i >= n ) err = msg ( "E3frame too long (%d, > %d max bytes)", i, n ) ; if ( len ) *len = i ; return err ;}/* Get a Class 1 command or response frame. An attempt to match and combine T.30 "Response Received?" and "Command Received?" protocol flowcharts. When receiving commands returns after first correct non-optional frame or after the time given by getcmd has elapsed. This is instead of looping through main flowchart. When receiving responses returns on the first detected non-optional frame, after timeout T4, or on errors. Returns immediately if gets a +FCERROR response so can retry as data carrier. Returns DCN as a valid frame instead of hanging up. Returns the command/response received, or EOF on timeout or error. */int getfr ( TFILE *mf, uchar *buf, int getcmd ){ int err=0, frame=0, frlen, c, t ; char remoteid [ IDLEN + 1 ] ; time_t start ; uchar *fif=buf+3 ; start = 10*time(0) ; t = getcmd ? ( getcmd > 1 ? getcmd : T2 ) : T4 ; Enter: err = 0 ; if ( nframes++ ) { c = cmd ( mf, "+FRH=3", t ) ; } else { c = CONNECT ; /* implied by ATA or ATD */ } switch ( c ) { case EOF: /* time out */ tput ( mf, CAN_STR, 1 ) ; ckcmd ( mf, 0, 0, TO_ABRT, OK ) ; err = 1 ; break ; case NO: /* S7 time out */ err = 1 ; break ; case MODULATION: /* data carrier (or DHS) */ return -msg ( "W-2 wrong carrier" ) ; break ; case CONNECT: /* frame */ break ; default: /* shouldn't happen */ err = msg ( "E3wrong response to receive-frame command" ) ; break ; } if ( ! err ) err = receive_frame_data ( mf, buf, MAXFRLEN, &frlen ) ; if ( ! err && frlen < 3 ) err = msg ( "E3received short frame (%d bytes)", frlen ) ; logfr ( "received", frname ( buf [ 2 ] ), buf, frlen ) ; if ( ! err ) { frlen = fixframe ( buf, frlen, mf ) ; frame = buf [ 2 ] & 0x7f ; switch ( frame ) { case CRP: err = 1 ; case NSF: case NSC: case NSS: goto Enter ; case CIG: case CSI: case TSI: revcpy ( fif , (uchar*) remoteid ) ; msg ( "I- remote ID -> %*.*s", IDLEN, IDLEN, remoteid ) ; goto Enter ; } } if ( err && getcmd && ( t -= 10*time(0) - start ) > 0 ) goto Enter ; return err ? EOF : frame ;}/* Class 1 send/receive. The logic in this function is a mess because it's meant to mirror the flowchart in ITU-T recommendation T.30 which is the protocol specification. */int c1sndrcv ( TFILE *mf, cap local, char *localid, OFILE *outf, IFILE *inf, int pages, char *header, faxfont *font, int maxpgerr, int noretry, int calling ){ int err=0, rxpage=0, page=1, t, disbit, good, frame, last, nerr ; int rxdislen, ppm, try=0, pagetry=0, retry=0, remtx=0, remrx=0 ; int writepending=0, dp=0 ; cap remote = { DEFCAP }, session = { DEFCAP } ; char *fname=0 ; uchar buf [ MAXFRLEN ], *fif=buf+3 ; if ( ! calling ) goto RX ; /* Class 1 Transmitter: */ T: /* Transmitter Phase B - wait for DIS or DTC */ pagetry = 0 ; frame = getfr ( mf, buf, T1 ) ; if ( frame <= 0 ) { err = msg ( "E3no answer from remote fax" ) ; goto B ; } if ( frame != DIS && frame != DTC ) { msg ( "W2 can't open page" ) ; goto C ; } disbit = ( frame == DIS ) ? 0x80 : 0x00 ; try = 0 ; A: /* decide to send or receive after DIS/DTC */ if ( frame == DIS || frame == DTC ) { rxdislen = dislen ( fif ) ; mkcap ( fif, remote, 1 ) ; remtx = fif[1] & 0x80 ; remrx = fif[1] & 0x40 ; } msg ( "N remote has %sdocument(s) to send, and can %sreceive", remtx ? "" : "no ", remrx ? "" : "not " ) ; if ( pages > 0 ) { if ( ! remrx ) msg ( "W remote cannot receive, trying anyways" ) ; goto D ; } else { if ( ! remtx ) msg ( "W remote has nothing to send, trying anyways" ) ; goto R ; } D: /* send DCS */ if ( rdpage ( inf, dp, &ppm, local, 0 ) ) { err = msg ( "E2can't open page" ) ; goto B ; } D_2: mincap ( local, remote, session ) ; revcpy ( (uchar*) localid, fif ) ; if ( ! err ) err = putframe ( TSI | MORE_FR | disbit, buf, IDLEN, mf, -1 ) ; mkdis ( session, fif, DCSLEN, 0, pages ) ; if ( ! err ) err = putframe ( DCS | SUB_FR | disbit, buf, DCSLEN, mf, -1 ) ;#ifdef USEFTS if ( cmd ( mf, "+FTS=" MODDLY, T3S ) != OK )#endif msleep ( TMOD ) ; /* if +FTS not supported */ if ( ! err ) err = puttrain ( mf, c1cmd[SND][TRN][session[BR]], TCFSECS*cps [ session[BR] ] ) ; try++ ; if ( ! err ) { cmd ( mf, "+FRS=1", T3S ) ; /* wait for TCF carrier to drop */ frame = getfr ( mf, buf, 0 ) ; } if ( err || frame < 0 ) { if ( try >= 3 ) { goto C_timeout ; } else { goto D_2 ; } } switch ( frame ) { case DIS: case DTC: if ( try >= 3 ) goto C_timeout ; else goto A ; case FTT: msg ( "I channel not usable at %d bps", 8*cps[session[BR]] ) ; remote[BR] = fallback[session[BR]] ; if ( remote[BR] >= 0 ) goto D_2 ; else { err = msg ( "E2 channel not usable at lowest speed" ) ; goto C ; } case CFR: goto I_2 ; default: err = msg ( "E3 invalid response to DCS (0x%02x)", frame ) ; goto C ; } I: /* send a page */ if ( rdpage ( inf, dp, &ppm, local, 0 ) ) { err = msg ( "E2can't open page" ) ; goto B ; } I_2: ckcmd ( mf, &err, c1cmd [SND][DTA][session[BR]], TO_FT, CONNECT ) ; if ( !err ) { msleep ( 1000 ) ; err = send_data ( mf, inf, page, pages, local, session, header, font ) ; } pagetry++ ; if ( !err ) err = end_data ( mf, session, 0, 0 ) ; #ifdef USEFTS if ( cmd ( mf, "+FTS=" MODDLY, T3S ) != OK )#endif msleep ( TMOD ) ; /* if +FTS not supported */ /* fix ppm if on last page of stdin */ if ( lastpage ( inf ) ) ppm = EOP ; try = 0 ; sendppm: if ( !err ) err = putframe ( ppm | disbit, buf, 0, mf, -1 ) ; try++ ; frame = getfr ( mf, buf, 0 ) ; if ( frame < 0 ) { if ( try >= 3 ) { goto C_timeout ; } else { goto sendppm ; } } fname = inf->page->fname ; switch ( noretry ? MCF : frame ) { /* common retry logic */ case MCF: case RTP: case PIP: fname = inf->page->fname ; if ( fname ) msg ( "Isent -> %s", fname ) ; pagetry=0 ; page++ ; dp = 1 ; break ; case PIN: case RTN: dp = 0 ; retry = pagetry < NTXRETRY ; break ; default: err = msg ( "E3invalid post-page response (0x%02x)", frame ) ; goto C ; } switch ( ppm ) { case MPS: switch ( frame ) { case PIN: goto E ; case PIP: goto E ; case MCF: goto I ; case RTP: goto D ; case RTN: goto D ; } case EOP: switch ( frame ) { case PIN: goto E ; case PIP: goto E ; case MCF: case RTP: nextipage ( inf, 1 ) ; /* skip ahead to mark all files done */ if ( remtx ) goto R ; /* poll after sending */ else goto C ; case RTN: if ( retry ) goto D ; else goto C ; } case EOM: switch ( frame ) { case PIN: goto E ; case PIP: goto E ; case MCF: case RTP: case RTN: cmd ( mf, "+FRS=20", T3S ) ; /* wait for ppr carrier to drop */ if ( retry ) goto T ; else goto T ; } } E: /* ignore PIN and PIP */ msg ( "W interrupt request ignored" ) ; try=0 ; goto A ; /* Class 1 Receiver */ RX: R: /* Receiver Phase B */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -