601 lines
13 KiB
C
601 lines
13 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Fidonet mailer
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2003
|
|
*
|
|
* 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#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/nodelist.h"
|
|
#include "../lib/mberrors.h"
|
|
#include "ttyio.h"
|
|
#include "statetbl.h"
|
|
#include "emsi.h"
|
|
#include "ftsc.h"
|
|
#include "session.h"
|
|
#include "yoohoo.h"
|
|
#include "mbcico.h"
|
|
#include "binkp.h"
|
|
#include "callstat.h"
|
|
#include "inbound.h"
|
|
#include "opentcp.h"
|
|
|
|
|
|
extern int tcp_mode;
|
|
extern pid_t mypid;
|
|
|
|
|
|
node *nlent = NULL;
|
|
fa_list *remote = NULL;
|
|
int session_flags;
|
|
int remote_flags;
|
|
|
|
int tx_define_type(void);
|
|
int rx_define_type(void);
|
|
|
|
static int type;
|
|
static char *data=NULL;
|
|
|
|
struct sockaddr_in peeraddr;
|
|
|
|
|
|
char *typestr(int);
|
|
char *typestr(int tp)
|
|
{
|
|
switch (tp) {
|
|
case SESSION_FTSC: return (char *)"FTS-0001";
|
|
case SESSION_YOOHOO: return (char *)"YooHoo/2U2";
|
|
case SESSION_EMSI: return (char *)"EMSI";
|
|
case SESSION_BINKP: return (char *)"Binkp";
|
|
default: return (char *)"Unknown";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int session(faddr *a, node *nl, int role, int tp, char *dt)
|
|
{
|
|
int rc = MBERR_OK, addrlen = sizeof(struct sockaddr_in);
|
|
fa_list *tmpl;
|
|
|
|
session_flags = 0;
|
|
type = tp;
|
|
nlent = nl;
|
|
|
|
if (getpeername(0,(struct sockaddr*)&peeraddr,&addrlen) == 0) {
|
|
Syslog('s', "TCP connection: len=%d, family=%hd, port=%hu, addr=%s",
|
|
addrlen,peeraddr.sin_family, peeraddr.sin_port, inet_ntoa(peeraddr.sin_addr));
|
|
if (role == 0) {
|
|
if (tcp_mode == TCPMODE_IBN) {
|
|
Syslog('+', "Incoming IBN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr));
|
|
IsDoing("Incoming IBN/TCP");
|
|
} else if (tcp_mode == TCPMODE_IFC) {
|
|
Syslog('+', "Incoming IFC/TCP connection from %s", inet_ntoa(peeraddr.sin_addr));
|
|
IsDoing("Incoming IFC/TCP");
|
|
} else if (tcp_mode == TCPMODE_ITN) {
|
|
Syslog('+', "Incoming ITN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr));
|
|
IsDoing("Incoming ITN/TCP");
|
|
} else if (tcp_mode == TCPMODE_NONE) {
|
|
WriteError("Unknown TCP connection, parameter missing");
|
|
die(MBERR_COMMANDLINE);
|
|
}
|
|
}
|
|
session_flags |= SESSION_TCP;
|
|
}
|
|
|
|
if (data)
|
|
free(data);
|
|
data=NULL;
|
|
|
|
if (dt)
|
|
data=xstrcpy(dt);
|
|
|
|
emsi_local_protos=0;
|
|
emsi_local_opts=0;
|
|
emsi_local_lcodes=0;
|
|
|
|
tidy_falist(&remote);
|
|
remote=NULL;
|
|
if (a) {
|
|
remote=(fa_list*)malloc(sizeof(fa_list));
|
|
remote->next=NULL;
|
|
remote->addr=(faddr*)malloc(sizeof(faddr));
|
|
remote->addr->zone=a->zone;
|
|
remote->addr->net=a->net;
|
|
remote->addr->node=a->node;
|
|
remote->addr->point=a->point;
|
|
remote->addr->domain=xstrcpy(a->domain);
|
|
remote->addr->name=NULL;
|
|
} else {
|
|
remote=NULL;
|
|
}
|
|
|
|
remote_flags=SESSION_FNC;
|
|
|
|
if (role) {
|
|
if (type == SESSION_UNKNOWN)
|
|
(void)tx_define_type();
|
|
Syslog('+', "Start outbound %s session with %s", typestr(type), ascfnode(a,0x1f));
|
|
switch(type) {
|
|
case SESSION_UNKNOWN: rc = MBERR_UNKNOWN_SESSION; break;
|
|
case SESSION_FTSC: rc = tx_ftsc(); break;
|
|
case SESSION_YOOHOO: rc = tx_yoohoo(); break;
|
|
case SESSION_EMSI: rc = tx_emsi(data); break;
|
|
case SESSION_BINKP: rc = binkp(role); break;
|
|
}
|
|
} else {
|
|
if (type == SESSION_FTSC)
|
|
session_flags |= FTSC_XMODEM_CRC;
|
|
if (type == SESSION_UNKNOWN)
|
|
(void)rx_define_type();
|
|
Syslog('+', "Start inbound %s session", typestr(type));
|
|
switch(type) {
|
|
case SESSION_UNKNOWN: rc = MBERR_UNKNOWN_SESSION; break;
|
|
case SESSION_FTSC: rc = rx_ftsc(); break;
|
|
case SESSION_YOOHOO: rc = rx_yoohoo(); break;
|
|
case SESSION_EMSI: rc = rx_emsi(data); break;
|
|
case SESSION_BINKP: rc = binkp(role); break;
|
|
}
|
|
}
|
|
sleep(2);
|
|
for (tmpl = remote; tmpl; tmpl = tmpl->next) {
|
|
/*
|
|
* Unlock all nodes, locks not owned by us are untouched.
|
|
*/
|
|
(void)nodeulock(tmpl->addr, mypid);
|
|
/*
|
|
* If successfull session, reset all status records.
|
|
*/
|
|
if (rc == 0)
|
|
putstatus(tmpl->addr, 0, 0);
|
|
}
|
|
tidy_falist(&remote);
|
|
if (data)
|
|
free(data);
|
|
data = NULL;
|
|
|
|
if (emsi_local_password)
|
|
free(emsi_local_password);
|
|
if (emsi_remote_password)
|
|
free(emsi_remote_password);
|
|
|
|
if (nlent->addr.domain)
|
|
free(nlent->addr.domain);
|
|
|
|
inbound_close(rc == 0);
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
SM_DECL(tx_define_type,(char *)"tx_define_type")
|
|
SM_STATES
|
|
skipjunk,
|
|
wake,
|
|
waitchar,
|
|
nextchar,
|
|
checkintro,
|
|
sendinq
|
|
SM_NAMES
|
|
(char *)"skipjunk",
|
|
(char *)"wake",
|
|
(char *)"waitchar",
|
|
(char *)"nextchar",
|
|
(char *)"checkintro",
|
|
(char *)"sendinq"
|
|
SM_EDECL
|
|
int c = 0;
|
|
char buf[256], *p;
|
|
char ebuf[13], *ep;
|
|
int standby = 0;
|
|
|
|
int maybeftsc=0;
|
|
int maybeyoohoo=0;
|
|
|
|
type = SESSION_UNKNOWN;
|
|
ebuf[0] = '\0';
|
|
ep = ebuf;
|
|
buf[0] = '\0';
|
|
p = buf;
|
|
|
|
SM_START(skipjunk)
|
|
|
|
SM_STATE(skipjunk)
|
|
|
|
Syslog('s', "tx_define_type SKIPJUNK");
|
|
while ((c = GETCHAR(1)) >= 0) /*nothing*/ ;
|
|
if (c == TIMEOUT) {
|
|
gpt_resettimers();
|
|
gpt_settimer(0, 60); /* 60 second master timer */
|
|
SM_PROCEED(wake);
|
|
} else {
|
|
SM_ERROR;
|
|
}
|
|
|
|
SM_STATE(wake)
|
|
|
|
Syslog('s', "tx_define_type WAKE");
|
|
if (gpt_expired(0)) {
|
|
Syslog('+', "Remote did not respond");
|
|
SM_ERROR;
|
|
}
|
|
|
|
p = buf;
|
|
PUTCHAR('\r');
|
|
if ((c = GETCHAR(2)) == TIMEOUT) {
|
|
SM_PROCEED(wake);
|
|
} else if (c < 0) {
|
|
WriteError("Error while waking remote");
|
|
SM_ERROR;
|
|
} else {
|
|
gpt_settimer(0, 60);
|
|
Syslog('S', "Got %c wakeup", c);
|
|
SM_PROCEED(nextchar);
|
|
}
|
|
|
|
SM_STATE(waitchar)
|
|
|
|
if ((c = GETCHAR(2)) == TIMEOUT) {
|
|
standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
if (gpt_expired(0)) {
|
|
Syslog('+', "Too many tries waking remote");
|
|
SM_ERROR;
|
|
}
|
|
SM_PROCEED(sendinq);
|
|
} else if (c < 0) {
|
|
Syslog('+', "Error while getting intro from remote");
|
|
SM_ERROR;
|
|
} else {
|
|
SM_PROCEED(nextchar);
|
|
}
|
|
|
|
SM_STATE(nextchar)
|
|
|
|
if (c == 'C') {
|
|
session_flags |= FTSC_XMODEM_CRC;
|
|
maybeftsc++;
|
|
}
|
|
if (c == NAK) {
|
|
session_flags &= ~FTSC_XMODEM_CRC;
|
|
maybeftsc++;
|
|
}
|
|
if (c == ENQ)
|
|
maybeyoohoo++;
|
|
|
|
if (((localoptions & NOWAZOO) == 0) && (maybeyoohoo > 1)) {
|
|
type = SESSION_YOOHOO;
|
|
SM_SUCCESS;
|
|
}
|
|
|
|
if (maybeftsc > 1) {
|
|
type = SESSION_FTSC;
|
|
SM_SUCCESS;
|
|
}
|
|
|
|
if ((c >= ' ') && (c <= '~')) {
|
|
if (c != 'C')
|
|
maybeftsc = 0;
|
|
maybeyoohoo = 0;
|
|
|
|
if ((p-buf) < (sizeof(buf)-1)) {
|
|
*p++ = c;
|
|
*p = '\0';
|
|
}
|
|
|
|
if (c == '*') {
|
|
standby = 1;
|
|
ep = ebuf;
|
|
buf[0] = '\0';
|
|
} else if (standby) {
|
|
if ((ep - ebuf) < (sizeof(ebuf) - 1)) {
|
|
*ep++ = c;
|
|
*ep = '\0';
|
|
}
|
|
if ((ep - ebuf) >= (sizeof(ebuf) - 1)) {
|
|
standby = 0;
|
|
SM_PROCEED(checkintro);
|
|
}
|
|
}
|
|
} else {
|
|
switch (c) {
|
|
case DC1: break;
|
|
case '\r':
|
|
case '\n': standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
if (buf[0])
|
|
Syslog('+', "Intro: \"%s\"", printable(buf, 0));
|
|
p = buf;
|
|
buf[0] = '\0';
|
|
break;
|
|
default: standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
Syslog('i', "Got '%s' reading intro", printablec(c));
|
|
break;
|
|
}
|
|
}
|
|
SM_PROCEED(waitchar);
|
|
|
|
SM_STATE(checkintro)
|
|
|
|
Syslog('i', "Check \"%s\" for being EMSI request",ebuf);
|
|
|
|
if (((localoptions & NOEMSI) == 0) && (strncasecmp(ebuf,"EMSI_REQA77E",12) == 0)) {
|
|
type = SESSION_EMSI;
|
|
data = xstrcpy((char *)"**EMSI_REQA77E");
|
|
Syslog('i', "Sending **EMSI_INQC816 (2 times)");
|
|
PUTSTR((char *)"\r**EMSI_INQC816\r**EMSI_INQC816\r\021");
|
|
SM_SUCCESS;
|
|
} else {
|
|
p = buf;
|
|
buf[0] = '\0';
|
|
SM_PROCEED(waitchar);
|
|
}
|
|
|
|
SM_STATE(sendinq)
|
|
|
|
Syslog('s', "tx_define_type SENDINQ");
|
|
PUTCHAR(DC1);
|
|
if ((localoptions & NOEMSI) == 0) {
|
|
Syslog('S', "send **EMSI_INQC816 (2 times)");
|
|
PUTSTR((char *)"\r**EMSI_INQC816\r**EMSI_INQC816");
|
|
}
|
|
if ((localoptions & NOWAZOO) == 0) {
|
|
Syslog('S', "send YOOHOO char");
|
|
PUTCHAR(YOOHOO);
|
|
}
|
|
Syslog('S', "send TSYNC char");
|
|
PUTCHAR(TSYNC);
|
|
if ((localoptions & NOEMSI) == 0)
|
|
PUTSTR((char *)"\r\021");
|
|
SM_PROCEED(waitchar);
|
|
|
|
SM_END
|
|
SM_RETURN
|
|
|
|
|
|
|
|
SM_DECL(rx_define_type,(char *)"rx_define_type")
|
|
SM_STATES
|
|
sendintro,
|
|
settimer,
|
|
waitchar,
|
|
nextchar,
|
|
checkemsi,
|
|
getdat
|
|
SM_NAMES
|
|
(char *)"sendintro",
|
|
(char *)"settimer",
|
|
(char *)"waitchar",
|
|
(char *)"nextchar",
|
|
(char *)"checkemsi",
|
|
(char *)"getdat"
|
|
SM_EDECL
|
|
int count=0;
|
|
int c=0;
|
|
int maybeftsc=0,maybeyoohoo=0;
|
|
char ebuf[13],*ep;
|
|
char *p;
|
|
int standby=0;
|
|
int datasize;
|
|
|
|
type=SESSION_UNKNOWN;
|
|
session_flags|=FTSC_XMODEM_CRC;
|
|
ebuf[0]='\0';
|
|
ep=ebuf;
|
|
gpt_resettimers();
|
|
gpt_settimer(0, 60);
|
|
gpt_settimer(1, 20);
|
|
|
|
SM_START(sendintro)
|
|
|
|
SM_STATE(sendintro)
|
|
|
|
if (count++ > 6) {
|
|
Syslog('+', "Too many tries to get anything from the caller");
|
|
SM_ERROR;
|
|
}
|
|
|
|
Syslog('s', "rxdefine_type SENDINTRO count=%d", count);
|
|
|
|
standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
|
|
if ((localoptions & NOEMSI) == 0) {
|
|
PUTSTR((char *)"**EMSI_REQA77E\r\021");
|
|
}
|
|
PUTCHAR('\r');
|
|
if (STATUS) {
|
|
SM_ERROR;
|
|
} else {
|
|
SM_PROCEED(settimer);
|
|
}
|
|
|
|
SM_STATE(settimer)
|
|
|
|
Syslog('s', "Set 20 secs timer");
|
|
gpt_settimer(1, 20);
|
|
SM_PROCEED(waitchar);
|
|
|
|
SM_STATE(waitchar)
|
|
|
|
if (gpt_expired(0)) {
|
|
Syslog('+', "Session setup timeout");
|
|
SM_ERROR;
|
|
}
|
|
|
|
if (gpt_expired(1)) {
|
|
Syslog('s', "20 sec timer timeout");
|
|
SM_PROCEED(sendintro);
|
|
}
|
|
|
|
if ((c = GETCHAR(1)) == TIMEOUT) {
|
|
SM_PROCEED(waitchar);
|
|
} else if (c < 0) {
|
|
Syslog('+', "Session setup error");
|
|
SM_ERROR;
|
|
} else {
|
|
SM_PROCEED(nextchar);
|
|
}
|
|
|
|
SM_STATE(nextchar)
|
|
|
|
if ((c >= ' ') && (c <= 'z')) {
|
|
if (c == '*') {
|
|
standby = 1;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
} else if (standby) {
|
|
if ((ep - ebuf) < (sizeof(ebuf) - 1)) {
|
|
*ep++ = c;
|
|
*ep = '\0';
|
|
}
|
|
if ((ep - ebuf) >= (sizeof(ebuf) - 1)) {
|
|
standby = 0;
|
|
SM_PROCEED(checkemsi);
|
|
}
|
|
}
|
|
SM_PROCEED(waitchar);
|
|
} else {
|
|
switch (c) {
|
|
case DC1: SM_PROCEED(waitchar);
|
|
break;
|
|
case TSYNC: standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
if (++maybeftsc > 1) {
|
|
type = SESSION_FTSC;
|
|
SM_SUCCESS;
|
|
} else {
|
|
SM_PROCEED(waitchar);
|
|
}
|
|
break;
|
|
case YOOHOO:standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
if (++maybeyoohoo > 1) {
|
|
type = SESSION_YOOHOO;
|
|
SM_SUCCESS;
|
|
} else {
|
|
SM_PROCEED(waitchar);
|
|
}
|
|
break;
|
|
case '\r':
|
|
case '\n': standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
if (ebuf[0]) {
|
|
SM_PROCEED(checkemsi);
|
|
} else {
|
|
/*
|
|
* If the 20 second timer is expired or after the
|
|
* first sendintro, send the intro again. After
|
|
* that take it easy.
|
|
*/
|
|
if (gpt_expired(1) || (count == 1)) {
|
|
Syslog('s', "sendintro after eol char");
|
|
SM_PROCEED(sendintro);
|
|
} else {
|
|
Syslog('s', "waitchar after eol char");
|
|
SM_PROCEED(waitchar);
|
|
}
|
|
}
|
|
break;
|
|
default: standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
Syslog('i', "Got '%s' from remote", printablec(c));
|
|
SM_PROCEED(waitchar);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SM_STATE(checkemsi)
|
|
|
|
Syslog('i', "check \"%s\" for being EMSI inquery or data",ebuf);
|
|
|
|
if (localoptions & NOEMSI) {
|
|
Syslog('s', "Force sendintro");
|
|
SM_PROCEED(sendintro);
|
|
}
|
|
|
|
if (strncasecmp(ebuf, "EMSI_INQC816", 12) == 0) {
|
|
type = SESSION_EMSI;
|
|
data = xstrcpy((char *)"**EMSI_INQC816");
|
|
SM_SUCCESS;
|
|
} else if (strncasecmp(ebuf, "EMSI_HBT", 8) == 0) {
|
|
standby = 0;
|
|
ep = ebuf;
|
|
ebuf[0] = '\0';
|
|
SM_PROCEED(settimer);
|
|
} else if (strncasecmp(ebuf, "EMSI_DAT", 8) == 0) {
|
|
SM_PROCEED(getdat);
|
|
} else {
|
|
SM_PROCEED(settimer);
|
|
}
|
|
|
|
SM_STATE(getdat)
|
|
|
|
Syslog('i', "Try get emsi_dat packet starting with \"%s\"",ebuf);
|
|
|
|
if (sscanf(ebuf+8, "%04x", &datasize) != 1) {
|
|
SM_PROCEED(sendintro);
|
|
}
|
|
|
|
datasize += 18; /* strlen("**EMSI_DATxxxxyyyy"), include CRC */
|
|
data=malloc(datasize+1);
|
|
strcpy(data,"**");
|
|
strcat(data, ebuf);
|
|
p = data + strlen(data);
|
|
|
|
while (((p - data) < datasize) && ((c = GETCHAR(8)) >= 0)) {
|
|
*p++ = c;
|
|
*p= '\0';
|
|
}
|
|
if (c == TIMEOUT) {
|
|
Syslog('s', "c = TIMEOUT -> sendintro");
|
|
SM_PROCEED(sendintro);
|
|
} else if (c < 0) {
|
|
Syslog('+', "Error while reading EMSI_DAT from the caller");
|
|
SM_ERROR;
|
|
}
|
|
type = SESSION_EMSI;
|
|
SM_SUCCESS;
|
|
|
|
SM_END
|
|
SM_RETURN
|
|
|