// --------------------------------------------------------------------------
// Citadel: LibOvl.CPP
//
// Table create/load/save stuff.

#include "ctdl.h"
#pragma hdrstop

#include "account.h"
#include "libovl.h"
#include "meminit.h"
#include "net.h"
#include "group.h"
#include "roompriv.h"
#include "room.h"
#include "msg.h"
#include "log.h"
#include "hall.h"
#include "tallybuf.h"
#include "term.h"


// --------------------------------------------------------------------------
// Contents
//
// getGroup()			loads groupBuffer
// putGroup()			stores groupBuffer to disk
//
// getHall()			loads hallBuffer
// putHall()			stores hallBuffer to disk
//
// writeTables()		writes all system tables to disk
// readTables() 		loads all tables into ram
//
// allocateTables() 	allocate table space

static Bool readMsgTab(void);
static Bool readRoomTab(void);
static void writeMsgTab(void);
static void writeRoomTab(void);

static Bool aloc_checker = FALSE;

Bool writeBordersDat(void)
	{
	Bool Good = TRUE;
	FILE *fl;

	changedir(cfg.homepath);

	if ((fl = fopen(bordersDat, FO_WB)) != NULL)
		{
		if (fwrite(borders, 81, cfg.maxborders, fl) != cfg.maxborders)
			{
			mPrintf(getmsg(83), bordersDat);
			Good = FALSE;
			}

		fclose(fl);
		}
	else
		{
		mPrintf(getmsg(78), bordersDat);
		Good = FALSE;
		}

	return (Good);
	}

Bool readBordersDat(void)
	{
	Bool Good = TRUE;
	FILE *fl;

	changedir(cfg.homepath);

	if ((fl = fopen(bordersDat, FO_RB)) != NULL)
		{
		int i;

		if (fread(borders, 81, cfg.maxborders, fl) != cfg.maxborders)
			{
			cPrintf(getmsg(83), bordersDat);
			Good = FALSE;
			}

		fclose(fl);

		// Make sure none of them overrun their space
		for (i = 0; i < cfg.maxborders; i++)
			{
			borders[(i + 1) * 81 - 1] = 0;
			}
		}
	else
		{
		cPrintf(getmsg(78), bordersDat);
		Good = FALSE;
		}

	return (Good);
	}

void LogTable::Save(void) const
	{
	assert(this);
	VerifyHeap();

	if (IsValid())
		{
		char FileName[80];
		FILE *fd;

		sprintf(FileName, sbs, cfg.homepath, lgTab);

		if ((fd = fopen(FileName, FO_WB)) != NULL)
			{
			fwrite(Table, sizeof(*Table), TableSize, fd);
			fclose(fd);
			}

		VerifyHeap();
		}
	}

Bool LogTable::Load(void)
	{
	assert(this);

	if (IsValid())
		{
		char FileName[80];
		FILE *fd;

		sprintf(FileName, sbs, cfg.homepath, lgTab);

		if ((fd = fopen(FileName, FO_RB)) == NULL)
			{
			return (FALSE);
			}

		VerifyHeap();
		if (fread(Table, sizeof(*Table), TableSize, fd) == TableSize)
			{
			VerifyHeap();
			fclose(fd);
			unlink(lgTab);
			return (TRUE);
			}
		else
			{
			VerifyHeap();
			fclose(fd);
			unlink(lgTab);
			return (FALSE);
			}
		}
	else
		{
		return (FALSE);
		}
	}


// --------------------------------------------------------------------------
// getHall(): Loads hall data into RAM buffer.

Bool HallBuffer::Load(const char *Name)
	{
	assert(this);
	VerifyHeap();
	Bool Good = TRUE;
	char fpath[80];

	sprintf(fpath, sbs, cfg.homepath, Name);

	FILE *HallFile1;

	if ((HallFile1 = fopen(fpath, FO_RB)) == NULL)
		{
		mPrintf(getmsg(78), fpath);
		Good = FALSE;
		}
	else
		{
		FILE *HallFile2;

		sprintf(fpath, sbs, cfg.homepath, hall2Dat);

		if ((HallFile2 = fopen(fpath, FO_RB)) == NULL)
			{
			mPrintf(getmsg(78), fpath);
			Good = FALSE;
			}
		else
			{
			h_slot HallSlot;

			for (HallSlot = 0; Good && HallSlot < NumHalls; HallSlot++)
				{
				if (!Halls[HallSlot].Load(HallSlot, HallFile1, HallFile2))
					{
					Good = FALSE;
					}
				}

			fclose(HallFile2);
			}

		fclose(HallFile1);
		}

	VerifyHeap();
	return (Good);
	}

