/* -------------------------------------------------------------------- */
/*	MSGOVL.CPP					Citadel 								*/
/* -------------------------------------------------------------------- */
/*				This is the overlayed high level message code.			*/
/* -------------------------------------------------------------------- */
#include "ctdl.h"
#pragma hdrstop

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

/* -------------------------------------------------------------------- */
/*								Contents								*/
/* -------------------------------------------------------------------- */
/*	MaySeeMsg() 		returns TRUE if person can see message. 100%	*/
/* -------------------------------------------------------------------- */

//	 Truth Tables
//
//	 (!a || !b) 	   ==	  !(a && b)
//	 ----------------		  -----------------
//	   1	 1	=  0			1	 1	=  0
//	   0	 1	=  1			0	 1	=  1
//	   1	 0	=  1			1	 0	=  1
//	   0	 0	=  1			0	 0	=  1
//
//
//	 (!a || b)
//	 ----------------
//	   1	1	=  1
//	   0	1	=  1
//	   1	0	=  0
//	   0	0	=  1

/* -------------------------------------------------------------------- */
/*	MaySeeMsg() 	returns TRUE if person can see message. 100%		*/
/* -------------------------------------------------------------------- */
MaySeeMsgType MaySeeMsg(Message *Msg)
	{
	int i;
	char msgflags_NET;
	char msgflags_NETWORKED;

	if (	/* Message is censored */
			(Msg->GetOriginalAttribute() & ATTR_CENSORED) &&

			/* And the user does not view censored messages */
			!TI()CurrentUser->IsViewCensoredMessages() &&

			/* And the user is not a node */
			!TI()CurrentUser->IsNode())
		{
		return (MSM_CENSORED);
		}

	/* check for PUBLIC non problem user messages first */
	if (!Msg->GetToUser()[0] && !Msg->GetX()[0] && !Msg->GetGroup()[0])
		{
		return (MSM_GOOD);
		}

	if (Msg->GetX()[0])
		{
		if (SameString(Msg->GetAuthor(), TI()CurrentUser->GetName()))
			{
			/* problem users cannot see copies of their own messages */
			if (Msg->IsViewDuplicate())
				{
				return (MSM_COPYOWNTWIT);
				}
			}
		else
			{
			// but everyone else cannot see the orignal if it has been
			// released

			if (!Msg->IsViewDuplicate() &&
					(Msg->GetOriginalAttribute() & ATTR_MADEVIS))
				{
				return (MSM_RELEASEDORIG);
				}

			/* problem user message... */
			if (
					Msg->GetX()[0] == 'Y' &&

					!TI()CurrentUser->IsAide() &&

					!Msg->IsMadeVisible())
				{
				return (MSM_TWIT);
				}

			/* moderated message... */
			if (
					Msg->GetX()[0] == 'M' &&

					!TI()CurrentUser->CanModerateRoom(Msg->GetRoomNumber()) &&

					!Msg->IsMadeVisible())
				{
				return (MSM_MODERATED);
				}
			}
		}

	/* mass e-mail or group only */
	if (Msg->GetGroup()[0])
		{
		i = FindGroupByName(Msg->GetGroup());

		if (i != CERROR)
			{
			return (TI()CurrentUser->IsInGroup(i) ? MSM_GOOD : MSM_NOTINGROUP);
			}
		else
			{
			if (TI()CurrentUser->IsSysop())
				{
				mPrintfCR(getmsg(1240), cfg.Lgroup_nym, Msg->GetGroup());
				}

			return (TI()CurrentUser->IsSysop() ? MSM_GOOD : MSM_GROUPBAD);
			}
		}

	// The following stuff was copied from indexmessage()
	// when updating that function make sure to update these too

	msgflags_NET = Msg->IsNetworkedMail() && !Msg->IsNetworkedMailForHere();
	msgflags_NETWORKED = *Msg->GetSourceID() != '\0';

	if (Msg->IsMail())
		{
		/* sysops see messages to 'Sysop' */
		if ((TI()CurrentUser->IsSysop() &&
				SameString(Msg->GetToUser(), getmsg(1020))) &&
				/* to keep messages to sysop @ blah from being seen on local */
				!msgflags_NET)
			{
			return (MSM_GOOD);
			}

		/* aides see messages to 'Aide' */
		if ((TI()CurrentUser->IsAide() &&
				SameString(Msg->GetToUser(), getmsg(1019))) &&
				/* to keep messages to aide @ blah from being seen on local */
				!msgflags_NET)
			{
			return (MSM_GOOD);
			}

		/* sysops see messages from 'Sysop' */
		if (TI()CurrentUser->IsSysop() &&
				SameString(Msg->GetAuthor(), getmsg(1020)) &&
				 /* to keep messages fr sysop @ blah from being seen on local */
				 !msgflags_NETWORKED)
			{
			return (MSM_GOOD);
			}

		/* aides see messages from 'Aide' */
		if (TI()CurrentUser->IsAide() &&
				SameString(Msg->GetAuthor(), getmsg(1019)) &&
				/* to keep messages fr aide @ blah from being seen on local */
				!msgflags_NETWORKED)
			{
			return (MSM_GOOD);
			}

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

		/* author can see his own private messages */
		/* but ONLY on local system. */
		if (SameString(Msg->GetAuthor(), TI()CurrentUser->GetName())
				&& !msgflags_NETWORKED)
			{
			return (MSM_GOOD);
			}

#ifdef GOODBYE
		// This one is easier to understand
		/* recipient can see private messages */
		if (SameString(Msg->GetToUser(), TI()CurrentUser->GetName())
		{
			if (!Msg->GetForward()[0])
			{
				if (!msgflags_NET)
				{
					return (MSM_GOOD);
				}
			}
			else
			{
				if (!msgflags_NETWORKED)
				{
					return (MSM_GOOD);
				}
			}
		}
#endif

		// But this one is more compact...
		if (SameString(Msg->GetToUser(), TI()CurrentUser->GetName())
			&&
			// Keeps out unforwarded outbound messages
			(Msg->GetForward()[0] || !msgflags_NET)
			&&
			// Keeps out forwarded networked messages
			!(Msg->GetForward()[0] && msgflags_NETWORKED)
			)
			{
			return (MSM_GOOD);
			}

		/* forwardee can see private messages */
		if (SameString(Msg->GetForward(), TI()CurrentUser->GetName())&&
			!msgflags_NET)
			{
			return (MSM_GOOD);
			}

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

	return (MSM_GOOD);
	}

Message& Message::operator =(const Message &Original)
	{
	VerifyHeap();
	assert(this != NULL);

	disposeUnknownList();
	disposeComments();

	for (unkLst *cur = Original.firstUnk; cur;
			cur = (unkLst *) getNextLL(cur))
		{
		unkLst *New = addUnknownList();

		if (New)
			{
			memcpy(New + sizeof(New->next), cur + sizeof(cur->next),
					sizeof(*New) - sizeof(New->next));
			}
		}

	for (strList *sl = Original.Comments; sl; sl = (strList *) getNextLL(sl))
		{
		AddComment(sl->string);
		}

	cur = firstUnk;
	sl = Comments;

	memcpy(this, &Original, sizeof(Message));

	firstUnk = cur;
	Comments = sl;

	VerifyHeap();
	return (*this);
	}

Message::Message(const Message &Original)
	{
	VerifyHeap();
	assert(this != NULL);

	firstUnk = NULL;		// Because ClearAll() tries to dispose it.
	Comments = NULL;		// same thing.
	ClearAll();

	for (unkLst *cur = Original.firstUnk; cur;
			cur = (unkLst *) getNextLL(cur))
		{
		unkLst *New = addUnknownList();

		if (New)
			{
			memcpy(New + sizeof(New->next), cur + sizeof(cur->next),
					sizeof(*New) - sizeof(New->next));
			}
		}

	for (strList *sl = Original.Comments; sl; sl = (strList *) getNextLL(sl))
		{
		AddComment(sl->string);
		}

	cur = firstUnk;
	sl = Comments;

	memcpy(this, &Original, sizeof(Message));

	firstUnk = cur;
	Comments = sl;

	VerifyHeap();
	}

/* -------------------------------------------------------------------- */
/*	getMsgChar()	reads a character from msg file, curent position	*/
/* -------------------------------------------------------------------- */
int getMsgChar(void)
	{
	int c;

	c = bufferedGetc(msgfl);

	if (c == EOF)
		{
		/* check for EOF */
		if (bufferedEof(msgfl))
			{
			bufferedClearerr(msgfl);
			bufferedSeek(msgfl, 0l);
			c = bufferedGetc(msgfl);
			}
		}

	return (c);
	}

Bool Message::SetMoreFlag(const char Flag, Bool New)
	{
	assert(this);
	assert(Flag);

	if (IsMoreFlag(Flag) && !New)
		{
		// Take it out
		for (char *Wow = MoreFlags; *Wow; Wow++)
			{
			if (*Wow == Flag)
				{
				for (char *Wow2 = Wow; *Wow2; Wow2++)
					{
					*Wow2 = *(Wow2 + 1);
					}

				Wow--;	// Retest this position, in case flag in multiple
						// times
				}
			}
		}
	else if (!IsMoreFlag(Flag) && New)
		{
		// Add it
		if (strlen(MoreFlags) < sizeof(MoreFlags) - 1)
			{
			char *Wow = strchr(MoreFlags, 0);

			*Wow = Flag;
			*(Wow + 1) = 0;
			}
		else
			{
			return (FALSE);
			}
		}

	return (!!Flag);	// Flag == 0 is bad
	}
