// --------------------------------------------------------------------------
// Citadel: LoginNew.CPP
//
// Overlayed new user login log code.

#include "ctdl.h"
#pragma hdrstop

#include "log.h"
#include "msg.h"
#include "account.h"
#include "maillist.h"
#include "blurbs.h"
#include "events.h"
#include "aplic.h"
#include "filecmd.h"
#include "cwindows.h"
#include "term.h"
#include "miscovl.h"


// --------------------------------------------------------------------------
// Contents
//
// loginNew()		login a new user, handle diffrent configs.
// newUser()		prompts for name and password
// newUserFile()	Writes new user info out to a file
// newlog() 		sets up a new log entry for new users returns CERROR
//						if cannot find a usable slot
// newslot()		attempts to find a slot for a new user to reside in
//						puts slot in global var thisSlot


static Bool newlog(void);
static int newslot(void);
static void newUser(char *initials, char *password);
static void newUserFile(void);


// --------------------------------------------------------------------------
// loginNew(): Login a new user, handle diffrent configs.

void loginNew(char *initials, char *password)
	{
	char string[128];

	sprintf(string, getmsg(1254), cfg.Luser_nym);

	if (getYesNo(cfg.l_verified ? string : getmsg(1255), 1))
		{
		if (!(HaveConnectionToUser()))
			{
			if (!login_user && (*initials || *password))
				{
				char TrapString[256];

				sprintf(TrapString, getmsg(1253), initials, password);
				trap(TrapString, T_HACK);
				}

			return;
			}

		if (cfg.l_closedsys && !sysopNew && !(onConsole && !debug))
			{
			dispBlb(B_CLOSESYS);

			CITWINDOW *w = ScreenSaver.IsOn() ? NULL :
				CitWindowsMsg(NULL, getmsg(1643));

			Hangup();

			if (w)
				{
				destroyCitWindow(w, FALSE);
				}

			return;
			}

		dispBlb(B_USERINFO);

		if (cfg.l_create || sysopNew || (onConsole && !debug))
			{
			TI()CurrentUser->SetVerified((onConsole && !debug) ?
					TRUE : cfg.l_verified);

			newUser(initials, password);

			if (!TI()loggedIn)
				{
				return;
				}

			if (cfg.accounting && TI()CurrentUser->IsAccounting())
				{
				TI()CurrentUserAccount->CreateAccount();
				}

			StatusLine.Update();
			}

		if ((cfg.NUQuest[0] != NUQ_NUMQUEST) && (!(onConsole && !debug)))
			{
			newUserFile();
			}

		if (*cfg.newuserapp && (!(onConsole && !debug)))
			{
			RunApplication(cfg.newuserapp, NULL, TRUE, TRUE);
			}

		if (cfg.l_sysop_msg && (!(onConsole && !debug)))
			{
			dispBlb(B_NEWMSG);

			Message *Msg = new Message;

			if (Msg)
				{
				// to sysop
				Msg->SetToUser(getmsg(1020));

				makeMessage(Msg, NULL, MAILROOM);

				delete Msg;
				}
			else
				{
				mPrintf(getmsg(188), getmsg(769));
				}
			}

		if (!TI()CurrentUser->IsVerified() && !sysopNew && TI()loggedIn)
			{
			TI()MRO.Verbose = FALSE;
			terminate(TRUE);
			CRmPrintfCR(getmsg(1256));

			CITWINDOW *w = ScreenSaver.IsOn() ? NULL :
					CitWindowsMsg(NULL, getmsg(1643));

			Hangup();

			if (w)
				{
				destroyCitWindow(w, FALSE);
				}
			}

		if (cfg.oldcount)
			{
			ulong newpointer = (cfg.newest - cfg.oldcount);

			if (newpointer < cfg.oldest)
				{
				newpointer = cfg.oldest;
				}

			for (r_slot i = 0; i < cfg.maxrooms; i++)
				{
				TI()CurrentUser->SetRoomNewPointer(i, newpointer);
				}
			}
		}
	else
		{
		if (!login_user && (*initials || *password))
			{
			char TrapString[256];

			sprintf(TrapString, getmsg(1253), initials, password);
			trap(TrapString, T_HACK);
			}
		}

	sysopNew = FALSE;
	}


