// --------------------------------------------------------------------------
// Citadel: MMakeHi.CPP
//
// High-level message making code.

#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "tallybuf.h"
#include "log.h"
#include "msg.h"
#include "net.h"
#include "blurbs.h"
#include "maillist.h"


// --------------------------------------------------------------------------
// Contents
//
// makeMessage()	is menu-level routine to enter a message
// fakeFullCase()	converts a message in uppercase-only to a


// --------------------------------------------------------------------------
// fakeFullCase(): Converts a message in uppercase-only to a reasonable mix.
//	It can't possibly make matters worse...
//
// Notes:
//	Algorithm: First alphabetic after a period is uppercase, all others are
//	lowercase, excepting pronoun "I" is a special case.  We assume an
//	imaginary period preceding the text.

static void fakeFullCase(char *text)
	{
	char *c;
	char lastWasPeriod;
	char state;

	for (lastWasPeriod = TRUE, c=text; *c; c++)
		{
		if ((*c != '.') && (*c != '?') && (*c != '!') && (*c != 1))
			{
			if (isalpha(*c))
				{
				if (!lastWasPeriod)
					{
					*c = (char)tolower(*c);
					}

				lastWasPeriod = FALSE;
				}
			}
		else
			{
			lastWasPeriod = TRUE ;
			}
		}

	// little state machine to search for ' i '
	#define NUTHIN		0
	#define FIRSTBLANK	1
	#define BLANKI		2

	for (state = NUTHIN, c = text; *c; c++)
		{
		switch (state)
			{
			case NUTHIN:
				{
				if (isspace(*c) || ispunct(*c))
					{
					state = FIRSTBLANK;
					}
				else
					{
					state = NUTHIN;
					}
				break;
				}

			case FIRSTBLANK:
				{
				if (*c == 'i')
					{
					state = BLANKI;
					}
				else
					{
					state = NUTHIN;
					}
				break;
				}

			case BLANKI:
				{
				if (isspace(*c) || ispunct(*c))
					{
					state = FIRSTBLANK;
					}
				else
					{
					state = NUTHIN;
					}

				if (!isalpha(*c))
					{
					*(c-1) = 'I';
					}

				break;
				}
			}
		}
	}


// --------------------------------------------------------------------------
// makeMessage(): Menu-level routine to enter a message.

