// --------------------------------------------------------------------------
// Citadel: MsgLoad.CPP
//
// Stuff for loading messages

#include "ctdl.h"
#pragma hdrstop

#include "msg.h"
#include "filerdwr.h"

// --------------------------------------------------------------------------
// Contents
//

/* -------------------------------------------------------------------- */
/*	getMsgStr() 	reads a NULL terminated string from msg file		*/
/*					returns:	TRUE if all is cool.					*/
/*								FALSE if an 0xff is found.				*/
/* -------------------------------------------------------------------- */
static Bool getMsgStr(char *dest, int lim)
	{
	char c;

	do
		{
		c = getMsgChar();

		if (c != -1 && lim) // if we have room then
			{
			lim--;
			*dest++ = c;	// copy char to buffer
			}
		} while (c != 0 && c != -1);

	*dest = 0;	// tie string off with nul

	return (c != -1);
	}


static char readCharFromNetworkFile(FILE *NetFile)
	{
	return (fgetc(NetFile));
	}

static char readCharFromMsgDat(FILE *)
	{
	return (getMsgChar());
	}

static Bool readStringFromNetworkFile(FILE *File, char *Buffer, int Length)
	{
	return (GetStr(File, Buffer, Length));
	}

static Bool readFilteredStringFromNetworkFile(FILE *File, char *Buffer, int Length)
	{
	GetFStr(File, Buffer, Length, 0);
	return (TRUE);
	}

static Bool readStringFromMsgDat(FILE *, char *Buffer, int Length)
	{
	return (getMsgStr(Buffer, Length));
	}

ReadMessageStatus Message::ReadAll(ReadMessageCode HowToRead, FILE *NetFile)
	{
	assert(HowToRead == RMC_NORMAL || NetFile);
	assert(HowToRead == RMC_NETWORK || !NetFile);
	assert(HowToRead != RMC_DUPLICATECHECK);

	// ReadHeader() does a ClearAll()
	ReadMessageStatus Status = ReadHeader(HowToRead, NetFile);
	if (Status == RMS_OK)
		{
		if (HowToRead == RMC_NORMAL)
			{
			if (!getMsgStr(GetTextPointer(), MAXTEXT))
				{
				Status = RMS_BADMESSAGE;
				}
			}
		else
			{
			GetFStr(NetFile, GetTextPointer(), MAXTEXT, 0);
			// not that any compressed messages should ever come in over the net...
			Decompress();
			}
		}

	return (Status);
	}


// --------------------------------------------------------------------------
// Message::ReadHeader(): Read a message header off disk into RAM.
//
// Input:
//	ReadMessageCode HowToRead: How to do it
//	FILE *NetFile: NULL if reading normal or for duplication checking; file

