381 lines
9.7 KiB
C
381 lines
9.7 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Fidonet mailer
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2001
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 1971 BV IJmuiden
|
|
* the Netherlands
|
|
*
|
|
* This file is part of MBSE BBS.
|
|
*
|
|
* This BBS 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, or (at your option) any
|
|
* later version.
|
|
*
|
|
* MBSE BBS is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../lib/libs.h"
|
|
#include "../lib/structs.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/records.h"
|
|
#include "../lib/common.h"
|
|
#include "../lib/clcomm.h"
|
|
#include "../lib/dbnode.h"
|
|
#include "session.h"
|
|
#include "callstat.h"
|
|
#include "call.h"
|
|
#include "config.h"
|
|
#include "dial.h"
|
|
#include "lutil.h"
|
|
#include "portsel.h"
|
|
#include "openport.h"
|
|
#include "opentcp.h"
|
|
#include "rdoptions.h"
|
|
|
|
|
|
extern int tcp_mode;
|
|
extern int forcedcalls;
|
|
extern int immediatecall;
|
|
extern char *forcedphone;
|
|
extern char *forcedline;
|
|
extern char *inetaddr;
|
|
|
|
|
|
int checkretry(callstat *);
|
|
int checkretry(callstat *st)
|
|
{
|
|
Syslog('d', "Checkretry nr %d status %d", st->tryno, st->trystat);
|
|
if (st->tryno > 30)
|
|
return 2;
|
|
return 0;
|
|
/* check retries and time; rc=1 - not reached, rc=2 - undialable */
|
|
}
|
|
|
|
|
|
|
|
int portopen(faddr *addr)
|
|
{
|
|
char *p, *q;
|
|
int rc, speed;
|
|
pp_list *pl = NULL, *tmp;
|
|
|
|
if (inetaddr) {
|
|
Syslog('d', "portopen inetaddr %s", inetaddr);
|
|
if ((rc = opentcp(inetaddr))) {
|
|
Syslog('+', "Cannot connect %s", inetaddr);
|
|
nodeulock(addr);
|
|
putstatus(addr,1,ST_NOCONN);
|
|
return ST_NOCONN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (forcedline) {
|
|
Syslog('d', "portopen forcedline %s", forcedline);
|
|
p = forcedline;
|
|
if ((q = strchr(p, ':'))) { /* Note: DIT KAN WEG ! */
|
|
*q++ = '\0';
|
|
if ((*q == 'l') || (*q == 'L'))
|
|
speed=atoi(++q);
|
|
else {
|
|
speed = atoi(q);
|
|
if (nlent->speed < speed)
|
|
speed = nlent->speed;
|
|
}
|
|
}
|
|
|
|
if (load_port(p)) {
|
|
speed = ttyinfo.portspeed;
|
|
rc = openport(p,speed);
|
|
if (rc) {
|
|
Syslog('+', "Cannot open port %s",p);
|
|
nodeulock(addr);
|
|
putstatus(addr, 10, ST_PORTERR);
|
|
return ST_PORTERR;
|
|
}
|
|
return 0;
|
|
} else {
|
|
nodeulock(addr);
|
|
putstatus(addr, 0, ST_PORTERR);
|
|
return ST_PORTERR;
|
|
}
|
|
}
|
|
|
|
if (make_portlist(nlent, &pl) == 0) {
|
|
WriteError("No matching ports defined");
|
|
nodeulock(addr);
|
|
putstatus(addr, 10, ST_NOPORT);
|
|
return ST_NOPORT;
|
|
}
|
|
|
|
for (tmp = pl; tmp; tmp = tmp->next) {
|
|
if (load_port(tmp->tty)) {
|
|
Syslog('+', "Port %s at %ld, modem %s", ttyinfo.tty, ttyinfo.portspeed, modem.modem);
|
|
p = xstrcpy(tmp->tty);
|
|
speed = ttyinfo.portspeed;
|
|
rc = openport(p, speed);
|
|
free(p);
|
|
if (rc == 0) {
|
|
tidy_pplist(&pl);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
tidy_pplist(&pl);
|
|
nodeulock(addr);
|
|
putstatus(addr, 0, ST_PORTERR);
|
|
return ST_PORTERR;
|
|
}
|
|
|
|
|
|
|
|
int call(faddr *addr)
|
|
{
|
|
int i, j, rc = 1;
|
|
callstat *st;
|
|
struct hostent *he;
|
|
|
|
/*
|
|
* Don't call points, call their boss instead.
|
|
*/
|
|
addr->point = 0;
|
|
|
|
/*
|
|
* First check if node is locked, if not lock it immediatly
|
|
* or stop further waste of time and logfile space.
|
|
*/
|
|
if (nodelock(addr)) {
|
|
Syslog('+', "System %s is locked", ascfnode(addr, 0x1f));
|
|
putstatus(addr, 0, ST_LOCKED);
|
|
return ST_LOCKED;
|
|
}
|
|
nodeulock(addr);
|
|
|
|
if ((nlent = getnlent(addr)) == NULL) {
|
|
WriteError("Cannot call %s: fatal in nodelist lookup", ascfnode(addr, 0x1f));
|
|
putstatus(addr,0,ST_LOOKUP);
|
|
return ST_LOOKUP;
|
|
}
|
|
|
|
/*
|
|
* Load the noderecord if the node is in the setup.
|
|
*/
|
|
noderecord(addr);
|
|
rdoptions(TRUE);
|
|
|
|
/*
|
|
* Fill default history info in case we get a FTS0001 session
|
|
*/
|
|
sprintf(history.system_name, "%s", nlent->name);
|
|
sprintf(history.location, "%s", nlent->location);
|
|
history.aka.zone = addr->zone;
|
|
history.aka.net = addr->net;
|
|
history.aka.node = addr->node;
|
|
history.aka.point = addr->point;
|
|
if (addr->domain && strlen(addr->domain))
|
|
sprintf(history.aka.domain, "%s", addr->domain);
|
|
|
|
/*
|
|
* First see if this node can be reached over the internet and
|
|
* that internet calls are allowed.
|
|
*/
|
|
if (nlent->iflags && ((localoptions & NOTCP) == 0)) {
|
|
if (!inetaddr) {
|
|
Syslog('d', "Trying to find IP address...");
|
|
/*
|
|
* There is no fdn or IP address at the commandline.
|
|
* First check nodesetup for an override in the phone field.
|
|
*/
|
|
if (strlen(nodes.phone[0])) {
|
|
inetaddr = xstrcpy(nodes.phone[0]);
|
|
} else if (strlen(nodes.phone[1])) {
|
|
inetaddr = xstrcpy(nodes.phone[1]);
|
|
} else {
|
|
/*
|
|
* Try to find the fdn in several places in the nodelist fields.
|
|
*/
|
|
if ((nlent->phone != NULL) && (strncmp(nlent->phone, (char *)"000-", 4) == 0)) {
|
|
inetaddr = xstrcpy(nlent->phone+4);
|
|
for (i = 0; i < strlen(inetaddr); i++)
|
|
if (inetaddr[i] == '-')
|
|
inetaddr[i] = '.';
|
|
Syslog('d', "Got IP address from phone field");
|
|
} else if ((he = gethostbyname(nlent->name))) {
|
|
inetaddr = xstrcpy(nlent->name);
|
|
Syslog('d', "Got hostname from nodelist system name");
|
|
} else if ((he = gethostbyname(nlent->location))) {
|
|
/*
|
|
* A fdn at the nodelist location field is not in the specs
|
|
* but the real world differs from the specs.
|
|
*/
|
|
inetaddr = xstrcpy(nlent->location);
|
|
Syslog('d', "Got hostname from nodelist location");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have an internet address, set protocol
|
|
*/
|
|
if (inetaddr) {
|
|
Syslog('d', "TCP/IP node \"%s\"", MBSE_SS(inetaddr));
|
|
|
|
if (tcp_mode == TCPMODE_NONE) {
|
|
/*
|
|
* If protocol not forced at the commandline, get it
|
|
* from the nodelist. If it fails, fallback to dial.
|
|
* Priority IBN, IFC, ITN.
|
|
*/
|
|
if (nlent->iflags & IP_IBN)
|
|
tcp_mode = TCPMODE_IBN;
|
|
else if (nlent->iflags & IP_IFC)
|
|
tcp_mode = TCPMODE_IFC;
|
|
else if (nlent->iflags & IP_ITN)
|
|
tcp_mode = TCPMODE_ITN;
|
|
else {
|
|
Syslog('+', "No common TCP/IP protocols for node %s", nlent->name);
|
|
free(inetaddr);
|
|
inetaddr = NULL;
|
|
}
|
|
Syslog('d', "TCP mode set to %d", tcp_mode);
|
|
}
|
|
} else {
|
|
Syslog('d', "No IP address, fallback to dial");
|
|
tcp_mode = TCPMODE_NONE;
|
|
}
|
|
}
|
|
|
|
if (((nlent->oflags & OL_CM) == 0) && (!IsZMH())) {
|
|
if (!forcedcalls) {
|
|
Syslog('d', "Node is ZMH only and it is not ZMH");
|
|
nodeulock(addr);
|
|
putstatus(addr,0,ST_NOTZMH);
|
|
return ST_NOTZMH;
|
|
}
|
|
Syslog('?', "Warning: calling MO system outside ZMH");
|
|
}
|
|
|
|
st = getstatus(addr);
|
|
if ((rc = checkretry(st))) {
|
|
Syslog('+', "Cannot call %s: %s", ascfnode(addr,0x1f), (rc == 1)?"retry time not reached":"node undialable");
|
|
return 5;
|
|
}
|
|
|
|
/*
|
|
* Over TCP/IP we don't do a delay because the node we are
|
|
* connecting can't be busy. Also forced calls don't delay.
|
|
*/
|
|
Syslog('d', "delay=%d inetaddr=%s immediatecall=%s",
|
|
CFG.dialdelay, inetaddr?"true":"false", immediatecall?"true":"false");
|
|
if ((CFG.dialdelay > 10) && (!inetaddr) && (!immediatecall)) {
|
|
/*
|
|
* Generate a random number between CFG.dialdelay and
|
|
* CFG.dialdelay / 10, minimum value is 10.
|
|
*/
|
|
srand(getpid());
|
|
while (TRUE) {
|
|
j = 1+(int) (1.0 * CFG.dialdelay * rand() / (RAND_MAX + 1.0));
|
|
if ((j > (CFG.dialdelay / 10)) && (j > 9))
|
|
break;
|
|
}
|
|
Syslog('d', "Dial delay %d seconds", j);
|
|
|
|
for (i = j; i > 0; i--) {
|
|
IsDoing("Delay %d seconds", i);
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
if (nodelock(addr)) {
|
|
Syslog('+', "System %s is locked", ascfnode(addr, 0x1f));
|
|
putstatus(addr, 0, ST_LOCKED);
|
|
return ST_LOCKED;
|
|
}
|
|
|
|
if (inbound)
|
|
free(inbound);
|
|
inbound = xstrcpy(CFG.pinbound); /* master sessions are secure */
|
|
|
|
/*
|
|
* Call when:
|
|
* the nodelist has a phone, or phone on commandline, or TCP address given
|
|
* and
|
|
* nodenumber on commandline, or node is CM and not down, hold, pvt
|
|
* and
|
|
* nocall is false
|
|
*/
|
|
if ((nlent->phone || forcedphone || inetaddr ) && ((forcedcalls || (nlent->oflags & OL_CM)) ||
|
|
(((nlent->pflag & (NL_DUMMY|NL_DOWN|NL_HOLD|NL_PVT)) == 0) && ((localoptions & NOCALL) == 0)))) {
|
|
Syslog('+', "Calling %s (%s, phone %s)",ascfnode(addr,0x1f), nlent->name,nlent->phone?nlent->phone:forcedphone);
|
|
IsDoing("Call %s", ascfnode(addr, 0x0f));
|
|
rc = portopen(addr);
|
|
|
|
if ((rc == 0) && (!inetaddr)) {
|
|
if ((rc = dialphone(forcedphone?forcedphone:nlent->phone))) {
|
|
Syslog('+', "Dial failed");
|
|
nodeulock(addr);
|
|
rc+=1; /* rc=2 - dial fail, rc=3 - could not reset */
|
|
}
|
|
}
|
|
|
|
if (rc == 0) {
|
|
if (!inetaddr)
|
|
nolocalport();
|
|
|
|
if (tcp_mode == TCPMODE_IBN)
|
|
rc = session(addr,nlent,SESSION_MASTER,SESSION_BINKP,NULL);
|
|
else
|
|
rc = session(addr,nlent,SESSION_MASTER,SESSION_UNKNOWN,NULL);
|
|
|
|
if (rc)
|
|
rc=abs(rc)+10;
|
|
}
|
|
|
|
IsDoing("Disconnect");
|
|
if (inetaddr) {
|
|
closetcp();
|
|
} else {
|
|
hangup();
|
|
if (rc == 0)
|
|
aftercall();
|
|
localport();
|
|
closeport();
|
|
}
|
|
} else {
|
|
IsDoing("NoCall");
|
|
Syslog('+', "Cannot call %s (%s, phone %s)", ascfnode(addr,0x1f),MBSE_SS(nlent->name), MBSE_SS(nlent->phone));
|
|
if ((nlent->phone || forcedphone || inetaddr ))
|
|
rc=ST_NOCALL8;
|
|
else
|
|
rc=ST_NOCALL7;
|
|
putstatus(addr, 10, rc);
|
|
nodeulock(addr);
|
|
return rc;
|
|
}
|
|
|
|
if ((rc > 10) && (rc < 20)) /* Session error */
|
|
putstatus(addr, 5, rc);
|
|
else if ((rc == 2) || (rc == 30))
|
|
putstatus(addr,1,rc);
|
|
else
|
|
putstatus(addr,0,rc);
|
|
return rc;
|
|
}
|
|
|
|
|