Bool HallEntry1::Load(h_slot Slot, FILE *File)
	{
	assert(this);
	Bool Good = TRUE;

	fseek(File, sizeof(long) + Slot * sizeof(HallEntry1), SEEK_SET);

	if (fread(this, sizeof(HallEntry1), 1, File) != 1)
		{
		mPrintf(getmsg(83), hallDat);
		Good = FALSE;
		}

	Verify();
	return (Good);
	}

Bool HallEntry2::Load(h_slot Slot, FILE *File)
	{
	assert(this);
	Bool Good = TRUE;

	fseek(File, Slot * GetSize(), SEEK_SET);

	if (fread(GetNCPointer(), 1, GetSize(), File) != GetSize())
		{
		mPrintf(getmsg(83), hall2Dat);
		Good = FALSE;
		}

	return (Good);
	}

Bool HallEntry3::Load(h_slot Slot, FILE *File)
	{
	assert(this);
	Bool Good = TRUE;

	fseek(File, (cfg.maxhalls + Slot) * GetSize(), SEEK_SET);

	if (fread(GetNCPointer(), 1, GetSize(), File) != GetSize())
		{
		mPrintf(getmsg(83), hall2Dat);
		Good = FALSE;
		}

	return (Good);
	}

Bool HallEntry::Load(h_slot HallSlot, FILE *File1, FILE *File2)
	{
	assert(this);

	if (HallEntry1::Load(HallSlot, File1) &&
			HallEntry2::Load(HallSlot, File2) &&
			HallEntry3::Load(HallSlot, File2))
		{
		return (TRUE);
		}
	else
		{
		return (FALSE);
		}
	}


// --------------------------------------------------------------------------
// putHall(): Stores group data into HALL.DAT.

Bool HallBuffer::Save(const char *Name) const
	{
	assert(this);
	VerifyHeap();
	Bool Good = TRUE;
	char fpath[80];

	sprintf(fpath, sbs, cfg.homepath, Name);

	FILE *HallFile1;

	if ((HallFile1 = fopen(fpath, FO_WB)) == NULL)
		{
		mPrintf(getmsg(78), fpath);
		Good = FALSE;
		}
	else
		{
		FILE *HallFile2;

		sprintf(fpath, sbs, cfg.homepath, hall2Dat);

		if ((HallFile2 = fopen(fpath, FO_WB)) == NULL)
			{
			mPrintf(getmsg(78), fpath);
			Good = FALSE;
			}
		else
			{
			long l = sizeof(HallEntry1);
			fwrite(&l, sizeof(l), 1, HallFile1);

			h_slot HallSlot;

			for (HallSlot = 0; Good && HallSlot < NumHalls; HallSlot++)
				{
				if (!Halls[HallSlot].Save(HallSlot, HallFile1, HallFile2))
					{
					Good = FALSE;
					}
				}

			fclose(HallFile2);
			}

		fclose(HallFile1);
		}

	VerifyHeap();
	return (Good);
	}

Bool HallEntry1::Save(h_slot Slot, FILE *File) const
	{
	assert(this);
	Bool Good = TRUE;

	fseek(File, sizeof(long) + Slot * sizeof(HallEntry1), SEEK_SET);

	if (fwrite(this, sizeof(HallEntry1), 1, File) != 1)
		{
		mPrintf(getmsg(661), hallDat);
		Good = FALSE;
		}

	return (Good);
	}

Bool HallEntry2::Save(h_slot Slot, FILE *File) const
	{
	assert(this);
	Bool Good = TRUE;

	fseek(File, Slot * GetSize(), SEEK_SET);

	if (fwrite(GetPointer(), 1, GetSize(), File) != GetSize())
		{
		mPrintf(getmsg(661), hall2Dat);
		Good = FALSE;
		}

	return (Good);
	}

