// --------------------------------------------------------------------------
// Citadel: ConOvl.CPP
//
// This handles the console on IBM PC and compatible computers. This code
// will probably need heavy modification for use with other computers.

#include "ctdl.h"
#pragma hdrstop

#include "log.h"
#include "cwindows.h"
#include "scrlback.h"
#include "cfgfiles.h"
#include "config.h"
#include "miscovl.h"
#include "term.h"


// --------------------------------------------------------------------------
// Contents
//
// fkey()			Deals with function keys from console
// outConRawBs()	BS to console, no overwrite
// cPrintf			send formatted output to console

Bool ConsoleLockC::IsLocked(Bool CheckingF6)
	{
	if (onConsole && TI()CurrentUser && TI()CurrentUser->IsSysop())
		{
		return (FALSE);
		}
	else if (LockState == CON_UNLOCKED)
		{
		return (FALSE);
		}
	else if (LockState == CON_LOCKED)
		{
		return (TRUE);
		}
	else
		{
		assert(LockState == CON_F6LOCKED);
		return (CheckingF6);
		}
	}

Bool ConsoleLockC::MayUnlock(void)
	{
	return (LockState == CON_LOCKED &&
			!(SameString(cfg.f6pass, getmsg(779)) ||
			SameString(cfg.f6pass, getmsg(780))));
	}

ConsoleLockC ConsoleLock;

void GetSysPWHandler(const char *PW)
	{
	if (SameString(PW, cfg.f6pass))
		{
		ConsoleLock.Unlock();
		ScreenSaver.Update();

		if (cfg.VerboseConsole)
			{
			CitWindowsNote(NULL, getmsg(1430));
			}
		}
	else
		{
		if (cfg.VerboseConsole)
			{
			CitWindowsNote(NULL, getmsg(1510));
			}
		}
	}

static void StartPrinting(const char *FileName)
	{
	if (TI()OC.Printing)
		{
		citClose(&TI()OC.PrintFile);
		}

	CopyStringToBuffer(TI()OC.PrintfileName, FileName,
			sizeof(TI()OC.PrintfileName) - 1);
	normalizeString(TI()OC.PrintfileName);

	if (citOpen(TI()OC.PrintfileName, CO_A, &TI()OC.PrintFile))
		{
		if (cfg.VerboseConsole)
			{
			CitWindowsNote(NULL, getmsg(1606));
			}

		TI()OC.Printing = TRUE;
		}
	else
		{
		if (cfg.VerboseConsole)
			{
			CitWindowsNote(NULL, getmsg(1607));
			}

		TI()OC.Printing = FALSE;
		}
	}

static void ExitYNHandler(int Result)
	{
	TI()ExitToMsdos = Result;
	}

#ifndef WINCIT

// fkey(): Deals with function keys from console.
//
// Input:
//	inkey: the high byte is the scan code returned by the IBM PC BIOS.	The
//		low byte is ignored.
//
// Return value:
//	None.

