/* -------------------------------------------------------------------- */
/*	NET86.CPP					Citadel 								*/
/* -------------------------------------------------------------------- */
/*		Networking libs for the Citadel bulletin board system			*/
/* -------------------------------------------------------------------- */
#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "tallybuf.h"
#include "auxtab.h"
#include "log.h"
#include "net.h"
#include "msg.h"
#include "filerdwr.h"

/* -------------------------------------------------------------------- */
/*								Contents								*/
/* -------------------------------------------------------------------- */
/*	net86_incorporate() 												*/
/*	net86_fetch()														*/
/* -------------------------------------------------------------------- */

/* -------------------------------------------------------------------- */
/*	net86_incorporate() 												*/
/* -------------------------------------------------------------------- */
void net86_incorporate(void)
	{
	Message *NewMsg = new Message;
	Message *DupeTest = new Message;

	if (NewMsg && DupeTest)
		{
		int our_new = 0, our_expired = 0, our_duplicate = 0;
		char errorflag = FALSE;
		Bool first = TRUE;

		SetDoWhat(NETWORKING);

		changedir(cfg.transpath);

		const char *PacketMask;

		if (*TI()node->GetExtractPacket())
			{
			PacketMask = TI()node->GetExtractPacket();
			}
		else
			{
			PacketMask = getnetmsg(129);
			}

		directoryinfo *files = filldirectory(PacketMask, 2, OldAndNew, FALSE);

		if (files)
			{
			for (int FileCounter = 0; files[FileCounter].name[0];
					FileCounter++)
				{
				char *packetname = files[FileCounter].name;

				FILE *msgfd;

				if ((msgfd = fopen(packetname, FO_RB)) != NULL)
					{
					doccr();
					cPrintf(getnetmsg(102), cfg.Lmsgs_nym,
							TI()node->GetName());
					doccr();
					doccr();
					cPrintf(getnetmsg(66));
					doccr();

					int total_new = 0;
					int total_expired = 0;
					int total_duplicate = 0;
					int total_rooms = 0;

					KBReady();

					r_slot prevroomNo = INT_MAX;

					while (NewMsg->ReadCit86Packet(msgfd) == RMS_OK)
						{
						label netid, here, there;
						Bool bad = FALSE;
						Bool More, foundit;
						r_slot roomNo;

						// The #ROOM lines in NODES.CIT match their room name
						// to our NetIDs.
						for (More = get_first_room(here, there),
								foundit = FALSE;

								More && !foundit;

								More = get_next_room(here, there))
							{
							if (SameString(there, NewMsg->GetCreationRoom()))
								{
								CopyStringToBuffer(netid, here, LABELSIZE);
								foundit = TRUE;

								// because get_next_room() closes the file
								// opened by get_first_room() when it is done.
								while (get_next_room(here, there));
								}
							}

						if (foundit)
							{
							roomNo = IdExists(netid, TRUE);
							}
						else
							{
							roomNo = CERROR;
							}

						if (roomNo == CERROR)
							{
							if (TI()node->IsVerbose(NCV_NONETIDONSYSTEM))
								{
								net69_error(FALSE, errorflag,
										TI()node->GetName(), getnetmsg(95),
										netid);

								errorflag = TRUE;
								}
							}

						if (first && roomNo != CERROR)
							{
							prevroomNo = roomNo;
							first = FALSE;
							}

						if (roomNo != prevroomNo && roomNo != CERROR)
							{
							cPrintf(getnetmsg(131),
									deansi(GetRoomName(prevroomNo)));

							if (our_new)
								{
								cPrintf(getnetmsg(132), our_new);
								}
							else
								{
								cPrintf(getnetmsg(133), our_new);
								}

							cPrintf(getnetmsg(134));
							if (our_expired)
								{
								cPrintf(getnetmsg(132), our_expired);
								}
							else
								{
								cPrintf(getnetmsg(133), our_expired);
								}

							cPrintf(getnetmsg(134));
							if (our_duplicate)
								{
								cPrintf(getnetmsg(132), our_duplicate);
								}
							else
								{
								cPrintf(getnetmsg(133), our_duplicate);
								}
							doccr();

							total_new += our_new;
							total_expired += our_expired;
							total_duplicate += our_duplicate;
							total_rooms++;
							our_new = 0;
							our_expired = 0;
							our_duplicate = 0;
							StatusLine.Update();

							prevroomNo = roomNo;
							}

						if (roomNo == CERROR)
							{
							bad = TRUE;
							}

						if (SameString(cfg.nodeTitle,
								NewMsg->GetOriginNodeName()))
							{
							bad = TRUE;
							our_duplicate++;
							}

						/* Throw away authorless messages */
						if (!NewMsg->GetAuthor()[0])
							{
							bad = TRUE;
							our_duplicate++;
							}

						/* Expired? */
						if (	!bad &&

								cfg.expire &&

								(
									labs(atol(NewMsg->GetCreationTime()) - time(NULL)) >
									(cfg.expire * SECSINDAY)
								)
							)
							{
							bad = TRUE;
							our_expired++;
							}

						/* is public */
						if (!bad)
							{
							m_slot size_table = sizetable();
							m_slot i;

							ulong oid = atol(NewMsg->GetSourceID());

							for (	i = size_table;

									#if defined(AUXMEM) || defined(WINCIT)
										i <= size_table && !bad; i--
									#else
										i != -1 && !bad; i--
									#endif
									)
								{
								if ((uint) oid == getOriginID(i))
									{
									ulong loc = getLocation(i);

									bufferedSeek(msgfl, loc);

									DupeTest->ReadHeader(RMC_DUPLICATECHECK, NULL);

									if (
											// If same author or node
											(
											SameString(NewMsg->GetAuthor(),
											DupeTest->GetAuthor())

											||

											SameString(NewMsg->GetOriginNodeName(),
											DupeTest->GetOriginNodeName())
											)

											&&

											// and same time
											SameString(NewMsg->GetCreationTime(),
											DupeTest->GetCreationTime())

											&&

											// and same source id
											SameString(NewMsg->GetSourceID(),
											DupeTest->GetSourceID())
											)
										{
										bad = TRUE;
										our_duplicate++;
										}
									}
								}
							}

						if (!bad)
							{					/* its good, save it */
							NewMsg->SetRoomNumber(roomNo);
							NewMsg->SetCreationRoom(GetRoomName(roomNo));

							putAndNoteMessage(NewMsg, TRUE);
							our_new++;
							}
						}

					if (prevroomNo != CERROR)
						{
						cPrintf(getnetmsg(131),
								deansi(GetRoomName(prevroomNo)));

						if (our_new)
							{
							cPrintf(getnetmsg(132), our_new);
							}
						else
							{
							cPrintf(getnetmsg(133), our_new);
							}
						cPrintf(getnetmsg(134));

						if (our_expired)
							{
							cPrintf(getnetmsg(132), our_expired);
							}
						else
							{
							cPrintf(getnetmsg(133), our_expired);
							}
						cPrintf(getnetmsg(134));

						if (our_duplicate)
							{
							cPrintf(getnetmsg(132), our_duplicate);
							}
						else
							{
							cPrintf(getnetmsg(133), our_duplicate);
							}
						doccr();

						total_new += our_new;
						total_expired += our_expired;
						total_duplicate += our_duplicate;
						total_rooms++;
						our_new = 0;
						our_expired = 0;
						our_duplicate = 0;
						StatusLine.Update();
						}

					cPrintf(getnetmsg(135));
					doccr();
					cPrintf(getnetmsg(136));

					if (total_rooms)
						{
						cPrintf(getnetmsg(132), total_rooms);
						}
					else
						{
						cPrintf(getnetmsg(133), total_rooms);
						}
					cPrintf(getnetmsg(134));

					if (total_new)
						{
						cPrintf(getnetmsg(132), total_new);
						}
					else
						{
						cPrintf(getnetmsg(133), total_new);
						}
					cPrintf(getnetmsg(134));


					if (total_expired)
						{
						cPrintf(getnetmsg(132), total_expired);
						}
					else
						{
						cPrintf(getnetmsg(133), total_expired);
						}
					cPrintf(getnetmsg(134));

					if (total_duplicate)
						{
						cPrintf(getnetmsg(132), total_duplicate);
						}
					else
						{
						cPrintf(getnetmsg(133), total_duplicate);
						}
					doccr();

					fclose(msgfd);
					changedir(cfg.transpath);
					unlink(packetname);
					}
				else
					{
					doccr();
					cPrintf(getmsg(78), packetname);
					doccr();
					}
				}

			delete [] files;
			}
		}
	else
		{
		cPrintf(getmsg(188), getnetmsg(137));
		}

	delete NewMsg;
	delete DupeTest;
	}