Bool HallEntry3::Save(h_slot Slot, FILE *File) const
	{
	assert(this);
	Bool Good = TRUE;
	fseek(File, (cfg.maxhalls + Slot) * GetSize(), SEEK_SET);

	if (fwrite(GetPointer(), 1, GetSize(), File) != GetSize())
		{
		mPrintf(getmsg(661), hall2Dat);
		Good = FALSE;
		}

	return (Good);
	}

Bool HallEntry::Save(h_slot HallSlot, FILE *File1, FILE *File2) const
	{
	assert(this);

	if (HallEntry1::Save(HallSlot, File1) &&
			HallEntry2::Save(HallSlot, File2) &&
			HallEntry3::Save(HallSlot, File2))
		{
		return (TRUE);
		}
	else
		{
		return (FALSE);
		}
	}


// --------------------------------------------------------------------------
// getRoomPos(): Loads roomPos data into RAM buffer.

Bool getRoomPos(void)
	{
	Bool Good = TRUE;
	citFILE rmposfl;
	char fpath[80];

	sprintf(fpath, sbs, cfg.homepath, roomposDat);

	if (!citOpen(fpath, CO_RB, &rmposfl))
		{
		mPrintf(getmsg(78), fpath);
		Good = FALSE;
		}
	else
		{
		citSeek(rmposfl, 0L, SEEK_SET);

		if (citRead(roomPos, sizeof(*roomPos), cfg.maxrooms, rmposfl) != cfg.maxrooms)
			{
			mPrintf(getmsg(83), fpath);
			Good = FALSE;
			}

		citClose(&rmposfl);

		// Make sure that each room has exactly one entry
		for (r_slot i = 0; Good && i < cfg.maxrooms; i++)
			{
			r_slot j, num;

			for (j = 0, num = 0; j < cfg.maxrooms; j++)
				{
				if (roomPos[j] == i)
					{
					num++;
					}
				}

			if (num != 1)
				{
				Good = FALSE;
				}
			}
		}

	// Something's wrong: recreate it
	if (!Good)
		{
		for (r_slot i = 0; i < cfg.maxrooms; i++)
			{
			roomPos[i] = i;
			}
		}

	return (Good);
	}


// --------------------------------------------------------------------------
// putRoomPos(): Stores roomPos data into ROOMPOS.DAT.

Bool putRoomPos(void)
	{
	Bool Good = TRUE;
	citFILE rmposfl;
	char fpath[80];

	sprintf(fpath, sbs, cfg.homepath, roomposDat);

	if (!citOpen(fpath, CO_WB, &rmposfl))
		{
		mPrintf(getmsg(78), fpath);
		Good = FALSE;
		}
	else
		{
		citSeek(rmposfl, 0L, SEEK_SET);

		if (citWrite(roomPos, sizeof(*roomPos), cfg.maxrooms, rmposfl) != cfg.maxrooms)
			{
			mPrintf(getmsg(661), fpath);
			Good = FALSE;
			}

		citClose(&rmposfl);
		}

	return (Good);
	}


// --------------------------------------------------------------------------
// readTables(): Loads all tables into RAM.