// --------------------------------------------------------------------------
// newUser(): Prompts for name and password.

static void newUser(char *initials, char *password)
	{
	label fullnm;
	char InitPw[62];

	Bool abort, good = FALSE;
	Bool askpw = login_user;

	if (!(HaveConnectionToUser()))
		{
		return;
		}

	// this only initializes TI()CurrentUser, does not write it out
	if (!newlog())
		{
		return;
		}

	// Give new users a chance to configure themselves
	DoEnterConfiguration(TRUE);

	dispBlb(B_PASSWORD);
	doCR();

	do
		{
		if (!login_user) // Use the name entered on Command Line 
			{
			do
				{
				getNormStr(cfg.enter_name, fullnm, LABELSIZE, ECHO);
				strip_special(fullnm);

				if (!(*fullnm) ||
						(FindPersonByName(fullnm) != CERROR) ||
						SameString(fullnm, getmsg(529)) ||
						SameString(fullnm, getmsg(1020)) ||
						SameString(fullnm, getmsg(1019)) ||
						SameString(fullnm, cfg.nodeTitle) ||
						SameString(fullnm, getmsg(1456)) ||
						inExternal(getmsg(353), fullnm) ||
						IsMailingList(fullnm))
					{
					CRmPrintfCR(getmsg(1257), fullnm);
					good = FALSE;
					}
				else
					{
					good = TRUE;
					}
				} while (!good && (HaveConnectionToUser()));
			}
		else
			{
			strcpy(fullnm, cmd_login);
			}

		if (!(HaveConnectionToUser()))
			{
			return;
			}

		do
			{
			if (askpw)
				{
				getNormStr(getmsg(570), InitPw, 61, NO_ECHO);
				dospCR();

				char *semicolon = strchr(InitPw, ';');

				if (semicolon)
					{
					normalizepw(InitPw, initials, password);
					}
				else
					{
					strcpy(initials, InitPw);
					}

				// dont allow anything over LABELSIZE characters
				initials[LABELSIZE] = '\0';

				if (!semicolon)
					{
					getNormStr(getmsg(571), password, LABELSIZE, NO_ECHO);
					dospCR();
					}
				}
			askpw = TRUE;

			if (FindPwInHashInTable(initials, password) != CERROR ||
					strlen(password) < 2)
				{
				good = FALSE;
				CRmPrintfCR(getmsg(605));
				}
			else
				{
				good = TRUE;
				}

			} while (!good && (HaveConnectionToUser()));

		TI()CurrentUser->SetPasswordChangeTime(time(NULL));

		displaypw(fullnm, initials, password);

		abort = getYesNo(getmsg(615), 2);

		if (abort == 2)
			{
			return; // check for Abort at (Y/N/A)[A]:
			}
		} while (!abort && (HaveConnectionToUser()));

	if (HaveConnectionToUser())
		{
		char trapstr[256];

		TI()CurrentUser->SetName(fullnm);
		TI()CurrentUser->SetInitials(initials);
		TI()CurrentUser->SetPassword(password);

		TI()CurrentUser->SetCallTime(time(NULL));
		TI()CurrentUser->SetFirstOn(TI()CurrentUser->GetCallTime());

		// trap it
		sprintf(trapstr, getmsg(1258), TI()CurrentUser->GetName());

		if (onConsole)
			{
#ifdef GOODBYE
			// This is just FUCKING EVIL for trap file analyzers.
			// I've taken it out of the message file, too.
			strcat(trapstr, " (Console)");
#else
			trap(getmsg(1259), T_LOGIN);	// dupe of 572
#endif
			}

		trap(trapstr, T_LOGIN);
		doEvent(EVT_NEWUSER);	// follow trap, 'cuz timing is everything

		TI()loggedIn = TRUE;
		slideLTab(TI()ThisSlot);

		storeLog();
		}
	}


