/* -------------------------------------------------------------------- */
/*	ROOMLOW.CPP 				Citadel 								*/
/*			Low-level parts of the room database subsystem. 			*/
/* -------------------------------------------------------------------- */
/*	For full information about the room database subsystem, see ROOM.C. */
/* -------------------------------------------------------------------- */
#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "roompriv.h"
#include "log.h"
#include "group.h"
#include "msg.h"
#include "lock.h"
#include "hall.h"

/* -------------------------------------------------------------------- */
/*								Contents								*/
/* -------------------------------------------------------------------- */
/*								Public									*/
/*																		*/
/*	Functions:															*/
/*		GetRoomPosInTable() 											*/
/*			Gets a room's slot in the roompos table.                    */
/*																		*/
/*		CanUserSeeRoom()												*/
/*			Checks to see if the current user has access to a specified */
/*			room.														*/
/*																		*/
/*		RoomExists()													*/
/*			Checks to see if a room exists, given a room name.			*/
/*																		*/
/*	getRoom()			load given room into RAM						*/
/*	putRoom()			store room to given disk slot					*/
/* -------------------------------------------------------------------- */


/* -------------------------------------------------------------------- */
/*	GetRoomPosInTable() 	Gets a room's slot in the roompos table.    */
/*																		*/
/*	Input:		RoomIndex	The room to find in the table.				*/
/*																		*/
/*	Output: 	return		The position in the table of the room.		*/
/* -------------------------------------------------------------------- */
r_slot GetRoomPosInTable(r_slot RoomIndex)
	{
	assert(RoomIndex < cfg.maxrooms);
	assert(RoomIndex >= 0);
	assert(roomPos != NULL);

	for (r_slot i = 0; i < cfg.maxrooms; i++)
		{
		if (roomPos[i] == RoomIndex)
			{
			return (i);
			}
		}

	// crashing is a bit bogus. perhaps recreate the table?
	crashout(getmsg(971));

	return (0); 	// bogus return value to keep the compiler happy.
	}


/* -------------------------------------------------------------------- */
/*	CanUserSeeRoom()		Checks to see if the current user has		*/
/*							access to a specified room. 				*/
/*																		*/
/*	Input:		RoomIndex	The room that we are checking.				*/
/*				ThisHall	TRUE if the room must be in current hall.	*/
/* -------------------------------------------------------------------- */
Bool LogEntry::CanAccessRoom(r_slot RoomIndex, Bool ThisHall, Bool IgnoreHidden) const
	{
	assert(this);
	assert(RoomIndex < cfg.maxrooms);
	assert(RoomIndex >= 0);

	return
		(
		// The room is in use
		IsRoomInuse(RoomIndex) &&

			// Don't care about halls, or it is in the current one
			(
			!ThisHall ||
				(
				IsUsePersonalHall() ?
					(
					IsRoomInPersonalHall(RoomIndex)
					)
				:
					(
					roominhall(RoomIndex, TI()thisHall)
					)
				) 
			)

		&&

			(
			// either the user is the #SYSOP
			IsMainSysop() ||

			// or...
				(
				// The user has group access to room
				HasGroupAccessToRoom(RoomIndex) &&

				// and either not the aide room, or the user is an Aide
				(RoomIndex != AIDEROOM || IsAide()) &&

					// and...
					(
					// not bio, hidden, or kicked out
					IsInRoom(RoomIndex) ||

					// or it is hidden, but we are ignoring that
					(IgnoreHidden && !getRoomTab(RoomIndex)->rtflags.IsPublic())
					)
				)
			)

		&&

			// Special restrictions for nodes
			(
			IsNode() ?
				(
				// it is not Aide)
				RoomIndex != AIDEROOM &&

				// and it is not Dump>
				RoomIndex != DUMP &&

				// and it is shared
				IsRoomShared(RoomIndex)
				)
			:
				(
				TRUE
				)
			)
		);
	}


