/*****************************************************************************
 *
 * File ..................: mbcico/ftsc.c
 * Purpose ...............: Fidonet mailer 
 * Last modification date : 05-Jun-1999
 *
 *****************************************************************************
 * Copyright (C) 1997-1999
 *   
 * Michiel Broek		FIDO:		2:2801/16
 * Beekmansbos 10		Internet:	mbroek@ux123.pttnwb.nl
 * 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 "../include/libs.h"
#include "../include/structs.h"
#include "../common/common.h"
#include "session.h"
#include "ttyio.h"
#include "statetbl.h"
#include "config.h"
#include "ftsc.h"
#include "rdoptions.h"
#include "recvbark.h"
#include "filelist.h"
#include "sendbark.h"
#include "xmrecv.h"
#include "xmsend.h"

extern int master;
static int rxftsc(void);
static int txftsc(void);
static int recvfiles(void);
static file_list *tosend;


int rx_ftsc(void)
{
	int	rc;

	Syslog('+', "Start inbound FTS-0001 session");
	IsDoing("FTS-0001 inbound");

	session_flags |= SESSION_BARK;
	if ((rc = rxftsc())) {
		WriteError("Session failed: rc=%d",rc);
		PUTCHAR(CAN);
		PUTCHAR(CAN);
		PUTCHAR(CAN);
	} else 
		Syslog('+', "FTS-0001 session completed");

	tidy_filelist(tosend,0);
	tosend = NULL;
	return rc;
}




int tx_ftsc(void)
{
	int	rc;

	Syslog('+', "Start outbound FTS-0001 session with %s",
		ascfnode(remote->addr,0x1f));
	IsDoing("FTS-0001 to %s", ascfnode(remote->addr, 0x0f));

	if ((rc = txftsc())) {
		WriteError("Session failed: rc=%d",rc);
		PUTCHAR(CAN);
		PUTCHAR(CAN);
		PUTCHAR(CAN);
	} else 
		Syslog('+', "FTS-0001 session completed");

	tidy_filelist(tosend,0);
	tosend = NULL;
	return rc;
}



SM_DECL(txftsc,(char *)"txftsc")
SM_STATES
	wait_command,
	recv_mail,
	send_req,
	recv_req
SM_NAMES
	(char *)"wait_command",
	(char *)"recv_mail",
	(char *)"send_req",
	(char *)"recv_req"
SM_EDECL

	int c,rc;
	char *nonhold_mail;

	if (localoptions & NOHOLD) nonhold_mail=(char *)ALL_MAIL;
	else nonhold_mail=(char *)NONHOLD_MAIL;
	tosend=create_filelist(remote,nonhold_mail,2);

	if ((rc=xmsndfiles(tosend))) return rc;

SM_START(wait_command)

SM_STATE(wait_command)

	c=GETCHAR(30);
	if (c == TIMEOUT)
	{
		Syslog('+', "timeout waiting for remote action, try receive");
		SM_PROCEED(recv_mail);
	}
	else if (c < 0)
	{
		Syslog('+', "got error waiting for TSYNC: received %d",c);
		SM_ERROR;
	}
	else switch (c)
	{
	case TSYNC:	SM_PROCEED(recv_mail);
			break;
	case SYN:	SM_PROCEED(recv_req);
			break;
	case ENQ:	SM_PROCEED(send_req);
			break;
	case 'C':
	case NAK:	PUTCHAR(EOT);
			SM_PROCEED(wait_command);
			break;
	case CAN:	SM_SUCCESS;  /* this is not in BT */
			break;
	default:	if (c > ' ') Syslog('s', "got '%c' waiting command",c);
			else Syslog('s', "got '\\%03o' waiting command",c);
			PUTCHAR(SUB);
			SM_PROCEED(wait_command);
			break;
	}

SM_STATE(recv_mail)

	if (recvfiles()) {SM_ERROR;}
	else {SM_PROCEED(wait_command);}

SM_STATE(send_req)

	if (sendbark()) {SM_ERROR;}
	else {SM_SUCCESS;}

SM_STATE(recv_req)

	if (recvbark()) {SM_ERROR;}
	else {SM_PROCEED(wait_command);}

SM_END
SM_RETURN


SM_DECL(rxftsc,(char *)"rxftsc")
SM_STATES
	recv_mail,
	send_mail,
	send_req,
	recv_req
SM_NAMES
	(char *)"recv_mail",
	(char *)"send_mail",
	(char *)"send_req",
	(char *)"recv_req"
SM_EDECL

	int c,count=0;

SM_START(recv_mail)

SM_STATE(recv_mail)

	if (recvfiles()) {SM_ERROR;}
	else {SM_PROCEED(send_mail);}

SM_STATE(send_mail)

	if (count > 6) {SM_ERROR;}

	if (tosend == NULL) {SM_PROCEED(send_req);}

	PUTCHAR(TSYNC);
	c=GETCHAR(15);
	count++;
	if (c == TIMEOUT)
	{
		Syslog('+', "no NAK, cannot send mail");
		SM_ERROR;
	}
	else if (c < 0)
	{
		Syslog('+', "got error waiting for NAK: received %d",c);
		SM_ERROR;
	}
	else switch (c)
	{
	case 'C':
	case NAK:	if (xmsndfiles(tosend)) {SM_ERROR;}
			else {SM_PROCEED(send_req);}
			break;
	case CAN:	Syslog('+', "remote refused to pick mail");
			SM_SUCCESS;
			break;
	case EOT:	PUTCHAR(ACK);
			SM_PROCEED(send_mail);
			break;
	default:	if (c > ' ') Syslog('s', "got '%c' waiting NAK",c);
			else Syslog('s', "got '\\%03o' waiting NAK",c);
			SM_PROCEED(send_mail);
			break;
	}

