// --------------------------------------------------------------------------
// Citadel: Net1.CPP
//
// Net 1.0/1.1 protocol implementation.

#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "net.h"
#include "filecmd.h"
#include "cfgfiles.h"
#include "aplic.h"
#include "cwindows.h"
#include "filerdwr.h"
#include "miscovl.h"


// --------------------------------------------------------------------------
// Contents
//
// Net1Slave()		Actual networking slave
// Net1Master() 	During network master code
// get_first_room() get the first room in the room list
// get_next_room()	gets the next room in the list
// Net1Cleanup()	Done with other system, save mail and messages


// --------------------------------------------------------------------------
// Net1Slave(): Actual networking slave
//
// Return value:
//	TRUE: Worked
//	FALSE: Didn't

Bool Net1Slave(void)
	{
	char line[100];
	label troo;
	label fn;
	FILE *file;
	int i = 0, rm;

	const protocols *theProt = GetProtocolByKey(TI()node->GetProtocol(),
			TRUE);

	if (!theProt)
		{
		doccr();
		cPrintf(getnetmsg(177));
		doCR();
		return (FALSE);
		}

	cPrintf(getnetmsg(178));
	doccr();

	sprintf(line, sbs, cfg.transpath, TI()node->GetMailFileName());

	// create empty mail file if there is none
	if ((file = fopen(line, FO_AB)) != NULL)
		{
		fclose(file);
		}

	wxsnd(cfg.temppath, line, theProt, 0);

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	cPrintf(getnetmsg(179));
	doccr();

	sprintf(line, sbs, cfg.temppath, roomreqTmp);
	unlink(line);

	wxrcv(cfg.temppath, roomreqTmp, theProt);
	changedir(cfg.temppath);

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	sprintf(line, sbs, cfg.temppath, roomreqTmp);
	if ((file = fopen(line, FO_RB)) == NULL)
		{
		perror(getnetmsg(1));
		return (FALSE);
		}

	doccr();
	cPrintf(getnetmsg(2));
	doccr();

	GetStr(file, troo, LABELSIZE);

	while (*troo && !feof(file))
		{
		KBReady();
		if ((rm = RoomExists(troo)) != CERROR)
			{
			if (TI()CurrentUser->CanAccessRoom(rm))
				{
				sprintf(fn, getnetmsg(126), i);
				cPrintf(getnetmsg(166), deansi(troo));
				if (!((i+1) % 3))
					{
					doccr();
					}

				NewRoom(rm, fn, NULL);
				}
			else
				{
				doccr();
				cPrintf(getnetmsg(111), deansi(troo));
				doccr();
				amPrintf(getnetmsg(4), troo, bn);
				TI()netError = TRUE;
				}
			}
		else
			{
			doccr();
			cPrintf(getnetmsg(5), deansi(troo));
			doccr();
			amPrintf(getnetmsg(167), troo, bn);
			TI()netError = TRUE;
			}

		i++;
		GetStr(file, troo, LABELSIZE);
		}

	doccr();
	fclose(file);
	unlink(line);

	cPrintf(getnetmsg(7), cfg.Lmsg_nym);
	doccr();

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	wxsnd(cfg.temppath, getnetmsg(162), theProt, 0);

	ambigUnlink(getnetmsg(162), FALSE);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// Net1Master(): Network master code
//
// Return value:
//	TRUE: Worked
//	FALSE: Didn't

Bool Net1Master(void)
	{
	char line[100], line2[100];
	label here, there;
	FILE *file;
	int i, rms;
	time_t t;

	const protocols *theProt = GetProtocolByKey(TI()node->GetProtocol(),
			TRUE);

	if (!theProt)
		{
		doccr();
		cPrintf(getnetmsg(8));
		doccr();
		return (FALSE);
		}

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	cPrintf(getnetmsg(9));
	doccr();

	wxrcv(cfg.temppath, getnetmsg(164), theProt);

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	sprintf(line, getnetmsg(168), cfg.temppath);
	if ((file = fopen(line, FO_WB)) == NULL)
		{
		perror(getnetmsg(1));
		return (FALSE);
		}

	for (i = get_first_room(here, there), rms = 0; i;
			i = get_next_room(here, there), rms++)
		{
		PutStr(file, there);
		}

	PutStr(file, ns);
	fclose(file);

	cPrintf(getnetmsg(10));
	doccr();

	wxsnd(cfg.temppath, getnetmsg(169), theProt, 0);
	unlink(line);

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	TI()SerialPort.Flush();


	cPrintf(getnetmsg(11));
	// wait for them to get thier shit together
	t = time(NULL);
	while (SerialPort.HaveCarrier() && !TI()SerialPort.IsInputReady())
		{
		KBReady();
		if (time(NULL) > (t + (TI()node->GetFetchTimeout() * 60)))
			{
			CITWINDOW *w = ScreenSaver.IsOn() ? NULL :
					CitWindowsMsg(NULL, getmsg(713), getmsg(1648));

			Hangup();

			if (w)
				{
				destroyCitWindow(w, FALSE);
				}
			}
		}
	doccr();

	if (!SerialPort.HaveCarrier())
		{
		return (FALSE);
		}

	cPrintf(getnetmsg(12), cfg.Lmsg_nym);
	doccr();

	wxrcv(cfg.temppath, ns, theProt);

	for (i = 0; i < rms; i++)
		{
		sprintf(line, getnetmsg(126), i);
		sprintf(line2, getnetmsg(127), i);
		rename(line, line2);
		}

	return (TRUE);
	}


// --------------------------------------------------------------------------
// Net1Cleanup(): Done with other system; save mail and messages

void Net1Cleanup(void)
	{
	int t, i, rm, err;
	int newMsgs = 0, exp = 0, dup = 0, rms = 0;
	label fn, here, there;
	char line[100];

	CITWINDOW *w = ScreenSaver.IsOn() ? NULL :
			CitWindowsMsg(NULL, getmsg(1643));

	Hangup();

	if (w)
		{
		destroyCitWindow(w, FALSE);
		}

	if (cfg.offhook == 1)
		{
		offhook();
		}

	sprintf(line, sbs, cfg.transpath, TI()node->GetMailFileName());
	unlink(line);

	TI()UserControl.SetOutFlag(IMPERVIOUS);

	doccr();
	cPrintf(getnetmsg(22));
	doccr();
	cPrintf(getnetmsg(23));
	doccr();
	cPrintf(getnetmsg(24));
	doccr();

	for (t = get_first_room(here, there), i = 0; t;
			t = get_next_room(here, there), i++)
		{
		sprintf(fn, getnetmsg(127), i);

		KBReady();

		rm = RoomExists(here);
		if (rm != CERROR && TI()CurrentUser->CanAccessRoom(rm))
			{
			cPrintf(getnetmsg(166), deansi(here));

			err = ReadMsgFl(rm, fn, NULL, here, &err, &TI()expired,
					&TI()duplicate, TI()CurrentUser);

			if (err != CERROR)
				{
				if (err)
					{
					TI()OC.ansiattr = cfg.cattr;
					}
				cPrintf(getnetmsg(133), err);
				TI()OC.ansiattr = cfg.attr;
				cPrintf(getnetmsg(134));

				if (TI()expired)
					{
					TI()OC.ansiattr = cfg.cattr;
					}

				cPrintf(getnetmsg(133), TI()expired);
				TI()OC.ansiattr = cfg.attr;
				cPrintf(getnetmsg(134));

				if (TI()duplicate)
					{
					TI()OC.ansiattr = cfg.cattr;
					}
				cPrintf(getnetmsg(133), TI()duplicate);
				TI()OC.ansiattr = cfg.attr;

				newMsgs += err;
				exp += TI()expired;
				dup += TI()duplicate;
				rms ++;
				}
			else
				{
				amPrintf(getnetmsg(28), there, bn);
				TI()netError = TRUE;
				cPrintf(getnetmsg(29));
				}

			doccr();
			}
		else
			{
			cPrintf(getnetmsg(30), deansi(here));
			amPrintf(getnetmsg(31), here, bn);
			TI()netError = TRUE;
			doccr();
			}

		unlink(fn);
		}

	cPrintf(getnetmsg(24));
	doccr();
	cPrintf(getnetmsg(32));
	if (rms)
		{
		TI()OC.ansiattr = cfg.cattr;
		}

	cPrintf(getnetmsg(133), rms);
	TI()OC.ansiattr = cfg.attr;
	cPrintf(getnetmsg(134));
	if (newMsgs)
		{
		TI()OC.ansiattr = cfg.cattr;
		}

	cPrintf(getnetmsg(133), newMsgs);
	TI()OC.ansiattr = cfg.attr;
	cPrintf(getnetmsg(134));
	if (exp)
		{
		TI()OC.ansiattr = cfg.cattr;
		}
	cPrintf(getnetmsg(133), exp);
	TI()OC.ansiattr = cfg.attr;
	cPrintf(getnetmsg(134));
	if (dup)
		{
		TI()OC.ansiattr = cfg.cattr;
		}

	cPrintf(getnetmsg(133), dup);
	TI()OC.ansiattr = cfg.attr;
	doccr();
	cPrintf(getnetmsg(33));
	doccr();
	doccr();
	cPrintf(getnetmsg(34));
	doccr();

	i = ReadMsgFl(MAILROOM, getnetmsg(164), NULL, ns, &i, &TI()expired,
			&TI()duplicate, NULL);

	label New, Routed, Rejected;
	strcpy(New, ltoac(i == CERROR ? 0 : i));
	strcpy(Routed, ltoac(TI()expired));
	strcpy(Rejected, ltoac(TI()duplicate));

	cPrintf(getnetmsg(35), New, i == 1 ? cfg.Lmsg_nym : cfg.Lmsgs_nym,
			Routed, Rejected,
			ltoac((i == CERROR ? 0 : i) + TI()expired + TI()duplicate));

	doccr();

	changedir(cfg.temppath);
	ambigUnlink(getnetmsg(162), FALSE);
	ambigUnlink(getnetmsg(163), FALSE);

	unlink(getnetmsg(164));

	changedir(cfg.homepath);

	TI()expired = exp;
	TI()duplicate = dup;
	TI()MS.Entered = newMsgs;

	if (TI()netError)
		{
		amPrintf(getnetmsg(36), bn, TI()CurrentUser->GetName(), bn);
		SaveAideMess(NULL);
		}

	readNetCmdTmp();

	// we are no longer calling out...
	TI()callout = FALSE;
	}


// --------------------------------------------------------------------------
// the folowing two routines are used for scaning through the rooms listed
// in NODES.CIT for the other node.

// This should become TI some time...
static FILE *nodefile;


// --------------------------------------------------------------------------
// get_first_room(): Get the first room in the room list, prepare for reading
//	the rest.
//
// Output:
//	char *here: Filled with the room name here; must be >= LABELSIZE+1
//	char *there: Filled with the room name there; must be >= LABELSIZE+1
//
// Return value:
//	TRUE: Rooms found
//	FALSE: nothing found
//
// Notes:
//	If this returns TRUE, you must keep calling get_next_room until it
//	returns FALSE. If this or get_next_room returns FALSE, get_next_room
//	must not be called again until this is called and it returns TRUE.

Bool get_first_room(char *here, char *there)
	{
	assert(!nodefile);

	char path[80];
	if (!TI()node->GetRoomOffset())
		{
		return (FALSE);
		}

	sprintf(path, sbs, cfg.homepath, citfiles[C_NODES_CIT]);

	if ((nodefile = fopen(path, FO_R)) == NULL) // ASCII mode
		{
		cPrintf(getmsg(15), citfiles[C_NODES_CIT]);
		doccr();
		return (FALSE);
		}

	fseek(nodefile, TI()node->GetRoomOffset(), SEEK_SET);

	return (get_next_room(here, there));
	}


// --------------------------------------------------------------------------
// get_next_room(): Gets the next room in the list
//
// Output:
//	char *here: Filled with the room name here; must be >= LABELSIZE+1
//	char *there: Filled with the room name there; must be >= LABELSIZE+1
//
// Return value:
//	TRUE: next room found
//	FALSE: no more rooms found
//
// Notes:
//	Before calling this, get_first_room() must be called, and it must return
//	TRUE. If get_first_room() returns FALSE, this must not be called.  If
//	get_first_room() returns TRUE, this must keep getting called until it
//	returns FALSE.	get_first_room() must not be called until this returns
//	FALSE.	After this returns FALSE, it must not be called again until
//	get_first_room() is called and returns TRUE.

Bool get_next_room(char *here, char *there)
	{
	assert(nodefile);

	char line[95];

	while (fgets(line, 90, nodefile) != NULL)
		{
		if (line[0] != '#')
			{
			continue;
			}

		char *words[256];
		const int count = parse_it(words, line);

		if (SameString(words[0], getnetmsg(37)))
			{
			fclose(nodefile);
			nodefile = NULL;
			return (FALSE);
			}

		if (SameString(words[0], getnetmsg(38)))
			{
			CopyStringToBuffer(here, words[1], LABELSIZE);

			if (count > 2)
				{
				CopyStringToBuffer(there, words[2], LABELSIZE);
				}
			else
				{
				strcpy(there, here);
				}

			return (TRUE);
			}
		}

	fclose(nodefile);
	nodefile = NULL;
	return (FALSE);
	}
