#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include "efaxio.h"
#include "efaxmsg.h"
#include "efaxos.h"
#define MAXRESPB 1024
char *prompts[] = {
"OOK", "-CONNECT FAX", "CCONNECT", "NNO CARRIER", "EERROR",
"NNO DIALTONE", "BBUSY", "NNO ANSWER", "M+FCERROR", "VVCON",
"DDATA", "++FRH:", 0 } ;
int lockpolldelay = 8000 ;
int catch [] = { CATCHSIGS, 0 } ;
int c1=0, c20=0 ;
int c2=0 ;
int cmdpause = T_CMD ;
int vfc = 0 ;
uchar startchar = DC2 ;
uchar rd_nexts [ 256 ] = { 0 }, rd_allowed [ 256 ] = { 0 } ;
void rd_init ( void )
{
int c ;
rd_nexts[CR] = rd_allowed[CR] = 0x01 | 0x08 ;
rd_nexts[LF] = rd_allowed[LF] = 0x02 | 0x10 ;
for ( c='A' ; c<'Z' ; c++ ) {
rd_allowed[c] = 0x04 | 0x08 ;
rd_nexts[c] = 0x04 ;
}
rd_allowed[' '] = 0x08 ;
}
char *tgets( TFILE *f, char *s, int len, int t )
{
int i, n, c ;
for ( i=n=0 ; 1 ; i++ ) {
if ( ( c = tgetc ( f, t ) ) == EOF ) break ;
if ( i == 0 ) msg ( "M-+ .%03d [", time_ms ( ) ) ;
msg ( "M-+ %s", cname ( c ) ) ;
if ( n > 0 && c == LF ) break ;
if ( ! iscntrl ( c ) && n < len ) s[n++] = c ;
}
if ( n >= len ) msg ( "W- modem response overflow" ) ;
s[ n < len ? n : len-1 ] = '\0' ;
if ( i > 0 ) {
if ( c == EOF ) msg ( "M- <...%.1f s>]", (float)t/10 ) ;
else msg ( "M- ]" ) ;
}
return c == EOF ? 0 : s ;
}
int sendbuf ( TFILE *f, uchar *p, int n, int dcecps )
{
int err=0, c, over ;
uchar *order = f->obitorder ;
uchar buf [ MINWRITE+1 ] ;
int i ;
for ( i=0 ; ! err && n > 0 ; n-- ) {
c = order [ *p++ ] ;
if ( c == DLE ) buf[i++] = DLE ;
buf[i++] = c ;
if ( i >= MINWRITE || n == 1 ) {
if ( vfc && dcecps > 0 ) {
over = f->bytes - ( proc_ms ( ) - f->mstart ) * dcecps / 1000
- MAXDCEBUF ;
if ( over > 0 ) msleep ( over * 1000 / dcecps ) ;
}
if ( tput ( f, buf, i ) < 0 )
err = msg ( "ES2fax device write error:" ) ;
i = 0 ;
}
}
return err ;
}
char responses [ MAXRESPB ], *lresponse = responses ;
char *sresponse ( char *s, int *ip )
{
char *p, *r = 0 ;
int lens, lenr ;
lens = strlen ( s ) ;
for ( p=responses ; p<lresponse ; p += strlen(p) + 1 ) {
if ( ! strncmp ( p, s, lens ) ) {
r = p + lens ;
lenr = strlen ( r ) ;
if ( strspn ( r, " \r\n" ) == lenr && r+lenr < lresponse ) r += lenr ;
if ( ip && sscanf ( r, "%d", ip ) > 0 )
msg ( "R read value %d from \"%s\"", *ip, r ) ;
}
}
return r ;
}
char *strinresp ( char *s )
{
char *p, *r = 0 ;
for ( p=responses ; p<lresponse && !r ; p += strlen(p) + 1 )
if ( strncmp ( p, "AT", 2 ) )
r = strstr ( p, s ) ;
return r ;
}
int getresp ( char *s, char *buf, int len )
{
int err=0, n ;
char *p, *q ;
if ( ( p = strinresp ( s ) ) ) {
if ( ( q = strchr ( p, '=' ) ) ) p = q+1 ;
for ( q = p+strlen(p)-1 ; q>=p && isspace(*q) ; q-- ) ;
n = q - p + 1 ;
if ( n + strlen(buf) < len )
strncat ( buf, p, n ) ;
else
strncat ( buf, p, len - strlen(buf) - 1 ) ;
} else {
err = 1 ;
}
return err ;
}
char *strtabmatch ( char **p, char *s )
{
while ( *p && strncmp ( *p+1, s, strlen ( *p+1 ) ) ) p++ ;
return ( ! *p || **p == '-' ) ? NULL : *p ;
}
int cmd ( TFILE *f, char *s, int t )
{
char buf [ CMDBUFSIZE ], *p = "" ;
int resplen=0, pause=0 ;
#if defined(__APPLE__)
int ringcount = 0;
#endif
if ( t < 0 ) {
pause = cmdpause ;
t = -t ;
}
lresponse = responses ;
retry:
if ( s ) {
while ( tgets ( f, buf, CMDBUFSIZE, pause ) )
msg ( "W- unexpected response \"%s\"", buf ) ;
msg ( "C- command \"%s\"", s ) ;
if ( strlen(s) >= CMDBUFSIZE-4 ) {
msg ( "E modem command \"%s\" too long", s ) ;
} else {
sprintf ( buf, "AT%s\r", s ) ;
tput ( f, buf, strlen(buf) ) ;
}
}
if ( t ) {
msg ( "C- waiting %.1f s", ((float) t)/10 ) ;
while ( ( p = tgets ( f, buf, CMDBUFSIZE, t ) ) ) {
if ( ( resplen += strlen ( buf ) + 1 ) <= MAXRESPB ) {
strcpy ( lresponse, buf ) ;
lresponse += strlen ( buf ) + 1 ;
}
if ( ( p = strtabmatch ( (char**) prompts, buf ) ) ) {
msg ( "C- response \"%s\"", buf ) ;
break ;
}
if ( ! strcmp ( buf, "RING" ) ) {
#if defined(__APPLE__)
CFNumberRef value;
ringcount++;
value = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type, &ringcount);
notify(CFSTR("ring"), value);
CFRelease(value);
#endif
msleep ( 100 ) ;
goto retry ;
}
}
}
return p ? *p : EOF ;
}
int ckcmd ( TFILE *f, int *err, char *s, int t, int r )
{
int c=0 ;
if ( ( ! err || ! *err ) && ( c = cmd ( f, s, t ) ) != r && r ) {
msg ( err ? "E %s %s %s" : "W %s %s %s",
c == EOF ? "timed out" : "wrong response",
s ? "after command: " : "after waiting",
s ? s : "" ) ;
if ( err ) *err = 3 ;
}
return c ;
}
int modemsync ( TFILE *f )
{
int err=0, method=0 ;
for ( method=0 ; ! err ; method++ ) {
switch ( method ) {
case 0 :
break ;
case 1 :
break ;
case 2 :
msg ("Isync: dropping DTR") ;
ttymode ( f, COMMAND ) ; msleep ( 200 ) ;
ttymode ( f, DROPDTR ) ; msleep ( 200 ) ;
ttymode ( f, COMMAND ) ;
break ;
case 3 :
msg ("Isync: sending escapes") ;
ttymode ( f, VOICECOMMAND ) ;
tput ( f, CAN_STR, 1 ) ;
tput ( f, DLE_ETX, 2 ) ;
msleep ( 100 ) ;
ttymode ( f, COMMAND ) ;
tput ( f, CAN_STR, 1 ) ;
tput ( f, DLE_ETX, 2 ) ;
msleep ( 1500 ) ;
tput ( f, "+++", 3 ) ;
break ;
case 4 :
err = msg ("E4sync: modem not responding") ;
continue ;
}
while ( method && cmd ( f, 0, 20 ) != EOF ) ;
if ( cmd ( f, "Q0V1", -20 ) == OK ) break ;
}
return err ;
}
int setup ( TFILE *f, char **cmds, int ignerr )
{
int err=0 ;
char c ;
for ( ; ! err && *cmds ; cmds++ ) {
#if 0
if ( *cmds && isdigit( **cmds ) ) {
}
#endif
if ( ( c = cmd ( f, *cmds, -TO_RESET ) ) != OK && c != VCONNECT &&
! ignerr ) {
err = msg ( "E3modem command (%s) failed", *cmds ? *cmds : "none" ) ;
}
}
return err ;
}
int end_session ( TFILE *f, char **zcmd, char **lkfile, int sync )
{
int err = 0 ;
if ( f && sync )
err = modemsync ( f ) ;
if ( f && zcmd && ! err && sync )
err = setup ( f, zcmd, 0 ) ;
if ( f )
ttymode ( f, ORIGINAL ) ;
if ( lkfile )
unlockall ( f, lkfile ) ;
return err ;
}
int begin_session ( TFILE *f, char *fname, int reverse, int hwfc,
char **lkfile, ttymodes mode, void (*onsig) (int), int wait )
{
int i, err=0, busy=0, minbusy=0 ;
do {
err = lockall ( f, lkfile, busy >= minbusy ) ;
if ( ! err ) err = ttyopen ( f, fname, reverse, hwfc ) ;
if ( err == 1 ) {
if ( busy++ >= minbusy ) {
msg ( "W %s locked or busy. waiting.", fname ) ;
minbusy = minbusy ? minbusy*2 : 1 ;
}
if (tdata ( f, lockpolldelay / 100 ) == -6)
err = -6;
}
} while ( err == 1 ) ;
if ( ! err ) msg ( "Iopened %s", fname ) ;
if ( ! err ) err = ttymode ( f, mode ) ;
if ( ! err ) {
rd_init ( ) ;
f->rd_state = RD_BEGIN ;
}
for ( i=0 ; ! err && catch [ i ] ; i++ )
if ( signal ( catch [ i ], onsig ) == SIG_ERR )
err = msg ( "ES2can't set signal %d handler:", catch [ i ] ) ;
if ( !err ) err = modemsync ( f ) ;
return err ;
}