SM_STATE(send_req)

	if (count > 6) {SM_ERROR;}

	if ( 1 /* has no .req file */ ) {SM_PROCEED(recv_req);}

	PUTCHAR(SYN);
	c=GETCHAR(15);
	count++;
	if (c == TIMEOUT)
	{
		Syslog('+', "no ENQ, cannot send requests");
		SM_ERROR;
	}
	else if (c < 0)
	{
		Syslog('+', "got error waiting for ENQ: received %d",c);
		SM_ERROR;
	}
	else switch (c)
	{
	case ENQ:	if (sendbark()) {SM_ERROR;}
			else {SM_PROCEED(recv_req);}
			break;
	case CAN:	Syslog('+', "remote refused to accept request");
			SM_PROCEED(recv_req);
			break;
	case 'C':
	case NAK:	PUTCHAR(EOT);
			SM_PROCEED(send_req);
			break;
	case SUB:	SM_PROCEED(send_req);
			break;
	default:	if (c > ' ') Syslog('s', "got '%c' waiting ENQ",c);
			else Syslog('s', "got '\\%03o' waiting ENQ",c);
			SM_PROCEED(send_req);
			break;
	}

SM_STATE(recv_req)

	if (recvbark()) {SM_ERROR;}
	else {SM_SUCCESS;}

SM_END
SM_RETURN


SM_DECL(recvfiles,(char *)"recvfiles")
SM_STATES
	recv_packet,
	scan_packet,
	recv_file
SM_NAMES
	(char *)"recv_packet",
	(char *)"scan_packet",
	(char *)"recv_file"
SM_EDECL

	int	rc=0;
	char	recvpktname[16];
	char	*fpath;
	FILE	*fp;
	faddr	f,t;
	fa_list	**tmpl;
	int	loaded = FALSE;

SM_START(recv_packet)

SM_STATE(recv_packet)

	sprintf(recvpktname,"%08lx.pkt",(unsigned long)sequencer());
	rc=xmrecv(recvpktname);
	if (rc == 1) {SM_SUCCESS;}
	else if (rc == 0)
	{
		if (master) {SM_PROCEED(recv_file);}
		else {SM_PROCEED(scan_packet);}
	}
	else {SM_ERROR;}

SM_STATE(scan_packet)

	fpath=xstrcpy(inbound);
	fpath=xstrcat(fpath,(char *)"/");
	fpath=xstrcat(fpath,recvpktname);
	fp=fopen(fpath,"r");
	free(fpath);
	if (fp == NULL)
	{
		WriteError("$cannot open received packet");
		SM_ERROR;
	}
	switch (getheader(&f , &t, fp, recvpktname))
	{
	case 3:	Syslog('+', "remote mistook us for %s",ascfnode(&t,0x1f));
		fclose(fp);
		SM_ERROR;
	case 0:	Syslog('+', "accepting session");
		fclose(fp);
		for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next));
		(*tmpl)=(fa_list*)xmalloc(sizeof(fa_list));
		(*tmpl)->next=NULL;
		(*tmpl)->addr=(faddr*)xmalloc(sizeof(faddr));
		(*tmpl)->addr->zone=f.zone;
		(*tmpl)->addr->net=f.net;
		(*tmpl)->addr->node=f.node;
		(*tmpl)->addr->point=f.point;
		(*tmpl)->addr->name=NULL;
		(*tmpl)->addr->domain=NULL;
		for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next)) {
			(void)nodelock((*tmpl)->addr);
			/* try lock all remotes, ignore locking result */
			if (!loaded)
				if (noderecord((*tmpl)->addr))
					loaded = TRUE;
		}

		if (((nlent=getnlent(remote->addr))) &&
		    (nlent->pflag != NL_DUMMY))
		{
			Syslog('+', "remote is a listed system");
			inbound=listinbound;
		}
		if (nlent) 
			rdoptions();

		/*
		 * It appears that if the remote gave no password, the 
		 * getheader function fills in a password itself. Maybe
		 * that's the reason why E.C did not switch to protected
		 * inbound, because of the failing password check. MB.
		 */
		if (f.name)
		{
			Syslog('s', "remote password \"%s\"", f.name);
			Syslog('+', "remote gave correct password, protected FTS-0001 session");
			inbound=listinbound; /* Protinbound?? */
		}

		tosend=create_filelist(remote,(char *)ALL_MAIL,1);
		if (rc == 0) {SM_PROCEED(recv_file);}
		else {SM_SUCCESS;}
	default: Syslog('+', "received bad packet apparently from",ascfnode(&f,0x1f));
		fclose(fp);
		SM_ERROR;
	}

SM_STATE(recv_file)

	switch (xmrecv(NULL))
	{
	case 0:		SM_PROCEED(recv_file); break;
	case 1:		SM_SUCCESS; break;
	default:	SM_ERROR; break;
	}

SM_END
SM_RETURN

