You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bforce/source/bforce/io_modem.c

466 lines
9.9 KiB
C

/*
* binkleyforce -- unix FTN mailer project
*
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* $Id$
*/
#include "includes.h"
#include "confread.h"
#include "logger.h"
#include "util.h"
#include "io.h"
const char *modem_errlist[] =
{
"No error",
"Modem return ERROR",
"Can't send string to modem",
"Modem not response",
NULL
};
/* ------------------------------------------------------------------------- */
/* Get connect speed from connect string returned by modem */
/* ------------------------------------------------------------------------- */
long modem_getconnspeed(const char *connstr)
{
const char *p;
for( p = connstr; *p; p++ )
{
if( isdigit(*p) )
return atol(p);
}
return 0L;
}
bool modem_isgood_phone(const char *str)
{
if( !str || !str[0] )
return FALSE;
if( str[0] == '-' && str[1] == '\0' )
return FALSE;
if( string_casestr(str, "unpublished") )
return FALSE;
if( string_casestr(str, "unknown") )
return FALSE;
if( string_casestr(str, "none") )
return FALSE;
return TRUE;
}
/* ------------------------------------------------------------------------- */
/* Translate phone number using given rules, returned value must be free'ed! */
/* ------------------------------------------------------------------------- */
char *modem_transphone(char *buffer, const char *phone, size_t buflen)
{
const char *p;
s_cval_entry *ptrl;
ASSERT(phone != NULL);
DEB((D_MODEM, "translate_phone: want translate \"%s\"", phone));
for( ptrl = conf_first(cf_phone_translate); ptrl;
ptrl = conf_next(ptrl) )
{
if( !ptrl->d.translate.find )
continue;
if( (p = strstr(phone, ptrl->d.translate.find)) )
{
DEB((D_MODEM, "translate_phone: replace \"%s\" with \"%s\"",
ptrl->d.translate.find, ptrl->d.translate.repl));
strnxcpy(buffer, phone, buflen);
if( p - phone < buflen - 1 )
{
buffer[p - phone] = '\0';
if( ptrl->d.translate.repl )
strnxcat(buffer, ptrl->d.translate.repl, buflen);
strnxcat(buffer, p + strlen(ptrl->d.translate.find), buflen);
}
DEB((D_MODEM, "translate_phone: result is \"%s\"", buffer));
return buffer;
}
}
return strnxcpy(buffer, phone, buflen);
}
/* ------------------------------------------------------------------------- */
/* Send string to modem, using some control character sequences, like */
/* '\r' - CR, '\P' - phone number, etc.. */
/* ------------------------------------------------------------------------- */
int modem_putstr(const char *str)
{
const char *ptr;
int rc;
bool flushed = FALSE;
DEB((D_MODEM, "modem_putstr: want to send \"%s\"", str));
rc = TTY_SUCCESS;
ptr = str;
while( *ptr )
{
/* Flush buffer before "special" operations */
if( !flushed && strchr("~`^v", *ptr) )
{
flushed = TRUE;
if( (rc = tty_flushout()) < 0 )
return rc;
}
switch( *ptr ) {
case '~':
sleep(1);
break;
case '`':
usleep(250000L);
break;
case '^':
rc = tio_set_dtr(0, 1);
break;
case 'v':
rc = tio_set_dtr(0, 0);
break;
case '|':
case '\r':
rc = tty_putc('\r', 2);
if( !rc && !(rc = tty_flushout()) )
{
/*
* Make sure that we will never send
* anything to the modem immediately
* after CR
*/
/* i changed value for my modem
* (from 250000 */
usleep(500000);
flushed = TRUE;
}
break;
case '\\':
++ptr;
switch(*ptr) {
case '\0':
rc = tty_putc('\\', 2);
break;
case 'r':
rc = tty_putc('\r', 2);
break;
case 'n':
rc = tty_putc('\n', 2);
break;
default:
rc = tty_putc(*ptr, 2);
}
flushed = FALSE;
break;
default:
rc = tty_putc(*ptr, 2);
flushed = FALSE;
}
if( rc < 0 )
return rc;
++ptr;
}
if( !flushed && (rc = tty_flushout()) < 0 )
return rc;
return 0;
}
void modem_clearin(int timeout)
{
time_t timer;
timer_set(&timer, timeout);
while( CHARWAIT(1) )
{
CLEARIN();
if( timer_expired(timer) )
return;
usleep(100000); /* 0.1 seconds delay */
}
}
/* ------------------------------------------------------------------------- */
/* Reads in at most one less than $bufsize characters from modem and */
/* stores them into the buffer pointed to by $buf, check for timeout. */
/* $timer must be set with tty_settimer() call! */
/* ------------------------------------------------------------------------- */
int modem_getline(char *buf, int bufsize, time_t timer)
{
int rc = 0, pos = 0;
ASSERT(buf != NULL || bufsize == 0);
while(1)
{
if( timer_expired(timer) )
return TTY_TIMEOUT;
if( (rc = tty_getc(1)) < 0 && rc != TTY_TIMEOUT )
return rc;
else if( rc == '\r' || rc == '\n' )
return pos;
else if( rc > 0 )
{
if( pos < bufsize-1 )
{
buf[pos++] = rc;
buf[pos ] = '\0';
} else
return pos;
}
}
}
/* ------------------------------------------------------------------------- */
/* Dial using phone number $phone, if connection will be established - */
/* put connect string to *connstr (must be freed) */
/* ------------------------------------------------------------------------- */
int modem_dial(const char *dialstr, int timeout, char **connstr)
{
s_cval_entry *ptrl;
char buf[MODEM_MAX_RESP+1];
time_t timer;
int len = 0;
ASSERT(dialstr != NULL && connstr != NULL);
*connstr = NULL;
if( modem_putstr(dialstr) != TTY_SUCCESS )
{
log("error sending dial string \"%s\"", dialstr);
return -1;
}
timer_set(&timer, timeout);
while(1)
{
if( timer_expired(timer) )
{
log("dialing timed out");
return -1;
}
if( (len = modem_getline(buf, sizeof(buf), timer)) < 0 )
{
if( len == TTY_TIMEOUT )
log("dialing timed out");
return -1;
}
else if( len > 0 )
{
DEB((D_MODEM, "modem_dial: got \"%s\"", buf));
for( ptrl = conf_first(cf_modem_dial_response); ptrl;
ptrl = conf_next(ptrl) )
{
if( ptrl->d.dialresp.mstr && strstr(buf, ptrl->d.dialresp.mstr) )
{
if( ptrl->d.dialresp.retv == RESPTYPE_CONNECT )
{
*connstr = xstrcpy(buf);
return 0;
}
return ptrl->d.dialresp.retv;
}
}
if( *buf )
log("modem: \"%s\"", string_printable(buf));
}
}
}
int modem_command(const char *command, int timeout, bool logit)
{
time_t timer;
size_t count = 0;
int len = 0;
char buffer[MODEM_MAX_RESP+1];
char cmdstr[MODEM_MAX_COMMAND+1];
char *n;
char *p;
ASSERT(command != NULL);
strnxcpy(cmdstr, command, sizeof(cmdstr));
DEB((D_MODEM, "modem_command: command string \"%s\"", cmdstr));
CLEARIN();
for( p = string_token(cmdstr, &n, NULL, 1); p;
p = string_token(NULL, &n, NULL, 1) )
{
DEB((D_MODEM, "modem_command: send \"%s\"",
string_printable(p)));
if( modem_putstr(p) < 0 )
return MODEM_CANTSEND;
count = 0;
timer_set(&timer, timeout);
while(1)
{
if( timer_expired(timer) )
return MODEM_NORESP;
if( (len = modem_getline(buffer, sizeof(buffer), timer)) < 0 )
{
return MODEM_NORESP;
}
else if( len > 0 )
{
count += len;
if( count > MODEM_MAX_RESP_SIZE )
{
log("modem response exceeds limit %ld bytes",
(long)count);
return MODEM_NORESP;
}
DEB((D_MODEM, "modem_command: got \"%s\"",
string_printable(buffer)));
if( !strcmp(buffer, "ERROR") )
return MODEM_ERROR;
else if( !strcmp(buffer, "OK") )
break;
else if( logit )
log("modem: \"%s\"", string_printable(buffer));
}
}
}
return MODEM_OK;
}
int modem_hangup(const char *command, int timeout)
{
#ifdef MODEM_HANGUP_WATCH_CARRIER
time_t timer;
ASSERT(command != NULL);
if( tio_get_dcd(0) == 1 )
{
DEB((D_MODEM, "modem_hangup: send \"%s\"", command));
if( modem_putstr(command) < 0 )
return MODEM_CANTSEND;
timer_set(&timer, timeout);
while( tio_get_dcd(0) == 1 )
{
if( timer_expired(timer) )
return MODEM_NORESP;
sleep(1);
}
}
sleep(2); CLEARIN(); CLEAROUT();
return MODEM_OK;
#else /* MODEM_HANGUP_WATCH_CARRIER */
return modem_command(command, timeout, FALSE);
#endif
}
bool modem_candialout(const char *modemdev)
{
char tmp[BF_MAXPATH+1];
const char *p_nodial = conf_string(cf_nodial_flag);
char *p = NULL;
if( p_nodial && *p_nodial )
{
if( access(p_nodial, F_OK) == 0 )
return FALSE;
strnxcpy(tmp, p_nodial, sizeof(tmp));
strnxcat(tmp, ".", sizeof(tmp));
strnxcat(tmp, (p = port_get_name(modemdev)), sizeof(tmp));
if( p )
free(p);
if( access(tmp, F_OK) == 0 )
return FALSE;
}
return TRUE;
}
/* ------------------------------------------------------------------------- */
/* Return pointer to the first not locked now tty */
/* ------------------------------------------------------------------------- */
s_modemport *modem_getfree_port(const char *lockdir)
{
s_cval_entry *ptrl;
/* Find first not locked modem device */
for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) )
{
if( port_checklock(lockdir, &ptrl->d.modemport) == LOCKCHECK_NOLOCK
&& modem_candialout(ptrl->d.modemport.name) == TRUE )
return &ptrl->d.modemport;
}
return NULL;
}
/* ------------------------------------------------------------------------- */
/* Return pointer to the first tty whose name contain substring `ttyname' */
/* ------------------------------------------------------------------------- */
s_modemport *modem_getmatch_port(const char *substr)
{
s_cval_entry *ptrl;
/* Find first matching modem device */
for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) )
{
if( strstr(ptrl->d.modemport.name, substr) )
return &ptrl->d.modemport;
}
return NULL;
}