void fkey(uint inkey)
	{
	int key = inkey >> 8;

	// this handles the keys for dialout mode
	if (TI()DoWhat == DIALOUT)
		{
		dialout_fkey = key;
		return;
		}

	// let RLM take over keyboard if it wants
	if (!CitadelIsConfiguring && rlmEvent(LT_KEYSTROKE, key, inkey))
		{
		return;
		}

	if (cfg.FullConLock && ConsoleLock.IsLocked() && ScreenSaver.IsOn() &&
			key != ALT_L)
		{
		return;
		}

	if (key == CTL_F2)		// CTRL_F2 is never locked.
		{
		if (allWindows)
			{
			setFocus(allWindows->wnd);
			}
		}
	else if (key != ALT_F1 && ConsoleLock.IsLocked(key == F6 ||
			key == ALT_F6 || key == SFT_F6 || key == CTL_F6))
		{
		if (key == ALT_L && ConsoleLock.MayUnlock())
			{
			GetStringFromConsole(getmsg(781), LABELSIZE, ns, GetSysPWHandler,
					TRUE);
			}
		else
			{
			if (cfg.VerboseConsole)
				{
				CitWindowsNote(NULL, (key == ALT_L) ?
						getmsg(1636) : getmsg(1635));
				}
			}
		}
	else
		{
		// Console is not locked

		if (CitadelIsConfiguring)
			{
			// Only let certain keystrokes through if configuring
			if (key != CTL_F6 && key != F7 && key != F8 && key != ALT_B &&
					key != ALT_D && key != ALT_L && key != ALT_M &&
					key != ALT_S && key != ALT_U)
				{
				WaitUntilDoneConfiguring();
				key = 0;
				}
			}

		ScreenSaver.Update();
		switch (key)
			{
			case F1:
				{
				CITWINDOW *w = CitWindowsMsg(NULL, getmsg(1610));

				TI()SerialPort.DropDtr();

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

				break;
				}

			case CTL_F1:
				{
				if (say_ascii != (int (cdecl *)(const char *, int)) nullFunc)
					{
					cfg.speechOn = !cfg.speechOn;

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1608), cfg.speechOn ?
								getmsg(317) : getmsg(316));
						}
					}
				else
					{
					cfg.speechOn = FALSE;

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1631));
						}
					}

				break;
				}

			case ALT_F1:
				{
				cls(SCROLL_SAVE);
				break;
				}

			case F2:
				{
				CITWINDOW *w = CitWindowsMsg(NULL, getmsg(1611));

				Initport();

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

				break;
				}

			case F3:
				{
				sysReq = !sysReq;

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1609), sysReq ?
							getmsg(317) : getmsg(316));
					}

				break;
				}

			case ALT_F3:
				{
				if (sysReq)
					{
					TI()altF3Timeout = 0;
					sysReq = FALSE;

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1609), getmsg(316));
						}
					}
				else
					{
					TI()altF3Timeout = time(NULL) + cfg.altF3Time;
					sysReq = TRUE;

					if (cfg.VerboseConsole)
						{
						long tme = time(NULL);

						CitWindowsNote(NULL, getmsg(1612),
								(TI()altF3Timeout - tme) / 60,
								(TI()altF3Timeout - tme) % 60);
						}
					}

				break;
				}

			case F4:
				{
				if (!StatusLine.ToggleFullScreen())
					{
					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1613));
						}
					}

				break;
				}

			case F5:
				{
				if (onConsole)
					{
					TI()whichIO = MODEM;
					setio();

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1614), getmsg(1615));
						}
					}
				else
					{
					TI()whichIO = CONSOLE;
					setio();

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1614), getmsg(1616));
						}
					}

				break;
				}

			case F6:
				{
				sysopkey = TRUE;
				break;
				}

			case CTL_F6:
				{
				doConsoleSysop();
				break;
				}

			case ALT_F6:
				{
				TI()CurrentUser->SetAide(!TI()CurrentUser->IsAide());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1617),
							TI()CurrentUser->IsAide() ? getmsg(1618) :
							getmsg(1619), getmsg(1019));
					}

				break;
				}

			case SFT_F6:
				{
				TI()CurrentUser->SetSysop(!TI()CurrentUser->IsSysop());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1617),
							TI()CurrentUser->IsSysop() ? getmsg(1618) :
							getmsg(1619), getmsg(1020));
					}

				break;
				}

			case F7:
				{
				cfg.noBells++;

				if (cfg.noBells == 3)
					{
					cfg.noBells = 0;
					}

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1620),
							getmsg(1621 + cfg.noBells));
					}

				break;
				}

			case ALT_C:
			case F8:
				{
				TI()chatkey = !TI()chatkey;
				break;
				}

			case F9:
				{
				cfg.noChat = !cfg.noChat;
				TI()chatReq = FALSE;

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1624), !cfg.noChat ?
							getmsg(317) : getmsg(316));
					}

				break;
				}

			case F10:
			case ALT_H:
				{
				StatusLine.ToggleHelp();
				break;
				}

			case ALT_F10:
				{
				StatusLine.ToggleSecond();
				break;
				}

			case SFT_F10:
				{
				StatusLine.Toggle();
				break;
				}

			case ALT_A:
				{
				TI()CurrentUser->SetAccounting(
						!TI()CurrentUser->IsAccounting());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1625),
							TI()CurrentUser->IsAccounting() ?
							getmsg(317) : getmsg(316));
					}

				break;
				}

			case ALT_B:
				{
				TI()OC.Psycho = !TI()OC.Psycho;
				break;
				}

			case ALT_D:
				{
				if (debug)
					{
					TurnDebugOff();

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1626), getmsg(316));
						}
					}
				else
					{
					if (TurnDebugOn())
						{
						if (cfg.VerboseConsole)
							{
							CitWindowsNote(NULL, getmsg(1626), getmsg(317));
							}
						}
					else
						{
						if (cfg.VerboseConsole)
							{
							CitWindowsNote(NULL, getmsg(19));
							}
						}
					}

				break;
				}

			case ALT_K:
				{
				if (!allWindows)
					{
					if (cfg.scrollSize)
						{
						DisplayScrollBackBuffer();
						time(&TI()LastActiveTime);
						}
					else
						{
						if (cfg.VerboseConsole)
							{
							CitWindowsNote(NULL, getmsg(1627),
									citfiles[C_CONFIG_CIT]);
							}
						}
					}
				else
					{
					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1673));
						}
					}

				break;
				}

			case ALT_L:
				{
				if (*cfg.f6pass)
					{
					if (!SameString(cfg.f6pass, getmsg(779)))
						{
						ConsoleLock.Lock();

						if (cfg.VerboseConsole)
							{
							CitWindowsNote(NULL, getmsg(1628));
							}
						}
					}
				else
					{
					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1629),
								citfiles[C_CONFIG_CIT]);
						}
					}

				break;
				}

			case ALT_M:
				{
				memoryDump();
				break;
				}

			case ALT_P:
				{
				if (TI()OC.Printing)
					{
					TI()OC.Printing = FALSE;
					fclose(TI()OC.PrintFile);

					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1630));
						}
					}
				else
					{
					if (cfg.printerprompt)
						{
						GetStringFromConsole(getmsg(1073), 63, cfg.printer,
								StartPrinting, FALSE);
						}
					else
						{
						StartPrinting(cfg.printer);
						}
					}

				break;
				}

			case ALT_R:
				repeatevent = TRUE;
				// fall through

			case ALT_F:
				forceevent = TRUE;
				// fall through

			case ALT_E:
				eventkey = TRUE;
				break;


			case ALT_S:
				{
				if (ScreenSaver.TurnOn())
					{
					while ((*sp_press)());
					}
				else
					{
					if (cfg.VerboseConsole)
						{
						CitWindowsNote(NULL, getmsg(1637));
						}
					}

				break;
				}

			case ALT_T:
				{
				TI()CurrentUser->SetProblem(!TI()CurrentUser->IsProblem());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1617),
							TI()CurrentUser->IsProblem() ? getmsg(1618) :
							getmsg(1619), getmsg(1632));
					}

				break;
				}

			case ALT_U:
				{
				cfg.ignore_uptime = !cfg.ignore_uptime;

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1633), citfiles[C_CONFIG_CIT],
							cfg.ignore_uptime ? getmsg(317) : getmsg(316));
					}

				break;
				}

			case ALT_V:
				{
				TI()CurrentUser->SetVerified(!TI()CurrentUser->IsVerified());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1617),
							TI()CurrentUser->IsVerified() ? getmsg(1618) :
							getmsg(1619), getmsg(1634));
					}

				break;
				}

			case ALT_X:
			case ALT_F4:
				{
				if (cfg.AltXPrompt)
					{
					GetYNFromConsole(getmsg(782), 0, ExitYNHandler);
					}
				else
					{
					TI()ExitToMsdos = TRUE;
					}

				break;
				}

			case ALT_Z:
				{
				if (SerialPort.HaveCarrier() || debug)
					{
					TI()sleepkey = TRUE;
					}

				break;
				}

			case ALT_3:
				{
				TI()CurrentUser->SetOut300(!TI()CurrentUser->IsOut300());

				if (cfg.VerboseConsole)
					{
					CitWindowsNote(NULL, getmsg(1617),
							TI()CurrentUser->IsOut300() ? getmsg(1618) :
							getmsg(1619), getmsg(1700));
					}

				break;
				}

			case PGUP:
				{
				TI()CurrentUser->SetCredits(TI()CurrentUser->GetCredits() + 5 * 60);
				break;
				}

			case PGDN:
				{
				TI()CurrentUser->SetCredits(TI()CurrentUser->GetCredits() - 5 * 60);
				break;
				}
			}
		}

	StatusLine.Update();
	}
#endif

// outConRawBs(): Send BS to console, no overwrite.
//
// Input:
//	None.
//
// Output:
//	None.

void outConRawBs(void)
	{
	int row, col;

	readpos(&row, &col);

	if (col == 0 && TI()prevChar != 10)
		{
		row--;
		col = conCols;
		}

	position(row, (uchar) (col - 1));
	TI()OC.CrtColumn--;
	}

// cPrintf(): outputs formatted text to console.
//
// Input:
//	const char *fmt: Formatting string, as in the C RTL's ...printf()
//		functions.
//
//	...: Anything needed by fmt.
//
// Return value:
//	None.

void cdecl cPrintf(const char *fmt, ...)
	{
	register char *buf = TI()OC.prtf_buff;
	va_list ap;
	Bool oldcolor = TI()term.ibmColor;
	Bool oldmodem;

	// for screenblanker
	if (!oPhys)
		{
		kb_hit();
		}

	va_start(ap, fmt);
	vsprintf(TI()OC.prtf_buff, fmt, ap);
	va_end(ap);

	if (TI()menu69)
		{
		// do a mPrintf
		TI()OC.Formatting = FALSE;
		mFormat(TI()OC.prtf_buff);
		ResetOutputControl();
		return;
		}

	TI()term.ibmColor = TRUE;

	outSpeech(FALSE, TI()OC.prtf_buff);

	while (*buf)
		{
		if (*buf == CTRL_A)
			{
			uchar wordBuf[MAXWORD + 8];
			int i;

			i = getWord(wordBuf, (uchar *) buf, 0, MAXWORD);

			oldmodem = TI()OC.Modem;
			TI()OC.Modem = FALSE;
			termCap(buf + 1);
			TI()OC.Modem = oldmodem;
			buf += i;
			}
		else
			{
			outCon(*buf++);
			}
		}

	TI()term.ibmColor = oldcolor;
	ansi(14);
	TI()OC.MCI_goto = FALSE;
	}
