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.
847 lines
20 KiB
C
847 lines
20 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$
|
|
*
|
|
* BUG: When we resend EMSIDAT packet, it's TRX# field is most probable
|
|
* out of date.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "confread.h"
|
|
#include "version.h"
|
|
#include "logger.h"
|
|
#include "util.h"
|
|
#include "io.h"
|
|
#include "nodelist.h"
|
|
#include "session.h"
|
|
#include "prot_common.h"
|
|
#include "prot_emsi.h"
|
|
|
|
/*
|
|
* #define EMSI_INQ "**EMSI_INQC816"
|
|
* #define EMSI_REQ "**EMSI_REQA77E"
|
|
* #define EMSI_ACK "**EMSI_ACKA490"
|
|
* #define EMSI_NAK "**EMSI_NAKEEC3"
|
|
* #define EMSI_CLI "**EMSI_CLIFA8C"
|
|
* #define EMSI_ICI "**EMSI_ICI2D73"
|
|
* #define EMSI_HBT "**EMSI_HBTEAEE"
|
|
* #define EMSI_IRQ "**EMSI_IRQ8E08"
|
|
*/
|
|
|
|
typedef struct tx_emsidat {
|
|
int caller;
|
|
int tries;
|
|
time_t mast_timer;
|
|
time_t sync_timer;
|
|
char buf[13];
|
|
int emsi_seq;
|
|
int nakcount; /* count received EMSI_NAK */
|
|
s_emsi *local_emsi;
|
|
} s_tx_emsidat;
|
|
|
|
typedef struct rx_emsidat {
|
|
int caller;
|
|
int rx_ack; /* strip second EMSI_ACK */
|
|
int tries;
|
|
int tries_recv;
|
|
time_t mast_timer;
|
|
time_t sync_timer;
|
|
char buf[13];
|
|
int emsi_seq;
|
|
s_emsi *remote_emsi;
|
|
} s_rx_emsidat;
|
|
|
|
/*
|
|
* State machine (TODO: REMOVE!) Now it is used only by EMSI protocol.
|
|
*/
|
|
static int state_machine(s_states *sm, void *data)
|
|
{
|
|
signed int cur_state = 0;
|
|
|
|
do
|
|
{
|
|
DEB((D_STATEM, "state_machine: entering with state \"%s\" (%d)",
|
|
sm[cur_state].st_name, cur_state));
|
|
cur_state = (*(sm[cur_state].proc))(data);
|
|
DEB((D_STATEM, "state_machine: return \"%s\" (%d)",
|
|
(cur_state>0)?sm[cur_state].st_name:"finish", cur_state));
|
|
}
|
|
while( cur_state > 0 );
|
|
|
|
return(cur_state);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Transmite EMSI_DAT packet state machine routines */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* SM0 */
|
|
static int sm_tx_init(s_tx_emsidat *d)
|
|
{
|
|
timer_set(&d->mast_timer, 60);
|
|
|
|
return(SM1);
|
|
}
|
|
|
|
/* SM1 */
|
|
static int sm_tx_senddat(s_tx_emsidat *d)
|
|
{
|
|
char *emsi_dat = NULL;
|
|
char buf[8];
|
|
|
|
if( ++d->tries > 6 )
|
|
{
|
|
log("too many tries sending emsi data");
|
|
return(SME);
|
|
}
|
|
|
|
if( d->tries > 1 )
|
|
log("emsi data send - retry %d", d->tries - 1);
|
|
|
|
DEB((D_HSHAKE, "sm_tx_senddat: try number %d", d->tries));
|
|
|
|
if( (emsi_dat = emsi_createdat(d->local_emsi)) == NULL )
|
|
{
|
|
log("cannot create emsi data packet");
|
|
return(SME);
|
|
}
|
|
|
|
DEB((D_HSHAKE, "sm_tx_senddat: emsi: \"%s\"", emsi_dat));
|
|
|
|
if( tty_puts(emsi_dat, 60) < 0 )
|
|
{
|
|
free(emsi_dat);
|
|
return SME;
|
|
}
|
|
|
|
/*
|
|
* Calculate and send CRC-16 of our emsi packet
|
|
*/
|
|
sprintf(buf, "%04hX\r",
|
|
(short unsigned)getcrc16xmodem(emsi_dat+2, strlen(emsi_dat+2)));
|
|
|
|
free(emsi_dat); emsi_dat = NULL;
|
|
|
|
if( PUTSTR(buf) < 0 || FLUSHOUT() < 0 )
|
|
return SME;
|
|
|
|
return SM2;
|
|
}
|
|
|
|
/* SM2 */
|
|
static int sm_tx_waitseq(s_tx_emsidat *d)
|
|
{
|
|
int rc, pos = 0;
|
|
|
|
timer_set(&d->sync_timer, (d->tries > 1) ? 20 : 10);
|
|
|
|
while(1)
|
|
{
|
|
if( timer_expired(d->mast_timer) )
|
|
{
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: master timer expired"));
|
|
log("master timer expired");
|
|
return(SME);
|
|
}
|
|
|
|
if( timer_expired(d->sync_timer) )
|
|
{
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: sync timer expired"));
|
|
return(SM1);
|
|
}
|
|
|
|
if( (rc = GETCHAR(1)) < 0 )
|
|
{
|
|
if( rc != TTY_TIMEOUT )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: got ERROR/HANGUP"));
|
|
return SME;
|
|
}
|
|
}
|
|
else if( rc == XON || rc == XOFF )
|
|
{
|
|
/* Do nothing. Drop them down */
|
|
}
|
|
else if( rc == '*' )
|
|
{
|
|
memset(d->buf, '\0', sizeof(d->buf));
|
|
pos = 0;
|
|
d->emsi_seq = 1;
|
|
}
|
|
else if( d->emsi_seq && rc > ' ' && rc < '~' )
|
|
{
|
|
if( pos < sizeof(d->buf)-1 )
|
|
{
|
|
d->buf[pos++] = rc;
|
|
d->buf[pos ] = '\0';
|
|
}
|
|
|
|
if( pos == (sizeof(d->buf) - 1) )
|
|
{
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: emsi buffer full \"%s\"", d->buf));
|
|
|
|
d->emsi_seq = 0;
|
|
|
|
if( !strncasecmp(d->buf, "EMSI_REQA77E", 12) )
|
|
{
|
|
/* Do nothing. Drop it down */
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_ACKA490", 12) )
|
|
{
|
|
/*
|
|
* Remote acknowleged our
|
|
* emsi data packet. exit.
|
|
*/
|
|
return SM0;
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_NAKEEC3", 12) )
|
|
{
|
|
/*
|
|
* Remote failed on our emsi data
|
|
* packet. Resend EMSI_DAT only after
|
|
* first EMSI_NAK
|
|
*/
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: got NAK"));
|
|
if( !d->nakcount++ )
|
|
return SM1;
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_INQC816", 12) )
|
|
{
|
|
/*
|
|
* Do nothing. Just update sync timer
|
|
*/
|
|
return SM2;
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_DAT", 8) )
|
|
{
|
|
/*
|
|
* 1) We are calling system
|
|
* We got an echo of our sequence,
|
|
* possible they don't know about
|
|
* FIDO. yet :) Resend EMSI_INQ
|
|
* again.
|
|
* 2) We are asnwering system
|
|
* Think where is a stupid mailer
|
|
* that didn't seen our EMSI_ACK,
|
|
* so send it again in hope to the
|
|
* best
|
|
*/
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: got echo \"%s\"",
|
|
string_printable(d->buf)));
|
|
|
|
if( d->caller )
|
|
{
|
|
/* Wait for a login prompt */
|
|
sleep(2);
|
|
|
|
if( PUTSTR("**EMSI_INQC816\r") < 0
|
|
|| FLUSHOUT() < 0 )
|
|
return SME;
|
|
|
|
/* Wait for a password prompt */
|
|
sleep(2);
|
|
|
|
if( PUTSTR("**EMSI_INQC816\r") < 0
|
|
|| FLUSHOUT() < 0 )
|
|
return SME;
|
|
|
|
return SM1;
|
|
}
|
|
else
|
|
{
|
|
/* Send acknowlegment */
|
|
if( PUTSTR("**EMSI_ACKA490\r**EMSI_ACKA490\r") < 0 )
|
|
return SME;
|
|
if( FLUSHOUT() < 0 )
|
|
return SME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEB((D_HSHAKE, "got unexpected emsi sequence: \"%s\"",
|
|
string_printable(d->buf)));
|
|
log("got unexpected emsi sequence \"%s\"",
|
|
string_printable(d->buf));
|
|
}
|
|
}
|
|
}
|
|
else if( d->emsi_seq )
|
|
{
|
|
d->emsi_seq = 0;
|
|
DEB((D_HSHAKE, "sm_tx_waitseq: bad character 0x%02x in \"%s\"",
|
|
rc, string_printable(d->buf)));
|
|
}
|
|
}
|
|
|
|
return SME;
|
|
}
|
|
|
|
static s_states st_tx_emsidat[] =
|
|
{
|
|
{ "sm_tx_init", sm_tx_init },
|
|
{ "sm_tx_senddat", sm_tx_senddat },
|
|
{ "sm_tx_waitseq", sm_tx_waitseq }
|
|
};
|
|
|
|
int emsi_send_emsidat(s_emsi *local_emsi)
|
|
{
|
|
s_tx_emsidat d;
|
|
|
|
memset(&d, '\0', sizeof(s_tx_emsidat));
|
|
|
|
d.caller = state.caller;
|
|
d.local_emsi = local_emsi;
|
|
|
|
return state_machine(st_tx_emsidat, &d) ? 1 : 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Receive EMSI_DAT packet state machine routines */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* SM0 */
|
|
static int sm_rx_init(s_rx_emsidat *d)
|
|
{
|
|
timer_set(&d->mast_timer, 60);
|
|
timer_set(&d->sync_timer, 20);
|
|
|
|
return SM1;
|
|
}
|
|
|
|
/* SM1 */
|
|
static int sm_rx_sendnak(s_rx_emsidat *d)
|
|
{
|
|
if( ++d->tries > 6 )
|
|
{
|
|
log("too many tries resyncing with remote");
|
|
return(SME);
|
|
}
|
|
|
|
DEB((D_HSHAKE, "sm_rx_sendnak: try number %d", d->tries));
|
|
|
|
if( !d->caller )
|
|
{
|
|
if( conf_boolean(cf_emsi_slave_sends_nak)
|
|
&& PUTSTR("**EMSI_NAKEEC3\r") < 0 )
|
|
return SME;
|
|
if( PUTSTR("**EMSI_REQA77E\r") < 0 )
|
|
return SME;
|
|
}
|
|
else if( d->tries > 1 )
|
|
{
|
|
if( PUTSTR("**EMSI_NAKEEC3\r") < 0 )
|
|
return SME;
|
|
}
|
|
|
|
if( FLUSHOUT() < 0 )
|
|
return SME;
|
|
|
|
return SM2;
|
|
}
|
|
|
|
/* SM2 */
|
|
static int sm_rx_waitseq(s_rx_emsidat *d)
|
|
{
|
|
int rc, pos = 0;
|
|
|
|
timer_set(&d->sync_timer, 20);
|
|
|
|
while(1)
|
|
{
|
|
if( timer_expired(d->mast_timer) )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: master timer expired"));
|
|
log("master timer expired");
|
|
return SME;
|
|
}
|
|
|
|
if( timer_expired(d->sync_timer) )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: sync timer expired"));
|
|
return SM1;
|
|
}
|
|
|
|
if( (rc = GETCHAR(1)) < 0 )
|
|
{
|
|
if( rc != TTY_TIMEOUT )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: got ERROR/HANGUP"));
|
|
return SME;
|
|
}
|
|
}
|
|
else if( rc == XON || rc == XOFF )
|
|
{
|
|
/* Do nothing. Drop them down */
|
|
}
|
|
else if( rc == '*' )
|
|
{
|
|
memset(d->buf, '\0', sizeof(d->buf));
|
|
pos = 0;
|
|
d->emsi_seq = 1;
|
|
}
|
|
else if( d->emsi_seq && rc > ' ' && rc < '~' )
|
|
{
|
|
if( pos < sizeof(d->buf)-1 )
|
|
{
|
|
d->buf[pos++] = rc;
|
|
d->buf[pos ] = '\0';
|
|
}
|
|
|
|
if( pos == sizeof(d->buf)-1 )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: emsi buffer full \"%s\"", d->buf));
|
|
|
|
d->emsi_seq = 0;
|
|
|
|
if( d->caller && !strncasecmp(d->buf, "EMSI_ACKA490", 12) )
|
|
{
|
|
/* Do nothing. Drop it down. */
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_HBTEAEE", 12) )
|
|
{
|
|
/*
|
|
* Remote wants some time to think
|
|
*/
|
|
return SM2;
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_DAT", 8) )
|
|
{
|
|
/*
|
|
* Start receiving emsi data packet
|
|
*/
|
|
return SM3;
|
|
}
|
|
else if( !strncasecmp(d->buf, "EMSI_INQC816", 12) )
|
|
{
|
|
return SM2;
|
|
}
|
|
else
|
|
{
|
|
DEB((D_HSHAKE, "got unexpected emsi sequence: \"%s\"",
|
|
string_printable(d->buf)));
|
|
log("got unexpected emsi sequence \"%s\"",
|
|
string_printable(d->buf));
|
|
}
|
|
}
|
|
}
|
|
else if( d->emsi_seq )
|
|
{
|
|
d->emsi_seq = 0;
|
|
DEB((D_HSHAKE, "sm_rx_waitseq: bad character 0x%02x in \"%s\"",
|
|
rc, string_printable(d->buf)));
|
|
}
|
|
}
|
|
|
|
return SME;
|
|
}
|
|
|
|
/* SM3 */
|
|
static int sm_rx_getdat(s_rx_emsidat *d)
|
|
{
|
|
int rc = 0;
|
|
int pos = 0;
|
|
int emsi_len = 0;
|
|
short unsigned ourcrc;
|
|
short unsigned remcrc;
|
|
char *emsi_dat = NULL;
|
|
|
|
if( d->tries_recv++ )
|
|
log("emsi data receive - retry %d", d->tries_recv);
|
|
|
|
/*
|
|
* At this point, there is a EMSI_DATXXXX packet in
|
|
* the buffer, there XXXX is the hex length of emsi
|
|
* data packet
|
|
*/
|
|
if( strspn(d->buf+8, "0123456789abcdefABCDEF") != 4 )
|
|
return SM1;
|
|
|
|
if( sscanf(d->buf+8, "%04x", &emsi_len) != 1 )
|
|
return SM1;
|
|
|
|
/*
|
|
* Don't receive emsi packet's longer our "limit"
|
|
*/
|
|
if( emsi_len > EMSI_MAXDAT )
|
|
{
|
|
CLEARIN();
|
|
log("emsi data packet too long %db (maximum %db allowed)",
|
|
emsi_len, EMSI_MAXDAT);
|
|
return SM1;
|
|
}
|
|
|
|
/* Increase packet's length on CRC length */
|
|
emsi_len += 16;
|
|
|
|
emsi_dat = (char*)xmalloc(emsi_len + 1);
|
|
strncpy(emsi_dat, d->buf, 12);
|
|
pos = 12;
|
|
|
|
while( pos < emsi_len )
|
|
{
|
|
if( timer_expired(d->mast_timer) )
|
|
break;
|
|
|
|
if( (rc = GETCHAR(1)) < 0 )
|
|
{
|
|
if( rc != TTY_TIMEOUT )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
emsi_dat[pos++] = (unsigned char)rc;
|
|
emsi_dat[pos ] = '\0';
|
|
}
|
|
}
|
|
|
|
if( pos != emsi_len )
|
|
{
|
|
/* Fatal error occured */
|
|
DEB((D_HSHAKE, "sm_rx_getdat: can't get emsi_dat packet"));
|
|
DEB((D_HSHAKE, "sm_rx_getdat: buffer: \"%s\"",
|
|
string_printable(emsi_dat)));
|
|
free(emsi_dat);
|
|
return SME;
|
|
}
|
|
|
|
DEB((D_HSHAKE, "sm_rx_getdat: got \"%s\"",
|
|
string_printable(emsi_dat)));
|
|
|
|
/*
|
|
* Get CRC given by remote
|
|
*/
|
|
if( sscanf(emsi_dat + emsi_len - 4 , "%04hX", &remcrc) != 1 )
|
|
{
|
|
log("bad emsi data packet (can't get CRC16)");
|
|
free(emsi_dat);
|
|
|
|
return(SM1);
|
|
}
|
|
|
|
/*
|
|
* Calculate our own crc of the data packet
|
|
*/
|
|
ourcrc = getcrc16xmodem(emsi_dat, emsi_len-4);
|
|
|
|
/*
|
|
* Compare our and remote CRCs
|
|
*/
|
|
if( ourcrc != remcrc )
|
|
{
|
|
DEB((D_HSHAKE, "sm_rx_getdat: our = %hX, remote = %hX", ourcrc, remcrc));
|
|
log("got emsi data packet with bad CRC");
|
|
free(emsi_dat);
|
|
|
|
return SM1;
|
|
}
|
|
|
|
/*
|
|
* Parse received emsi data packet. All obtained
|
|
* information will be stored in d->remote_emsi
|
|
*/
|
|
rc = emsi_parsedat(emsi_dat+12, d->remote_emsi);
|
|
|
|
free(emsi_dat);
|
|
|
|
if( rc )
|
|
{
|
|
log("received invalid emsi data packet");
|
|
return SM1;
|
|
}
|
|
|
|
/* Send acknowlegment */
|
|
if( PUTSTR("**EMSI_ACKA490\r**EMSI_ACKA490\r") < 0 )
|
|
return SME;
|
|
if( FLUSHOUT() < 0 )
|
|
return SME;
|
|
|
|
return SM0;
|
|
}
|
|
|
|
static s_states st_rx_emsidat[] =
|
|
{
|
|
{ "sm_rx_init", sm_rx_init },
|
|
{ "sm_rx_sendnak", sm_rx_sendnak },
|
|
{ "sm_rx_waitseq", sm_rx_waitseq },
|
|
{ "sm_rx_getdat", sm_rx_getdat }
|
|
};
|
|
|
|
int emsi_recv_emsidat(s_emsi *remote_emsi)
|
|
{
|
|
s_rx_emsidat d;
|
|
|
|
memset(&d, '\0', sizeof(s_rx_emsidat));
|
|
|
|
d.caller = state.caller;
|
|
d.remote_emsi = remote_emsi;
|
|
|
|
return state_machine(st_rx_emsidat, &d) ? 1 : 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Fill/update our outgoing emsi oriented structure */
|
|
/* ------------------------------------------------------------------------- */
|
|
void emsi_set_sysinfo(s_emsi *emsi, s_emsi *remote_emsi, int hrc,
|
|
e_protocol protocol)
|
|
{
|
|
char buf[64];
|
|
s_cval_entry *addr_ptr;
|
|
s_cval_entry *hide_ptr;
|
|
s_faddr *primary = NULL;
|
|
|
|
const long options = conf_options(cf_options);
|
|
const long speed = conf_number(cf_max_speed);
|
|
const char *p_systname = conf_string(cf_system_name);
|
|
const char *p_location = conf_string(cf_location);
|
|
const char *p_sysopname = conf_string(cf_sysop_name);
|
|
const char *p_phone = conf_string(cf_phone);
|
|
const char *p_flags = conf_string(cf_flags);
|
|
const char *p_emsioh = conf_string(cf_emsi_OH_time);
|
|
const char *p_emsifr = conf_string(cf_emsi_FR_time);
|
|
|
|
/* free previously allocated memory */
|
|
if( emsi->addrs ) free(emsi->addrs);
|
|
|
|
memset(emsi, '\0', sizeof(s_emsi));
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* Data for {EMSI} field */
|
|
/* ----------------------------------------------------------------- */
|
|
emsi->have_emsi = 1;
|
|
|
|
/* Set best primary address */
|
|
primary = session_get_bestaka(state.node.addr);
|
|
|
|
/* Add primary address */
|
|
if( primary )
|
|
session_addrs_add(&emsi->addrs, &emsi->anum, *primary);
|
|
|
|
/* Add other AKAs */
|
|
for( addr_ptr = conf_first(cf_address); addr_ptr;
|
|
addr_ptr = conf_next(addr_ptr) )
|
|
{
|
|
for( hide_ptr = conf_first(cf_hide_our_aka); hide_ptr;
|
|
hide_ptr = conf_next(hide_ptr) )
|
|
{
|
|
if( !ftn_addrcomp(hide_ptr->d.falist.addr, addr_ptr->d.falist.addr) )
|
|
break;
|
|
}
|
|
|
|
if( !hide_ptr && primary != &addr_ptr->d.falist.addr )
|
|
session_addrs_add(&emsi->addrs, &emsi->anum,
|
|
addr_ptr->d.falist.addr);
|
|
}
|
|
|
|
if( emsi->anum == 0 )
|
|
log("warning: no addresses will be presented to remote");
|
|
|
|
/* session password */
|
|
if( state.caller )
|
|
{
|
|
session_get_password(state.node.addr, emsi->passwd, sizeof(emsi->passwd));
|
|
}
|
|
else if( hrc == HRC_OK )
|
|
{
|
|
/* Satisfy remote with their password */
|
|
const char *p = state.handshake->remote_password(state.handshake);
|
|
if( p )
|
|
strnxcpy(emsi->passwd, p, sizeof(emsi->passwd));
|
|
}
|
|
|
|
/* link codes */
|
|
if( state.caller ) /* CALLER */
|
|
{
|
|
if( (options & OPTIONS_NO_RH1) != OPTIONS_NO_RH1
|
|
&& (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA)
|
|
{ emsi->linkcodes.RH1 = 1; }
|
|
|
|
if( (options & OPTIONS_NO_PICKUP) == OPTIONS_NO_PICKUP )
|
|
{ emsi->linkcodes.NPU = 1; }
|
|
else
|
|
{ emsi->linkcodes.PUA = 1; }
|
|
|
|
if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY )
|
|
{ emsi->linkcodes.HXT = 1; }
|
|
|
|
if( (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II )
|
|
{
|
|
/* EMSI-II */
|
|
if( (options & OPTIONS_HOLDREQ) != OPTIONS_HOLDREQ )
|
|
{ emsi->linkcodes.RMA = 1; }
|
|
}
|
|
else
|
|
{
|
|
/* EMSI-I */
|
|
emsi->linkcodes.N81 = 1;
|
|
}
|
|
}
|
|
else if( (remote_emsi->compcodes.EII == 1)
|
|
&& (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II )
|
|
{
|
|
/* ANSWER/EMSI-II */
|
|
if( remote_emsi->linkcodes.RH1 && protocol == PROT_HYDRA )
|
|
{ emsi->linkcodes.RH1 = 1; }
|
|
|
|
if( state.reqstat == REQS_ALLOW && remote_emsi->linkcodes.RMA )
|
|
{ emsi->linkcodes.RMA = 1; }
|
|
else if( state.reqstat == REQS_NOTALLOW )
|
|
{ emsi->linkcodes.HRQ = 1; }
|
|
|
|
if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY )
|
|
{ emsi->linkcodes.HXT = 1; }
|
|
}
|
|
else
|
|
{
|
|
/* ANSWER/EMSI-I */
|
|
if( remote_emsi->linkcodes.RH1 && protocol == PROT_HYDRA )
|
|
{ emsi->linkcodes.RH1 = 1; }
|
|
|
|
if( state.reqstat == REQS_NOTALLOW )
|
|
{ emsi->linkcodes.HRQ = 1; }
|
|
|
|
if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY )
|
|
{ emsi->linkcodes.HXT = 1; }
|
|
}
|
|
|
|
/* compatibility codes */
|
|
if( state.caller )
|
|
{
|
|
if( (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II )
|
|
{
|
|
/* EMSI-II */
|
|
emsi->compcodes.EII = 1;
|
|
}
|
|
else
|
|
{
|
|
/* EMSI-I */
|
|
emsi->compcodes.ARC = 1;
|
|
emsi->compcodes.XMA = 1;
|
|
}
|
|
if( (options & OPTIONS_NO_ZMODEM) != OPTIONS_NO_ZMODEM )
|
|
{ emsi->compcodes.ZMO = 1; }
|
|
if( (options & OPTIONS_NO_ZEDZAP) != OPTIONS_NO_ZEDZAP )
|
|
{ emsi->compcodes.ZAP = 1; }
|
|
if( (options & OPTIONS_NO_DIRZAP) != OPTIONS_NO_DIRZAP )
|
|
{ emsi->compcodes.DZA = 1; }
|
|
if( (options & OPTIONS_NO_JANUS) != OPTIONS_NO_JANUS )
|
|
{ emsi->compcodes.JAN = 1; }
|
|
if( (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA )
|
|
{ emsi->compcodes.HYD = 1; }
|
|
}
|
|
else
|
|
{
|
|
if( (remote_emsi->compcodes.EII == 1)
|
|
&& (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II )
|
|
{
|
|
/* EMSI-II */
|
|
emsi->compcodes.EII = 1;
|
|
}
|
|
else
|
|
{
|
|
/* EMSI-I */
|
|
emsi->compcodes.ARC = 1;
|
|
emsi->compcodes.XMA = 1;
|
|
}
|
|
|
|
if( state.reqstat == REQS_DISABLED )
|
|
{ emsi->compcodes.NRQ = 1; }
|
|
|
|
switch(protocol) {
|
|
case PROT_NOPROT: emsi->compcodes.NCP = 1; break;
|
|
case PROT_ZMODEM: emsi->compcodes.ZMO = 1; break;
|
|
case PROT_ZEDZAP: emsi->compcodes.ZAP = 1; break;
|
|
case PROT_DIRZAP: emsi->compcodes.DZA = 1; break;
|
|
case PROT_JANUS: emsi->compcodes.JAN = 1; break;
|
|
case PROT_HYDRA: emsi->compcodes.HYD = 1; break;
|
|
default: ASSERT(FALSE); break;
|
|
}
|
|
}
|
|
|
|
strnxcpy(emsi->m_pid, BF_EMSI_NUM, sizeof(emsi->m_pid));
|
|
strnxcpy(emsi->m_name, BF_EMSI_NAME, sizeof(emsi->m_name));
|
|
|
|
if( hrc != HRC_BAD_PASSWD )
|
|
{
|
|
strnxcpy(emsi->m_ver, BF_EMSI_VER, sizeof(emsi->m_ver));
|
|
strnxcpy(emsi->m_reg, BF_EMSI_REG, sizeof(emsi->m_reg));
|
|
}
|
|
else
|
|
{
|
|
strnxcpy(emsi->m_ver, "?", sizeof(emsi->m_ver));
|
|
strnxcpy(emsi->m_reg, "?", sizeof(emsi->m_reg));
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* Data for {IDENT} field */
|
|
/* ----------------------------------------------------------------- */
|
|
emsi->have_ident = 1;
|
|
emsi->speed = (speed > 0) ? speed : 300;
|
|
|
|
strnxcpy(emsi->sysop, p_sysopname ? p_sysopname : "Unknown", sizeof(emsi->sysop));
|
|
strnxcpy(emsi->phone, p_phone ? p_phone : "Unknown", sizeof(emsi->phone));
|
|
|
|
switch(hrc) {
|
|
case HRC_BAD_PASSWD:
|
|
strnxcpy(emsi->sname, "Bad password", sizeof(emsi->sname));
|
|
strnxcpy(emsi->location, "Check security table", sizeof(emsi->location));
|
|
strnxcpy(emsi->flags, "Password Error", sizeof(emsi->flags));
|
|
break;
|
|
case HRC_LOW_SPEED:
|
|
strnxcpy(emsi->sname, "Connect speed too low", sizeof(emsi->sname));
|
|
strnxcpy(emsi->location, "Buy new modem and call again", sizeof(emsi->location));
|
|
sprintf(buf, "Minimal speed: %ldbps", (long)state.minspeed);
|
|
strnxcpy(emsi->flags, buf, sizeof(emsi->flags));
|
|
break;
|
|
case HRC_BUSY:
|
|
strnxcpy(emsi->sname, "All AKAs are busy", sizeof(emsi->sname));
|
|
strnxcpy(emsi->location, "Possible another session is running", sizeof(emsi->location));
|
|
strnxcpy(emsi->flags, "Please, call later", sizeof(emsi->flags));
|
|
break;
|
|
default:
|
|
strnxcpy(emsi->sname, p_systname ? p_systname : "Unknown", sizeof(emsi->sname));
|
|
strnxcpy(emsi->location, p_location ? p_location : "Unknown", sizeof(emsi->location));
|
|
strnxcpy(emsi->flags, p_flags ? p_flags : "MO", sizeof(emsi->flags));
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* Data for {OHFR} field */
|
|
/* ----------------------------------------------------------------- */
|
|
if( p_emsioh && *p_emsioh && hrc != HRC_BAD_PASSWD )
|
|
{
|
|
emsi->have_ohfr = 1;
|
|
strnxcpy(emsi->oh_time, p_emsioh, sizeof(emsi->oh_time));
|
|
if( p_emsifr && *p_emsifr )
|
|
strnxcpy(emsi->fr_time, p_emsifr, sizeof(emsi->fr_time));
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* Data for {TRX#} field */
|
|
/* ----------------------------------------------------------------- */
|
|
emsi->have_trx = 1;
|
|
emsi->time = localtogmt(time(NULL));
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* Data for {TRAF} and {MOH#} fields */
|
|
/* ----------------------------------------------------------------- */
|
|
if( state.caller == 0 && hrc != HRC_BAD_PASSWD )
|
|
{
|
|
emsi->have_traf = 1;
|
|
emsi->netmail_size = state.traff_send.netmail_size;
|
|
emsi->arcmail_size = state.traff_send.arcmail_size;
|
|
if ( state.traff_send.files_size )
|
|
{
|
|
emsi->have_moh = 1;
|
|
emsi->files_size = state.traff_send.files_size;
|
|
}
|
|
}
|
|
}
|
|
|