/* -------------------------------------------------------------------- */
/*	RoomExists()			Checks to see if a room exists, given a 	*/
/*							room name.									*/
/*																		*/
/*	Input:		RoomName	The room name to look for.					*/
/*																		*/
/*	Output: 	return		Index into room database of the room if a	*/
/*							match is found, else CERROR.				*/
/* -------------------------------------------------------------------- */
r_slot RoomExists(const char *RoomName)
	{
	if (*RoomName)
		{
		r_slot i, p;

		for (i = TI()lastFoundRoom, p = 0; p < cfg.maxrooms;
				i = (i + 1) % cfg.maxrooms, p++)
			{
			if (IsRoomInuse(i) &&
					SameString(RoomName, GetRoomName(i)))
				{
				TI()lastFoundRoom = i;
				return (i);
				}
			}
		}

	return (CERROR);
	}


/* -------------------------------------------------------------------- */
/*	IdExists()				Checks to see if a room exists, given a 	*/
/*							Network ID. 								*/
/*																		*/
/*	Input:		NetID		The Network ID to look for. 				*/
/*				Network 	TRUE if the room has to be a shared room.	*/
/*																		*/
/*	Output: 	return		Index into room database of the room if a	*/
/*							match is found, else CERROR.				*/
/* -------------------------------------------------------------------- */
r_slot IdExists(const char *NetID, Bool Network)
	{
	r_slot i;

	if (*NetID)
		{
		for (i = 0; i < cfg.maxrooms; i++)
			{
			if (	IsRoomInuse(i) &&
					(!Network || IsRoomShared(i)) &&
					(SameString(GetRoomNetID(i), NetID)))
				{
				return (i);
				}
			}
		}

	return (CERROR);
	}

/* -------------------------------------------------------------------- */
/*	getRoom()															*/
/* -------------------------------------------------------------------- */
void getRoom(int rm, aRoom *buffer)
	{
	long s;

	citWinReOpen(&roomfl);

	s = (long) rm * (long) sizeof (aRoom);

	citSeek(roomfl, s + sizeof(long), SEEK_SET);

	if (citRead(buffer, sizeof (aRoom), 1, roomfl) != 1)
		{
		crashout(getmsg(83), roomDat);
		}

	citWinCloseTmp(&roomfl);
	}

/* -------------------------------------------------------------------- */
/*	putRoom()			stores room in buf into slot rm in room.dat 	*/
/* -------------------------------------------------------------------- */
void putRoom(int rm, aRoom *buffer)
	{
	long int s;
	int key;

	assert(strlen(buffer->rbname) <= LABELSIZE);
	assert(strlen(buffer->netID) <= LABELSIZE);

	key = lockRoom(rm);

	if (key)
		{
		citWinReOpen(&roomfl);

		s = (long) rm * (long) sizeof(aRoom);

		citSeek(roomfl, s + sizeof(long), SEEK_SET);

		if (citWrite(buffer, sizeof(aRoom), 1, roomfl) != 1)
			{
			crashout(getmsg(661), roomDat);
			}

		fflush(roomfl);

		/* enter room into RAM index array. */

		CopyStringToBuffer(getRoomTab(rm)->rtname, buffer->rbname, LABELSIZE);
		getRoomTab(rm)->grpno = buffer->rbgrpno;
		getRoomTab(rm)->pgrpno = buffer->rbPgrpno;

		/* don't YOU like ansi C? */
		getRoomTab(rm)->rtflags = buffer->rbflags;

		CopyStringToBuffer(getRoomTab(rm)->netID, buffer->netID, LABELSIZE);

		memcpy(getRoomTab(rm)->GroupExpression, buffer->GroupExpression,
				sizeof(BoolExpr));

		citWinCloseTmp(&roomfl);
		unlockRoom(rm, key);
		}
	else
		{
		mPrintf(getmsg(1316));
		}
	}