Bool makeMessage(Message *Msg, Message *ReplyTo, r_slot PutInRoom)
	{
	// the next three are changed later if responding to aide/sysop messages.
	if (!*Msg->GetAuthor())
		{
		Msg->SetAuthor(TI()CurrentUser->GetName());
		}

	if (!*Msg->GetSurname())
		{
		Msg->SetSurname(TI()CurrentUser->GetSurname());
		}

	if (!*Msg->GetTitle())
		{
		Msg->SetTitle(TI()CurrentUser->GetTitle());
		}

	if (*Msg->GetDestinationAddress() && !*Msg->GetToNodeName())
		{
		Msg->SetToNodeName(Msg->GetDestinationAddress());
		}

	// if replying, author becomes recipient. Also record message which
	// message is being replied to
	if (ReplyTo)
		{
		// baskin stuff
		if (SameString(ReplyTo->GetToUser(), getmsg(1019)))
			{
			Msg->SetAuthor(getmsg(1019));
			Msg->SetSurname(TI()CurrentUser->GetName());
			Msg->SetTitle(ns);
			}

		if (SameString(ReplyTo->GetToUser(), getmsg(1020)))
			{
			Msg->SetAuthor(getmsg(1020));
			Msg->SetSurname(TI()CurrentUser->GetName());
			Msg->SetTitle(ns);
			}

		Msg->SetToUser(ReplyTo->GetAuthor());
		Msg->SetReplyToMessage(*ReplyTo->GetSourceID() ?
				ReplyTo->GetSourceID() : ReplyTo->GetLocalID());

		// If networked
		if (*ReplyTo->GetSourceID())
			{
			Msg->SetToNodeName(ReplyTo->GetOriginNodeName());
			Msg->SetToRegion(ReplyTo->GetOriginRegion());
			Msg->SetToCountry(ReplyTo->GetOriginCountry());
			Msg->SetDestinationAddress(oaddress(ReplyTo));
			}

		Msg->SetSubject(ReplyTo->GetSubject());
		}
	else
		{
		if (IsRoomSubject(PutInRoom == CERROR ? TI()thisRoom : PutInRoom) &&
				!*Msg->GetSubject())
			{
			char Subject[81];

			getNormStr(getmsg(415), Subject, 80, ECHO);

			Msg->SetSubject(Subject);
			}
		}

	if (!*Msg->GetGroup() && *Msg->GetToUser()) 	// not mass email
		{
		ResolveMessageAddressingIssues(Msg, MODEM);
		}

	// moderated messages
	if (
			(
			// The room is moderated or...
			IsRoomModerated(PutInRoom == CERROR ? TI()thisRoom : PutInRoom) ||

			// ... networked and not a net user
			(IsRoomShared(PutInRoom == CERROR ? TI()thisRoom : PutInRoom) &&
			!TI()CurrentUser->IsNetUser())
			)

			&&

			// and not mail
			!*Msg->GetToUser())
		{
		Msg->SetX("M");
		}

	// problem user message
	if (	// problem user
			TI()CurrentUser->IsProblem() &&

			// and not mail
			!*Msg->GetToUser())
		{
		Msg->SetX("Y");
		}

	if (IsRoomShared(PutInRoom == CERROR ? TI()thisRoom : PutInRoom))
		{
		Msg->SetSignature(cfg.nodeSignature);
		}

	// echo to both for sysop messages
	if (SameString(Msg->GetToUser(), getmsg(1020)) ||
		SameString(Msg->GetToUser(), getmsg(1019)) ||
		SameString(Msg->GetAuthor(), getmsg(1020)) ||
		SameString(Msg->GetAuthor(), getmsg(1019)))
		{
		TI()OC.Echo = BOTH;
		setio();
		}

	// copy author name into message buffer
	if (IsRoomAnonymous(PutInRoom == CERROR ? TI()thisRoom : PutInRoom))
		{
		Msg->SetAuthor(getmsg(1456));
		Msg->SetSurname(ns);
		Msg->SetTitle(ns);
		}
	else
		{
		// non-anonymous messages get real name
		Msg->SetRealName(TI()CurrentUser->GetRealName());
		}

	// clear our flags
	if (TI()MS.AbortedMessage)
		{
		delete TI()MS.AbortedMessage;
		TI()MS.AbortedMessage = NULL;
		}

	// set room# and attribute byte for message
	Msg->SetRoomNumber(PutInRoom == CERROR ? TI()thisRoom : PutInRoom);

	if (!*Msg->GetFileLink())
		{
		if (TI()loggedIn && TI()CurrentUser->GetSignature()[0] &&
				!IsRoomAnonymous(Msg->GetRoomNumber()))
			{
			Msg->SetUserSignature(TI()CurrentUser->GetSignature());
			}

		if (getText(Msg, NULL))
			{
			Bool allUpper;
			const char *pc;

			for (pc = Msg->GetText(), allUpper = TRUE;
					*pc && allUpper; pc++)
				{
				if (*pc == 1)
					{
					if (*(pc + 1))
						{
						pc++;
						}
					}
				else if (toupper(*pc) != *pc)
					{
					allUpper = FALSE;
					}
				}

			if (allUpper)
				{
				fakeFullCase(Msg->GetTextPointer());
				}
			}
		else
			{
			return (FALSE);
			}
		}
	else
		{
		doCR();
		putheader(TRUE, Msg);
		}

	label Buffer;
	Msg->SetLocalID(ltoa(cfg.newest + 1, Buffer, 10));

	if (TI()CurrentUser->IsSysop() && Msg->GetX()[0] == 'M')
		{
		char prompt[80];

		sprintf(prompt, getmsg(1141), cfg.Lmsg_nym);

		if (getYesNo(prompt, 1))
			{
			Msg->SetX(ns);
			}
		}

	if (*Msg->GetToNodeName())	// save it for netting...
		{
		// room names get included in networked mail
		Msg->SetCreationRoom(GetRoomName(Msg->GetRoomNumber()));

		if (!save_mail(Msg, FALSE))
			{
			delete TI()MS.AbortedMessage;
			TI()MS.AbortedMessage = NULL;

			compactMemory();

			TI()MS.AbortedMessage = new Message;

			if (TI()MS.AbortedMessage)
				{
				*TI()MS.AbortedMessage = *Msg;

				CRmPrintfCR(getmsg(1142), Msg->GetToNodeName(), cfg.Lmsg_nym);
				return (FALSE);
				}
			else
				{
				mPrintf(getmsg(188), getmsg(350));
				return (FALSE);
				}
			}
		}

	if (putAndNoteMessage(Msg, TRUE))
		{
		dispBlb(B_CENSOR);
		}

	if (*Msg->GetToUser() && !*Msg->GetToNodeName() &&
			IsMailingList(Msg->GetToUser()))
		{
		SendMailToList(Msg);
		}

	if (!(ReplyTo && *ReplyTo->GetToUser()))
		{
		IncrementMessagesEnteredInRoom(Msg->GetRoomNumber());
		}

	if (IsRoomAnonymous(Msg->GetRoomNumber()))
		{
		char TrapString[256];
		sprintf(TrapString, getmsg(1143), Msg->GetLocalID());
		trap(TrapString, T_ANONYMOUS);
		}

	return (TRUE);
	}