Bool readTables()
	{
	FILE *fd;

	getcwd(etcpath, 64);

	// ETC.TAB
	if ((fd = fopen(etcTab, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	if (filelength(fileno(fd)) != sizeof(config) ||
			(fread(&cfg, 1, sizeof(config), fd) != sizeof(config)) ||
			(cfg.version != cfgver))	// Detect early, since we read it
		{
		fclose(fd);
		memset(&cfg, 0, sizeof(cfg));
		reconfig = TRUE;
		return (FALSE);
		}
	fclose(fd);
	unlink(etcTab);

	changedir(cfg.homepath);

	allocateTables();

	if (!LogTab->Load())
		{
		return (FALSE);
		}

	// MSG.TAB
	if (readMsgTab() == FALSE)
		{
		return (FALSE);
		}

	// ROOM.TAB
	if (readRoomTab() == FALSE)
		{
		return (FALSE);
		}

	Cron.ReadTable();

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeTables(): Stores all tables to disk.

void writeTables(void)
	{
	FILE *fd;

	changedir(etcpath);

	if ((fd = fopen(etcTab, FO_WB)) == NULL)
		{
		crashout(getmsg(8), etcTab);
		}

	// write out etc.tab
	fwrite(&cfg, sizeof (config), 1, fd);
	fclose(fd);

	changedir(cfg.homepath);

	LogTab->Save();

	writeMsgTab();
	writeRoomTab();

	Cron.WriteTable();

	changedir(etcpath);
	}

#ifdef MULTI
void freeTaskInfo(taskInfo **oti)
	{
	if (*oti)
		{
		if ((*oti)->CurrentUser)
			{
			delete (*oti)->CurrentUser;
			(*oti)->CurrentUser = NULL;
			}

		delete (*oti)->roomInfo;
		if ((*oti)->talleyInfo) 	DestroyTalleyBuffer((*oti));
		if ((*oti)->MS.AbortedMessage)	delete (*oti)->MS.AbortedMessage;
		if ((*oti)->CurrentUserAccount) delete (*oti)->CurrentUserAccount;
		freeNode(&(*oti)->node);

		delete *oti;
		*oti = NULL;
		}
	}

Bool initTaskInfo(taskInfo **nti)
	{
	if (!*nti)
		{
		*nti = new taskInfo;

		if (*nti)
			{
			memset(*nti, 0, sizeof(taskInfo));
			}
		}

	if (*nti)
		{
		Bool good = TRUE;

		// start with fresh task info
		if ((*nti)->CurrentUser)
			{
			delete (*nti)->CurrentUser;
			(*nti)->CurrentUser = NULL;
			}

		if ((*nti)->CurrentUserAccount)
			{
			delete (*nti)->CurrentUserAccount;
			(*nti)->CurrentUserAccount = NULL;
			}

		delete (*nti)->roomInfo;
		(*nti)->roomInfo = NULL;

		if ((*nti)->talleyInfo)
			{
			DestroyTalleyBuffer((*nti));
			}

		if ((*nti)->MS.AbortedMessage)
			{
			delete (*nti)->MS.AbortedMessage;
			(*nti)->MS.AbortedMessage = NULL;
			}

		freeNode(&(*nti)->node);

		if (cfg.accounting)
			{
			if (((*nti)->CurrentUserAccount = new UserAccountInfo) == NULL)
				{
				good = FALSE;
				}
			}

		if (good && ((*nti)->roomInfo = new aRoom) == NULL)
			{
			good = FALSE;
			}

		if (good && cfg.maxrooms)
			{
			(*nti)->CurrentUser = new LogEntry(cfg.maxrooms, cfg.maxgroups,
					cfg.maxjumpback);

			if (!(*nti)->CurrentUser)
				{
				good = FALSE;
				}
			}

		if (good)
			{
			good = CreateTalleyBuffer(*nti);
			}

		if (!good)
			{
			freeTaskInfo(nti);	// free however much did get allocated
			}
		else
			{
			uchar r, c;
			physReadpos(&r, &c);
			(*nti)->logiRow = r;
			(*nti)->logiCol = c;

			(*nti)->OC.Modem = TRUE;
			(*nti)->OC.Console = TRUE;
			(*nti)->MRO.DotoMessage = NO_SPECIAL;
			(*nti)->OC.Formatting = TRUE;
			(*nti)->OC.UseMCI = cfg.mci;
			(*nti)->showPrompt = TRUE;
			(*nti)->OC.ansiattr = 7;

			(*nti)->lastMonthHoliday = NUM_MONTHS;

			setdefaultTerm(2);
			}

		return (good);
		}
	else
		{
		return (FALSE);
		}
	}
#else
static void freeFakeTaskInfo(void)
	{
	if (CurrentUser)
		{
		delete CurrentUser;
		CurrentUser = NULL;
		}

	delete roomInfo;
	roomInfo = NULL;

	if (talleyInfo) 	DestroyTalleyBuffer();

	if (MS.AbortedMessage)	
		{
		delete MS.AbortedMessage;
		MS.AbortedMessage = NULL;
		}

	if (CurrentUserAccount) 
		{
		delete CurrentUserAccount;
		CurrentUserAccount = NULL;
		}

	freeNode(&node);
	}

Bool initFakeTaskInfo(void)
	{
	Bool good = TRUE;

	// start with fresh task info
	if (CurrentUser)
		{
		delete CurrentUser;
		CurrentUser = NULL;
		}

	if (CurrentUserAccount)
		{
		delete CurrentUserAccount;
		CurrentUserAccount = NULL;
		}

	delete roomInfo;
	roomInfo = NULL;

	if (talleyInfo)
		{
		DestroyTalleyBuffer();
		}

	if (MS.AbortedMessage)
		{
		delete MS.AbortedMessage;
		MS.AbortedMessage = NULL;
		}

	freeNode(&node);

	if (cfg.accounting)
		{
		if ((CurrentUserAccount = new UserAccountInfo) == NULL)
			{
			good = FALSE;
			}
		}

	if (good && (roomInfo = new aRoom) == NULL)
		{
		good = FALSE;
		}

	if (good && cfg.maxrooms)
		{
		CurrentUser = new LogEntry(cfg.maxrooms, cfg.maxgroups,
				cfg.maxjumpback);

		if (!CurrentUser)
			{
			good = FALSE;
			}
		}

	if (good)
		{
		good = CreateTalleyBuffer();
		}

	if (!good)
		{
		freeFakeTaskInfo(); // free however much did get allocated
		}
	else
		{
		uchar r, c;
		physReadpos(&r, &c);
		logiRow = r;
		logiCol = c;

		OC.Modem = TRUE;
		OC.Console = TRUE;
		MRO.DotoMessage = NO_SPECIAL;
		OC.Formatting = TRUE;
		OC.UseMCI = cfg.mci;
		showPrompt = TRUE;
		OC.ansiattr = 7;
		lastMonthHoliday = NUM_MONTHS;

		setdefaultTerm(2);
		}

	return (good);
	}
#endif


// --------------------------------------------------------------------------
// allocateTables(): Allocate Log, Msg, Room, Group, and Hall tables.

void allocateTables(void)
	{
	if (aloc_checker)
		{
		crashout(getcfgmsg(90));
		}

	aloc_checker = TRUE;

	createLogTab();
	createMsgTab();
	createRoomTab();

	GroupData = new GroupBuffer(cfg.maxgroups);
	HallData = new HallBuffer(cfg.maxhalls, cfg.maxrooms);

	if (// task independent stuff
		GroupData == NULL ||

		HallData == NULL ||

		((roomPos = new r_slot[cfg.maxrooms]) == NULL) ||
		((statList = new statRecord[cfg.statnum]) == NULL) ||

#ifdef MULTI
		!initTaskInfo(&ti)
#else
		!initFakeTaskInfo()
#endif
		)
		{
		crashout(getcfgmsg(107));
		}
	}


// --------------------------------------------------------------------------
// freeTables(): Deallocate msgTab and logTab.

void freeTables(void)
	{
	if (!aloc_checker)
		{
		crashout(getmsg(904));
		}

	aloc_checker = FALSE;

	destroyLogTab();
	destroyRoomTab();
	destroyMsgTab();

	delete [] roomPos;
	delete [] statList;

	delete GroupData;
	delete HallData;

	if (AccountingData)
		{
		delete [] AccountingData;
		AccountingData = NULL;
		}

#ifdef MULTI
	freeTaskInfo(&ti);
#else
	freeFakeTaskInfo();
#endif
	}

#ifdef WINCIT
// --------------------------------------------------------------------------
// readRoomTab(): Read ROOM.TAB off disk.
//	Windows version

static Bool readRoomTab(void)
	{
	char huge *ptr;
	long left;
	FILE *fd;

	if ((fd = fopen(rmTab, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	left = (long) cfg.maxrooms * (long) sizeof(rTable);
	ptr = (char huge *) roomTab;

	while (left)
		{
		long cur = min(32768l, left);

		if (fread(ptr, (uint) cur, 1, fd) != 1)
			{
			fclose(fd);
			unlink(rmTab);
			return (FALSE);
			}

		ptr += cur;
		left -= cur;
		}

	fclose(fd);
	unlink(rmTab);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeRoomTab(): Write ROOM.TAB.
//	Windows version

static void writeRoomTab(void)
	{
	char huge *ptr;
	long left;
	FILE *fd;

	if ((fd = fopen(rmTab, FO_WB)) == NULL)
		{
		return;
		}

	left = (long) cfg.maxrooms * (long) sizeof(rTable);
	ptr = (char huge *) roomTab;

	while (left)
		{
		long cur = min(32768l, left);

		fwrite(ptr, (uint) cur, 1, fd);

		ptr += cur;
		left -= cur;
		}

	fclose(fd);
	}


// --------------------------------------------------------------------------
// readMsgTab(): Read MSG.TAB off disk.
//	Windows version.

static Bool readMsgTab(void)
	{
	char huge *ptr;
	long left;
	FILE *fd;

	if ((fd = fopen(msgTab, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	left = (long) (cfg.nmessages + 1) * (long) sizeof(*msgTabWin);
	ptr = (char huge *) msgTabWin;

	while (left)
		{
		long cur = min(32768l, left);

		if (fread(ptr, (uint) cur, 1, fd) != 1)
			{
			fclose(fd);
			unlink(msgTab);
			return (FALSE);
			}

		ptr += cur;
		left -= cur;
		}

	if (fread(FirstMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd) !=
			cfg.maxrooms)
		{
		fclose(fd);
		unlink(msgTab);
		return (FALSE);
		}

	if (fread(LastMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd) !=
			cfg.maxrooms)
		{
		fclose(fd);
		unlink(msgTab);
		return (FALSE);
		}

	fclose(fd);
	unlink(msgTab);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeMsgTab(): Write MSG.TAB.
//	Windows version

static void writeMsgTab(void)
	{
	char huge *ptr;
	long left;
	FILE *fd;

	if ((fd = fopen(msgTab, FO_WB)) == NULL)
		{
		return;
		}

	left = (long) (cfg.nmessages + 1) * (long) sizeof(*msgTabWin);
	ptr = (char huge *) msgTabWin;

	while (left)
		{
		long cur = min(32768l, left);

		fwrite(ptr, (uint) cur, 1, fd);

		ptr += cur;
		left -= cur;
		}

	fwrite(FirstMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd);
	fwrite(LastMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd);

	fclose(fd);
	}

#else

#ifndef AUXMEM
// --------------------------------------------------------------------------
// readRoomTab(): Read ROOM.TAB off disk.
//	Regular version

static Bool readRoomTab(void)
	{
	FILE *fd;

	if ((fd = fopen(rmTab, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	if (!fread(roomTab, sizeof(rTable), cfg.maxrooms, fd))
		{
		fclose(fd);
		return (FALSE);
		}

	fclose(fd);
	unlink(rmTab);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeRoomTab(): Write ROOM.TAB.
//	Regular version

static void writeRoomTab(void)
	{
	FILE *fd;

	if ((fd = fopen(rmTab, FO_WB)) == NULL)
		{
		return;
		}

	fwrite(roomTab, sizeof(rTable), cfg.maxrooms, fd);
	fclose(fd);
	}


// --------------------------------------------------------------------------
// readMsgTab(): Read MSG.TAB off disk.
//	Regular version

static Bool readMsgTab(void)
	{
	FILE *fd;
	char temp[80];

	sprintf(temp, sbs, cfg.homepath, msgTab);

	if ((fd = fopen(temp, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	if (!fread(msgTab_mtmsgflags, sizeof(*msgTab_mtmsgflags), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mtmsgLocLO, sizeof(*msgTab_mtmsgLocLO), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mtmsgLocHI, sizeof(*msgTab_mtmsgLocHI), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mtroomno, sizeof(*msgTab_mtroomno), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mttohash, sizeof(*msgTab_mttohash), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mtauthhash, sizeof(*msgTab_mtauthhash), cfg.nmessages, fd)) return (FALSE);
	if (!fread(msgTab_mtomesg, sizeof(*msgTab_mtomesg), cfg.nmessages, fd)) return (FALSE);

	fclose(fd);
	unlink(temp);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeMsgTab(): Write MSG.TAB.
//	Regular version

static void writeMsgTab(void)
	{
	FILE *fd;
	char temp[80];

	sprintf(temp, sbs, cfg.homepath, msgTab);

	if ((fd = fopen(temp, FO_WB)) == NULL)
		{
		return;
		}

	fwrite(msgTab_mtmsgflags, sizeof(*msgTab_mtmsgflags), cfg.nmessages , fd);
	fwrite(msgTab_mtmsgLocLO, sizeof(*msgTab_mtmsgLocLO), cfg.nmessages , fd);
	fwrite(msgTab_mtmsgLocHI, sizeof(*msgTab_mtmsgLocHI), cfg.nmessages , fd);
	fwrite(msgTab_mtroomno, sizeof(*msgTab_mtroomno), cfg.nmessages , fd);
	fwrite(msgTab_mttohash, sizeof(*msgTab_mttohash), cfg.nmessages , fd);
	fwrite(msgTab_mtauthhash, sizeof(*msgTab_mtauthhash), cfg.nmessages , fd);
	fwrite(msgTab_mtomesg, sizeof(*msgTab_mtomesg), cfg.nmessages , fd);

	fclose(fd);
	}

#else


// --------------------------------------------------------------------------
// readRoomTab(): Read ROOM.TAB off disk.
//	Auxmem version

static Bool readRoomTab(void)
	{
	FILE *fd;

	rTable *lrt;
	r_slot i;

	if ((fd = fopen(rmTab, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	for (i = 0; i < cfg.maxrooms; i += ROOMTABPERPAGE)
		{
		lrt = getRoomTab(i);
		if (!fread(lrt, AUXPAGESIZE, 1, fd))
			{
			return (FALSE);
			}
		}

	fclose(fd);
	unlink(rmTab);

	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeRoomTab(): Write ROOM.TAB.
//	Auxmem version.

static void writeRoomTab(void)
	{
	FILE *fd;

	rTable *lrt;
	r_slot i;

	if ((fd = fopen(rmTab, FO_WB)) == NULL)
		{
		return;
		}

	for (i = 0; i < cfg.maxrooms; i += ROOMTABPERPAGE)
		{
		lrt = getRoomTab(i);
		fwrite(lrt, AUXPAGESIZE, 1 , fd);
		}

	fclose(fd);
	}


// --------------------------------------------------------------------------
// readMsgTab(): Read MSG.TAB off disk.
//	Auxmem version

static Bool readMsgTab(void)
	{
	FILE *fd;
	char temp[80];
	messagetable *lmt;
	m_slot i;

	sprintf(temp, sbs, cfg.homepath, msgTab);

	if ((fd = fopen(temp, FO_RB)) == NULL)
		{
		return (FALSE);
		}

	for (i = 0; i < cfg.nmessages; i += MSGTABPERPAGE)
		{
		lmt = getMsgTab(i);
		if (fread(lmt, AUXPAGESIZE, 1, fd) != 1)
			{
			fclose(fd);
			unlink(temp);
			return (FALSE);
			}
		}

	if (fread(FirstMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd) !=
			cfg.maxrooms)
		{
		fclose(fd);
		unlink(temp);
		return (FALSE);
		}

	if (fread(LastMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd) !=
			cfg.maxrooms)
		{
		fclose(fd);
		unlink(temp);
		return (FALSE);
		}

	fclose(fd);
	unlink(temp);
	return (TRUE);
	}


// --------------------------------------------------------------------------
// writeMsgTab(): Write MSG.TAB.
//	Auxmem version

static void writeMsgTab(void)
	{
	FILE *fd;
	char temp[80];
	messagetable *lmt;
	m_slot i;

	sprintf(temp, sbs, cfg.homepath, msgTab);

	if ((fd = fopen(temp, FO_WB)) == NULL)
		{
		return;
		}

	for (i = 0; i < cfg.nmessages; i += MSGTABPERPAGE)
		{
		lmt = getMsgTab(i);
		fwrite(lmt, AUXPAGESIZE, 1 , fd);
		}

	fwrite(FirstMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd);
	fwrite(LastMessageInRoom, sizeof(m_slot), cfg.maxrooms, fd);

	fclose(fd);
	}

#endif
#endif
