1621 lines
47 KiB
C
1621 lines
47 KiB
C
/* OpenDoors Online Software Programming Toolkit
|
||
* (C) Copyright 1991 - 1999 by Brian Pirie.
|
||
*
|
||
* Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net)
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, write to the Free Software
|
||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
*
|
||
*
|
||
* File: ODCore.c
|
||
*
|
||
* Description: Implements the core of OpenDoors, including chat mode
|
||
* and standard input/output functions that are
|
||
* used throughout OpenDoors.
|
||
*
|
||
* Revisions: Date Ver Who Change
|
||
* ---------------------------------------------------------------
|
||
* Oct 13, 1994 6.00 BP New file header format.
|
||
* Oct 19, 1994 6.00 BP Changed paging hours logic.
|
||
* Oct 21, 1994 6.00 BP Further isolated com routines.
|
||
* Oct 22, 1994 6.00 BP Name case conversion /w punct.
|
||
* Dec 08, 1994 6.00 BP Allow custom chat mode deactivation.
|
||
* Dec 09, 1994 6.00 BP Remove global dir entry structure.
|
||
* Dec 13, 1994 6.00 BP Remove include of dir.h.
|
||
* Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
|
||
* Dec 31, 1994 6.00 BP Remove old multitasker definitions.
|
||
* Jan 01, 1995 6.00 BP Don't use ODComInbound().
|
||
* Jan 01, 1995 6.00 BP _waitdrain() -> ODWaitDrain().
|
||
* Jan 01, 1995 6.00 BP Use new millisecond timer functions.
|
||
* Jan 01, 1995 6.00 BP Remove od_init() from _remotechar()
|
||
* Jan 01, 1995 6.00 BP Split off odkrnl.c from odcore.c
|
||
* Aug 19, 1995 6.00 BP 32-bit portability.
|
||
* Nov 11, 1995 6.00 BP Moved first_word() to odlist.c
|
||
* Nov 11, 1995 6.00 BP Removed register keyword.
|
||
* Nov 14, 1995 6.00 BP Added include of odscrn.h.
|
||
* Nov 16, 1995 6.00 BP Create odcore.h.
|
||
* Nov 17, 1995 6.00 BP Use new input queue mechanism.
|
||
* Dec 12, 1995 6.00 BP Added od_set_color().
|
||
* Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
|
||
* Dec 13, 1995 6.00 BP Moved chat mode code to ODKrnl.h.
|
||
* Dec 19, 1995 6.00 BP Request reason for chat outside hours.
|
||
* Dec 23, 1995 6.00 BP Allow space to continue at page pause.
|
||
* Dec 24, 1995 6.00 BP Added abtGreyBlock.
|
||
* Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
|
||
* Jan 03, 1996 6.00 BP Use OD_API_VAR_DEFN for od_control.
|
||
* Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent.
|
||
* Jan 23, 1996 6.00 BP No od_set_statusline() under Win32.
|
||
* Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
|
||
* Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout.
|
||
* Jan 09, 1996 6.00 BP ODComOutbound() returns actual size.
|
||
* Jan 09, 1996 6.00 BP Reduce kernel calls from od_disp...().
|
||
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
|
||
* Mar 03, 1996 6.10 BP Begin version 6.10.
|
||
* Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
|
||
* Mar 21, 1996 6.10 BP Added od_control_get().
|
||
* Sep 01, 1996 6.10 BP Update output area on od_set_per...().
|
||
* Oct 19, 2001 6.20 RS od_get_key now ignores linefeeds.
|
||
* Mar 14, 2002 6.22 RS Fixed od_get_key(bWait=FALSE)
|
||
* Aug 10, 2003 6.23 SH *nix support
|
||
*/
|
||
|
||
#define BUILDING_OPENDOORS
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
|
||
#include "OpenDoor.h"
|
||
#include "ODStr.h"
|
||
#include "ODGen.h"
|
||
#include "ODPlat.h"
|
||
#include "ODCom.h"
|
||
#include "ODKrnl.h"
|
||
#include "ODScrn.h"
|
||
#include "ODCore.h"
|
||
#include "ODInQue.h"
|
||
#ifdef ODPLAT_WIN32
|
||
#include "ODFrame.h"
|
||
#endif /* ODPLAT_WIN32 */
|
||
|
||
|
||
/* GLOBAL VARIABLES SHARED THROUGHOUT OPENDOORS. */
|
||
|
||
/* Global declaration of the OpenDoors control structure. */
|
||
OD_API_VAR_DEFN tODControl
|
||
#ifndef _WIN32 /* warning C4229: anachronism used : modifiers on data are ignored */
|
||
OD_GLOBAL_CONV
|
||
#endif
|
||
od_control;
|
||
|
||
/* OpenDoors global initialized flag. */
|
||
BOOL bODInitialized = FALSE;
|
||
|
||
/* Global serial port object handle. */
|
||
tPortHandle hSerialPort;
|
||
|
||
/* Global input queue object handle. */
|
||
tODInQueueHandle hODInputQueue;
|
||
|
||
/* Reentrancy control. */
|
||
BOOL bIsCallbackActive = FALSE;
|
||
BOOL bShellChatActive = FALSE;
|
||
|
||
/* Global working space. */
|
||
char szODWorkString[OD_GLOBAL_WORK_STRING_SIZE];
|
||
|
||
/* Global instance of the text information structure for general use. */
|
||
tODScrnTextInfo ODTextInfo;
|
||
|
||
/* Logfile function hooks. */
|
||
BOOL (*pfLogWrite)(INT) = NULL;
|
||
void (*pfLogClose)(INT) = NULL;
|
||
|
||
/* od_color_config() support for od_printf(). */
|
||
char chColorCheck = 0;
|
||
char *pchColorEndPos;
|
||
|
||
/* Status line information. */
|
||
BYTE btCurrentStatusLine = STATUS_NONE;
|
||
OD_PERSONALITY_CALLBACK *pfCurrentPersonality = NULL;
|
||
char szDesiredPersonality[33] = "";
|
||
SET_PERSONALITY_FUNC *pfSetPersonality = NULL;
|
||
|
||
/* Commonly used character sequences. */
|
||
char abtBlackBlock[2] = {' ', 0x07};
|
||
char abtGreyBlock[2] = {' ', 0x70};
|
||
char szBackspaceWithDelete[4] = {8, ' ', 8, 0};
|
||
|
||
/* Current output area on screen. */
|
||
BYTE btOutputTop = 1;
|
||
BYTE btOutputBottom = 23;
|
||
|
||
|
||
/* PRIVATE VARIABLES. */
|
||
|
||
/* Display color varaibles. */
|
||
char bAnyColorChangeYet;
|
||
|
||
/* Static character sequences. */
|
||
static char szClearScreen[2] = {12, 0};
|
||
|
||
/* Lookup table to map colors from PC values to ANSI color values. */
|
||
static BYTE abtPCToANSIColorTable[8] = {30, 34, 32, 36, 31, 35, 33, 37};
|
||
|
||
|
||
/* LOCAL HELPER FUNCTIONS. */
|
||
static void ODAddANSIParameter(char *szControlSequence, int nParameterValue);
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODWaitDrain()
|
||
*
|
||
* Waits for up to the specified number of milliseconds for the output serial
|
||
* buffer to drain.
|
||
*
|
||
* Parameters: MaxWait - Specifies the maximum number of milliseconds to wait
|
||
* before timing out.
|
||
*
|
||
* Return: void
|
||
*/
|
||
void ODWaitDrain(tODMilliSec MaxWait)
|
||
{
|
||
int nOutboundSize;
|
||
tODTimer Timer;
|
||
|
||
/* If we are operating in local mode, then don't do anything. */
|
||
if(od_control.baud == 0) return;
|
||
|
||
/* Otherwise, start a timer that is set to elapse after the maximum */
|
||
/* wait period. */
|
||
ODTimerStart(&Timer, MaxWait);
|
||
|
||
/* Loop until either the outbound buffer is empty, or the */
|
||
/* timer has elapsed. */
|
||
for(;;)
|
||
{
|
||
/* Check whether any data is in the outbound serial queue. */
|
||
ODComOutbound(hSerialPort, &nOutboundSize);
|
||
|
||
/* If the queue is empty or the timer has elapsed, then stop */
|
||
/* waiting. */
|
||
if(nOutboundSize == 0 || ODTimerElapsed(&Timer)) break;
|
||
|
||
/* Otherwise, give other tasks a chance to run. */
|
||
od_sleep(0);
|
||
|
||
/* Give od_kernel() activities a chance to run. */
|
||
CALL_KERNEL_IF_NEEDED();
|
||
}
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_clr_scr()
|
||
*
|
||
* Clears the contents of the local and remote screens, if screen clearing is
|
||
* enabled.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_clr_scr(void)
|
||
{
|
||
INT16 nOriginalAttrib;
|
||
|
||
/* Log function entry if running in trace mode */
|
||
TRACE(TRACE_API, "od_clr_scr()");
|
||
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Don't clear screen if disabled. */
|
||
if(!od_control.od_always_clear && !(od_control.user_attribute & 2)
|
||
&& (od_control.od_extended_info || od_control.od_info_type == CUSTOM))
|
||
{
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
if(od_control.user_rip)
|
||
{
|
||
od_disp("!|*", 3, FALSE);
|
||
if(!od_control.od_default_rip_win)
|
||
{
|
||
od_disp("!|w0000270M12", 13, FALSE);
|
||
}
|
||
}
|
||
|
||
if(od_control.user_ansi)
|
||
{
|
||
od_disp("\x1b[2J\x1b[1;1H", 10, FALSE);
|
||
}
|
||
else {
|
||
/* Send ascii 12 to modem, no local echo. */
|
||
od_disp(szClearScreen, 1, FALSE);
|
||
}
|
||
|
||
/* Clear local window. */
|
||
ODScrnClear();
|
||
|
||
/* Get color set prior to screen clear. */
|
||
nOriginalAttrib = od_control.od_cur_attrib;
|
||
|
||
/* Current color state is unknown. */
|
||
od_control.od_cur_attrib = -1;
|
||
|
||
/* Set color to original value. This gurantees that local and */
|
||
/* remote systems both have the same current color set. */
|
||
od_set_attrib(nOriginalAttrib);
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_input_str()
|
||
*
|
||
* Allows the user to input a string up to the specified length, using
|
||
* characters in the specified range. This string input function is designed
|
||
* to be compatible with all terminal types.
|
||
*
|
||
* Parameters: pszInput - Pointer to string to store input in.
|
||
*
|
||
* nMaxLength - Maximum number of characters to permit the user
|
||
* to input.
|
||
*
|
||
* chMin - The minimum character value to permit. This must
|
||
* be at least ASCII 32.
|
||
*
|
||
* chMax - The maximum character value to permit.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_input_str(char *pszInput,
|
||
INT nMaxLength,
|
||
unsigned char chMin,
|
||
unsigned char chMax)
|
||
{
|
||
char chKeyPressed;
|
||
INT nPosition;
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_input_str()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Start at the beginning of the string. */
|
||
nPosition = 0;
|
||
|
||
/* Check that input parameters are valid. */
|
||
if(pszInput == NULL || nMaxLength < 1 || chMin > chMax)
|
||
{
|
||
od_control.od_error = ERR_PARAMETER;
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
for(;;)
|
||
{
|
||
chKeyPressed = od_get_key(TRUE);
|
||
|
||
/* If user pressed enter. */
|
||
if(chKeyPressed == '\r' || chKeyPressed == '\n')
|
||
{
|
||
/* Terminate the string. */
|
||
pszInput[nPosition] = '\0';
|
||
|
||
/* Display CR-LF sequence. */
|
||
od_disp_str("\n\r");
|
||
|
||
/* Exit the function. */
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* If the user pressed backspace. */
|
||
else if(chKeyPressed == 8)
|
||
{
|
||
/* If we are not currently at the beginning of the string. */
|
||
if(nPosition > 0)
|
||
{
|
||
/* Send backspace sequence. */
|
||
od_disp_str(szBackspaceWithDelete);
|
||
|
||
/* Move current position back by one position in the string. */
|
||
--nPosition;
|
||
}
|
||
}
|
||
|
||
/* If this is a valid character to place in the string and we have */
|
||
/* not reached the maximum size of the string yet. */
|
||
else if(chKeyPressed >= chMin && chKeyPressed <= chMax
|
||
&& nPosition < nMaxLength)
|
||
{
|
||
/* Display key that was pressed. */
|
||
od_putch(chKeyPressed);
|
||
|
||
/* Add the entered character to the string and increment our */
|
||
/* current position in the string. */
|
||
pszInput[nPosition++] = chKeyPressed;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_clear_keybuffer()
|
||
*
|
||
* Clears any keystrokes from the inbound buffers. Both input from local and
|
||
* remote systems is discarded, by clearing both OpenDoors' common input
|
||
* event queue, and the serial port inbound buffer. This function is called
|
||
* to cause any input by the user prior to the time the function was called
|
||
* to be ignored.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_clear_keybuffer(void)
|
||
{
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_clear_keybuffer()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Empty any events in the common input event queue. */
|
||
ODInQueueEmpty(hODInputQueue);
|
||
|
||
/* If we are not operating in local mode ... */
|
||
if(od_control.baud != 0)
|
||
{
|
||
/* ... then remove any items in the serial port inbound buffer. */
|
||
ODComClearInbound(hSerialPort);
|
||
}
|
||
|
||
/* Call the OpenDoors kernel function. */
|
||
CALL_KERNEL_IF_NEEDED();
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_key_pending()
|
||
*
|
||
* Returns TRUE if there's a key pending, FALSE otherwise.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: TRUE if character is waiting, FALSE if no character is waiting.
|
||
*/
|
||
ODAPIDEF BOOL ODCALL od_key_pending(void)
|
||
{
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_get_key()");
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Call the OpenDoors kernel. */
|
||
CALL_KERNEL_IF_NEEDED();
|
||
|
||
if(!ODInQueueWaiting(hODInputQueue))
|
||
{
|
||
OD_API_EXIT();
|
||
return(FALSE);
|
||
}
|
||
|
||
OD_API_EXIT();
|
||
return(TRUE);
|
||
}
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_get_key()
|
||
*
|
||
* Inputs a single character, optionally waiting for the next character if no
|
||
* character has been received yet. This function returns data received from
|
||
* either the local or remote system, in the order in which it was received.
|
||
*
|
||
* Parameters: bWait - FALSE if od_get_key() should return right away with
|
||
* a value of 0 if no characters have been received, or
|
||
* TRUE if od_get_key() should wait for the next received
|
||
* character.
|
||
*
|
||
* Return: Character that was received, or 0 if no character is waiting.
|
||
*/
|
||
ODAPIDEF char ODCALL od_get_key(BOOL bWait)
|
||
{
|
||
tODInputEvent InputEvent;
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_get_key()");
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Call the OpenDoors kernel. */
|
||
CALL_KERNEL_IF_NEEDED();
|
||
|
||
do {
|
||
|
||
/* If we aren't supposed to wait for input, then check whether any */
|
||
/* input is waiting in the input queue, and if not return right away */
|
||
/* without any data. */
|
||
if(!bWait)
|
||
{
|
||
if(!ODInQueueWaiting(hODInputQueue))
|
||
{
|
||
OD_API_EXIT();
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
/* Obtain the next character from the input queue. If we get to this */
|
||
/* point and there is no data waiting in the input queue, then the */
|
||
/* ODInQueueGetNextEvent() function will block until a character */
|
||
/* is available in the input queue. */
|
||
ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT);
|
||
|
||
/* Only keyboard input events are currently supported by od_get_key(). */
|
||
ASSERT(InputEvent.EventType == EVENT_CHARACTER);
|
||
|
||
/* Update OpenDoors control structure member that records whether the */
|
||
/* last input came from the local or remote user. */
|
||
od_control.od_last_input = InputEvent.bFromRemote ? 0 : 1;
|
||
|
||
} while(InputEvent.chKeyPress == '\n'); /* Ignore line-feed char */
|
||
|
||
/* Return the character that was pressed by the user. */
|
||
OD_API_EXIT();
|
||
return(InputEvent.chKeyPress);
|
||
}
|
||
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_carrier()
|
||
*
|
||
* Allows programs to determine the current state of the carrier detect
|
||
* signal when OpenDoors' automatic carrier detection has been disabled.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: TRUE if the carrier detct signal is present, FALSE if it
|
||
* isn't. When operating in local mode, this function always
|
||
* returns FALSE.
|
||
*/
|
||
ODAPIDEF BOOL ODCALL od_carrier(void)
|
||
{
|
||
BOOL bIsCarrier;
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Log function entry if running in trace mode */
|
||
TRACE(TRACE_API, "od_carrier()");
|
||
|
||
/* If we are operating in local mode, then return FALSE. */
|
||
if(od_control.baud == 0)
|
||
{
|
||
od_control.od_error = ERR_NOREMOTE;
|
||
OD_API_EXIT();
|
||
return(FALSE);
|
||
}
|
||
|
||
/* In remote mode, obtain the current state of the carrier detect signal. */
|
||
ODComCarrier(hSerialPort, &bIsCarrier);
|
||
|
||
/* Return the current state of the carrier detect signal. */
|
||
OD_API_EXIT();
|
||
return(bIsCarrier);
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_repeat()
|
||
*
|
||
* This function displays the same character the specified number of times on
|
||
* the local and remote screens, using any available optimal control sequences
|
||
* under the current display mode.
|
||
*
|
||
* Parameters: chValue - Character to repeat.
|
||
*
|
||
* btTimes - Number of times to repeat the character.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_repeat(char chValue, BYTE btTimes)
|
||
{
|
||
char *pchCurStringPos;
|
||
BYTE btLeft;
|
||
char szBuffer[3];
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_repeat()");
|
||
|
||
/* Ensure that OpenDoors has been initialized. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* If the caller asked to repeat the character 0 times, then we can */
|
||
/* safely return right away without doing anything. */
|
||
if(btTimes == 0)
|
||
{
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* Generate string of repeat characters. */
|
||
pchCurStringPos = szODWorkString;
|
||
for(btLeft = btTimes; btLeft--;)
|
||
{
|
||
*pchCurStringPos++ = chValue;
|
||
}
|
||
*pchCurStringPos = '\0';
|
||
|
||
/* Display repeated string on local screen. */
|
||
ODScrnDisplayString(szODWorkString);
|
||
|
||
/* If we are operating in AVATAR mode. */
|
||
if(od_control.user_avatar)
|
||
{
|
||
/* Generate the AVATAR control sequence to repeat this character */
|
||
/* the specified number of times. */
|
||
szBuffer[0] = 25;
|
||
szBuffer[1] = chValue;
|
||
szBuffer[2] = btTimes;
|
||
od_disp(szBuffer, 3, FALSE);
|
||
}
|
||
|
||
/* If AVATAR mode is not available. */
|
||
else
|
||
{
|
||
/* Send the entire repeated string to the remote system. */
|
||
od_disp(szODWorkString, btTimes, FALSE);
|
||
}
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_page()
|
||
*
|
||
* This function is called when the user wished to page the system operator.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_page(void)
|
||
{
|
||
INT16 nCount;
|
||
tODTimer Timer;
|
||
time_t nUnixTime;
|
||
struct tm *TimeBlock;
|
||
INT16 nMinute;
|
||
BOOL bFailed = FALSE;
|
||
INT16 nOriginalAttrib;
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_page()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Save current display color attribute. */
|
||
nOriginalAttrib = od_control.od_cur_attrib;
|
||
|
||
/* Clear the screen. */
|
||
od_clr_scr();
|
||
od_set_attrib(od_control.od_chat_color1);
|
||
|
||
/* Ask reason for chat. */
|
||
od_disp_str(od_control.od_chat_reason);
|
||
od_set_attrib(od_control.od_chat_color2);
|
||
od_putch('[');
|
||
|
||
/* Use extended ASCII characters if operating in ANSI or AVATAR mode. */
|
||
if(od_control.user_ansi || od_control.user_avatar)
|
||
{
|
||
od_repeat('<EFBFBD>',77);
|
||
}
|
||
else
|
||
{
|
||
od_repeat('-',77);
|
||
}
|
||
od_disp_str("]\n\r ");
|
||
od_input_str(od_control.user_reasonforchat,77,32,255);
|
||
|
||
/* If the user did not abort sysop paging by entering a blank reason */
|
||
/* for chat. */
|
||
if(strlen(od_control.user_reasonforchat) != 0)
|
||
{
|
||
/* Indicate that the user wants to chat. */
|
||
od_control.user_wantchat = TRUE;
|
||
#ifdef ODPLAT_WIN32
|
||
ODFrameUpdateWantChat();
|
||
#endif /* ODPLAT_WIN32 */
|
||
|
||
/* Determine whether or not sysop paging should be permitted at */
|
||
/* the current time. */
|
||
nUnixTime = time(NULL);
|
||
TimeBlock = localtime(&nUnixTime);
|
||
nMinute = (60 * TimeBlock->tm_hour) + TimeBlock->tm_min;
|
||
if(od_control.od_pagestartmin < od_control.od_pageendmin)
|
||
{
|
||
if(nMinute < od_control.od_pagestartmin
|
||
|| nMinute >= od_control.od_pageendmin)
|
||
{
|
||
bFailed = TRUE;
|
||
}
|
||
}
|
||
else if(od_control.od_pagestartmin > od_control.od_pageendmin)
|
||
{
|
||
if(nMinute < od_control.od_pagestartmin
|
||
&& nMinute >= od_control.od_pageendmin)
|
||
{
|
||
bFailed = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bFailed = FALSE;
|
||
}
|
||
|
||
/* If paging is set to PAGE_ENABLE, meaning that sysop paging should */
|
||
/* be permitted regardless of the time of day, then allow paging. */
|
||
if(od_control.od_okaytopage == PAGE_ENABLE)
|
||
{
|
||
bFailed = FALSE;
|
||
}
|
||
|
||
/* If paging is explicitly disable by PAGE_DISABLE, or the current */
|
||
/* time of the day is not normally permitted for paging. */
|
||
if(od_control.od_okaytopage == PAGE_DISABLE || bFailed)
|
||
{
|
||
/* Indicate this to user. */
|
||
od_disp_str("\n\r");
|
||
od_disp_str(od_control.od_no_sysop);
|
||
od_disp_str(od_control.od_press_key);
|
||
od_get_answer("\x0d\x0a");
|
||
|
||
/* Return from this function. */
|
||
goto cleanup;
|
||
}
|
||
|
||
/* Update status line right away. */
|
||
bForceStatusUpdate = TRUE;
|
||
CALL_KERNEL_IF_NEEDED();
|
||
|
||
/* Write sysop page information to the logfile, if the log file */
|
||
/* system is hooked up. */
|
||
if(pfLogWrite != NULL)
|
||
{
|
||
(*pfLogWrite)(8);
|
||
}
|
||
|
||
/* Tell the user that we are now paging the system operator. */
|
||
od_set_attrib(od_control.od_chat_color1);
|
||
od_disp_str(od_control.od_paging);
|
||
|
||
#ifdef OD_TEXTMODE
|
||
/* Display sysop page status line if it exists and the sysop status */
|
||
/* line is currently active. */
|
||
if(od_control.od_page_statusline != -1 && btCurrentStatusLine != 8)
|
||
{
|
||
od_set_statusline(od_control.od_page_statusline);
|
||
}
|
||
#endif /* OD_TEXTMODE */
|
||
|
||
/* Increment the total number of times that the user has paged */
|
||
/* the sysop. */
|
||
++od_control.user_numpages;
|
||
|
||
/* Sysop hasn't responded yet. */
|
||
bChatted=FALSE;
|
||
|
||
/* Loop for length of sysop page. */
|
||
for(nCount = 0; nCount < od_control.od_page_len; ++nCount)
|
||
{
|
||
/* Start a timer that is set to elapse in exactly one second. */
|
||
ODTimerStart(&Timer, 1000);
|
||
|
||
/* Display another period character. */
|
||
od_putch('.');
|
||
|
||
/* Abort page if system operator answered */
|
||
if(bChatted) goto cleanup;
|
||
|
||
/* Send beep to local and remote systems. */
|
||
od_putch('\a');
|
||
|
||
/* Check whether system operator has answered after playing beep. */
|
||
if (bChatted) goto cleanup;
|
||
|
||
/* Wait for the timer to elapse, calling od_kernel() so that */
|
||
/* chat mode will start as soon as the sysop presses the */
|
||
/* chat key. */
|
||
while(!ODTimerElapsed(&Timer))
|
||
{
|
||
CALL_KERNEL_IF_NEEDED();
|
||
}
|
||
}
|
||
|
||
/* If sysop page time has elapsed without a response from the */
|
||
/* sysop, then notify the user. */
|
||
od_disp_str(od_control.od_no_response);
|
||
od_disp_str(od_control.od_press_key);
|
||
od_get_answer("\x0d\x0a");
|
||
od_disp_str("\n\r\n\r");
|
||
}
|
||
|
||
cleanup:
|
||
/* Restore original display color attribute. */
|
||
od_set_attrib(nOriginalAttrib);
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_disp()
|
||
*
|
||
* Function to send one or more character to the remote system, optionally
|
||
* also echoing the same characters to the local screen.
|
||
*
|
||
* Parameters: pachBuffer - Pointer to buffer of characters to send.
|
||
*
|
||
* nSize - Number of characters to send from the buffer.
|
||
*
|
||
* bLocalEcho - TRUE to also echo the characters to the local
|
||
* screen, FALSE to just send the characters to the
|
||
* remote system.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_disp(const char *pachBuffer, INT nSize, BOOL bLocalEcho)
|
||
{
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_disp()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Call the OpenDoors kernel, if needed. */
|
||
#ifndef OD_MULTITHREADED
|
||
if(ODTimerElapsed(&RunKernelTimer))
|
||
{
|
||
CALL_KERNEL_IF_NEEDED();
|
||
}
|
||
#endif /* !OD_MULTITHREADED */
|
||
|
||
/* If we are operating in remote mode, then send the buffer to the */
|
||
/* remote system. */
|
||
if(od_control.baud != 0)
|
||
{
|
||
ODComSendBuffer(hSerialPort, (BYTE *)pachBuffer, nSize);
|
||
}
|
||
|
||
/* If we are also to display the character on the local screen, then */
|
||
/* display the buffer on the local screen. */
|
||
if(bLocalEcho)
|
||
{
|
||
ODScrnDisplayBuffer(pachBuffer, nSize);
|
||
}
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_disp_str()
|
||
*
|
||
* Displays a string on both the local and remote systems.
|
||
*
|
||
* Parameters: pszToDisplay - Pointer to the string to be displayed.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_disp_str(const char *pszToDisplay)
|
||
{
|
||
/* Log function entry if running in trace mode */
|
||
TRACE(TRACE_API, "od_disp_str()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Call the OpenDoors kernel, if needed. */
|
||
#ifndef OD_MULTITHREADED
|
||
if(ODTimerElapsed(&RunKernelTimer))
|
||
{
|
||
CALL_KERNEL_IF_NEEDED();
|
||
}
|
||
#endif /* !OD_MULTITHREADED */
|
||
|
||
/* Send the string to the remote system, if we are running in remote mode. */
|
||
if(od_control.baud != 0)
|
||
{
|
||
ODComSendBuffer(hSerialPort, (BYTE *)pszToDisplay, strlen(pszToDisplay));
|
||
}
|
||
|
||
/* Display the screen on the local screen. */
|
||
ODScrnDisplayString(pszToDisplay);
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_set_statusline()
|
||
*
|
||
* Switches to one of the available status lines provided by the current
|
||
* personality, or turns off the status line altogether.
|
||
*
|
||
* Parameters: nSetting - Indicates which status line (if any) should be
|
||
* activated.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_set_statusline(INT nSetting)
|
||
{
|
||
#ifdef OD_TEXTMODE
|
||
INT nDistance;
|
||
BYTE btCount
|
||
#endif /* OD_TEXTMODE */
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_set_statusline()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY()
|
||
|
||
#ifdef OD_TEXTMODE
|
||
|
||
/* If status line is disabled, then don't do anything. */
|
||
if(!od_control.od_status_on)
|
||
{
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* Ensure that the parameter is within the valid range. */
|
||
if(nSetting < 0 || nSetting > 8)
|
||
{
|
||
nSetting = 0;
|
||
}
|
||
|
||
/* If the specified status line is already active, and status line */
|
||
/* update isn't being forced, then return without doing anything. */
|
||
if(!od_control.od_update_status_now && nSetting == btCurrentStatusLine)
|
||
{
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* Save the current cursor settings. */
|
||
ODStoreTextInfo();
|
||
|
||
/* Reset screen boundary to allow access to the entire screen. */
|
||
ODScrnSetBoundary(1,1,80,25);
|
||
|
||
/* If status line is being turned off. */
|
||
if(btCurrentStatusLine == STATUS_NONE)
|
||
{
|
||
if((nDistance = (INT)ODTextInfo.cury - ( 1 + (INT)btOutputBottom
|
||
- (INT)btOutputTop)) > 0)
|
||
{
|
||
ODScrnCopyText(1, (BYTE)((INT)btOutputTop + nDistance), 80,
|
||
(BYTE)((INT)btOutputBottom + nDistance), (BYTE)btOutputTop, 1);
|
||
ODTextInfo.cury = 1 + btOutputBottom - btOutputTop;
|
||
}
|
||
else if(ODTextInfo.cury < btOutputTop)
|
||
{
|
||
ODTextInfo.cury = btOutputTop;
|
||
ODScrnCopyText(1, (BYTE)(btOutputTop + 24 - btOutputBottom), 80, 25,
|
||
btOutputTop, 1);
|
||
}
|
||
}
|
||
|
||
od_control.od_current_statusline = btCurrentStatusLine = nSetting;
|
||
|
||
if(nSetting == 8)
|
||
{
|
||
ODScrnSetAttribute(0x07);
|
||
|
||
for(btCount = 1; btCount <= 25; ++btCount)
|
||
{
|
||
if(btCount < btOutputTop || btCount > btOutputBottom)
|
||
{
|
||
if(btCount == 25)
|
||
{
|
||
ODScrnPutText(80, 25, 80, 25, abtBlackBlock);
|
||
ODScrnSetCursorPos(1, 25);
|
||
ODScrnDisplayString(" ");
|
||
}
|
||
else
|
||
{
|
||
ODScrnSetCursorPos(1, 24);
|
||
ODScrnDisplayString(" ");
|
||
}
|
||
}
|
||
}
|
||
|
||
ODScrnSetAttribute(ODTextInfo.attribute);
|
||
ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
|
||
}
|
||
|
||
else
|
||
{
|
||
ODScrnEnableCaret(FALSE);
|
||
ODScrnEnableScrolling(FALSE);
|
||
|
||
(*pfCurrentPersonality)((BYTE)nSetting);
|
||
|
||
ODScrnEnableCaret(TRUE);
|
||
ODScrnEnableScrolling(TRUE);
|
||
|
||
ODScrnSetBoundary(1, btOutputTop, 80, btOutputBottom);
|
||
ODScrnSetAttribute(ODTextInfo.attribute);
|
||
ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
|
||
}
|
||
|
||
#else /* !OD_TEXTMODE */
|
||
|
||
od_control.od_error = ERR_UNSUPPORTED;
|
||
|
||
#endif /* !OD_TEXTMODE */
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODStoreTextInfo()
|
||
*
|
||
* Stores the current text settings into the OpenDoors global text information
|
||
* structure.
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: void
|
||
*/
|
||
void ODStoreTextInfo(void)
|
||
{
|
||
ODScrnGetTextInfo(&ODTextInfo);
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODRestoreTextInfo()
|
||
*
|
||
* Restores display settings previously stored by ODStoreTextInfo()
|
||
*
|
||
* Parameters: none
|
||
*
|
||
* Return: void
|
||
*/
|
||
void ODRestoreTextInfo(void)
|
||
{
|
||
ODScrnSetBoundary(ODTextInfo.winleft, ODTextInfo.wintop,
|
||
ODTextInfo.winright, ODTextInfo.winbottom);
|
||
ODScrnSetAttribute(ODTextInfo.attribute);
|
||
ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODStringToName()
|
||
*
|
||
* Reformats a string so that it has the correct capitalization for a name,
|
||
* and removes any trailing line break character.
|
||
*
|
||
* Parameters: pszToConvert - Pointer to the string to reformat.
|
||
*
|
||
* Return: void
|
||
*/
|
||
void ODStringToName(char *pszToConvert)
|
||
{
|
||
/* Begin by changing the entire string to lower case. */
|
||
strlwr(pszToConvert);
|
||
|
||
/* Trim any newline character that may be at the end of the string. */
|
||
if(pszToConvert[strlen(pszToConvert) - 1] == '\n')
|
||
{
|
||
pszToConvert[strlen(pszToConvert) - 1] = '\0';
|
||
}
|
||
/* Trim any CR character that may be at the end of the string. */
|
||
if(pszToConvert[strlen(pszToConvert) - 1] == '\r')
|
||
{
|
||
pszToConvert[strlen(pszToConvert) - 1] = '\0';
|
||
}
|
||
|
||
/* Change the first character to lower case. */
|
||
*pszToConvert = toupper(*pszToConvert);
|
||
|
||
/* Loop through the rest of the string, capitalizing any other words */
|
||
/* in the string. */
|
||
while(*pszToConvert)
|
||
{
|
||
switch(*pszToConvert++)
|
||
{
|
||
case ' ':
|
||
case '\t':
|
||
case ',':
|
||
case '.':
|
||
case '-':
|
||
*pszToConvert = toupper(*pszToConvert);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_set_color()
|
||
*
|
||
* Sets the current display color for both local and remote output.
|
||
*
|
||
* Parameters: nForeground - New foreground (text) color.
|
||
*
|
||
* nBackground - New background color.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_set_color(INT nForeground, INT nBackground)
|
||
{
|
||
/* Use od_set_attrib() to perform the actual color setting. */
|
||
/* Here, we rely on od_set_attrib() to look after initialization, */
|
||
/* API_ENTRY() and API_EXIT() calls, etc. This allows od_set_color() */
|
||
/* (which was previously just a macro) to be implemented with as */
|
||
/* little overhead as possible. */
|
||
od_set_attrib(nForeground | (nBackground << 4));
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_set_attrib()
|
||
*
|
||
* Sets the current display color for both local and remote output.
|
||
*
|
||
* Parameters: nColor - New Display color to set, or -1 for no change.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_set_attrib(INT nColor)
|
||
{
|
||
char szControlSequence[40];
|
||
|
||
/* Log function entry if running in trace mode */
|
||
TRACE(TRACE_API, "od_set_attrib()");
|
||
|
||
/* Ensure that OpenDoors has been initialized. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* If color value is -1, then make no change. */
|
||
if(nColor == -1)
|
||
{
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* If we are operating in AVATAR mode. */
|
||
if(od_control.user_avatar)
|
||
{
|
||
if(od_control.od_cur_attrib != nColor || od_control.od_full_color)
|
||
{
|
||
/* Change local text color. */
|
||
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib = nColor));
|
||
|
||
/* Generate AVATAR control sequence. */
|
||
szControlSequence[0] = 22;
|
||
szControlSequence[1] = 1;
|
||
szControlSequence[2] = nColor;
|
||
|
||
/* Send AVATAR control sequence. */
|
||
od_disp(szControlSequence, 3, FALSE);
|
||
}
|
||
}
|
||
|
||
/* If we are operating in ANSI mode. */
|
||
else if(od_control.user_ansi)
|
||
{
|
||
bAnyColorChangeYet = FALSE;
|
||
|
||
if(od_control.od_cur_attrib == -1 || od_control.od_full_color)
|
||
{
|
||
ansi_reset:
|
||
/* Reset ANSI terminal status. */
|
||
ODAddANSIParameter(szControlSequence, 0);
|
||
|
||
/* If blink attribute is set. */
|
||
if(nColor & 0x80)
|
||
{
|
||
/* Add it to the ANSI color sequence. */
|
||
ODAddANSIParameter(szControlSequence, 5);
|
||
}
|
||
|
||
/* If high intensity attribute is set. */
|
||
if(nColor & 0x08)
|
||
{
|
||
/* Add it to the ANSI color sequence. */
|
||
ODAddANSIParameter(szControlSequence, 1);
|
||
}
|
||
}
|
||
|
||
/* If current color is known. */
|
||
else
|
||
{
|
||
/* If have to reset flashing or bright. */
|
||
if(((od_control.od_cur_attrib&0x80) &&
|
||
!(nColor & 0x80)) || ((od_control.od_cur_attrib & 0x08)
|
||
&& !(nColor & 0x08)))
|
||
{
|
||
/* Must reset entire colour settings. */
|
||
od_control.od_cur_attrib = -1;
|
||
goto ansi_reset;
|
||
}
|
||
|
||
/* If flashing has to be turned on. */
|
||
if((nColor & 0x80) != (od_control.od_cur_attrib & 0x80))
|
||
{
|
||
/* Add it to the ANSI color sequence. */
|
||
ODAddANSIParameter(szControlSequence, 5);
|
||
}
|
||
|
||
/* If bright has to be turned on. */
|
||
if((nColor & 0x08) != (od_control.od_cur_attrib & 0x08)
|
||
|| od_control.od_cur_attrib == -1)
|
||
{
|
||
/* Add it to the ANSI color sequence. */
|
||
ODAddANSIParameter(szControlSequence, 1);
|
||
}
|
||
}
|
||
|
||
|
||
/* If foreground color has changed. */
|
||
if((nColor & 0x07) != (od_control.od_cur_attrib & 0x07)
|
||
|| od_control.od_cur_attrib == -1 || od_control.od_full_color)
|
||
{
|
||
/* Add translated color to sequence. */
|
||
ODAddANSIParameter(szControlSequence,
|
||
abtPCToANSIColorTable[nColor&0x07]);
|
||
}
|
||
|
||
/* If background color has changed. */
|
||
if((nColor & 0x70) != (od_control.od_cur_attrib & 0x70)
|
||
|| od_control.od_cur_attrib == -1 || od_control.od_full_color)
|
||
{
|
||
/* Add translated color to sequence. */
|
||
ODAddANSIParameter(szControlSequence,
|
||
abtPCToANSIColorTable[(nColor & 0x70) >> 4] + 10);
|
||
}
|
||
|
||
/* If any change in color. */
|
||
if(bAnyColorChangeYet)
|
||
{
|
||
/* Append change-attribute command. */
|
||
strcat(szControlSequence, "m");
|
||
|
||
/* Send ANSI sequence to the modem. */
|
||
od_disp(szControlSequence, strlen(szControlSequence), FALSE);
|
||
}
|
||
|
||
/* Change local text color. */
|
||
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib = nColor));
|
||
}
|
||
else
|
||
{
|
||
od_control.od_error = ERR_NOGRAPHICS;
|
||
}
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODAddANSIParameter() *** PRIVATE FUNCTION ***
|
||
*
|
||
* Adds a parameter to an ANSI color sequence.
|
||
*
|
||
* Parameters: szControlSequence - The contents of the control sequence string
|
||
* generated so far.
|
||
*
|
||
* nParameterValue - Value of the parameter to add.
|
||
*
|
||
* Return: void
|
||
*/
|
||
static void ODAddANSIParameter(char *szControlSequence, int nParameterValue)
|
||
{
|
||
char szTemp[5];
|
||
|
||
if(bAnyColorChangeYet)
|
||
{
|
||
sprintf(szTemp, ";%d", nParameterValue);
|
||
strcat(szControlSequence, szTemp);
|
||
}
|
||
else
|
||
{
|
||
bAnyColorChangeYet = TRUE;
|
||
sprintf(szControlSequence, "x[%d", nParameterValue);
|
||
szControlSequence[0] = 27;
|
||
}
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_putch()
|
||
*
|
||
* Displays a character on the local and remote screens.
|
||
*
|
||
* Parameters: chToDisplay - The character to display.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_putch(char chToDisplay)
|
||
{
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_putch()");
|
||
|
||
/* Initialize OpenDoors if it hasn't been done already. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* Display the character on the local screen. */
|
||
ODScrnDisplayChar(chToDisplay);
|
||
|
||
/* If not operating in local mode, then send the character to the */
|
||
/* serial port. */
|
||
if(od_control.baud)
|
||
{
|
||
ODComSendByte(hSerialPort, chToDisplay);
|
||
}
|
||
|
||
/* If it is time to call the kernel, then do so. */
|
||
if(ODTimerElapsed(&RunKernelTimer))
|
||
{
|
||
CALL_KERNEL_IF_NEEDED();
|
||
}
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_set_dtr()
|
||
*
|
||
* Changes the state of the DTR line to the modem, if not running in local
|
||
* mode.
|
||
*
|
||
* Parameters: bHigh - TRUE to raise DTR, FALSE to lower it.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF void ODCALL od_set_dtr(BOOL bHigh)
|
||
{
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_set_dtr()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
/* If we are running in local mode, then return with an error. */
|
||
if(!od_control.baud)
|
||
{
|
||
od_control.od_error = ERR_NOREMOTE;
|
||
OD_API_EXIT();
|
||
return;
|
||
}
|
||
|
||
/* Otherwise, change the state of the DTR line. */
|
||
ODComSetDTR(hSerialPort, bHigh);
|
||
|
||
OD_API_EXIT();
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_get_answer()
|
||
*
|
||
* Waits for the user to press one of the keys listed in pszOptions. Case is
|
||
* not sensitive, although the pressed key is returned in the same case as it
|
||
* is specified in pszOptions.
|
||
*
|
||
* Parameters: pszOptions - String listing characters to accept.
|
||
*
|
||
* Return: void
|
||
*/
|
||
ODAPIDEF char ODCALL od_get_answer(const char *pszOptions)
|
||
{
|
||
char *pchPossibleOption;
|
||
char chPressed;
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_get_answer()");
|
||
|
||
/* Initialize OpenDoors if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
for(;;)
|
||
{
|
||
/* Wait for the next key press by the user. */
|
||
chPressed = od_get_key(TRUE);
|
||
chPressed = tolower(chPressed);
|
||
|
||
/* Loop through list of possible options. */
|
||
pchPossibleOption = (char *)pszOptions;
|
||
while(*pchPossibleOption)
|
||
{
|
||
/* If the key pressed matches this possible option. */
|
||
if(tolower(*pchPossibleOption) == chPressed)
|
||
{
|
||
/* Then return the character in the case originally specified */
|
||
/* by the caller. */
|
||
OD_API_EXIT();
|
||
return(*pchPossibleOption);
|
||
}
|
||
|
||
/* Move on to the next possible option. */
|
||
++pchPossibleOption;
|
||
}
|
||
|
||
/* If the key pressed did not match a possible option, then we */
|
||
/* just loop again, getting the next key. */
|
||
}
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_color_config()
|
||
*
|
||
* Determines the color attribute that is described by the provided string.
|
||
* This string is in the same format that is used for specifying colors in the
|
||
* OpenDoors configuration file.
|
||
*
|
||
* Parameters: pszColorDesc - Color description string.
|
||
*
|
||
* Return: The PC-style color attribute corresponding to the color
|
||
* description string.
|
||
*/
|
||
ODAPIDEF BYTE ODCALL od_color_config(char *pszColorDesc)
|
||
{
|
||
BYTE btColor = 0x07;
|
||
char szToken[40];
|
||
char *pszStart=(char *)pszColorDesc;
|
||
char *pszEnd;
|
||
BYTE btLength;
|
||
BYTE btIdentifier;
|
||
BOOL bForeground = TRUE;
|
||
|
||
/* Log function entry if running in trace mode. */
|
||
TRACE(TRACE_API, "od_color_config()");
|
||
|
||
/* Initialize OpenDoros if it hasn't already been done. */
|
||
if(!bODInitialized) od_init();
|
||
|
||
OD_API_ENTRY();
|
||
|
||
while(*pszStart && *pszStart!=chColorCheck)
|
||
{
|
||
if(*pszStart == ' ' || *pszStart== '\t')
|
||
{
|
||
++pszStart;
|
||
}
|
||
else
|
||
{
|
||
btLength = 0;
|
||
pszEnd = (char *)pszStart;
|
||
while(*pszEnd && *pszEnd != chColorCheck && *pszEnd != ' '
|
||
&& *pszEnd != '\t')
|
||
{
|
||
++btLength;
|
||
++pszEnd;
|
||
}
|
||
|
||
if(btLength > 39) btLength = 39;
|
||
strncpy(szToken, pszStart, btLength);
|
||
szToken[btLength] = '\0';
|
||
strupr(szToken);
|
||
|
||
for(btIdentifier = 0; btIdentifier < 12; ++btIdentifier)
|
||
if(strcmp(od_config_colours[btIdentifier], szToken) == 0)
|
||
{
|
||
if(btIdentifier <= 9)
|
||
{
|
||
if(btIdentifier >= 8) btIdentifier -= 2;
|
||
|
||
if(bForeground)
|
||
{
|
||
bForeground=FALSE;
|
||
btColor &=~ 0x07;
|
||
btColor |= btIdentifier;
|
||
}
|
||
else
|
||
{
|
||
btColor &=~ 0x70;
|
||
btColor |= (btIdentifier << 4);
|
||
}
|
||
}
|
||
|
||
else if(btIdentifier == 10)
|
||
{
|
||
btColor |= 0x08;
|
||
}
|
||
|
||
else if(btIdentifier == 11)
|
||
{
|
||
btColor |= 0x80;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
pszStart = (char *)pszEnd;
|
||
}
|
||
}
|
||
|
||
pchColorEndPos = (char *)pszStart;
|
||
|
||
OD_API_EXIT();
|
||
|
||
return(btColor);
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* ODPagePrompt()
|
||
*
|
||
* Called to display the page prompt at the end of a screen of text. This page
|
||
* prompt allows the user to stop further display, to display the next page,
|
||
* or to display in continuous (non-stop) mode with page pausing disabled.
|
||
*
|
||
* Parameters: pbPausing - Pointer to current page pausing enabled flag.
|
||
*
|
||
* Return: FALSE if display should be continued, or TRUE to abort display.
|
||
*/
|
||
BOOL ODPagePrompt(BOOL *pbPausing)
|
||
{
|
||
INT nPromptLength = strlen(od_control.od_continue);
|
||
tODScrnTextInfo TextInfo;
|
||
BOOL bToReturn = FALSE;
|
||
char chKeyPressed;
|
||
BYTE btCount;
|
||
|
||
/* Return right away if page pausing is disabled. */
|
||
if(!*pbPausing) return(FALSE);
|
||
|
||
/* Get current text color. */
|
||
ODScrnGetTextInfo(&TextInfo);
|
||
|
||
/* Set to prompt color. */
|
||
od_set_attrib(od_control.od_continue_col);
|
||
|
||
/* Display page prompt string. */
|
||
od_disp_str(od_control.od_continue);
|
||
|
||
/* Restore original text color. */
|
||
od_set_attrib(TextInfo.attribute);
|
||
|
||
/* Loop until the user makes a valid choice. */
|
||
for(;;)
|
||
{
|
||
/* Obtain the next key from the user. */
|
||
chKeyPressed = od_get_key(TRUE);
|
||
|
||
/* If user chooses to continue. */
|
||
if(chKeyPressed == tolower(od_control.od_continue_yes) ||
|
||
chKeyPressed == toupper(od_control.od_continue_yes) ||
|
||
chKeyPressed == 13 ||
|
||
chKeyPressed == ' ')
|
||
{
|
||
/* Remove the prompt and return. */
|
||
goto finished_pausing;
|
||
}
|
||
|
||
/* If user requested nonstop display. */
|
||
else if(chKeyPressed == tolower(od_control.od_continue_nonstop) ||
|
||
chKeyPressed == toupper(od_control.od_continue_nonstop))
|
||
{
|
||
/* Disable page pausing. */
|
||
*pbPausing = FALSE;
|
||
|
||
/* Remove the prompt and return. */
|
||
goto finished_pausing;
|
||
}
|
||
|
||
/* If user chooses to stop display. */
|
||
else if(chKeyPressed == tolower(od_control.od_continue_no) ||
|
||
chKeyPressed == toupper(od_control.od_continue_no) ||
|
||
chKeyPressed == 's' || chKeyPressed == 'S' || chKeyPressed == 3
|
||
|| chKeyPressed == 11 || chKeyPressed == 0x18)
|
||
{
|
||
/* If we are operating in remote mode. */
|
||
if(od_control.baud)
|
||
{
|
||
/* Clear the output buffer. */
|
||
ODComClearOutbound(hSerialPort);
|
||
}
|
||
|
||
/* Tell the caller to stop displaying more text. */
|
||
bToReturn = TRUE;
|
||
|
||
/* Remove the prompt and return. */
|
||
goto finished_pausing;
|
||
}
|
||
}
|
||
|
||
finished_pausing:
|
||
/* Remove the pause prompt. */
|
||
for(btCount = 0; btCount < nPromptLength; ++btCount)
|
||
{
|
||
od_disp_str(szBackspaceWithDelete);
|
||
}
|
||
|
||
return(bToReturn);
|
||
}
|
||
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* od_control_get()
|
||
*
|
||
* Returns a pointer to the od_control structure containing information
|
||
* and settings associated with the current session.
|
||
*
|
||
* Parameters: None.
|
||
*
|
||
* Return: A pointer to the od_control structure associated with this
|
||
* session.
|
||
*/
|
||
ODAPIDEF tODControl * ODCALL od_control_get(void)
|
||
{
|
||
/* Log function entry if running in trace mode */
|
||
TRACE(TRACE_API, "od_disp_str()");
|
||
|
||
return(&od_control);
|
||
}
|