// --------------------------------------------------------------------------
// newUserFile(): Writes new user info out to a file.

static void newUserFile(void)
	{
	char FileName[128];
	sprintf(FileName, sbs, cfg.homepath, newuserLog);

	FILE *fl;
	if ((fl = fopen(FileName, FO_A)) != NULL)
		{
		char dtstr[85];
		strftime(dtstr, 79, cfg.vdatestamp, 0l);

		fprintf(fl, bn);
		fprintf(fl, pcts, dtstr);
		fprintf(fl, bn);
		fprintf(fl, getmsg(1401), deansi(TI()CurrentUser->GetName()));
		fprintf(fl, bn);
		fprintf(fl, getmsg(1407), connectbauds[TI()ModemSpeed]);
		fprintf(fl, bn);
		}
	else
		{
		cPrintf(getmsg(78), FileName);
		doccr();
		}


	dispBlb(B_NEWQUEST);

	for (int QIndex = 0;
			cfg.NUQuest[QIndex] != NUQ_NUMQUEST && QIndex < NUQ_NUMQUEST;
			QIndex++)
		{
		switch (cfg.NUQuest[QIndex])
			{
			case NUQ_REALNAME:
				{
				label name;

				do
					{
					GetStringWithBlurb(getmsg(1262), name, LABELSIZE, ns,
							B_REALNAME);

					normalizeString(name);
					} while (!*name && HaveConnectionToUser());

				TI()CurrentUser->SetRealName(name);

				if (fl)
					{
					fprintf(fl, getmsg(1402), deansi(name));
					fprintf(fl, bn);
					}

				break;
				}

			case NUQ_PHONENUMBER:
				{
				label phone;

				do
					{
					GetStringWithBlurb(getmsg(770), phone, LABELSIZE, ns,
							B_PHONENUM);

					normalizeString(phone);
					} while (!*phone && HaveConnectionToUser());

				TI()CurrentUser->SetPhoneNumber(phone);

				if (fl)
					{
					fprintf(fl, getmsg(1403), deansi(phone));
					fprintf(fl, bn);
					}

				break;
				}

			case NUQ_ADDRESS:
				{
				label addr1, addr2, addr3;

				*addr2 = 0;
				*addr3 = 0;

				GetStringWithBlurb(getmsg(1263), addr1, LABELSIZE, ns,
						B_ADDRESS);

				normalizeString(addr1);
				if (*addr1)
					{
					GetStringWithBlurb(getmsg(1264), addr2, LABELSIZE, ns,
							B_ADDRESS);

					normalizeString(addr2);
					if (*addr2)
						{
						GetStringWithBlurb(getmsg(1265), addr3, LABELSIZE,
								ns, B_ADDRESS);
						}
					}

				TI()CurrentUser->SetMailAddr1(addr1);
				TI()CurrentUser->SetMailAddr2(addr2);
				TI()CurrentUser->SetMailAddr3(addr3);


				if (*addr1 && fl)
					{
					fprintf(fl, getmsg(1404), deansi(addr1));
					fprintf(fl, bn);

					if (*addr2)
						{
						fprintf(fl, getmsg(1404), deansi(addr2));
						fprintf(fl, bn);

						if (*addr3)
							{
							fprintf(fl, getmsg(1404), deansi(addr3));
							fprintf(fl, bn);
							}
						}
					}


				break;
				}

			case NUQ_TITLE:
				{
				if (cfg.titles)
					{
					label title;

					GetStringWithBlurb(getmsg(1260), title, LABELSIZE, ns,
							B_TITLESUR);

					normalizeString(title);
					TI()CurrentUser->SetTitle(title);

					if (*title && fl)
						{
						fprintf(fl, getmsg(1405), deansi(title));
						fprintf(fl, bn);
						}
					}
				else
					{
					cPrintf(getmsg(1399), getmsg(771));
					doccr();
					}

				break;
				}

			case NUQ_SURNAME:
				{
				if (cfg.surnames)
					{
					label surname;

					GetStringWithBlurb(getmsg(1261), surname, LABELSIZE, ns,
							B_TITLESUR);

					normalizeString(surname);
					TI()CurrentUser->SetSurname(surname);

					if (*surname && fl)
						{
						fprintf(fl, getmsg(1406), deansi(surname));
						fprintf(fl, bn);
						}
					}
				else
					{
					cPrintf(getmsg(1400), getmsg(771));
					doccr();
					}

				break;
				}

			case NUQ_MESSAGE:
				{
				Message *Msg = new Message;

				if (Msg)
					{
					dispBlb(B_NEWQMSG);

					Msg->ClearAll();
					Msg->SetSurname(TI()CurrentUser->GetSurname());
					Msg->SetTitle(TI()CurrentUser->GetTitle());

					Msg->SetToUser(getmsg(1020));
					Msg->SetAuthor(TI()CurrentUser->GetName());

					getText(Msg, NULL);
					stripansi(Msg->GetTextPointer());
					}
				else
					{
					mPrintf(getmsg(188), getmsg(771));
					}

				if (fl)
					{
					if (Msg)
						{
						dFormat(Msg->GetText(), fl);
						}
					else
						{
						fprintf(fl, getmsg(188), getmsg(771));
						fprintf(fl, bn);
						}
					}

				delete Msg;
				break;
				}

			case NUQ_PROTOCOL:
				{
				int c = 0;

				do
					{
					if (!TI()CurrentUser->IsExpert() || (c == '?'))
						{
						doCR();

						for (protocols *theProt = extProtList; theProt;
								theProt = (protocols *) getNextLL(theProt))
							{
							if (!theProt->NetOnly)
								{
								mPrintfCR(getmsg(1408), theProt->CommandKey,
										theProt->MenuName);
								}
							}
						}

					c = DoMenuPrompt(getmsg(1409), NULL);

					if (c == ' ')
						{
						TI()CurrentUser->SetDefaultProtocol(0);
						}
					else
						{
						const protocols *theProt = GetProtocolByKey(c);

						if (theProt)
							{
							mPrintfCR(pcts, theProt->name);
							TI()CurrentUser->SetDefaultProtocol(c);
							}
						else
							{
							oChar(c);
							if (c == '?')
								{
								doCR();
								}
							else
								{
								mPrintfCR(sqst);
								c = '?';
								}
							}
						}
					} while (c == '?' && HaveConnectionToUser());

				break;
				}

			case NUQ_OCCUPATION:
				{
				label Occupation;

				getNormStr(getmsg(1410), Occupation, LABELSIZE, ECHO);
				TI()CurrentUser->SetOccupation(Occupation);

				if (*Occupation && fl)
					{
					fprintf(fl, getmsg(1411), deansi(Occupation));
					fprintf(fl, bn);
					}

				break;
				}

			case NUQ_WHEREHEAR:
				{
				char Wherehear[80];

				getNormStr(getmsg(1412), Wherehear, 79, ECHO);
				TI()CurrentUser->SetWhereHear(Wherehear);

				if (*Wherehear && fl)
					{
					fprintf(fl, getmsg(1413), deansi(Wherehear));
					fprintf(fl, bn);
					}

				break;
				}

			case NUQ_BIRTHDAY:
				{
				label BDay;
				datestruct date;

				do
					{
					date.Date = 1;

					GetStringWithBlurb(getmsg(1414), BDay, LABELSIZE, ns,
							B_DATESET);

					normalizeString(BDay);

					if (*BDay)
						{
						gdate(BDay, &date);

						if (date.Date == 0)
							{
							CRmPrintfCR(getmsg(1415));
							}
						}
					} while (!date.Date && HaveConnectionToUser());

				if (*BDay)
					{
					struct date bdate;
					struct time btime;

					bdate.da_mon = date.Month + 1;		// i hate dostounix
					bdate.da_day = date.Date;
					bdate.da_year = date.Year + 1900;	// i hate dostounix

					btime.ti_hour = 0;
					btime.ti_min = 0;
					btime.ti_sec = 0;
					btime.ti_hund = 0;

					TI()CurrentUser->SetBirthDate(dostounix(&bdate, &btime));

					if (fl)
						{
						fprintf(fl, getmsg(721), monthTab[date.Month],
								date.Date, date.Year + 1900);
						fprintf(fl, bn);
						}
					}

				break;
				}

			case NUQ_COLORS:
				{
				if (TI()CurrentUser->IsIBMANSI())
					{
					askAttributes(TI()CurrentUser);
					}

				break;
				}

			case NUQ_SEX:
				{
				int dfault;

				switch (TI()CurrentUser->GetSex())
					{
					case SEX_MALE:		dfault = 0; break;
					case SEX_FEMALE:	dfault = 1; break;
					default:			dfault = 2; break;
					}

				int Sex = GetOneKey(getmsg(1106), getmsg(1109),
						getmsg(1109)[dfault], B_MFU, getmsg(1107),
						getmsg(1108), getmsg(1679));

				if (Sex == 0)		// Male
					{
					TI()CurrentUser->SetSex(SEX_MALE);
					}
				else if (Sex == 1)	// Female
					{
					TI()CurrentUser->SetSex(SEX_FEMALE);
					}
				else if (Sex == 3)	// Unspecified
					{
					TI()CurrentUser->SetSex(SEX_UNKNOWN);
					}

				if (fl)
					{
					fprintf(fl, getmsg(1416));

					switch (TI()CurrentUser->GetSex())
						{
						case SEX_MALE:
							{
							fprintf(fl, getmsg(1107));
							break;
							}

						case SEX_FEMALE:
							{
							fprintf(fl, getmsg(1108));
							break;
							}

						default:
							assert(FALSE);

						case SEX_UNKNOWN:
							{
							fprintf(fl, getmsg(1679));
							break;
							}
						}

					fprintf(fl, bn);
					}

				break;
				}

			default:
				{
				cPrintf(getmsg(1398), getmsg(771));
				doccr();
				break;
				}
			}
		}

	if (fl)
		{
		fclose(fl);
		}

	doCR();
	}


// --------------------------------------------------------------------------
// newlog(): Sets up a new log entry for new users returns FALSE if cannot
//	find a usable slot

static Bool newlog(void)
	{
	// get a new slot for this user
	TI()ThisSlot = newslot();

	if (TI()ThisSlot == CERROR)
		{
		TI()ThisSlot = 0;
		return (FALSE);
		}

	TI()ThisLog = LogTab->GetEntry(TI()ThisSlot)->GetLogIndex();

	setdefaultconfig(cfg.autoansi);

	TI()CurrentUser->SetInuse(TRUE);

	setlogTerm();

	for (r_slot i = 0; i < cfg.maxrooms; i++)
		{
		TI()CurrentUser->SetRoomNewPointer(i, cfg.oldest);
		}

	// accurate read-userlog for first time call
	TI()CurrentUser->SetCallNumber(cfg.callno + 1);

	return (TRUE);
	}

// --------------------------------------------------------------------------
// newslot(): Attempts to find a slot for a new user to reside in CERROR if
//	none.

static int newslot(void)
	{
	int i;
	int foundit = CERROR;

	// find one not in use
	for (i = cfg.MAXLOGTAB - 1; ((i > -1) && (foundit == CERROR)); --i)
		{
		if (!LogTab->GetEntry(i)->IsInuse())
			{
			foundit = i;
			}
		}

	if (foundit == CERROR)
		{
		// find one not permanent
		for (i = cfg.MAXLOGTAB - 1; ((i > -1) && (foundit == CERROR)); --i)
			{
			if (!LogTab->GetEntry(i)->IsPermanent())
				{
				foundit = i;
				}
			}

		if (foundit == CERROR)
			{
			CRmPrintfCR(getmsg(1266));
			}
		}

	return (foundit);
	}