/* -------------------------------------------------------------------- */
/*	net86_fetch(void)													*/
/* -------------------------------------------------------------------- */
Bool net86_fetch(void)
	{
	label	netid;
	int 	roomNo;
	FILE	*msgfd;
	int 	msgsread;
	int 	crcounter = 0;
	char	packetname[20];
	char	errorflag = FALSE;
	int 	i;
	int 	oldmread = TI()MS.Read;
	TI()MS.Read = 0;

	SetDoWhat(NETWORKING);

	changedir(cfg.transpath);

	roomtalley();

	if (*TI()node->GetCreatePacket())
		{
		CopyStringToBuffer(packetname, TI()node->GetCreatePacket(),
				sizeof(packetname) - 1);
		}
	else
		{
		sprintf(packetname, getnetmsg(138),
				TI()CurrentUser->GetPoopcount() % 1000);
		}

	if ((msgfd = fopen(packetname, FO_AB)) == NULL)
		{
		doccr();
		cPrintf(getmsg(78), packetname);
		doccr();
		if (TI()menu69)
			{
			TI()MS.Read = oldmread;
			}

		return (FALSE);
		}

	doccr();

	cPrintf(getnetmsg(73), cfg.Lmsgs_nym);

	doccr();
	doccr();

	cPrintf(getnetmsg(76));

	doccr();

	for (i = get_first_room(netid, c86_there);
			i;
			i = get_next_room(netid, c86_there))
		{
		KBReady();

		if ((roomNo = IdExists(netid, TRUE)) != CERROR)
			{
			if (TI()CurrentUser->CanAccessRoom(roomNo))
				{
				if (GetRoomNewMessages(roomNo))
					{
					cPrintf(getnetmsg(139), deansi(GetRoomName(roomNo)));

					msgsread = NewRoom(roomNo, NULL, msgfd);

					cPrintf(getnetmsg(140), msgsread);

					if (!((crcounter + 1) % 2))
						{
						doccr();
						}

					crcounter++;
					}
				}
			else
				{
				if (TI()node->IsVerbose(NCV_NOACCESS))
					{
					net69_error(TRUE, errorflag, TI()node->GetName(),
								getnetmsg(111), GetRoomName(roomNo));
					errorflag = TRUE;
					}
				}
			}
		else
			{
			if (TI()node->IsVerbose(NCV_NONETIDONSYSTEM))
				{
				net69_error(TRUE, errorflag, TI()node->GetName(), getnetmsg(95),
						netid);
				errorflag = TRUE;
				}
			}
		}

	fclose(msgfd);

	doccr();
	doccr();
	cPrintf(getnetmsg(74), ltoac(TI()MS.Read),
			(TI()MS.Read == 1) ? cfg.Lmsg_nym : cfg.Lmsgs_nym);
	doccr();
	doccr();

	TI()CurrentUser->SetPoopcount(TI()CurrentUser->GetPoopcount() + 1);

	return (TRUE);
	}

Bool Citadel86Network(Bool master)
	{
	if (!master)
		{
		cPrintf(getnetmsg(172));
		return (FALSE);
		}

	label DeleteMask;

	if (*TI()node->GetCreatePacket())
		{
		CopyStringToBuffer(DeleteMask, TI()node->GetCreatePacket(), LABELSIZE);
		}
	else
		{
		strcpy(DeleteMask, getnetmsg(176));
		}

	changedir(cfg.transpath);
	ambigUnlink(DeleteMask, FALSE);

	net86_incorporate();

	return (TRUE);
	}


/* -------------------------------------------------------------------- */
/*	Cit86_PutMessage()	Puts a message to a file (cit86 style)			*/
/* -------------------------------------------------------------------- */
void Message::MakeCit86Packet(FILE *NetFile)
	{
	int i;
	label c86time, c86date;
	long msgno;

	KBReady();

	if (!GetSourceID()[0])
		{
		SetOriginNodeName(cfg.nodeTitle);
		SetSourceID(GetLocalID());
		SetCit86Country(cfg.Cit86Country);
		SetOriginPhoneNumber(cfg.nodephone);
		}

	if (!GetEZCreationTime()[0])
		{
		label Buffer;
		SetEZCreationTime(net69_gateway_time(atol(GetCreationTime()), Buffer));
		}

	sscanf(GetEZCreationTime(), getnetmsg(113), &c86date, &c86time);

	if (!GetOriginPhoneNumber()[0])
		{
		SetOriginPhoneNumber(getnetmsg(114));
		}

	if (*GetCit86Country())
		{
		sprintf(OriginRegion, getnetmsg(113), GetCit86Country(),
				GetOriginPhoneNumber());
		}
	else
		{
		sprintf(OriginRegion, getnetmsg(115), GetOriginPhoneNumber());
		}

	for (i = 3; i < strlen(GetCreationRoom()) + 1; i++)
		{
		CreationRoom[i - 4] = CreationRoom[i];
		}

	msgno = atoi(GetSourceID());

	sprintf(SourceID, getnetmsg(116), long_HI(msgno), long_LO(msgno));

	stripansi(Author);
	stripansi(OriginNodeName);
	stripansi(OriginRegion);
	stripansi(c86_there);
	stripansi(Text);

	if (SameString(GetAuthor(), getmsg(1456)))
		{
		fputc('D', NetFile); PutStr(NetFile, getmsg(1456));
		}
	else
		{
		fputc('A', NetFile); PutStr(NetFile, GetAuthor());
		fputc('D', NetFile); PutStr(NetFile, c86date);
		}

	fputc('C', NetFile); PutStr(NetFile, c86time);
	fputc('N', NetFile); PutStr(NetFile, GetOriginNodeName());
	fputc('O', NetFile); PutStr(NetFile, GetOriginRegion());
	fputc('R', NetFile); PutStr(NetFile, c86_there);
	fputc('S', NetFile); PutStr(NetFile, GetSourceID());

	if (*cfg.Cit86Domain)
		{
		fputc('X', NetFile); PutStr(NetFile, deansi(cfg.Cit86Domain));
		}

	/* put the message field */
	fputc('M', NetFile); PutStr(NetFile, GetText());
	}

/* -------------------------------------------------------------------- */
/*	Cit86_GetMessage()													*/
/* -------------------------------------------------------------------- */
ReadMessageStatus Message::ReadCit86Packet(FILE *NetFile)
	{
	KBReady();

	// clear message buffer out
	ClearAll();

	char c;
	do
		{
		c = (uchar) fgetc(NetFile);

		switch (c)
			{
			case 'A':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetAuthor(Buffer);
				break;
				}

			case 'C':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetCreationTime(Buffer);
				break;
				}

			case 'D':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetEZCreationTime(Buffer);
				break;
				}

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

			case 'N':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetOriginNodeName(Buffer);
				break;
				}

			case 'O':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetOriginPhoneNumber(Buffer);
				break;
				}

			case 'R':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetCreationRoom(Buffer);
				break;
				}

			case 'S':
				{
				label Buffer;

				GetStr(NetFile, Buffer, LABELSIZE);
				SetSourceID(Buffer);
				break;
				}

			case 'X':
				{
				label Buffer;

				GetFStr(NetFile, Buffer, LABELSIZE, 0);
				SetOriginRegion(Buffer);
				break;
				}


			case 0:
				break;

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

				if ((lul = addUnknownList()) != NULL)
					{
					lul->whatField = c;
					GetStr(NetFile, lul->theValue, MAXUNKLEN);
					}
				else
					{
					// cannot save it - discard unknown field
					GetStr(NetFile, GetTextPointer(), MAXTEXT);
					SetText(ns);
					}
				}
			}
		} while (c != 'M' && !feof(NetFile));

	if (feof(NetFile))
		{
		return (RMS_BADMESSAGE);
		}

	// get the message field
	GetFStr(NetFile, GetTextPointer(), MAXTEXT, 0);

	// Do a bunch of converting

	// Country
	char Country[3];
	strncpy(Country, GetOriginPhoneNumber(), 2);
	Country[2] = 0;
	SetOriginCountry(Country);

	// Path
	if (SameString(GetOriginNodeName(), TI()node->GetName()))
		{
		SetFromPath(GetOriginNodeName());
		}
	else
		{
		// last node did not originate, make due with what we got...
		char Buffer[80];

		sprintf(Buffer, getnetmsg(119), GetOriginNodeName(),
				TI()node->GetName());

		SetFromPath(Buffer);
		}

	if (SameString(GetEZCreationTime(), getmsg(1456)))
		{
		// Convert anonymous messages

		label Buffer;
		SetCreationTime(ltoa(time(NULL), Buffer, 10));
		SetAuthor(getmsg(1456));
		}
	else
		{
		// Convert split date
		label Buffer, Buffer2;

		strcpy(Buffer, GetEZCreationTime());
		strcat(Buffer, spc);
		strcat(Buffer, GetCreationTime());
		SetCreationTime(ltoa(net69_time(Buffer), Buffer2, 10));
		}

	// Convert source id formats
	long hi, lo;
	sscanf(GetSourceID(), getnetmsg(116), &hi, &lo);

	label SourceID;
	ltoa(long_JOIN(lo, hi), SourceID, 10);
	SetSourceID(SourceID);

	return (RMS_OK);
	}