ReadMessageStatus Message::ReadHeader(ReadMessageCode HowToRead,
		FILE *NetFile)
	{
	Bool MavenAnon = FALSE;

	char (*ReadFileChar)(FILE *File);
	Bool (*ReadFileString)(FILE *File, char *Buffer, int Length);
	Bool (*ReadFileFilteredString)(FILE *File, char *Buffer, int Length);

	assert((HowToRead == RMC_NORMAL || HowToRead == RMC_DUPLICATECHECK) || NetFile);
	assert(HowToRead == RMC_NETWORK || !NetFile);

	switch (HowToRead)
		{
		case RMC_NETWORK:
			{
			KBReady();
			ReadFileChar = readCharFromNetworkFile;
			ReadFileString = readStringFromNetworkFile;
			ReadFileFilteredString = readFilteredStringFromNetworkFile;
			break;
			}

		case RMC_NORMAL:
		case RMC_DUPLICATECHECK:
			{
			ReadFileChar = readCharFromMsgDat;
			ReadFileString = readStringFromMsgDat;
			ReadFileFilteredString = readStringFromMsgDat;
			break;
			}

		default:
			{
			crashout(getmsg(153));
			}
		}

	// clear message buffer out
	ClearAll();

	// look 10000 chars for start message
	for (int i = 0; i < 10000; ++i)
		{
		char c;

		c = (*ReadFileChar)(NetFile);

		if (c == -1)
			{
			break;
			}

		if (HowToRead == RMC_NETWORK)
			{
			if (feof(NetFile))
				{
				return (RMS_NOMESSAGE);
				}
			}
		}

	if (i == 10000)
		{
		return (RMS_NOMESSAGE);
		}

	if (HowToRead != RMC_NETWORK)
		{
		// record exact position of start of message
		SetHeadLoc(bufferedTell(msgfl) - 1l);
		}

	// get message's attribute byte
	char ReadByte;

	ReadByte = (*ReadFileChar)(NetFile);

	if (ReadByte == -1)
		{
		return (RMS_BADMESSAGE);
		}

	SetAttribute(ReadByte);

	SetCompressed(IsCompressed());	// Sets onceWasCompressed;

	if (GetAttribute() & ATTR_MORE)
		{
		ReadByte = (*ReadFileChar)(NetFile);

		if (ReadByte == -1)
			{
			return (RMS_BADMESSAGE);
			}

		Attribute2 = ReadByte;
		}

	if (HowToRead != RMC_NETWORK)
		{
		// get message's room #
		if (IsBigRoom())
			{
			uchar roomno_lo;
			uchar roomno_hi;

			roomno_lo = (uchar) getMsgChar();

			if (roomno_lo == 0xff)
				{
				return (RMS_BADMESSAGE);
				}

			roomno_hi = (uchar) getMsgChar();

			if (roomno_hi == 0xff)
				{
				return (RMS_BADMESSAGE);
				}

			SetRoomNumber(int_JOIN(roomno_lo, roomno_hi) / 2);
			}
		else
			{
			SetRoomNumber(getMsgChar());

			if (GetRoomNumber() == 0xff)
				{
				return (RMS_BADMESSAGE);
				}
			}
		}

	if (!(*ReadFileString)(NetFile, LocalID, LABELSIZE) &&
			(HowToRead != RMC_NETWORK))
		{
		return (RMS_BADMESSAGE);
		}

	// Local IDs have to be numeric, and non-zero if from MSG.DAT
	if (
			!isNumeric(GetLocalID()) ||

				(
				HowToRead != RMC_NETWORK &&
				!atol(GetLocalID())
				)
		)
		{
		return (RMS_BADMESSAGE);
		}

	char c;
	int FoundDupFields = 0;

	do
		{
		c = (*ReadFileChar)(NetFile);

		switch (c)
			{
			case 'A':
				{
				if (!ReadFileFilteredString(NetFile, Author, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				FoundDupFields++;

				break;
				}

			case 'a':
				{
				MavenAnon = TRUE;

				label Bogus;
				ReadFileFilteredString(NetFile, Bogus, LABELSIZE);
				break;
				}

			case 'B':
				{
				if (!ReadFileFilteredString(NetFile, Subject, 80))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'C':
				{
				if (!ReadFileFilteredString(NetFile, CopyOfMessage,
						LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'D':
				{
				if (!ReadFileFilteredString(NetFile, CreationTime, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				FoundDupFields++;

				break;
				}

			case 'd':
				{
				if (HowToRead == RMC_NETWORK)
					{
					if (!ReadFileFilteredString(NetFile, EZCreationTime,
							LABELSIZE));
						{
						return (RMS_BADMESSAGE);
						}
					}

				break;
				}

			case 'F':
				{
				if (!ReadFileFilteredString(NetFile, Forward, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'G':
				{
				if (!ReadFileFilteredString(NetFile, Group, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'I':
				{
				if (!ReadFileFilteredString(NetFile, ReplyToMessage, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'J':
				{
				if (!ReadFileFilteredString(NetFile, TwitRegion, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'j':
				{
				if (!ReadFileFilteredString(NetFile, TwitCountry, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'L':
				{
				if (HowToRead == RMC_NORMAL)
					{
					if (!ReadFileFilteredString(NetFile, FileLink, 63))
						{
						return (RMS_BADMESSAGE);
						}
					}
				else
					{
					char Bogus[64];

					if (!ReadFileFilteredString(NetFile, Bogus, 63))
						{
						return (RMS_BADMESSAGE);
						}
					}

				break;
				}

			case 'l':
				{
				if (HowToRead == RMC_NORMAL)
					{
					if (!ReadFileFilteredString(NetFile, LinkedApplication, 127))
						{
						return (RMS_BADMESSAGE);
						}
					}
				else
					{
					char Bogus[128];

					if (!ReadFileFilteredString(NetFile, Bogus, 127))
						{
						return (RMS_BADMESSAGE);
						}
					}

				break;
				}

			case 'M': break;    // will be read off disk later

			case 'N':
				{
				if (!ReadFileFilteredString(NetFile, Title, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'n':
				{
				if (!ReadFileFilteredString(NetFile, Surname, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'O':
				{
				if (!ReadFileFilteredString(NetFile, OriginNodeName, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				FoundDupFields++;

				break;
				}

			case 'o':
				{
				if (!ReadFileFilteredString(NetFile, OriginRegion, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'P':
				{
				if (!ReadFileFilteredString(NetFile, FromPath, PATHSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'p':
				{
				if (!ReadFileFilteredString(NetFile, ToPath, PATHSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'Q':
				{
				if (!ReadFileFilteredString(NetFile, OriginCountry, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'q':
				{
				if (!ReadFileFilteredString(NetFile, ToCountry, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'R':
				{
				if (!ReadFileFilteredString(NetFile, CreationRoom, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'r':
				{
				if (!ReadFileFilteredString(NetFile, SourceRoomName, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'S':
				{
				if (!ReadFileFilteredString(NetFile, SourceID, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				FoundDupFields++;

				break;
				}

			case 's':
				{
				if (!ReadFileFilteredString(NetFile, OriginSoftware, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'T':
				{
				if (!ReadFileFilteredString(NetFile, ToUser, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 't':
				{
				if (!ReadFileFilteredString(NetFile, PublicToUser, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'U':
				{
				if (!ReadFileFilteredString(NetFile, Cit86Country, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'X':
				{
				if (HowToRead == RMC_NORMAL)
					{
					if (!ReadFileFilteredString(NetFile, X, LABELSIZE))
						{
						return (RMS_BADMESSAGE);
						}
					}

				break;
				}

			case 'Z':
				{
				if (!ReadFileFilteredString(NetFile, ToNodeName, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'z':
				{
				if (!ReadFileFilteredString(NetFile, ToRegion, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '.':
				{
				if (!ReadFileFilteredString(NetFile, Signature, 90))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '_':
				{
				if (!ReadFileFilteredString(NetFile, UserSignature, 90))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '!':
				{
				if (!ReadFileFilteredString(NetFile, RealName, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'H':
				{
				if (!ReadFileFilteredString(NetFile, OriginPhoneNumber, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case 'h':
				{
				if (!ReadFileFilteredString(NetFile, ToPhoneNumber, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '>':
				{
				if (!ReadFileFilteredString(NetFile, DestinationAddress, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '%':
				{
				char String[256];

				if (!ReadFileFilteredString(NetFile, String, 255))
					{
					return (RMS_BADMESSAGE);
					}

				if (*String)
					{
					AddComment(String);
					}

				break;
				}

			case '#':
				{
				if (!ReadFileFilteredString(NetFile, MoreFlags, LABELSIZE))
					{
					return (RMS_BADMESSAGE);
					}

				break;
				}

			case '\0':
				{
				return (RMS_BADMESSAGE);
				}

			default:
				{
				// try to store unknown field
				unkLst *lul;

				if ((lul = addUnknownList()) != NULL)
					{
					lul->whatField = c;

					if (!ReadFileString(NetFile, lul->theValue,
							MAXUNKLEN))
						{
						return (RMS_BADMESSAGE);
						}
					}
				else
					{
					// cannot save it - discard unknown field
					if (!ReadFileString(NetFile, GetTextPointer(), MAXTEXT))
						{
						return (RMS_BADMESSAGE);
						}

					SetText(ns);
					}
				}
			}

		if (HowToRead == RMC_NETWORK)
			{
			if (feof(NetFile))
				{
				return (RMS_BADMESSAGE);
				}
			}

		if (HowToRead == RMC_DUPLICATECHECK)
			{
			if (FoundDupFields == 4)
				{
				break;
				}
			}
		} while (c != 'M');

	if (MavenAnon)
		{
		strcpy(Author, getmsg(1456));
		*UserSignature = 0;
		*Title = 0;
		*Surname = 0;
		*RealName = 0;
		}

	if (HowToRead == RMC_NETWORK)
		{
		FixupNetwork();
		}

	if (HowToRead == RMC_NORMAL)
		{
		SetOriginalAttribute(GetAttribute());
		SetOriginalID(atol(GetLocalID()));
		SetOriginalRoom(GetRoomNumber());
		SetViewDuplicate(FALSE);	// will be set to TRUE when we need it
		}

	return (RMS_OK);
	}



/* -------------------------------------------------------------------- */
/*	GetFStr()	gets a null-terminated FILTERED string from a file		*/
/*					fLevel		0 = filters ^B codes only				*/
/*								1 = filters ^A codes & ^B codes.		*/
/* -------------------------------------------------------------------- */
Bool GetFStr(FILE *fl, char *str, int mlen, int fLevel)
	{
	int l = 0;
	uchar ch = 1;
	Bool ctrla = FALSE;
	Bool ctrlb = FALSE;

	while (!feof(fl) && ch)
		{
		ch = (uchar) fgetc(fl);

		if ((ch != 0xFF && ch != '\r')      /* no FFs or CRs (LFs only) */
			&& l < mlen)					/* Not past end of str */
			{
			if (ch == CTRL_A)
				{
				ctrla = TRUE;
				}
			else if (ch == CTRL_B)
				{
				ctrlb = TRUE;
				}
			else if (ctrlb || (ctrla && fLevel > 0))
				{
				ctrla = TRUE;
				ctrlb = FALSE;
				}
			else
				{
				if (ctrla)
					{
					str[l] = CTRL_A;
					l++;
					ctrla = FALSE;
					}

				str[l] = ch;
				l++;
				}
			}
		}

	str[l] = 0;

	return (TRUE);
	}

