📄 efax.c
字号:
{ int err=0, i ; int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ; printcap ( "local ", local ) ; printcap ( "remote ", remote ) ; for ( i=0 ; i<NCAP && i!=ST && i !=BR ; i++ ) session[i] = remote[i] < local[i] ? remote[i] : local[i] ; session[BR] = brindex[ remote[BR] ] < brindex[ local[BR] ] ? remote[BR] : local[BR] ; session[ST] = msttab [ session[VR] ] [ remote[ST] ] ; printcap ( "session", session ) ; if ( local[WD] != session[WD] || local[LN] > session[LN] || local[DF] != session[DF] ) err = msg ("W3incompatible local and remote capabilities" ) ; return err ;}/* Skip to start of first/next page (or to start of previous page if dp is 0). If ppm in not null, it is then set to EOP if there are no pages following this one, MPS if the next page has the same format as `local' (assumed to be the format of the previous page), EOM if the page has a different format. If local is non-NULL its format fields are set according to the format of the new page. Currently only considers the file's y-resolution. This function is called before send_data() and obtains the ppm for that page. It can be called again with dp=0 if a PIN or RTN is received to restart the page. Returns 0 or 2 on errors. */int rdpage ( IFILE *f, int dp, int *ppm, cap local, int *changed ){ int err=0, m=EOP, yres, fVR, nVR ; if ( nextipage ( f, dp ) ) err = msg ( "E2 can't happen (rdpage: can't go to %s page)", dp ? "next" : "same" ) ; if ( ! err ) { yres = f->page->yres ; fVR = ( yres > (196+98)/2 ) ? 1 : 0 ; if ( local && yres ) { if ( local [ VR ] != fVR ) { local [ VR ] = fVR ; if ( changed ) *changed = 1 ; } else { if ( changed ) *changed = 0 ; } } if ( lastpage ( f ) ) { m = EOP ; } else { PAGE *p = f->page + 1 ; nVR = ( p->yres > (196+98)/2 ) ? 1 : 0 ; m = ( nVR != fVR ) ? EOM : MPS ; } } if ( ppm ) { *ppm = err ? EOP : m ; } return err ;}/* Terminate previous page if page number is non-zero and start next output page if page number is non-negative. If page is -1 removes the most recently opened file. Returns 0 if OK, 2 on errors. */int wrpage ( OFILE *f, int page ){ int err=0 ; err = nextopage ( f, page ) ; if ( ! err && page == -1 ) { if ( remove ( f->cfname ) ) { err = msg ( "ES2can't delete file %s:", f->cfname ) ; } else { msg ( "Fremoved %s", f->cfname ) ; } } return err ;}/* Send data for one page. Figures out required padding and 196->98 lpi decimation based on local and session capabilitites, substitutes page numbers in header string and enables serial port flow control. Inserts the page header before the input file data. Converts each scan line to T.4 codes and adds padding (FILL) and EOL codes before writing out. Sends RTC when done. Sends DLE-ETX and returns serial port to command mode when done. Returns 0 if OK, non-0 on errors. */int send_data ( TFILE *mf, IFILE *f, int page, int pages, cap local, cap session, char *header, faxfont *font ){ int done=0, err=0, noise=0, nr=0, lastnr=0, line, pixels ; int i, decimate, pwidth, minlen, dcecps, inheader, skip=0 ; uchar buf [ MAXCODES + 2*EOLBITS/8 + 1 ], *p ; short runs [ MAXRUNS ], lastruns [ MAXRUNS ] ; char headerbuf [ MAXLINELEN ] ; ENCODER e ; newENCODER ( &e ) ; dcecps = cps[session[BR]] ; minlen = ( (long)dcecps * mst[session[ST]] - 1500 + 500 ) / 1000 ; pwidth = pagewidth [ session [ WD ] ] ; decimate = local[VR] > session[VR] ; msg ( "T padding to %d bytes/scan line.%s", minlen+1, decimate ? " reducing 196->98 lpi." : "" ) ; if ( vfc ) msg ( "T limiting output to %d bps for %d byte modem buffer", dcecps*8, MAXDCEBUF + MINWRITE ) ; if ( ckfmt ( header, 6 ) ) msg ( "W too many %%d escapes in header format string \"%s\"", header ) ; else sprintf ( headerbuf, header, page, pages, page, pages, page, pages ) ; msg ("I header:[%s]", headerbuf ) ; done = err = ttymode ( mf, SEND ) ; mf->start = time(0) ; mf->mstart = proc_ms() ; mf->bytes = mf->pad = mf->lines = 0 ; /* start T.4 data with some FILL and an EOL */ for ( i=0 ; i<32 ; i++ ) p = putcode ( &e, 0, 8, buf ) ; p = putcode ( &e, EOLCODE, EOLBITS, p ) ; if ( ! f || ! f->f ) err = msg ( "E2can't happen(send_data)" ) ; mf->lines=0 ; for ( line=0 ; ! done && ! err ; line++ ) { if ( line < HDRSPCE ) { /* insert blank lines at the top */ runs[0] = pwidth ; pixels = pwidth ; nr = 1 ; } else { if ( ( nr = readline ( f, runs, &pixels ) ) < 0 ) { done = 1 ; continue ; } } /* generate and OR in header pixels */ if ( line >= HDRSTRT && line < HDRSTRT + HDRCHRH ) { int hnr ; short hruns [ MAXRUNS ] ; hnr = texttorun ( (uchar*) headerbuf, font, line-HDRSTRT, HDRCHRW, HDRCHRH, HDRSHFT, hruns, 0 ) ; nr = runor ( runs, nr, hruns, hnr, 0, &pixels ) ; } inheader = line < HDRSTRT + HDRCHRH ; if ( decimate || ( inheader && local[VR] == 0 ) ) { if ( ++skip & 1 ) { /* save the first of every 2 lines */ memcpy ( lastruns, runs, nr * sizeof(short) ) ; lastnr = nr ; continue ; /* get next line */ } else { /* OR previous line into current line */ nr = runor ( runs, nr, lastruns, lastnr, 0, &pixels ) ; } } if ( nr > 0 ) { if ( pixels ) { /* make line the right width */ if ( pixels != pwidth ) nr = xpad ( runs, nr, pwidth - pixels ) ; /* convert to MH coding */ p = runtocode ( &e, runs, nr, p ) ; /* zero pad to minimum scan time */ while ( p - buf < minlen ) { p = putcode ( &e, 0, 8, p ) ; mf->pad ++ ; } /* add EOL */ p = putcode ( &e, EOLCODE, EOLBITS, p ) ; sendbuf ( mf, buf, p - buf, dcecps ) ; mf->bytes += p - buf ; mf->lines++ ; } else { /* probably read an EOL as part of RTC */ } if ( tdata ( mf, 0 ) ) noise = 1 ; p = buf ; } } for ( i=0 ; i < RTCEOL ; i++ ) p = putcode ( &e, EOLCODE, EOLBITS, p ) ; p = putcode ( &e, 0, 0, p ) ; sendbuf ( mf, buf, p - buf, dcecps ) ; mf->bytes += p - buf ; if ( noise ) msg ("W- characters received while sending" ) ; return err ;}int end_data ( TFILE *mf, cap session, int ppm, int *good ){ int err=0, c ; uchar *p ; long dt, draintime ; if ( ! ppm ) p = DLE_ETX ; else if ( ppm == MPS ) p = "\020," ; else if ( ppm == EOM ) p = "\020;" ; else if ( ppm == EOP ) p = "\020." ; else { p = "" ; err = msg ( "E2 can't happen (end_data)" ) ; } tput ( mf, p, 2 ) ; dt = time(0) - mf->start ; /* time to drain buffers + 100% + 4s */ draintime = ( 2 * ( mf->bytes / cps[ session[BR] ] + 1 - dt ) + 4 ) * 10 ; draintime = draintime < TO_DRAIN_D ? TO_DRAIN_D : draintime ; c = ckcmd ( mf, 0, 0, (int) draintime, OK ) ; if ( good ) *good = ( c == OK ) ? 1 : 0 ; dt = time(0) - mf->start ; msg ( "Isent %d+%d lines, %d+%d bytes, %d s %d bps" , HDRSPCE, mf->lines-HDRSPCE, mf->bytes-mf->pad, mf->pad, (int) dt, (mf->bytes*8)/dt ) ; if ( mf->bytes / (dt+1) > cps[session[BR]] ) msg ( "E flow control did not work" ) ; if ( ! err ) err = ttymode ( mf, COMMAND ) ; return err ;}/* Read one scan line from fax device. If pointer pels is not null it is used to save pixel count. Returns number of runs stored, EOF on RTC, or -2 on EOF, DLE-ETX or other error. */int readfaxruns ( TFILE *f, DECODER *d, short *runs, int *pels ){ int err=0, c=EOF, x, n ; dtab *tab, *t ; short shift ; short *p, *maxp, *q, len=0 ; uchar rd_state ; maxp = ( p = runs ) + MAXRUNS ; x = d->x ; shift = d->shift ; tab = d->tab ; /* restore decoder state */ rd_state = f->rd_state ; do { do { while ( shift < 0 ) { c = tgetd ( f, TO_CHAR ) ; rd_state = ( rd_state & rd_allowed[c] ) ? ( ( rd_state & rd_nexts[c] ) ? rd_state <<= 1 : rd_state ) : RD_BEGIN ; if ( rd_state == RD_END ) msg ( "W+ modem response in data" ) ; if ( c < 0 ) { x = ( x << 15 ) | 1 ; shift += 15 ; /* EOL pad at EOF */ } else { x = ( x << 8 ) | c ; shift += 8 ; } } t = tab + ( ( x >> shift ) & 0x1ff ) ; tab = t->next ; shift -= t->bits ; } while ( ! t->code ) ; if ( p < maxp ) *p++ = t->code ; } while ( t->code != -1 ) ; d->x = x ; d->shift = shift ; d->tab = tab ; /* save state */ f->rd_state = rd_state ; if ( p >= maxp ) msg ( "Wrun length buffer overflow" ) ; /* combine make-up and terminating codes and remove +1 offset in run lengths */ n = p - runs - 1 ; for ( p = q = runs ; n-- > 0 ; ) if ( *p > 64 && n-- > 0 ) { len += *q++ = p[0] + p[1] - 2 ; p+=2 ; } else { len += *q++ = *p++ - 1 ; } n = q - runs ; /* check for RTC and errors */ if ( len ) d->eolcnt = 0 ; else if ( ++(d->eolcnt) >= RTCEOL ) err = EOF ; if ( c < 0 ) err = - 2 ; if ( pels ) *pels = len ; return err ? err : n ;}/* Receive data. Reads scan lines from modem and writes to output file. Checks for errors by comparing received line width and session line width. Check that the output file is still OK and if not, send one CANcel character and wait for protocol to complete. Returns 0 if OK or 2 if there was a file write error. */int receive_data ( TFILE *mf, OFILE *f, cap session, int *nerr ){ int err=0, line, lines, nr, len ; int pwidth = pagewidth [ session [ WD ] ] ; short runs [ MAXRUNS ] ; DECODER d ; if ( ! f || ! f->f ) { msg ( "E2 can't happen (writeline)" ) ; } newDECODER ( &d ) ; *nerr = 0 ; lines=0 ; for ( line=0 ; ( nr = readfaxruns ( mf, &d, runs, &len ) ) >= 0 ; line++ ) { if ( nr > 0 && len > 0 && line ) { /* skip first line+EOL and RTC */ if ( len != pwidth ) { (*nerr)++ ; if ( *nerr <= MAXERRPRT ) msg ("R-+ (%d:%d)", line, len ) ; nr = xpad ( runs, nr, pwidth - len ) ; } writeline ( f, runs, nr, 1 ) ; lines++ ; } if ( ferror ( f->f ) ) { err = msg ("ES2file write:") ; tput ( mf, CAN_STR, 1 ) ; msg ("Wdata reception CANcelled") ; } } if ( *nerr ) { if ( *nerr > MAXERRPRT ) msg ("R-+ ....." ) ; msg ("R- : reception errors" ) ; msg ("W- %d reception errors", *nerr ) ; } if ( nr == EOF ) while ( tgetd ( mf, TO_CHAR ) >= 0 ) ; /* got RTC, wait for DLE-ETX */ msg ( "I- received %d lines, %d errors", lines, *nerr ) ; return err ;}/* Send training check sequence of n zeroes. Returns 0 or 2 on error. */int puttrain ( TFILE *f, char *s, int n ){ int i, m, err=0 ; uchar buf [ MINWRITE ] = { 0 } ; ckcmd ( f, &err, s, TO_FT, CONNECT ) ; if ( ! err ) { ttymode ( f, SEND ) ; for ( i=0 ; i < n ; i += m ) { m = n-i < MINWRITE ? n-i : MINWRITE ; sendbuf ( f, buf, m, 0 ) ; } buf[0] = 1 ; /* make sure last byte is non-zero */ buf[1] = DLE ; buf[2] = ETX ; sendbuf ( f, buf, 3, 0 ) ; ttymode ( f, COMMAND ) ; ckcmd ( f, &err, 0, TO_DRAIN_D, OK ) ; msg ( "I- sent TCF - channel check of %d bytes", n ) ; } return err ;}/* Checks for an error-free run of at least n bytes in the received training check sequence. Sets good if it's not null, the run was long enough and there were no errors. Returns 0 or 3 on other errors. */int gettrain ( TFILE *f, char *s, int n, int *good ) { int err=0, c, i=0, maxrunl=0, runl=0 ; ckcmd ( f, &err, s, T2, CONNECT ) ; if ( ! err ) { for ( i=0 ; ( c = tgetd ( f, T3S ) ) >= 0 ; i++ ) if ( c ) { if ( runl > maxrunl ) maxrunl = runl ; runl = 0 ; } else { runl ++ ; } if ( c == EOF ) err = msg ( "E3timed out during training check data" ) ; else ckcmd ( f, &err, 0, TO_RTCMD, NO ) ; } if ( runl > maxrunl ) maxrunl = runl ; if ( good ) *good = !err && maxrunl > n ; if ( !err ) { msg ( "I- received TCF - channel check (%sOK: run of %d in %d)", maxrunl > n ? "" : "not ", maxrunl, i ) ; } return err ;}/* Log a sent/received HDLC frame. Display of these messages is delayed to avoid possible timing problems. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -