// --------------------------------------------------------------------------
// Citadel: Msg.CPP
//
// Often-used message related routines.

#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "auxtab.h"
#include "msg.h"
#include "log.h"
#include "group.h"

// --------------------------------------------------------------------------
// Contents
//
// clearmsgbuf()		this clears the message buffer out
// indexslot()			give it a message # and it returns a slot#
// MaySeeIndexMsg() 	Can see message by slot #. 99%
// sizetable()			returns # messages in table


#ifdef AUXMEM
	auxTabList	*mtList;				// base of our linked list
	int 		msgBlocksInHeap;		// how many we have

	m_slot *FirstMessageInRoom; 		// array of table indexes
	m_slot *LastMessageInRoom;			// array of table indexes
#else
	#ifdef WINCIT
		messagetable huge *msgTabWin;	// the windows message table
	#else
		msgflags	*msgTab_mtmsgflags; // every message gets flags
		int 		*msgTab_mtmsgLocLO; // offset where message starts
		int 		*msgTab_mtmsgLocHI; // offset where message starts
		int 		*msgTab_mtroomno;	// room # of message
		int 		*msgTab_mttohash;	// hash of recipient or group
		int 		*msgTab_mtauthhash; // hash of author of message
		uint		*msgTab_mtomesg;	// LO net id, forwardee hash, 
										//	copy offset
	#endif
#endif


// --------------------------------------------------------------------------
// indexslot(): Give it a message # and it returns a slot#.

m_slot indexslot(ulong msgno)
	{
	if (msgno < cfg.mtoldest || msgno > cfg.newest)
		{
		DebugOut(getdbmsg(33));
		return (M_SLOT_ERROR);
		}

	return ((m_slot) (msgno - cfg.mtoldest));
	}


// --------------------------------------------------------------------------
// MaySeeIndexMsg(): Can see message by slot #? 99+%

MaySeeMsgType MaySeeIndexMsg(m_slot slot)
	{
	int i;

	char copy = FALSE;
	m_slot oslot;
#ifdef AUXMEM
	messagetable *lmt;
#endif

	oslot = slot;

#ifdef AUXMEM
	lmt = getMsgTab(slot);
#endif

	// seek out original message table entry */
	while (getFlagsLMT(slot)->IsCopy())
		{
		copy = TRUE;
		if (getCopyLMT(slot) > (m_slot) slot)
			{
			// copy has scrolled
			return (MSM_COPYSCROLLED);
			}
		else	// look at original message index
			{
			assert(getCopyLMT(slot) != 0);
			slot = slot - getCopyLMT(slot);
#ifdef AUXMEM
			lmt = getMsgTab(slot);
#endif
			}
		}

	if (getFlagsLMT(slot)->IsCensored() &&
			(!TI()CurrentUser->IsViewCensoredMessages() &&
			!TI()CurrentUser->IsNode()))
		{
		return (MSM_CENSORED);
		}

	// check for PUBLIC non problem user messages first
	if (!getToHashLMT(slot) && !getFlagsLMT(slot)->IsProblem() &&
			!getFlagsLMT(slot)->IsModerated() &&
			!getFlagsLMT(slot)->IsMassemail() &&
			!getFlagsLMT(slot)->IsLimited())
		{
		return (MSM_GOOD);
		}

	if (getFlagsLMT(slot)->IsProblem() || getFlagsLMT(slot)->IsModerated())
		{
		if (getAuthHashLMT(slot) == (int) hash(TI()CurrentUser->GetName()))
			{
			// problem or moderated users cannot see copies of their own
			// messages

			if (copy)
				{
				return (MSM_COPYOWNTWIT);
				}
			}
		else
			{
			// but everyone else cannot see the original if it has been
			// released
			if (!copy && getFlags(oslot)->IsMadevis())
				{
				return (MSM_RELEASEDORIG);
				}

			// problem user message...
			if (	getFlagsLMT(slot)->IsProblem() &&
					!TI()CurrentUser->IsAide() &&
					!getFlags(slot)->IsMadevis())
				{
				return (MSM_TWIT);
				}

			// moderated message...
			if (	getFlagsLMT(slot)->IsModerated() &&
					!TI()CurrentUser->CanModerateRoom(getRoomNum(slot)) &&
					!getFlags(slot)->IsMadevis())
				{
				return (MSM_MODERATED);
				}
			}
		}

	// mass e-mail or group only
	if (getFlagsLMT(slot)->IsLimited() || getFlagsLMT(slot)->IsMassemail())
		{
		for (i = 0; i < cfg.maxgroups; ++i)
			{
			// check to see which group message is to
			if ((hash(GroupData->GetEntry(i)->GetName()) == getToHashLMT(slot)) &&
					GroupData->GetEntry(i)->IsInuse())
				{
				return (TI()CurrentUser->IsInGroup(i) ? MSM_GOOD : MSM_NOTINGROUP);
				}
			}

		// The group does not exist: can only read if a sysop.
		return (TI()CurrentUser->IsSysop() ? MSM_GOOD : MSM_GROUPBAD);
		}

	if (getFlagsLMT(slot)->IsMail())
		{
		// sysops see messages to 'Sysop'
		if (TI()CurrentUser->IsSysop() && (getToHashLMT(slot) == (int) hash(getmsg(1020))) &&
				// to keep messages to sysop @ blah from being seen on local
				!getFlagsLMT(slot)->IsNet())
			{
			return (MSM_GOOD);
			}

		// aides see messages to 'Aide'
		if (TI()CurrentUser->IsAide() && (getToHashLMT(slot) == (int) hash(getmsg(1019))) &&
				// to keep messages to aide @ blah from being seen on local
				!getFlagsLMT(slot)->IsNet())
			{
			return (MSM_GOOD);
			}

		// sysops see messages from 'Sysop'
		if (TI()CurrentUser->IsSysop() && (getAuthHashLMT(slot) == (int) hash(getmsg(1020))) &&
				// to keep messages fr sysop @ blah from being seen on local
				!getFlagsLMT(slot)->IsNetworked())
			{
			return (MSM_GOOD);
			}

		// aides see messages from 'Aide'
		if (TI()CurrentUser->IsAide() && (getAuthHashLMT(slot) == (int) hash(getmsg(1019))) &&
				// to keep messages fr aide @ blah from being seen on local
				!getFlagsLMT(slot)->IsNetworked())
			{
			return (MSM_GOOD);
			}

		// Unlogged users see no mail if not sysop and not aide.
		if (!TI()loggedIn)
			{
			return (MSM_NOTLOGGEDIN);
			}

		// author can see his or her own private messages...
		//	but ONLY on local system
		if (getAuthHashLMT(slot) == hash(TI()CurrentUser->GetName()) &&
				!getFlagsLMT(slot)->IsNetworked())
			{
			return (MSM_GOOD);
			}

#ifdef GOODBYE
		// This one is easier to understand
		// recipient can see private messages
		if (getToHashLMT(slot) == (int) hash(TI()CurrentUser->GetName())
		{
			if (!getFlagsLMT(slot)->IsForwarded())
			{
				if (!getFlagsLMT(slot)->IsNet())
				{
					return (MSM_GOOD);
				}
			}
			else
			{
				if (!getFlagsLMT(slot)->IsNetworked())
				{
					return (MSM_GOOD);
				}
			}
		}
#endif
		// recipient can see private messages
		if (getToHashLMT(slot) == (int) hash(TI()CurrentUser->GetName())
			&&
			// Keeps out unforwarded outbound messages
			 (getFlagsLMT(slot)->IsForwarded()	|| !getFlagsLMT(slot)->IsNet())
			&&
			// Keeps out forwarded networked messages
			!(getFlagsLMT(slot)->IsForwarded() && getFlagsLMT(slot)->IsNetworked())
			)
			{
			return (MSM_GOOD);
			}

		// forwardee can see private messages
		if (getFlagsLMT(slot)->IsForwarded())
			{
			// if networked message, the FORWARDEE hash is stored in the
			//	RECIPIENT hash and RECIPIENT does not see message.
			if (((!getFlagsLMT(slot)->IsNetworked()) ?
					(int)getOriginIDLMT(slot) : (int)getToHashLMT(slot))
					== (int) hash(TI()CurrentUser->GetName()) &&
					!getFlagsLMT(slot)->IsNet())
				{
				return (MSM_GOOD);
				}
			}

		// none of those so cannot see message
		return (MSM_MAIL);
		}

	return (MSM_GOOD);
	}


// --------------------------------------------------------------------------
// sizetable(): Returns # messages in table.

m_slot sizetable(void)
	{
	return ((m_slot) (cfg.newest - cfg.mtoldest + 1));
	}
