diff --git a/.gitignore b/.gitignore index 0cb8e07..34b9245 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,9 @@ logs/* *.a lua/lua lua/luac +netmail.out +echomail.out +utils/magiedit/odoors/libs-* +utils/magiedit/odoors/exe-* +utils/magiedit/odoors/objs-* +utils/magiedit/magiedit diff --git a/utils/magiedit/build.sh b/utils/magiedit/build.sh new file mode 100755 index 0000000..253b2a3 --- /dev/null +++ b/utils/magiedit/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd odoors +make +cd .. +gcc -I./odoors -c main.c +gcc -o magiedit main.o odoors/libs-`uname`/libODoors.a diff --git a/utils/magiedit/magiedit.sh b/utils/magiedit/magiedit.sh new file mode 100755 index 0000000..fc90487 --- /dev/null +++ b/utils/magiedit/magiedit.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd /home/andrew/MagickaBBS/utils/magiedit +./magiedit -D /home/andrew/MagickaBBS/node$1/dorinfo1.def -MSGTMP /home/andrew/MagickaBBS/node$1 diff --git a/utils/magiedit/main.c b/utils/magiedit/main.c new file mode 100644 index 0000000..44b9ef4 --- /dev/null +++ b/utils/magiedit/main.c @@ -0,0 +1,670 @@ +#if WIN32 +# define _MSC_VER 1 +# define _CRT_SECURE_NO_WARNINGS +# include +#else +# +#endif + +#include +#include +#include +#include +#include +#include + +char **quote_lines; +int quote_line_count; + +char *msgfrom; +char *msgto; +char *msgsubj; +char *msgarea; +int msgpriv; + +char *message_editor() { + char **body_lines; + int body_line_count; + int position_x; + int position_y; + int done; + char line[81]; + char line_cpy[81]; + int top_of_screen = 0; + int i, j; + char *return_body; + int body_len; + tODInputEvent ch; + int q_done; + char q_marker; + int q_start; + int q_position; + int *q_lines; + int q_line_count; + int q_unquote; + + position_x = 0; + position_y = 0; + + body_line_count = 0; + done = 0; + + memset(line, 0, 81); + memset(line_cpy, 0, 81); + + while (!done) { + od_clr_scr(); + od_set_cursor(1, 1); + od_set_color(L_WHITE, D_BLUE); + od_printf(" TO: %-32.32s AREA: %-32.32s", msgto, msgarea); + od_clr_line(); + od_set_cursor(2, 1); + od_printf("SUBJ: %s", msgsubj); + od_clr_line(); + od_set_cursor(24, 1); + od_printf("Enter /S to save, /Q to quote or /A to abort on a new line."); + od_clr_line(); + od_set_cursor(3, 1); + od_set_color(L_WHITE, D_BLACK); + while (1) { + od_get_input(&ch, OD_NO_TIMEOUT, GETIN_NORMAL); + if (ch.EventType == EVENT_EXTENDED_KEY) { + if (ch.chKeyPress == OD_KEY_UP) { + if (position_y > 0) { + strcpy(line_cpy, body_lines[position_y - 1]); + free(body_lines[position_y - 1]); + body_lines[position_y - 1] = strdup(line); + strcpy(line, line_cpy); + position_y--; + + if (position_x >= strlen(line)) { + position_x = strlen(line); + } + + if (position_y < top_of_screen) { + top_of_screen--; + + } + od_set_cursor(3, 1); + + for (i=top_of_screen;i= strlen(line)) { + position_x = strlen(line); + } + + if (position_y > top_of_screen +20) { + top_of_screen++; + + } + od_set_cursor(3, 1); + + for (i=top_of_screen;i 0) { + position_x--; + od_set_cursor(position_y - top_of_screen + 3, position_x + 1); + } + + } else if (ch.chKeyPress == OD_KEY_RIGHT) { + if (position_x < strlen(line)) { + position_x++; + od_set_cursor(position_y - top_of_screen + 3, position_x + 1); + } + } + } else if (ch.EventType == EVENT_CHARACTER) { + if (ch.chKeyPress == '\r' || strlen(line) == 78) { + if (strcasecmp(line, "/S") == 0) { + // save message + body_len = 0; + for (i=0;i 0) { + od_clr_scr(); + od_set_cursor(1, 1); + od_set_color(L_WHITE, D_BLUE); + od_printf("Quoting Message --"); + od_clr_line(); + od_set_cursor(2, 1); + od_printf("Press Enter to Select a line, Q to Quote, A to Abort"); + od_clr_line(); + od_set_cursor(3, 1); + od_set_color(L_WHITE, D_BLACK); + + q_start = 0; + q_position = 0; + q_line_count = 0; + q_done = 0; + q_marker = ' '; + while (!q_done) { + for (i=q_start;i= quote_line_count) { + q_position = quote_line_count - 1; + } + + if (q_position > q_start + 20) { + q_start = q_start + 20; + if (q_start + 20 >= quote_line_count) { + q_start = quote_line_count - 20; + } + } + } + } else if (ch.EventType == EVENT_CHARACTER) { + if (ch.chKeyPress == 13) { + q_unquote = 0; + if (q_line_count > 0) { + for (i=0;iposition_y;i--) { + body_lines[i] = body_lines[i-1]; + } + body_line_count++; + body_lines[i] = (char *)malloc(sizeof(char) * (position_x + 1)); + strncpy(body_lines[i], line, position_x); + body_lines[i][position_x] = '\0'; + strcpy(line_cpy, &line[position_x]); + memset(line, 0, 81); + strcpy(line, line_cpy); + memset(line_cpy, 0, 81); + + position_y++; + if (position_y - top_of_screen > 20) { + top_of_screen++; + } + + } else { + if (body_line_count == 0) { + body_lines = (char **)malloc(sizeof(char *)); + } else { + body_lines = (char **)realloc(body_lines, sizeof(char *) * (body_line_count + 1)); + } + + for (i=body_line_count;i>position_y;i--) { + body_lines[i] = body_lines[i-1]; + } + body_line_count++; + body_lines[i] = strdup(line); + + position_y++; + if (position_y - top_of_screen > 20) { + top_of_screen++; + } + position_x = 0; + memset(line, 0, 81); + } + + + + od_set_cursor(3, 1); + + for (i=top_of_screen;i= strlen(line)) { + strncpy(line_cpy, line, strlen(line) - 1); + memset(line, 0, 81); + strcpy(line, line_cpy); + memset(line_cpy, 0, 81); + position_x--; + } else { + strncpy(line_cpy, line, position_x -1); + strcpy(line, line_cpy); + memset(line_cpy, 0, 81); + position_x--; + strcat(line_cpy, &line[position_x]); + } + } + } else { + if (position_x >= strlen(line)) { + strncat(line, &ch.chKeyPress, 1); + } else { + strncpy(line_cpy, line, position_x); + strncat(line_cpy, &ch.chKeyPress, 1); + strcat(line_cpy, &line[position_x]); + memset(line, 0, 81); + strcpy(line, line_cpy); + memset(line_cpy, 0, 81); + } + position_x++; + + } + + if (position_y > 20) { + od_set_cursor(23, 1); + od_clr_line(); + } else { + od_set_cursor(position_y + 3, 1); + od_clr_line(); + } + + for (i = 0; i < position_x; i++) { + od_printf("%c", line[i]); + } + + if (position_x < strlen(line) ) { + for (i = position_x; i < strlen(line); i++) { + od_printf("%c", line[i]); + } + } + + if (position_y > 22) { + od_set_cursor(23, position_x + 1); + } else { + od_set_cursor(position_y + 3, position_x + 1); + } + } + } + } + } +} + +#if _MSC_VER +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) +{ +#else +int main(int argc, char **argv) +{ +#endif + char *msgtmp; + char *msginf; + char path_sep; + char *msgpath; + int noquote; + char buffer[256]; + FILE *fptr; + char *body; + int i; +#if _MSC_VER + int j; + + for (i=0;i 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + msgfrom = strdup(buffer); + + fgets(buffer, 256, fptr); + for (i=strlen(buffer) - 1; i > 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + msgto = strdup(buffer); + + fgets(buffer, 256, fptr); + for (i=strlen(buffer) - 1; i > 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + msgsubj = strdup(buffer); + + fgets(buffer, 256, fptr); // msg no, we don't care + + fgets(buffer, 256, fptr); + for (i=strlen(buffer) - 1; i > 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + msgarea = strdup(buffer); + + fgets(buffer, 256, fptr); + for (i=strlen(buffer) - 1; i > 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + if (strcasecmp(buffer, "YES") == 0) { + msgpriv = 1; + } else { + msgpriv = 0; + } + + + fclose(fptr); + + noquote = 0; + + fptr = fopen(msgtmp, "r"); + + if (!fptr) { + sprintf(msgtmp, "%s%cmsgtmp", msgpath, path_sep); + fptr = fopen(msgtmp, "r"); + if (!fptr) { + noquote = 1; + } + } + quote_line_count = 0; + if (!noquote) { + fgets(buffer, 74, fptr); + while (!feof(fptr)) { + for (i=strlen(buffer) - 1; i > 0; i--) { + if (buffer[i] != '\r' && buffer[i] != '\n') { + break; + } else { + buffer[i] = '\0'; + } + } + + if (quote_line_count == 0) { + quote_lines = (char **)malloc(sizeof(char *)); + } else { + quote_lines = (char **)realloc(quote_lines, sizeof(char *) * (quote_line_count + 1)); + } + + quote_lines[quote_line_count] = (char *)malloc(strlen(buffer) + 5); + + sprintf(quote_lines[quote_line_count], " %c> %s", msgto[0], buffer); + + quote_line_count++; + + fgets(buffer, 74, fptr); + } + fclose(fptr); + unlink(msgtmp); + } + + body = message_editor(); + + if (body == NULL) { + od_printf("Message Aborted!\r\n"); + od_exit(0, FALSE); + return 0; + } + + for (i=0;i +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODTypes.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODCore.h" +#include "ODKrnl.h" + + +/* Private function prototypes. */ +static char ODWaitNoCase(char *pszWaitFor, tODMilliSec WaitTime); + + +/* Number of attempts and timeout values for testing each terminal emulation */ +/* protocol. */ +#define ANSI_TRIES 1 +#define ANSI_WAIT 660 /* Time in milliseconds. */ +#define RIP_TRIES 1 +#define RIP_WAIT 660 /* Time in milliseconds. */ + +/* Strings to use for autodetection. */ +#define ANSI_QUERY "\x1b[6n\r \r" +#define ANSI_RESPONSE "\x1b[" +#define RIP_QUERY "\r\x1b[!\r \r" +#define RIP_RESPONSE "RIP" + +/* Maximum number of characters to match with _waitnocase(). */ +#define MATCH_LEN 3 + + +/* ---------------------------------------------------------------------------- + * od_autodetect() + * + * Determines the terminal emulation capabilities of the remote communications + * software, when possible. Turns on ANSI and/or RIP modes if they are + * supported by the remote system. + * + * Parameters: nFlags - Currently unused. + * + * Return: void + */ +ODAPIDEF void ODCALL od_autodetect(INT nFlags) +{ + INT nCount; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_autodetect()"); + + /* Initialize OpenDoors if it hasn't aready been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Temporary code that will be optimized out, which prevents a compiler */ + /* warning from being generated for the currently unused flags parameter. */ + (void)nFlags; + + /* If operating in local mode, turn on ANSI mode, but not RIP. */ + if(od_control.baud == 0) + { + od_control.user_ansi = TRUE; + OD_API_EXIT(); + return; + } + + /* If user_ansi is not set, attempt to determine ANSI capabilities. */ + if(!od_control.user_ansi) + { + /* Clear inbound keyboard buffer. */ + od_clear_keybuffer(); + + /* Try twice to test ANSI capabilities. */ + for(nCount = 0; nCount < ANSI_TRIES; ++nCount) + { + /* Send a string that an ANSI capable terminal will usually */ + /* respond to. */ + od_disp(ANSI_QUERY, strlen(ANSI_QUERY), FALSE); + + /* Wait for response expected from an ANSI terminal, for up to */ + /* 12/18.2 second. */ + if(ODWaitNoCase(ANSI_RESPONSE, ANSI_WAIT)) + { + /* If expected sequence was received, turn on ANSI mode and */ + /* exit the loop. */ + od_control.user_ansi = TRUE; + break; + } + } + od_clear_keybuffer(); + } + + /* If user_rip is not set, attempt to determine RIP capabilities. */ + if(!od_control.user_rip) + { + /* Clear inbound keyboard buffer. */ + od_clear_keybuffer(); + + /* Try twice to test RIP capabilities. */ + for(nCount = 0; nCount < RIP_TRIES; ++nCount) + { + /* Send a string that a RIP capable terminal will usually */ + /* respond to. */ + od_disp(RIP_QUERY, strlen(RIP_QUERY), FALSE); + + /* Wait for response expected from a RIP terminal. */ + if(ODWaitNoCase(RIP_RESPONSE, RIP_WAIT)) + { + /* If expected sequence was received, turn on RIP mode and */ + /* exit the loop. */ + od_control.user_rip = TRUE; + break; + } + } + od_clear_keybuffer(); + } + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * ODWaitNoCase() *** PRIVATE FUNCTION *** + * + * Waits up to the specified maximum time for a specified string to be sent + * from the remote system. String matching is not case sensitive. + * + * Parameters: pszWaitFor - String to wait for. + * + * WaitTime - Maximum time, in milliseconds, to wait. + * + * Return: TRUE on success, FALSE on failure. + */ +static char ODWaitNoCase(char *pszWaitFor, tODMilliSec WaitTime) +{ + tODTimer Timer; + char szReceived[MATCH_LEN + 1]; + int nCount; + char chReceived; + int nMatchChars = MIN(MATCH_LEN, strlen(pszWaitFor)); + + ASSERT(pszWaitFor != NULL); + ASSERT(strlen(pszWaitFor) != 0); + ASSERT(WaitTime >= 0); + + ODTimerStart(&Timer, WaitTime); + + for(nCount = 0; nCount <= MATCH_LEN; ++nCount) + { + szReceived[nCount] = '\0'; + } + + do + { + if((chReceived = od_get_key(FALSE)) != 0) + { + for(nCount = 0; nCount < MATCH_LEN - 1; ++ nCount) + { + szReceived[nCount] = szReceived[nCount + 1]; + } + szReceived[MATCH_LEN - 1] = chReceived; + + if(strnicmp(szReceived + (MATCH_LEN - nMatchChars), pszWaitFor, + nMatchChars) == 0) + { + return(TRUE); + } + } + } while(!ODTimerElapsed(&Timer)); + + return(FALSE); +} diff --git a/utils/magiedit/odoors/ODBlock.c b/utils/magiedit/odoors/ODBlock.c new file mode 100644 index 0000000..dbb965b --- /dev/null +++ b/utils/magiedit/odoors/ODBlock.c @@ -0,0 +1,832 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODBlock.c + * + * Description: Implements the text block manipulation functions. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Aug 19, 1995 6.00 BP 32-bit portability. + * 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 Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODKrnl.h" + + +/* Set to TRUE when od_puttext() should leave the cursor in its original */ +/* position */ +static BOOL bScrollAction = TRUE; + + + +/* ---------------------------------------------------------------------------- + * od_puttext() + * + * Displays the contents of the buffer passed in block. Leaves cursor in + * original position, unless bScrollAction is FALSE. Leaves colour at + * original value. + * + * Parameters: nLeft - Column number of left edge of block of text to + * transfer, where 1 is the leftmost column of the + * screen. + * + * nTop - Row number of the top edge of block of text to + * to transfer, where 1 is the top row of the screen. + * + * nRight - Column number of the right edge of block. + * + * nBottom - Row number of bottom edge of block. + * + * pBlock - Pointer to buffer that has been filled in the format + * used by od_gettext(). + * + * Return: TRUE on success, FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_puttext(INT nLeft, INT nTop, INT nRight, INT nBottom, + void *pBlock) +{ + INT nRowLength = nRight - nLeft +1; + INT nRowBytes = nRowLength * 2; + char *pchTest; + char *pchMemory; + char *pBuffer=NULL; + char *pchScreenBlock; + INT nBlockRow = 0; + INT nOutRow; + INT nOutColour = 999; + INT nOutColumn, nCheckColumn; + char *pchMemBlock; + INT nMoveCost = od_control.user_avatar ? 4 : 7; + BYTE btMaxRight, btMaxBottom; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_puttext()"); + + /* Ensure that OpenDoors is initialized before proceeding. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Get current display setting profile. */ + ODScrnGetTextInfo(&ODTextInfo); + + /* Calculate the maximum values for bottom and right of block. */ + btMaxRight=ODTextInfo.winright-ODTextInfo.winleft+1; + btMaxBottom=ODTextInfo.winbottom-ODTextInfo.wintop+1; + + /* Check that parameters seem reasonable. */ + if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom + || nTop > nBottom || nLeft > nRight || pBlock==NULL) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Ensure that ANSI and/or AVATAR mode is available. */ + if(!od_control.user_ansi && !od_control.user_avatar) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(FALSE); + } + + /* If OpenDoors is operating in remote mode. */ + if(od_control.baud != 0) + { + /* Allocate temporary buffer to store original screen contents while */ + /* buffer paste is being performed. */ + if((pBuffer=malloc(nRowBytes*(nBottom-nTop+1)))==NULL) + { + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return(FALSE); + } + + /* Get current screen contents of area to be pasted into, storing */ + /* into the temporary buffer. */ + if(!ODScrnGetText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom, + pBuffer)) + { + od_control.od_error = ERR_PARAMETER; + free(pBuffer); + OD_API_EXIT(); + return(FALSE); + } + } + + /* Display the block to be pasted on the local screen. */ + if(!ODScrnPutText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom, + pBlock)) + { + od_control.od_error = ERR_PARAMETER; + if(pBuffer) + free(pBuffer); + OD_API_EXIT(); + return(FALSE); + } + + /* If operating in remote mode. */ + if(od_control.baud != 0) + { + /* Loop for each line in the buffer to be pasted */ + for(nOutRow=nTop;nOutRow<=nBottom;++nOutRow,++nBlockRow) + { + /* Setup pointer to beginning of line of original screen contents. */ + pchScreenBlock=(char *)pBuffer+(nRowBytes*nBlockRow); + + /* Setup pointer to beginning of line of block to be displayed. */ + pchMemBlock=(char *)pBlock+(nRowBytes*nBlockRow); + + /* Loop for each column on this line. */ + for(nOutColumn=0;nOutColumnnMoveCost) + { + nOutColumn=nCheckColumn; + /* If AVATAR mode is available. */ + if(od_control.user_avatar) + { + /* Advance cursor appropriate number of characters */ + /* using the AVATAR cursor position command. */ + szODWorkString[0]=22; + szODWorkString[1]=8; + szODWorkString[2]=nOutRow; + szODWorkString[3]=nLeft+nOutColumn; + od_disp(szODWorkString,4,FALSE); + } + else + { + /* Otherwise, advance cursor appropriate number of */ + /* characters using the ANSI cursor position command. */ + sprintf(szODWorkString,"x[%d;%dH",nOutRow,nLeft + nOutColumn); + szODWorkString[0]=27; + od_disp(szODWorkString,strlen(szODWorkString),FALSE); + } + } + + /* Output text for the number of characters found to be */ + /* different. */ + pchTest=(char *)&pchMemBlock[nOutColumn*2]; + for(;nOutColumn<=nCheckColumn;++nOutColumn) + { + if(pchTest[1] != nOutColour) + { + od_set_attrib(nOutColour=pchTest[1]); + } + od_disp(pchTest,1,FALSE); + pchTest++; + pchTest++; + } + } +next_line: + ; + } + + /* If not disabled, update cursor position. */ + if(bScrollAction) + { + od_set_cursor(ODTextInfo.cury,ODTextInfo.curx); + } + + /* Deallocate temporary buffer. */ + free(pBuffer); + } + + /* Restore the original display attribute. */ + od_set_attrib(ODTextInfo.attribute); + + /* Return with success. */ + OD_API_EXIT(); + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * od_gettext() + * + * Retrieves text from the screen (based on what is current displayed on the + * local display), storing it in the buffer provided by the caller. + * + * Parameters: nLeft - Column number of left edge of block of text to + * transfer, where 1 is the leftmost column of the + * screen. + * + * nTop - Row number of the top edge of block of text to + * to transfer, where 1 is the top row of the screen. + * + * nRight - Column number of the right edge of block. + * + * nBottom - Row number of bottom edge of block. + * + * pBlock - Pointer to buffer large enough to hold two bytes + * for each character in the block. + * + * Return: TRUE on success, FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_gettext(INT nLeft, INT nTop, INT nRight, INT nBottom, + void *pBlock) +{ + BYTE btMaxRight, btMaxBottom; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_gettext()"); + + /* Initialize OpenDoors if not already done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + ODScrnGetTextInfo(&ODTextInfo); + + btMaxRight=ODTextInfo.winright-ODTextInfo.winleft+1; + btMaxBottom=ODTextInfo.winbottom-ODTextInfo.wintop+1; + if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom || !pBlock) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + if(!od_control.user_ansi && !od_control.user_avatar) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(FALSE); + } + + OD_API_EXIT(); + return(ODScrnGetText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom, + pBlock)); +} + + +/* ---------------------------------------------------------------------------- + * od_scroll() + * + * Scrolls the specified area of the screen by the specified number of + * lines, in either the up or down directions. The cursor is left at its + * original locaiton, and the display attribute is left at its original + * setting. New lines are created in the current display colour. + * + * Parameters: nLeft - Column number of left edge of area to scroll, where + * 1 is the leftmost column of the screen. + * + * nTop - Row number of the top edge of the area to scroll, + * where 1 is the top row of the screen. + * + * nRight - Column number of the right edge of area to scroll. + * + * nBottom - Row number of bottom edge of area to scroll. + * + * nDistance - Number of lines to scroll the text. A value of 0 + * has no effect on the specified area, a positive + * value moves the text upwards (leaving blank lines + * at the bottom of the specified area), while a + * negative value moves the text upwards. If the + * distance is equal to the number of lines in the + * area, then the entire area is cleared. + * + * nFlags - Bitwise-or (|) of SCROLL_* flags. SCROLL_NORMAL + * is the default. SCROLL_NO_CLEAR does not clear + * the new area at the top/bottom of the scroll + * region if doing so would be slower. + * + * Return: TRUE on success, FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_scroll(INT nLeft, INT nTop, INT nRight, INT nBottom, + INT nDistance, WORD nFlags) +{ + BYTE btWidth, btHeight; + BYTE btCount; + BYTE btFirst, btLast; + char szAVTSeq[7]; + void *pBlock; + char szBlank[81]; + BYTE btKeepHeight; + BYTE btMaxRight; + BYTE btMaxBottom; + tODScrnTextInfo TextState; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_scroll()"); + + /* Ensure that OpenDoors has been initialized before proceeding. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Get current display setting information. */ + ODScrnGetTextInfo(&TextState); + + /* Determine the height and width of the area to be scrolled. */ + btWidth=nRight-nLeft+1; + btHeight=nBottom-nTop+1; + + /* Determine the number of lines currently in the area that will still */ + /* be visible after scrolling. */ + btKeepHeight=btHeight-((nDistance>=0) ? nDistance : -nDistance); + + /* Determine the maximum bottom and left coordinates of an area to be */ + /* scrolled. */ + btMaxRight=TextState.winright-TextState.winleft+1; + btMaxBottom=TextState.winbottom-TextState.wintop+1; + + /* Check that parameters are valid. */ + if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom || + nLeft > nRight || nTop > nBottom) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Check that ANSI or AVATAR graphics mode is available. */ + if(!od_control.user_ansi && !od_control.user_avatar) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(FALSE); + } + + /* If distance to be scrolled is 0, then we are finished already and */ + /* can return immediately. */ + if(nDistance == 0) + { + OD_API_EXIT(); + return(TRUE); + } + + /* If distance is positive, then we are moving text upwards. */ + if(nDistance>0) + { + /* Ensure that distance is not greater than size of scrolled area. */ + if(nDistance>btHeight) + { + nDistance=btHeight; + } + + /* Calculate first and last line to be moved. */ + btFirst=nBottom-(nDistance-1); + btLast=nBottom; + } + + /* If distance is negative, then we are moving text downwards. */ + else /* if(nDistance<0) */ + { + /* Ensure that distance is not greater than size of scrolled area. */ + if(nDistance<-btHeight) + { + nDistance=-btHeight; + } + + /* Calculate first and last line to be moved. */ + btFirst=nTop; + btLast=nTop-nDistance-1; + } + + /* If AVATAR mode is available */ + if(od_control.user_avatar) + { + /* Generate AVATAR sequence which causes the remote terminal to */ + /* scroll an area of its screen. */ + szAVTSeq[0]=22; + + /* If scrolling text upwards. */ + if(nDistance>0) + { + /* Specify control sequence for scrolling upwards. */ + szAVTSeq[1]=10; + szAVTSeq[2]=nDistance; + + /* Move text appropriate direction on local screen. */ + ODScrnCopyText((BYTE)nLeft, (BYTE)(nTop + nDistance), (BYTE)nRight, + (BYTE)nBottom, (BYTE)nLeft, (BYTE)nTop); + } + /* If scrolling text downwards. */ + else /* if(disatnce<0) */ + { + /* Specify control sequence for scrolling downwards. */ + szAVTSeq[1]=11; + szAVTSeq[2]=-nDistance; + + /* Move text appropriate direction on local screen. */ + ODScrnCopyText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, + (BYTE)(nBottom + nDistance), (BYTE)nLeft, (BYTE)(nTop - nDistance)); + } + + /* Specify area to be scrolled to the AVATAR terminal. */ + szAVTSeq[3]=nTop; + szAVTSeq[4]=nLeft; + szAVTSeq[5]=nBottom; + szAVTSeq[6]=nRight; + + /* Send the control sequence to the AVATAR terminal. */ + od_disp(szAVTSeq,7,FALSE); + + /* Generate string containing a blank line of text. */ + for(btCount=0;btCount0) + { + /* Allocate some temporary memory to hold text to be "got". */ + if((pBlock=malloc(btKeepHeight*btWidth*2))==NULL) + { + /* If memory allocation failed, then scrolling fails. */ + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return(FALSE); + } + + /* If we are scrolling text upwards. */ + if(nDistance > 0) + { + /* Move text that will still be visible, using od_gettext() */ + /* and od_puttext(). */ + od_gettext(nLeft,nTop+nDistance,nRight,nBottom,pBlock); + bScrollAction=FALSE; + od_puttext(nLeft,nTop,nRight,nBottom-nDistance,pBlock); + bScrollAction=TRUE; + } + + /* If we are scrolling text downwards. */ + else /* if(nDistance < 0) */ + { + /* Move text that will still be visible, using od_gettext() */ + /* and od_puttext(). */ + od_gettext(nLeft,nTop,nRight,nBottom+nDistance,pBlock); + bScrollAction=FALSE; + od_puttext(nLeft,nTop-nDistance,nRight,nBottom,pBlock); + bScrollAction=TRUE; + } + + /* Deallocate temporary memory block. */ + free(pBlock); + } + + /* If new area clearing has not been disabled. */ + if(!(nFlags&SCROLL_NO_CLEAR)) + { + /* Loop for lines that should be blank. */ + for(;btFirst<=btLast;++btFirst) + { + /* Move cursor to the beginning of this line. */ + od_set_cursor(btFirst,nLeft); + + /* If right boarder of area to be scrolled is the edge of the */ + /* screen, then we can use a quick control sequence to clear */ + /* the rest of the line. Call od_clr_line() to do this. */ + if(nRight == 80) + { + od_clr_line(); + } + + /* If right boarder of area to be scrolled is not at the edge */ + /* of the screen, then each line must be manually erased, by */ + /* sending the appropriate number of blanks (spaces). */ + else /* if(right != 80) */ + { + od_repeat(' ',btWidth); + } + } + } + + /* Reset the cursor to its original position. */ + od_set_cursor(TextState.cury,TextState.curx); + } + + /* Return with success */ + OD_API_EXIT(); + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * od_save_screen() + * + * Stores the contents of the entire screen into a buffer, along with + * the current cursor location and display colour. Supports all display + * modes. + * + * Parameters: pBuffer - Pointer to a buffer of at least 4004 bytes in size, + * where the information on the current screen state + * will be stored. + * + * Return: TRUE on success, FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_save_screen(void *pBuffer) +{ + char btHeight; + tODScrnTextInfo TextState; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_save_screen()"); + + /* Ensure that OpenDoors is initialized before proceeding. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check parameters and current output window size. */ + ODScrnGetTextInfo(&TextState); + if(TextState.winleft!=1 || TextState.winright!=80 || !pBuffer) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Store current cursor location in buffer. */ + ((char *)pBuffer)[0]=TextState.curx; + ((char *)pBuffer)[1]=TextState.cury; + + /* Store current display colour in buffer. */ + ((char *)pBuffer)[2]=TextState.attribute; + + /* Store height of buffer stored. */ + ((char *)pBuffer)[3]=btHeight=TextState.winbottom-TextState.wintop+1; + + /* Store screen contents using local screen gettext() function. */ + OD_API_EXIT(); + return(ODScrnGetText(1,1,80,btHeight,(char *)pBuffer+4)); +} + + +/* ---------------------------------------------------------------------------- + * od_restore_screen() + * + * Restores the screen contents, along with the current text colour and cursor + * location, as previously stored by od_save_screen(). + * + * Parameters: pBuffer - Pointer to buffer which was filled by a previous call + * to od_save_screen(). + * + * Return: TRUE on success, FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_restore_screen(void *pBuffer) +{ + char *pch; + char btPos; + char chLast; + char *pchTextBuffer; + char btHeight; + int nToReturn=TRUE; + tODScrnTextInfo TextState; + char btLine; + char btDistance=0; + char btCursorRow; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_restore_screen()"); + + /* Ensure that OpenDoors is initialized before proceeding. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check parameters and current output window size. */ + ODScrnGetTextInfo(&TextState); + if(TextState.winleft!=1 || TextState.winright!=80 || !pBuffer) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Determine current window height were text will be restored. */ + btHeight=TextState.winbottom-TextState.wintop+1; + + /* If current display window height is too small for entire buffer */ + /* to be re-displayed. */ + if(btHeight<((char *)pBuffer)[3]) + { + /* Then we will always display as much of the END of the buffer */ + /* as possible. */ + btDistance = btHeight - ((char *)pBuffer)[3]; + } + else if(btHeight > ((char *)pBuffer)[3]) + { + /* Otherwise, ensure that we don't try to display more lines that */ + /* are in the buffer. */ + btHeight=((char *)pBuffer)[3]; + } + + /* Clear the remote and local screens. */ + od_clr_scr(); + + /* If ANSI or AVATAR modes are available. */ + if(od_control.user_avatar || od_control.user_ansi) + { + /* Then we can efficiently display the buffer using od_puttext(). */ + bScrollAction=FALSE; + nToReturn=od_puttext(1,1,80,btHeight,(char *)pBuffer+(4+((int)btDistance*160))); + bScrollAction=TRUE; + + /* Restore original cursor location. */ + od_set_cursor(((char *)pBuffer)[1],((char *)pBuffer)[0]); + + /* Restore original display attribute. */ + od_set_attrib(((char *)pBuffer)[2]); + } + + /* If we are operating in ASCII mode. */ + else /* if (!od_control.od_avatar && !od_control.caller_ansi) */ + { + /* Then the buffer is displayed one line at a time, beginning */ + /* at the top of the screen, up to the saved cusrsor location. */ + + /* Set pointer to beginning of buffer to be displayed. */ + pchTextBuffer=(char *)pBuffer+4; + + /* Get final cursor row number. */ + btCursorRow=((char *)pBuffer)[1]; + + /* Loop for each line in the buffer. */ + for(btLine=1;btLine<=btHeight;++btLine) + { + /* Set pointer to last character of line. */ + pch=(char *)pchTextBuffer+158; + + /* Loop backwards until a non-blank character is found, or we */ + /* reach the beginning of the line. */ + for(chLast=80;chLast>1;) + { + /* If this is a blank character. */ + if(*pch==32 || *pch==0) + { + /* Move to previous character. */ + --chLast; + pch-=2; + } + + /* If this is not a blank character, then stop looping. */ + else + { + break; + } + } + + /* If this is the line on which the cursor resides. */ + if(btLine==btCursorRow) + { + /* If last non-blank character of line is at or past the final */ + /* cursor location, then we backup the last character to be */ + /* displayed to the cursor before the final cursor position. */ + /* This code could be improved to be able to display text on */ + /* the entire cursor line by displaying the entire line, */ + /* sending a C/R, and redisplaying first portion of line to */ + /* end up with the cursor in the desired position. */ + if(chLast>=((char *)pBuffer)[0]) + { + chLast=((char *)pBuffer)[0]-1; + } + } + + /* Display all characters on this line */ + pch = (char *)pchTextBuffer; + for(btPos=1;btPos<=chLast;++btPos) + { + od_putch(*pch); + pch+=2; + } + + /* If this is the row where the cursor should be left, then we */ + /* stop displaying now. */ + if(btLine==btCursorRow) + { + break; + } + + /* If cursor hasn't been wrapped, then we should send a C/R - */ + /* L/F sequence. */ + if(chLast != 80) + { + od_disp_str("\n\r"); + pchTextBuffer+=160; + } + } + } + + /* Return with the appropriate success/failure status. */ + OD_API_EXIT(); + return(nToReturn); +} diff --git a/utils/magiedit/odoors/ODCFile.c b/utils/magiedit/odoors/ODCFile.c new file mode 100644 index 0000000..dc311fd --- /dev/null +++ b/utils/magiedit/odoors/ODCFile.c @@ -0,0 +1,933 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODCFile.c + * + * Description: Implements the configuration file sub-system. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Nov 11, 1995 6.00 BP 32-bit portability. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 01, 1996 6.00 BP Added DisableDTR and NoDTRDisable. + * Jan 19, 1996 6.00 BP Display error if config file not found + * 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. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODInEx.h" +#include "ODUtil.h" + + +/* Internal private variables */ +static WORD awTimeVal[3]; +static BYTE btTimeNumVals; + + +/* Local functions. */ +static WORD ODCfgGetWordDecimal(char *pszConfigText); +static DWORD ODCfgGetDWordDecimal(char *pszConfigText); +static WORD ODCfgGetWordHex(char *pszConfigText); +static void ODCfgGetNextTime(char **ppchConfigText); +static BOOL ODCfgIsTrue(char *pszConfigText); + + +/* ---------------------------------------------------------------------------- + * ODConfigInit() + * + * Called to perform OpenDoors initialization when the configuration file + * system is being used. This function is called from the normal od_init(), + * and also uses the normal od_init() to perform base initialization after + * the configuration file has been read, but before certain configuration + * settings are set in od_control. + * + * Parameters: none + * + * Return: void + */ +ODAPIDEF void ODCALL ODConfigInit(void) +{ + void (*custom_line_function)(char *keyword, char *options) + = od_control.config_function; + char *pchConfigText; + WORD wCurrent; + INT nConfigOption; + BOOL bConfigFileRequired = TRUE; + static FILE *pfConfigFile; + static FILE *pfCustomDropFile = NULL; + static char szConfigLine[257]; + static char szToken[33]; + static char szTempString[256]; + static char szWorkDir[80]; + static BOOL bWorkDirSet = FALSE; + static time_t nUnixTime; + static struct tm *TimeBlock; + static INT16 nPageStart; + static INT16 nPageEnd; + static BOOL bPageSet = FALSE; + static BOOL bInactivitySet = FALSE; + static INT16 nInactivity; + static char *pszWork; + static BOOL bPageLengthSet = FALSE; + static BYTE btPageLength; + static char *apszFileNames[1]; + + bIsCallbackActive = TRUE; + + nUnixTime = time(NULL); + TimeBlock = localtime(&nUnixTime); + + /* Use default configuration file filename if none has been specified. */ + if(od_control.od_config_filename == NULL) + { + od_control.od_config_filename = "door.cfg"; + bConfigFileRequired = FALSE; + } + + if((pfConfigFile = fopen(od_control.od_config_filename, "rt")) == NULL) + { + if(strchr(od_control.od_config_filename, DIRSEP) != NULL + || strchr(od_control.od_config_filename, ':') != NULL) + { + wCurrent = strlen(od_control.od_config_filename); + pchConfigText = (char *)od_control.od_config_filename + (wCurrent - 1); + while(wCurrent > 0) + { + if(*pchConfigText == DIRSEP || *pchConfigText == ':') + { + strcpy(szConfigLine, (char *)pchConfigText + 1); + pfConfigFile = fopen(szConfigLine, "rt"); + break; + } + + --pchConfigText; + --wCurrent; + } + } + else + { + strcpy(szConfigLine, od_control.od_config_filename); + } + } + + /* If we were able to open the configuration file. */ + if(pfConfigFile != NULL) + { + /* Get configuration file strings in upper case. */ + for(wCurrent = 0; wCurrent < TEXT_SIZE; ++wCurrent) + { + strupr(od_config_text[wCurrent]); + } + for(wCurrent = 0; wCurrent < LINES_SIZE; ++wCurrent) + { + strupr(od_config_lines[wCurrent]); + } + + for(;;) + { + /* Read the next line from the configuration file. */ + if(fgets(szConfigLine, 257, pfConfigFile) == NULL) break; + + /* Ignore all of line after comments or CR/LF char. */ + pchConfigText = (char *)szConfigLine; + while(*pchConfigText) + { + if(*pchConfigText == '\n' || *pchConfigText == '\r' + || *pchConfigText == ';') + { + *pchConfigText = '\0'; + break; + } + ++pchConfigText; + } + + /* Search for beginning of first token on line. */ + pchConfigText = (char *)szConfigLine; + while(*pchConfigText + && (*pchConfigText == ' ' || *pchConfigText == '\t')) + { + ++pchConfigText; + } + if(!*pchConfigText) continue; + + /* Get first token from line. */ + wCurrent = 0; + while(*pchConfigText + && !(*pchConfigText == ' ' || *pchConfigText == '\t')) + { + if(wCurrent < 32) szToken[wCurrent++] = *pchConfigText; + ++pchConfigText; + } + if(wCurrent <= 32) + { + szToken[wCurrent] = '\0'; + } + else + { + szToken[32] = '\0'; + } + strupr(szToken); + + /* Find beginning of configuration option parameters */ + while(*pchConfigText && (*pchConfigText == ' ' + || *pchConfigText == '\t')) + { + ++pchConfigText; + } + + /* Trim trailing spaces from setting string. */ + for(wCurrent = strlen(pchConfigText) - 1; wCurrent > 0; --wCurrent) + { + if(pchConfigText[wCurrent] == ' ' + || pchConfigText[wCurrent] == '\t') + { + pchConfigText[wCurrent] = '\0'; + } + else + { + break; + } + } + + + for(wCurrent = 0; wCurrent < TEXT_SIZE; ++wCurrent) + { + if(strcmp(szToken, od_config_text[wCurrent]) == 0) + { + switch(wCurrent) + { + case 0: + wODNodeNumber = ODCfgGetWordDecimal(pchConfigText); + break; + + case 1: + strcpy(od_control.info_path,pchConfigText); + break; + + case 2: + if(pchConfigText[strlen(pchConfigText) - 1] == DIRSEP + && pchConfigText[strlen(pchConfigText) - 2] != ':' + && strlen(pchConfigText) > 1) + { + pchConfigText[strlen(pchConfigText) - 1] = '\0'; + } + + szOriginalDir = (char *)malloc(256); + if(szOriginalDir != NULL) + { + ODDirGetCurrent(szOriginalDir, 256); + } + + strcpy(szWorkDir, pchConfigText); + bWorkDirSet = TRUE; + break; + + case 3: + strcpy(od_control.od_logfile_name, pchConfigText); + break; + + case 4: + od_control.od_logfile_disable = TRUE; + break; + + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + if((wCurrent - 5) == (WORD)TimeBlock->tm_wday) + { + ODCfgGetNextTime((char **)&pchConfigText); + nPageStart = awTimeVal[0] * 60 + awTimeVal[1]; + ODCfgGetNextTime((char **)&pchConfigText); + nPageEnd = awTimeVal[0] * 60 + awTimeVal[1]; + bPageSet = TRUE; + } + break; + + case 12: + od_control.od_maxtime = ODCfgGetWordDecimal(pchConfigText); + break; + + case 13: + bSysopNameSet = TRUE; + strncpy((char *)&szForcedSysopName, pchConfigText, 39); + szForcedSysopName[39] = '\0'; + break; + + case 14: + bSystemNameSet = TRUE; + strncpy((char *)&szForcedSystemName, pchConfigText, 39); + szForcedSystemName[39] = '\0'; + break; + + case 15: + od_control.od_swapping_disable = TRUE; + break; + + case 16: + strncpy(od_control.od_swapping_path, pchConfigText, 79); + od_control.od_swapping_path[79] = '\0'; + break; + + case 17: + od_control.od_swapping_noems = TRUE; + break; + + case 18: + dwForcedBPS = ODCfgGetDWordDecimal(pchConfigText); + break; + + case 19: + nForcedPort = ODCfgGetWordDecimal(pchConfigText); + break; + + case 20: + if(pfCustomDropFile == NULL && !od_control.od_force_local) + { + apszFileNames[0] = (char *)pchConfigText; + if(ODSearchForDropFile(apszFileNames, 1, szTempString, + NULL) != -1) + { + if((pfCustomDropFile = fopen(szTempString, "rt")) + != NULL) + { + od_control.od_info_type = CUSTOM; + od_control.user_attribute = 0x06; + od_control.user_screen_length = 23; + od_control.user_ansi = TRUE; + od_control.user_rip = FALSE; + od_control.user_avatar = FALSE; + od_control.od_page_pausing = TRUE; + od_control.od_page_len = 15; + od_control.user_timelimit = 0; + strcpy(od_control.user_name, "Unknown User"); + strcpy(od_control.user_location, + "Unknown Location"); + od_control.user_security = 1; + } + } + } + break; + + case 21: + if(pfCustomDropFile != NULL) + { + if(fgets(szTempString, 255, pfCustomDropFile)!=NULL) + { + if(szTempString[strlen(szTempString) - 1] == '\n') + { + szTempString[strlen(szTempString) - 1] = '\0'; + } + else + { + INT ch; + do + { + ch = fgetc(pfCustomDropFile); + } while(ch != '\n' && ch != EOF); + } + if(szTempString[strlen(szTempString) - 1] == '\r') + { + szTempString[strlen(szTempString) - 1] = '\0'; + } + + strupr(pchConfigText); + + for(nConfigOption = 0; nConfigOption < LINES_SIZE; + ++nConfigOption) + { + if(strcmp(pchConfigText, + od_config_lines[nConfigOption]) == 0) + { + switch(nConfigOption) + { + case 1: + od_control.port = + ODCfgGetWordDecimal(szTempString) - 1; + break; + + case 2: + od_control.port = + ODCfgGetWordDecimal(szTempString); + break; + + case 3: + od_control.baud = + ODCfgGetWordDecimal(szTempString); + break; + + case 4: + if(ODCfgIsTrue(szTempString)) + { +#ifdef ODPLAT_NIX + od_control.baud = 1; +#else + od_control.baud = 0; +#endif + } + break; + + case 5: + case 6: + ODStringToName(szTempString); + strncpy(od_control.user_name, + szTempString, 34); + od_control.user_name[34] = '\0'; + break; + + case 7: + strcat(od_control.user_name, " "); + ODStringToName(szTempString); + strncat(od_control.user_name, + szTempString, + 35 - strlen(od_control.user_name)); + od_control.user_name[35] = '\0'; + break; + + case 8: + ODStringToName(szTempString); + strncpy(od_control.user_handle, + szTempString, 35); + od_control.user_handle[35] = '\0'; + break; + + case 9: + pszWork = (char *)szTempString; + ODCfgGetNextTime((char **)&pszWork); + od_control.user_timelimit += + (awTimeVal[0] * 60); + break; + + case 10: + pszWork = (char *)szTempString; + ODCfgGetNextTime((char **)&pszWork); + if(btTimeNumVals <= 1) + { + od_control.user_timelimit += + awTimeVal[0]; + } + else + { + od_control.user_timelimit += + awTimeVal[1] + (awTimeVal[0] * 60); + } + break; + + case 11: + pszWork = (char *)szTempString; + ODCfgGetNextTime((char **)&pszWork); + if(btTimeNumVals <= 1) + { + od_control.user_timelimit += + awTimeVal[0] / 60; + } + else if(btTimeNumVals == 2) + { + od_control.user_timelimit += + (awTimeVal[1] / 60) + awTimeVal[0]; + } + else + { + od_control.user_timelimit += + (awTimeVal[2] / 60) + awTimeVal[1] + + (awTimeVal[0] * 60); + } + break; + + case 12: + od_control.user_ansi = + ODCfgIsTrue(szTempString); + break; + + case 13: + od_control.user_avatar = + ODCfgIsTrue(szTempString); + break; + + case 14: + od_control.od_page_pausing = + ODCfgIsTrue(szTempString); + break; + + case 15: + od_control.user_screen_length = + ODCfgGetWordDecimal(szTempString); + break; + + case 16: + if(ODCfgIsTrue(szTempString)) + { + od_control.user_attribute |= 0x02; + } + else + { + od_control.user_attribute &=~ 0x02; + } + break; + + case 17: + od_control.user_security = + ODCfgGetWordDecimal(szTempString); + break; + + case 18: + ODStringToName(szTempString); + strncpy(od_control.user_location, + szTempString, 25); + od_control.user_location[25] = '\0'; + break; + + case 19: + wODNodeNumber = + ODCfgGetWordDecimal(szTempString); + break; + + case 20: + case 21: + ODStringToName(szTempString); + strncpy(od_control.sysop_name, + szTempString, 38); + od_control.sysop_name[38] = '\0'; + break; + + case 22: + strcat(od_control.sysop_name, " "); + ODStringToName(szTempString); + strncat(od_control.sysop_name, + szTempString, + 39 - strlen(od_control.system_name)); + od_control.sysop_name[39] = '\0'; + break; + + case 23: + strncpy(od_control.system_name, + szTempString, 39); + od_control.system_name[39] = '\0'; + break; + + case 24: + od_control.user_rip = + ODCfgIsTrue(szTempString); + } + } + } + } + } + break; + + case 22: + bInactivitySet = TRUE; + nInactivity = ODCfgGetWordDecimal(pchConfigText); + if(nInactivity < 0) nInactivity = 0; + break; + + case 23: + btPageLength = (BYTE)ODCfgGetWordDecimal(pchConfigText); + bPageLengthSet = TRUE; + break; + + case 24: + od_control.od_chat_color2 = + od_color_config(pchConfigText); + break; + + case 25: + od_control.od_chat_color1 = + od_color_config(pchConfigText); + break; + + case 26: + od_control.od_list_title_col = + od_color_config(pchConfigText); + break; + + case 27: + od_control.od_list_name_col = + od_color_config(pchConfigText); + break; + + case 28: + od_control.od_list_size_col = + od_color_config(pchConfigText); + break; + + case 29: + od_control.od_list_comment_col = + od_color_config(pchConfigText); + break; + + case 30: + od_control.od_list_offline_col = + od_color_config(pchConfigText); + break; + + case 31: + strncpy(szDesiredPersonality, pchConfigText, 32); + szDesiredPersonality[32] = '\0'; + break; + + case 32: + /* "NoFossil" */ + od_control.od_no_fossil = TRUE; + break; + + case 33: + /* "PortAddress" */ + od_control.od_com_address = ODCfgGetWordHex(pchConfigText); + break; + + case 34: + /* "PortIRQ" */ + od_control.od_com_irq = + (char)ODCfgGetWordDecimal(pchConfigText); + break; + + case 35: + /* "ReceiveBuffer" */ + od_control.od_com_rx_buf = + ODCfgGetWordDecimal(pchConfigText); + break; + + case 36: + /* "TransmitBuffer" */ + od_control.od_com_tx_buf = + ODCfgGetWordDecimal(pchConfigText); + break; + + case 37: + /* "PagePromptColour" */ + od_control.od_continue_col = + od_color_config(pchConfigText); + break; + + case 38: + /* "LocalMode" */ + od_control.od_force_local = TRUE; + break; + + case 39: + /* "PopupMenuTitleColour" */ + od_control.od_menu_title_col = + od_color_config(pchConfigText); + break; + + case 40: + /* "PopupMenuBorderColour" */ + od_control.od_menu_border_col = + od_color_config(pchConfigText); + break; + + case 41: + /* "PopupMenuTextColour" */ + od_control.od_menu_text_col = + od_color_config(pchConfigText); + break; + + case 42: + /* "PopupMenuKeyColour" */ + od_control.od_menu_key_col = + od_color_config(pchConfigText); + break; + + case 43: + /* "PopupMenuHighlightColour" */ + od_control.od_menu_highlight_col = + od_color_config(pchConfigText); + break; + + case 44: + /* "PopupMenuHighKeyColour" */ + od_control.od_menu_highkey_col = + od_color_config(pchConfigText); + break; + + case 45: + /* "NoFIFO" */ + od_control.od_com_no_fifo = TRUE; + break; + + case 46: + /* "FIFOTriggerSize" */ + od_control.od_com_fifo_trigger = + (BYTE)ODCfgGetWordDecimal(pchConfigText); + break; + + case 47: + /* "DisableDTR" */ + ODStringCopy(od_control.od_disable_dtr, pchConfigText, + sizeof(od_control.od_disable_dtr)); + break; + + case 48: + /* "NoDTRDisable" */ + od_control.od_disable |= DIS_DTR_DISABLE; + break; + } + } + } + + /* Check if command is a programmer customized option. */ + if(wCurrent >= TEXT_SIZE && custom_line_function != NULL) + { + (*custom_line_function)((char *)&szToken, pchConfigText); + } + } + + /* Close the configuration file. */ + fclose(pfConfigFile);} + else + { + if(bConfigFileRequired) + { + od_control.od_error = ERR_FILEOPEN; + ODInitError("Unable to access configuration file."); + exit(od_control.od_errorlevel[1]); + } + } + + /* Close custom door info file */ + if(pfCustomDropFile != NULL) + { + fclose(pfCustomDropFile); + } + + bIsCallbackActive = FALSE; + + /* Carry out normal OpenDoors initialization. */ + bCalledFromConfig = TRUE; + od_init(); + bCalledFromConfig = FALSE; + + /* Update any settings that need to be updated. */ + if(bPageSet) + { + od_control.od_pagestartmin = nPageStart; + od_control.od_pageendmin = nPageEnd; + } + + if(bInactivitySet && nInactivity != 0) + { + od_control.od_inactivity = nInactivity; + } + + if(bSysopNameSet) + { + strcpy((char *)&od_control.sysop_name, (char *)&szForcedSysopName); + } + + if(bSystemNameSet) + { + strcpy((char *)&od_control.system_name, (char *)&szForcedSystemName); + } + + if(bPageLengthSet) + { + od_control.od_page_len = btPageLength; + } + + if(bWorkDirSet) + { + ODDirChangeCurrent(szWorkDir); + } +} + + +/* ---------------------------------------------------------------------------- + * ODCfgGetWordDecimal() *** PRIVATE FUNCTION *** + * + * Obtains the value of the next decimal number in the provided string, in the + * form of a WORD (16 bit value). + * + * Parameters: pszConfigText - String to examine. + * + * Return: The first number obtained from the string. + */ +static WORD ODCfgGetWordDecimal(char *pszConfigText) +{ + ASSERT(pszConfigText != NULL); + + /* Skip any initial non-numerical characters. */ + while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9')) + { + ++pszConfigText; + } + + /* Return value of number. */ + return(atoi(pszConfigText)); +} + + +/* ---------------------------------------------------------------------------- + * ODCfgGetDWordDecimal() *** PRIVATE FUNCTION *** + * + * Obtains the value of the next decimal number in the provided string, in the + * form of a DWORD (32 bit value). + * + * Parameters: pszConfigText - String to examine. + * + * Return: The first number obtained from the string. + */ +static DWORD ODCfgGetDWordDecimal(char *pszConfigText) +{ + ASSERT(pszConfigText != NULL); + + /* Skip any initial non-numerical characters. */ + while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9')) + { + ++pszConfigText; + } + + /* Return value of number. */ + return(atol(pszConfigText)); +} + + +/* ---------------------------------------------------------------------------- + * ODCfgGetWordHex() *** PRIVATE FUNCTION *** + * + * Obtains the value of the next hexidecimal number in the provided string, in + * the form of a WORD (16 bit value). + * + * Parameters: pszConfigText - String to examine. + * + * Return: The first number obtained from the string. + */ +static WORD ODCfgGetWordHex(char *pszConfigText) +{ + WORD wToReturn; + + ASSERT(pszConfigText != NULL); + + /* Skip any initial non-hexidecimal characters. */ + while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9') + && (toupper(*pszConfigText) < 'A' || toupper(*pszConfigText) > 'F')) + { + ++pszConfigText; + } + + sscanf(pszConfigText, "%x", &wToReturn); + + return(wToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODCfgGetNextTime() *** PRIVATE FUNCTION *** + * + * Obtains the next time from a string, updating the string pointer to point to + * the position in the string after the end of the time. The time information + * is stored in the btTimeNumVals and awTimeVal private global variables. + * + * Parameters: ppchConfigText - Pointer to character pointer to the string, + * which is to be updated. + * + * Return: void + */ +static void ODCfgGetNextTime(char **ppchConfigText) +{ + char *pchConfigText = (char *)(*ppchConfigText); + + ASSERT(ppchConfigText != NULL); + ASSERT(*ppchConfigText != NULL); + + btTimeNumVals = 0; + awTimeVal[0] = 0; + awTimeVal[1] = 0; + awTimeVal[2] = 0; + + + while(*pchConfigText && (*pchConfigText == ' ' || *pchConfigText == '\t')) + { + ++pchConfigText; + } + + + while(*pchConfigText && btTimeNumVals < 3) + { + if(*pchConfigText < '0' || *pchConfigText > '9') break; + awTimeVal[btTimeNumVals++] = atoi(pchConfigText); + while(*pchConfigText && *pchConfigText >= '0' && *pchConfigText <= '9') + { + ++pchConfigText; + } + if(*pchConfigText == ':' || *pchConfigText == '.' || *pchConfigText == ',' + || *pchConfigText == ';') + { + ++pchConfigText; + } + } + + *ppchConfigText = (char *)pchConfigText; +} + + +/* ---------------------------------------------------------------------------- + * ODCfgIsTrue() *** PRIVATE FUNCTION *** + * + * Determines whether the specified string represents a TRUE or FALSE value. + * For example "Yes", "TRUE", "Y" and "1" all represent TRUE values, while + * "No", "FALSE", "N" and "0" all represent FALSE values. + * + * Parameters: pszConfigText - String to examine. + * + * Return: The Boolean value represented by the string. + */ +static BOOL ODCfgIsTrue(char *pszConfigText) +{ + ASSERT(pszConfigText != NULL); + + while(*pszConfigText && (*pszConfigText == ' ' || *pszConfigText == '\t')) + { + ++pszConfigText; + } + + switch(*pszConfigText) + { + case '1': + case 't': + case 'T': + case 'y': + case 'Y': + case 'g': + case 'G': + return(TRUE); + } + + return(FALSE); +} diff --git a/utils/magiedit/odoors/ODCmdLn.c b/utils/magiedit/odoors/ODCmdLn.c new file mode 100644 index 0000000..5d0da98 --- /dev/null +++ b/utils/magiedit/odoors/ODCmdLn.c @@ -0,0 +1,664 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODCmdLn.c + * + * Description: Implementation of od_parse_cmd_line() function, which + * parses standard command-line parameters for OpenDors programs. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Jan 29, 1995 6.00 BP Created. + * Aug 19, 1995 6.00 BP Cleaned up indentations. + * Nov 12, 1995 6.00 BP 32-bit portability. + * Nov 12, 1995 6.00 BP Added -CONFIG parameter. + * Dec 21, 1995 6.00 BP Added -HANDLE parameter. + * Dec 24, 1995 6.00 BP puts() -> printf(). + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 03, 1996 6.00 BP Recognize -D for -DROPFILE. + * Jan 03, 1996 6.00 BP Parameters must begin with - or /. + * Feb 06, 1996 6.00 BP Added -SILENT for od_silent_mode. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 20, 1996 6.00 BP Added bParsedCmdLine. + * Feb 21, 1996 6.00 BP Make cmd line options overriding. + * Feb 25, 1996 6.00 BP Fix -P COMx. + * Feb 27, 1996 6.00 BP Add -P COMx to command line help. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Apr 08, 1996 6.10 BP Added command-line parsing callbacks. + * Apr 24, 2002 6.22 RS Added -SOCKET parameter. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODPlat.h" +#include "ODCore.h" +#include "ODInEx.h" + + +/* Maximum number of command-line arguments. Any additional arguments will */ +/* simply be ignored. */ +#define MAX_ARGS 32 + +/* Size of temporary string that will hold any options following custom */ +/* command-line keywords that are passed to the client application's handler */ +/* function. */ +#define CUSTOM_OPTION_SIZE 80 + +/* Command-line parameter identifiers. */ +typedef enum +{ + kParamConfigFile, + kParamLocal, + kParamBPS, + kParamPort, + kParamNode, + kParamHelp, + kParamPersonality, + kParamMaxTime, + kParamAddress, + kParamIRQ, + kParamNoFOSSIL, + kParamNoFIFO, + kParamDropFile, + kParamUserName, + kParamTimeLeft, + kParamSecurity, + kParamLocation, + kParamGraphics, + kParamBBSName, + kParamPortHandle, + kParamSocketDescriptor, + kParamSilentMode, + kParamOption, + kParamUnknown +} tCommandLineParameter; + + +/* Private function prototypes. */ +static void ODAdvanceToNextArg(INT *pnCurrentArg, INT nArgCount, + char *pszOption); +static void ODGetNextArgName(INT *pnCurrentArg, INT nArgCount, + char *papszArguments[], char *pszString, size_t nStringSize); +static tCommandLineParameter ODGetCommandLineParameter(char *pszArgument); + + +/* Private variables. */ +#define CONFIG_FILENAME_SIZE 80 +static char szConfigFilename[CONFIG_FILENAME_SIZE]; + + +/* ---------------------------------------------------------------------------- + * od_parse_cmd_line() + * + * Function to parse an OpenDoors program's command-line, interpreting + * standard command-line parameters. This is one of the few OpenDoors APIs + * that will not automatically initialize OpenDoors if it hasn't already + * been done. This is because od_parse_cmd_line() performs setup that must + * be done prior to OpenDoors initialization. + * + * Parameters: FOR NON-WIN32 VERSIONS: + * + * nArgCount - Number of command line arguments, as passed to + * main() in argc. + * + * papszArguments - Pointer to array of pointers to string + * arguments, as passed to main() in argv. The + * first element of this array (usually the + * full path and filename of the executable) + * is ignored. + * + * FOR WIN32 VERSION: + * + * pszCmdLine - Pointer to the command line string, as passed + * to WinMain(). + * + * Return: void + */ +#ifdef ODPLAT_WIN32 +ODAPIDEF void ODCALL od_parse_cmd_line(LPSTR pszCmdLine) +#else /* !ODPLAT_WIN32 */ +ODAPIDEF void ODCALL od_parse_cmd_line(INT nArgCount, char *papszArguments[]) +#endif /* !ODPLAT_WIN32 */ +{ + char *pszCurrentArg; + INT nCurrentArg; + INT n; +#ifdef ODPLAT_WIN32 + INT nArgCount; + char *papszArguments[MAX_ARGS]; + char *pszCmdLineCopy; + char *pchCurrent +#endif /* ODPLAT_WIN32 */ + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_parse_cmd_line()"); + +#ifdef ODPLAT_WIN32 + /* Attempt to allocate space for a copy of the command line. */ + pszCmdLineCopy = malloc(strlen(pszCmdLine) + 1); + if(pszCmdLineCopy == NULL) + { + od_control.od_error = ERR_MEMORY; + return; + } + + /* Copy the command line text into our working copy. */ + strcpy(pszCmdLineCopy, pszCmdLine); + + /* Loop, building papszArguments and nArgCount. */ + pchCurrent = pszCmdLineCopy; + for(nArgCount = 0; nArgCount < MAX_ARGS && *pchCurrent != '\0'; ++nArgCount) + { + /* Store address of the next command line argument. */ + papszArguments[nArgCount] = pchCurrent; + + /* Skip forward to the next white space. */ + while(*pchCurrent != '\0' && !isspace(*pchCurrent)) + { + ++pchCurrent; + } + + /* Replace white space characters with '\0' string terminators, until */ + /* we reach the next command line argument, or the end of the string. */ + while(*pchCurrent != '\0' && isspace(*pchCurrent)) + { + *pchCurrent = '\0'; + ++pchCurrent; + } + } +#endif /* ODPLAT_WIN32 */ + +#ifndef ODPLAT_WIN32 + /* Check validity of parameters. */ + if(papszArguments == NULL) + { + od_control.od_error = ERR_PARAMETER; + return; + } +#endif /* !ODPLAT_WIN32 */ + + /* Record that od_parse_cmd_line() has been called. */ + bParsedCmdLine = TRUE; + + /* Initialize variables that are not initialized in od_init() if */ + /* od_parse_cmd_line is specified. */ + od_control.user_ansi = TRUE; + od_control.user_timelimit = 60; + +#ifdef ODPLAT_WIN32 + for(nCurrentArg = 0; nCurrentArg < nArgCount; ++nCurrentArg) +#else /* !ODPLAT_WIN32 */ + for(nCurrentArg = 1; nCurrentArg < nArgCount; ++nCurrentArg) +#endif /* !ODPLAT_WIN32 */ + { + pszCurrentArg = papszArguments[nCurrentArg]; + + switch(ODGetCommandLineParameter(pszCurrentArg)) + { + case kParamConfigFile: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + strncpy(szConfigFilename, papszArguments[nCurrentArg], + sizeof(szConfigFilename) - 1); + szConfigFilename[sizeof(szConfigFilename) - 1] = '\0'; + od_control.od_config_filename = szConfigFilename; + break; + + case kParamLocal: + od_control.od_force_local = TRUE; + break; + + case kParamBPS: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.baud = atol(papszArguments[nCurrentArg]); + wPreSetInfo |= PRESET_BPS; + break; + + case kParamPort: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + if(strnicmp(papszArguments[nCurrentArg], "COM", 3) == 0) + { + od_control.port = atoi(papszArguments[nCurrentArg] + 3) - 1; + } + else + { + od_control.port = atoi(papszArguments[nCurrentArg]); + } + wPreSetInfo |= PRESET_PORT; + break; + + case kParamHelp: + if(od_control.od_cmd_line_help_func != NULL) + { + (*od_control.od_cmd_line_help_func)(); + exit(0); + } + +#ifdef ODPLAT_WIN32 + sprintf(szODWorkString, "%s Command Line Options", + strlen(od_control.od_prog_name) > 0 ? od_control.od_prog_name + : OD_VER_SHORTNAME); + if(od_control.od_cmd_line_help != NULL) + { + MessageBox(NULL, od_control.od_cmd_line_help, szODWorkString, + MB_ICONINFORMATION | MB_OK); + } + else + { + MessageBox(NULL, + "(Note that some options can be overriden by configuration or drop files.)\n" + "\n" + "-C x or -CONFIG x\t- Specfies configuration filename.\n" + "-L or -LOCAL\t- Causes door to operate in local mode, without requiring a drop file.\n" + "-D or -DROPFILE x\t- Door information file directory and/or filename.\n" + "-N x or -NODE x\t- Sets the node number to use.\n" + "-B x or -BPS x\t- Sets the serial port <---> modem bps (baud) rate to use.\n" + "-P x or -PORT x\t- Sets serial port to use. For COM1: use -P 0 or -P COM1, for COM2: use -P 1 or -P COM2, etc.\n" + "-HANDLE x\t- Provides an already open serial port handle.\n" + "-SOCKET x\t- Provides an already open TCP/IP socket descriptor.\n" + "-SILENT\t\t- Operate in silent mode, with no local display.\n" + "-MAXTIME x\t- Sets the maximum number of minutes that user will be permitted to access the door.\n" + "-G or -GRAPHICS\t- Unless followed by 0 or N, turns on ANSI display mode.\n" + "-BBSNAME x\t- Name of BBS.\n" + "-USERNAME x\t- Name of user who is currently online.\n" + "-TIMELEFT x\t- User's time remaining online.\n" + "-SECURITY x\t- User's security level.\n" + "-LOCATION x\t- Location from which user is calling.\n" + "-?, -H or -HELP\t- Displays command-line help and exits.", + szODWorkString, MB_ICONINFORMATION | MB_OK); + } +#else /* !ODPLAT_WIN32 */ + printf("AVALIABLE COMMAND LINE OPTIONS "); + if(od_control.od_cmd_line_help != NULL) + { + printf(od_control.od_cmd_line_help); + } + else + { + printf("(Some can be overriden by config/drop file)\n"); + printf(" -C or -CONFIG - Specfies configuration filename.\n"); + printf(" -L or -LOCAL - Causes door to operate in local mode, without requiring a\n"); + printf(" door information (drop) file.\n"); + printf(" -D or -DROPFILE - Door information file directory and/or filename.\n"); + printf(" -N x or -NODE x - Sets the node number to use.\n"); + printf(" -B x or -BPS x - Sets the serial port <---> modem bps (baud) rate to use.\n"); + printf(" -P x or -PORT x - Sets serial port to use. For COM1: use -P 0 or -P COM1, for\n"); + printf(" COM2: use -P 1 or -P COM2, etc.\n"); + printf(" -ADDRESS x - Sets serial port address in HEXIDECIMAL (if no FOSSIL).\n"); + printf(" -IRQ x - Sets the serial port IRQ line (if FOSSIL is not used).\n"); + printf(" -NOFOSSIL - Disables use of FOSSIL driver, even if available.\n"); + printf(" -NOFIFO - Disables use of 16550 FIFO buffers (only if no FOSSIL).\n"); + printf(" -MAXTIME x - Sets the maximum number of minutes that any user will be\n"); + printf(" permitted to access the door, regardless of time left.\n"); + printf(" -SILENT - Operate in silent mode, with no local display.\n"); + printf(" -G or -GRAPHICS - Unless followed by 0 or N, turns on ANSI display mode.\n"); + printf(" -BBSNAME x - Name of BBS.\n"); + printf(" -USERNAME x - Name of user who is currently online.\n"); + printf(" -TIMELEFT x - User's time remaining online.\n"); + printf(" -SECURITY x - User's security level.\n"); + printf(" -LOCATION x - Location from which user is calling.\n"); + printf(" -?, -H or -HELP - Displays command-line help and exits.\n"); + } +#endif /* !ODPLAT_WIN32 */ + exit(1); + break; + + case kParamNode: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_node = atoi(papszArguments[nCurrentArg]); + break; + + case kParamMaxTime: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_maxtime = atoi(papszArguments[nCurrentArg]); + break; + + case kParamAddress: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_address = + (WORD)strtol(papszArguments[nCurrentArg], NULL, 16); + break; + + case kParamIRQ: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_irq = atoi(papszArguments[nCurrentArg]); + break; + + case kParamNoFOSSIL: + od_control.od_no_fossil = TRUE; + break; + + case kParamNoFIFO: + od_control.od_com_no_fifo = TRUE; + break; + + case kParamDropFile: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + strncpy(od_control.info_path, papszArguments[nCurrentArg], + sizeof(od_control.info_path) - 1); + od_control.info_path[sizeof(od_control.info_path) - 1] = '\0'; + break; + + case kParamUserName: + ODGetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_name, sizeof(od_control.user_name)); + break; + + case kParamTimeLeft: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_timelimit = atoi(papszArguments[nCurrentArg]); + break; + + case kParamSecurity: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_security = atoi(papszArguments[nCurrentArg]); + break; + + case kParamLocation: + ODGetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_location, sizeof(od_control.user_location)); + break; + + case kParamGraphics: + n = nCurrentArg; + if(++n < nArgCount) + { + if(atoi(papszArguments[n]) == 0 || + stricmp(papszArguments[n], "N") == 0) + { + od_control.user_ansi = FALSE; + ++nCurrentArg; + break; + } + } + od_control.user_ansi = TRUE; + break; + + case kParamBBSName: + ODGetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.system_name, sizeof(od_control.system_name)); + break; + + case kParamSocketDescriptor: + od_control.od_use_socket = TRUE; + /* fall through */ + + case kParamPortHandle: + ODAdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_open_handle = atoi(papszArguments[nCurrentArg]); + break; + + case kParamSilentMode: + od_control.od_silent_mode = TRUE; + break; + + case kParamUnknown: + /* If the client application provided a custom command line */ + /* handler function, then pass this unrecognized command-line */ + /* parameter and any options to that callback function. */ + if(od_control.od_cmd_line_handler != NULL) + { + char szCustomOptions[CUSTOM_OPTION_SIZE]; + ODGetNextArgName(&nCurrentArg, nArgCount, papszArguments, + szCustomOptions, sizeof(szCustomOptions)); + (*od_control.od_cmd_line_handler)(pszCurrentArg, + szCustomOptions); + } + break; + } + } + +#ifdef ODPLAT_WIN32 + free(pszCmdLineCopy); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODAdvanceToNextArg() *** PRIVATE FUNCTION *** + * + * Moves to the argument for a particular command line option. + * + * Parameters: pnCurrentArg - Pointer to current argument number. + * + * nArgCount - Total number of arguments available. + * + * pszOption - Pointer to command line option name. + * + * Return: void + */ +static void ODAdvanceToNextArg(INT *pnCurrentArg, INT nArgCount, + char *pszOption) +{ + ASSERT(pnCurrentArg != NULL); + ASSERT(pszOption != NULL); + + if(++*pnCurrentArg >= nArgCount) + { + printf("Missing parameter for option: %s\n", pszOption); + exit(1); + } +} + + +/* ---------------------------------------------------------------------------- + * ODGetNextArgName() *** PRIVATE FUNCTION *** + * + * Obtains a multi-word name from command-line. + * + * Parameters: pnCurrentArg - Pointer to integer storing current argument + * number. + * + * nArgCount - The total number of command-line argument + * + * papszArguments - Pointer to array of pointers to string + * arguments, as passed to main() in argv. + * + * pszString - Pointer to string in which name will string + * be stored. + * + * nStringSize - Size of the string. + * + * Return: void + */ +static void ODGetNextArgName(INT *pnCurrentArg, INT nArgCount, + char *papszArguments[], char *pszString, size_t nStringSize) +{ + BOOL bFirst = TRUE; + + ASSERT(pnCurrentArg != NULL); + ASSERT(papszArguments != NULL); + ASSERT(pszString != NULL); + ASSERT(nStringSize > 0); + + if((*pnCurrentArg) + 1 >= nArgCount) + { + printf("Missing parameter for option: %s\n", + papszArguments[(*pnCurrentArg) - 1]); + exit(1); + } + + pszString[0] = '\0'; + + while(++*pnCurrentArg < nArgCount) + { + if(ODGetCommandLineParameter(papszArguments[*pnCurrentArg]) + != kParamOption) + { + --*pnCurrentArg; + break; + } + + if(strlen(pszString) >= nStringSize - 1) + { + break; + } + + if(!bFirst) + { + strcat(pszString, " "); + } + + strncat(pszString, papszArguments[*pnCurrentArg], + strlen(pszString) - nStringSize - 1); + pszString[nStringSize - 1] = '\0'; + + bFirst = FALSE; + } + +} + + +/* ---------------------------------------------------------------------------- + * ODGetCommandLineParameter() *** PRIVATE FUNCTION *** + * + * Determines which command-line option, if any, is specified by an argument + * string. + * + * Parameters: pszArgument - Pointer to string containing raw command-line + * argument. + * + * Return: A tCommandLineParameter, identifying which command-line option, + * if any, matches the argument string. + */ +static tCommandLineParameter ODGetCommandLineParameter(char *pszArgument) +{ + ASSERT(pszArgument != NULL); + + if(*pszArgument == '-' || *pszArgument == '/') + { + ++pszArgument; + } + else + { + return(kParamOption); + } + + if(stricmp(pszArgument, "C") == 0 + || stricmp(pszArgument, "CONFIG") == 0 + || stricmp(pszArgument, "CONFIGFILE") == 0 + || stricmp(pszArgument, "CFGFILE") == 0 + || stricmp(pszArgument, "CFG") == 0) + { + return(kParamConfigFile); + } + else if(stricmp(pszArgument, "L") == 0 + || stricmp(pszArgument, "LOCAL") == 0) + { + return(kParamLocal); + } + else if(stricmp(pszArgument, "B") == 0 + || stricmp(pszArgument, "BPS") == 0 + || stricmp(pszArgument, "BAUD") == 0) + { + return(kParamBPS); + } + else if(stricmp(pszArgument, "P") == 0 + || stricmp(pszArgument, "PORT") == 0) + { + return(kParamPort); + } + else if(stricmp(pszArgument, "N") == 0 + || stricmp(pszArgument, "NODE") == 0) + { + return(kParamNode); + } + else if(stricmp(pszArgument, "?") == 0 + || stricmp(pszArgument, "H") == 0 + || stricmp(pszArgument, "HELP") == 0) + { + return(kParamHelp); + } + else if(stricmp(pszArgument, "PERSONALITY") == 0) + { + return(kParamPersonality); + } + else if(stricmp(pszArgument, "MAXTIME") == 0) + { + return(kParamMaxTime); + } + else if(stricmp(pszArgument, "ADDRESS") == 0) + { + return(kParamAddress); + } + else if(stricmp(pszArgument, "IRQ") == 0) + { + return(kParamIRQ); + } + else if(stricmp(pszArgument, "NOFOSSIL") == 0) + { + return(kParamNoFOSSIL); + } + else if(stricmp(pszArgument, "NOFIFO") == 0) + { + return(kParamNoFIFO); + } + else if(stricmp(pszArgument, "DROPFILE") == 0 || + stricmp(pszArgument, "D") == 0) + { + return(kParamDropFile); + } + else if(stricmp(pszArgument, "USERNAME") == 0) + { + return(kParamUserName); + } + else if(stricmp(pszArgument, "TIMELEFT") == 0) + { + return(kParamTimeLeft); + } + else if(stricmp(pszArgument, "SECURITY") == 0) + { + return(kParamSecurity); + } + else if(stricmp(pszArgument, "LOCATION") == 0) + { + return(kParamLocation); + } + else if(stricmp(pszArgument, "GRAPHICS") == 0 + || stricmp(pszArgument, "G") == 0) + { + return(kParamGraphics); + } + else if(stricmp(pszArgument, "BBSNAME") == 0) + { + return(kParamBBSName); + } + else if(stricmp(pszArgument, "HANDLE") == 0) + { + return(kParamPortHandle); + } + else if(stricmp(pszArgument, "SOCKET") == 0) + { + return(kParamSocketDescriptor); + } + else if(stricmp(pszArgument, "SILENT") == 0) + { + return(kParamSilentMode); + } + else + { + return(kParamUnknown); + } +} diff --git a/utils/magiedit/odoors/ODCom.c b/utils/magiedit/odoors/ODCom.c new file mode 100644 index 0000000..10a6e9a --- /dev/null +++ b/utils/magiedit/odoors/ODCom.c @@ -0,0 +1,3690 @@ +/* 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: ODCom.c + * + * Description: Generic serial I/O routines, provide a single interface to + * serial ports on any platform. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 20, 1994 6.00 BP Handle BIOS missing port addrs. + * Oct 20, 1994 6.00 BP Standardized coding style. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Dec 07, 1994 6.00 BP Support for RTS/CTS flow control. + * Dec 10, 1994 6.00 BP Allow word frmt setting for intern I/O + * Dec 13, 1994 6.00 BP Remove include of dir.h. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Jan 01, 1995 6.00 BP Integrate in Win32 code. + * Jan 01, 1995 6.00 BP Add FLOW_DEFAULT setting. + * Jan 01, 1995 6.00 BP Added ODComWaitEvent(). + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 21, 1995 6.00 BP Ported to Win32. + * Dec 21, 1995 6.00 BP Add ability to use already open port. + * Jan 09, 1996 6.00 BP Supply actual in/out buffer size used. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Initial support for Door32 interface. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Jan 13, 1997 6.10 BP Fixes for Door32 support. + * Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support. + * Oct 22, 2001 6.21 RS Fixed disconnected socket detection. + * Aug 22, 2002 6.22 RS Fixed bugs in ODComCarrier and ODComWaitEvent + * Aug 22, 2002 6.22 MD Modified socket functions for non-blocking use. + * Sep 18, 2002 6.22 MD Fixed bugs in ODComWaitEvent for non-blocking sockets. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#ifdef ODPLAT_NIX +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include "ODCore.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODCom.h" +#include "ODUtil.h" + + +/* The following define determines whether serial port function should */ +/* ASSERT or return an error code on programmer erorrs (e.g. invalid */ +/* parameters. */ +#define ASSERT_ON_INVALID_CALLS + +/* The following code defines the VERIFY_CALL() macro, which maps to an */ +/* ASSERT if ASSERT_ON_INVALID_CALLS is defined. Otherwise, this macro */ +/* maps to a test which will return an error code to the caller. */ +#ifdef ASSERT_ON_INVALID_CALLS +#define VERIFY_CALL(x) ASSERT(x) +#else /* !ASSERT_ON_INVALID_CALLS */ +#define VERIFY_CALL(x) if(x) return(kODRCInvalidCall) +#endif /* !ASSERT_ON_INVALID_CALLS */ + + +/* The following defines determine which serial I/O mechanisms should be */ +/* supported. */ + +/* Serial I/O mechanisms supported under MS-DOS version. */ +#ifdef ODPLAT_DOS +#define INCLUDE_FOSSIL_COM /* INT 14h FOSSIL-based I/O. */ +#define INCLUDE_UART_COM /* Internal interrupt driven I/O. */ +#endif /* ODPLAT_DOS */ + +/* Serial I/O mechanisms supported under Win32 version. */ +#ifdef ODPLAT_WIN32 +#define INCLUDE_WIN32_COM /* Win32 API serial I/O. */ +#define INCLUDE_DOOR32_COM /* Door32 I/O interface. */ +#define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */ +#endif /* ODPLAT_WIN32 */ + +/* Serial I/O mechanisms supported inder *nix version */ +#ifdef ODPLAT_NIX +#define INCLUDE_STDIO_COM +#define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */ + +/* Win32 Compat. Stuff */ +#define SOCKET int +#define WSAEWOULDBLOCK EAGAIN +#define SOCKET_ERROR -1 +#define WSAGetLastError() errno +#define ioctlsocket ioctl +#define closesocket close +#endif /* ODPLAT_NIX */ + +/* Include "windows.h" for Win32-API based serial I/O. */ +#ifdef INCLUDE_WIN32_COM +#include "windows.h" +#endif /* INCLUDE_WIN32_COM */ + +/* terminal variables */ +#ifdef INCLUDE_STDIO_COM +struct termios tio_default; /* Initial term settings */ +#endif + + +#if defined(_WIN32) && defined(INCLUDE_SOCKET_COM) + #include + static WSADATA WSAData; /* WinSock data */ +#endif + +/* ========================================================================= */ +/* Serial port object structure. */ +/* ========================================================================= */ + +/* Win32-API serial I/O implementation requires current timeout setting */ +/* status variable in serial port object structure. */ +#ifdef INCLUDE_WIN32_COM +typedef enum +{ + kNotSet, + kBlocking, + kNonBlocking +} tReadTimeoutState; +#endif /* INCLUDE_WIN32_COM */ + +/* Structure associated with each serial port handle. */ +typedef struct +{ + BOOL bIsOpen; + BOOL bUsingClientsHandle; + BYTE btFlowControlSetting; + long lSpeed; + BYTE btPort; + int nPortAddress; + BYTE btIRQLevel; + BYTE btWordFormat; + int nReceiveBufferSize; + int nTransmitBufferSize; + BYTE btFIFOSetting; + tComMethod Method; + void (*pfIdleCallback)(void); +#ifdef INCLUDE_WIN32_COM + HANDLE hCommDev; + tReadTimeoutState ReadTimeoutState; +#endif /* INCLUDE_WIN32_COM */ +#ifdef INCLUDE_DOOR32_COM + HINSTANCE hinstDoor32DLL; + BOOL (WINAPI *pfDoorInitialize)(void); + BOOL (WINAPI *pfDoorShutdown)(void); + BOOL (WINAPI *pfDoorWrite)(const BYTE *pbData, DWORD dwSize); + DWORD (WINAPI *pfDoorRead)(BYTE *pbData, DWORD dwSize); + HANDLE (WINAPI *pfDoorGetAvailableEventHandle)(void); + HANDLE (WINAPI *pfDoorGetOfflineEventHandle)(void); +#endif /* INCLUDE_DOOR32_COM */ +#ifdef INCLUDE_SOCKET_COM + SOCKET socket; + int old_delay; +#endif +} tPortInfo; + +/* ========================================================================= */ +/* Internal interrupt-driven serial I/O specific defintions & functions. */ +/* ========================================================================= */ + +#ifdef INCLUDE_UART_COM + +/* Private function prototypes, used by internal UART async serial I/O. */ +static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void)); +static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void); +static void INTERRUPT ODComInternalISR(); +static BOOL ODComInternalTXReady(void); +static void ODComInternalResetRX(void); +static void ODComInternalResetTX(void); + + +/* Offsets of UART registers. */ +#define TXBUFF 0 /* Transmit buffer register. */ +#define RXBUFF 0 /* Receive buffer register. */ +#define DLLSB 0 /* Divisor latch LS byte. */ +#define DLMSB 1 /* Divisor latch MS byte. */ +#define IER 1 /* Interrupt enable register. */ +#define IIR 2 /* Interrupt ID register. */ +#define LCR 3 /* Line control register. */ +#define MCR 4 /* Modem control register. */ +#define LSR 5 /* Line status register. */ +#define MSR 6 /* Modem status register. */ + +/* FIFO control register bits. */ +#define FE 0x01 /* FIFO enable. */ +#define RR 0x02 /* FIFO receive buffer reset. */ +#define TR 0x04 /* FIFO transmit buffer reset. */ +#define FTS_1 0x00 /* FIFO trigger size 1 byte. */ +#define FTS_4 0x40 /* FIFO trigger size 4 bytes. */ +#define FTS_8 0x80 /* FIFO trigger size 8 bytes. */ +#define FTS_14 0xc0 /* FIFO trigger size 14 bytes. */ + +/* Modem control register (MCR) bits. */ +#define DTR 0x01 /* Data terminal ready. */ +#define NOT_DTR 0xfe /* All bits other than DTR. */ +#define RTS 0x02 /* Request to send. */ +#define NOT_RTS 0xfd /* All bits other than RTS. */ +#define OUT1 0x04 /* Output #1. */ +#define OUT2 0x08 /* Output #2. */ +#define LPBK 0x10 /* Loopback mode bit. */ + +/* Modem status register (MSR) bits. */ +#define DCTS 0x01 /* Delta clear to send. */ +#define DDSR 0x02 /* Delta data set ready. */ +#define TERI 0x04 /* Trailing edge ring indicator. */ +#define DRLSD 0x08 /* Delta Rx line signal detect. */ +#define CTS 0x10 /* Clear to send. */ +#define DSR 0x20 /* Data set ready. */ +#define RI 0x40 /* Ring indicator. */ +#define RLSD 0x80 /* Receive line signal detect. */ + +/* Line control register (LCR) bits. */ +#define DATA5 0x00 /* 5 Data bits. */ +#define DATA6 0x01 /* 6 Data bits. */ +#define DATA7 0x02 /* 7 Data bits. */ +#define DATA8 0x03 /* 8 Data bits. */ + +#define STOP1 0x00 /* 1 Stop bit. */ +#define STOP2 0x04 /* 2 Stop bits. */ + +#define NOPAR 0x00 /* No parity. */ +#define ODDPAR 0x08 /* Odd parity. */ +#define EVNPAR 0x18 /* Even parity. */ +#define STKPAR 0x28 /* Sticky parity. */ +#define ZROPAR 0x38 /* Zero parity. */ + +#define DLATCH 0x80 /* Baud rate divisor latch. */ +#define NOT_DL 0x7f /* Turns off divisor latch. */ + +/* Line status register (LSR) bits. */ +#define RDR 0x01 /* Receive data ready. */ +#define ERRS 0x1E /* All the error bits. */ +#define TXR 0x20 /* Transmitter ready. */ + +/* Interrupt enable register (IER) bits. */ +#define DR 0x01 /* Data ready. */ +#define THRE 0x02 /* Transmit holding register empty. */ +#define RLS 0x04 /* Receive line status. */ +#define MS 0x08 /* Modem status. */ + +/* Flow control receive buffer limits. */ +#define RECEIVE_LOW_NUM 1 /* Numerator for low water mark. */ +#define RECEIVE_LOW_DENOM 4 /* Denominator for low water mark. */ +#define RECEIVE_HIGH_NUM 3 /* Numerator for high water mark. */ +#define RECEIVE_HIGH_DENOM 4 /* Denominator for high water mark. */ + + +/* Built-in async serial I/O global variables. */ + +/* These variabes are shared throughout the functions that handle the */ +/* built-in UART-base serial I/O, including the interrupt service routine. */ +/* Since only one copy of these variables exist, the built-in serial I/O */ +/* routines may only be used to access one port at a time. */ + +/* Default port addresses. */ +/* First 4 addresses are standard addresses used for PC/AT COM1 thru COM4. */ +/* Second 4 addresses are PS/2 standard addresses used for COM5 thru COM8. */ +static int anDefaultPortAddr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8, + 0x4220, 0x4228, 0x5220, 0x5228}; + +/* UART address variables. */ +static int nDataRegAddr; /* Data register address. */ +static int nIntEnableRegAddr; /* Interrupt enable register. */ +static int nIntIDRegAddr; /* Interrupt ID register address. */ +static int nLineCtrlRegAddr; /* Line control register address. */ +static int nModemCtrlRegAddr; /* Modem control register address. */ +static int nLineStatusRegAddr; /* Line status register address. */ +static int nModemStatusRegAddr; /* Modem status register address. */ + +/* General variables. */ +static BYTE btIntVector; /* Interrupt vector number for port. */ +static char btI8259Bit; /* 8259 bit mask. */ +static char btI8259Mask; /* Copy as it was before open. */ +static int nI8259MaskRegAddr; /* Address of i8259 mask register. */ +static int nI8259EndOfIntRegAddr; /* Address of i8259 EOI register. */ +static int nI8259MasterEndOfIntRegAddr; /* Address of master PIC EOI reg. */ +static char btOldIntEnableReg; /* Original IER contents. */ +static char btOldModemCtrlReg; /* Original MCR contents. */ +static void (INTERRUPT far *pfOldISR)();/* Original ISR routine for IRQ. */ +static char bUsingFIFO = FALSE; /* Are we using 16550 FIFOs? */ +static unsigned char btBaseFIFOCtrl; /* FIFO control register byte. */ + + +/* Transmit queue variables. */ +static int nTXQueueSize; /* Actual size of transmit queue. */ +static char *pbtTXQueue; /* Pointer to transmit queue. */ +static int nTXInIndex; /* Location to store next byte. */ +static int nTXOutIndex; /* Location to get next byte. */ +static int nTXChars; /* Count of characters in queue. */ + +/* Receive queue variables. */ +static int nRXQueueSize; /* Actual size of receive queue. */ +static char *pbtRXQueue; /* Pointer to receive queue. */ +static int nRXInIndex; /* Location to store next byte. */ +static int nRXOutIndex; /* Location to retrieve next byte. */ +static int nRXChars; /* Count of characters in queue. */ + +/* Flow control variables. */ +static int nRXHighWaterMark; /* High water mark for queue size. */ +static int nRXLowWaterMark; /* Low water mark for queue size. */ +static BYTE btFlowControl; /* Flow control method. */ +static BOOL bStopTrans; /* Flag set to stop transmitting. */ + +/* ---------------------------------------------------------------------------- + * ODComSetVect() *** PRIVATE FUNCTION *** + * + * Sets the function to be called for the specified interrupt level. + * + * Parameters: btVector - Interrupt vector level, a value from 0 to 255. + * + * pfISR - Pointer to the ISR function to be called. + * + * Return: void + */ +static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void)) +{ + ASM push ds + ASM mov ah, 0x25 + ASM mov al, btVector + ASM lds dx, pfISR + ASM int 0x21 + ASM pop ds +} + + +/* ---------------------------------------------------------------------------- + * ODComGetVect() *** PRIVATE FUNCTION *** + * + * Returns the address of the function that is currently called for the + * specified interrupt level. + * + * Parameters: btVector - Interrupt vector level, a value from 0 to 255. + * + * Return: A pointer to the code that is currently executed on an interrupt + * of the speceified level. + */ +static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void) +{ + void (INTERRUPT far *pfISR)(void); + + ASM push es + ASM mov ah, 0x35 + ASM mov al, btVector + ASM int 0x21 + ASM mov word ptr pfISR, bx + ASM mov word ptr [pfISR+2], bx + ASM pop es + + return(pfISR); +} + + +/* ---------------------------------------------------------------------------- + * ODComInternalTXReady() *** PRIVATE FUNCTION *** + * + * Returns TRUE if the internal serial I/O transmit buffer is not full. + * + * Parameters: none + * + * Return: void + */ +static BOOL ODComInternalTXReady(void) +{ + /* Return TRUE if tx_chars is less than total tx buffer size. */ + return(nTXChars < nTXQueueSize); +} + + +/* ---------------------------------------------------------------------------- + * ODComInternalResetTX() *** PRIVATE FUNCTION *** + * + * Clears transmit buffer used by internal serial I/O routines. + * + * Parameters: none + * + * Return: void + */ +static void ODComInternalResetTX(void) +{ + /* Disable interrupts. */ + ASM cli + + /* If we are using 16550A FIFO buffers, then clear the FIFO transmit */ + /* buffer. */ + if(bUsingFIFO) + { + ASM mov al, btBaseFIFOCtrl + ASM or al, TR + ASM mov dx, nIntIDRegAddr + ASM out dx, al + } + + /* Reset start, end and total count of characters in buffer */ + /* If buffer is still empty on next transmit interrupt, transmit */ + /* interrupts will be turned off. */ + nTXChars = nTXInIndex = nTXOutIndex = 0; + + /* Re-enable interrupts. */ + ASM sti +} + + +/* ---------------------------------------------------------------------------- + * ODComInternalResetRX() *** PRIVATE FUNCTION *** + * + * Clears receive buffer used by internal serial I/O routines. + * + * Parameters: none + * + * Return: void + */ +static void ODComInternalResetRX(void) +{ + /* Disable interrupts. */ + ASM cli + + /* If we are using 16550A FIFO buffers, then clear the FIFO receive */ + /* buffer. */ + if(bUsingFIFO) + { + ASM mov al, btBaseFIFOCtrl + ASM or al, RR + ASM mov dx, nIntIDRegAddr + ASM out dx, al + } + + /* Reset start, end and total count of characters in buffer */ + /* On the next receive interrupt, data will be added at the beginning */ + /* of the buffer. */ + nRXChars = nRXInIndex = nRXOutIndex = 0; + + /* Re-enable interrupts. */ + ASM sti +} + + +/* ---------------------------------------------------------------------------- + * ODComInternalISR() *** PRIVATE FUNCTION *** + * + * Interrupt service routine for internal UART-based serial I/O. + * + * Parameters: none + * + * Return: void + */ +static void INTERRUPT ODComInternalISR() +{ + char btIIR; + BYTE btTemp; + + /* Loop until there are no more pending operations to perform with the */ + /* UART. */ + for(;;) + { + /* While bit 0 of the UART IIR is 0, there remains pending operations. */ + /* Read IIR. */ + ASM mov dx, nIntIDRegAddr + ASM in al, dx + ASM mov btIIR, al + + /* If IIR bit 0 is set, then UART processing is finished. */ + if(btIIR & 0x01) break; + + /* Bits 1 and 2 of the IIR register identify the type of operation */ + /* to be performed with the UART. */ + + /* Switch on bits 1 and 2 of IIR register. */ + switch(btIIR & 0x06) + { + case 0x00: + /* Operation: modem status has changed. */ + + /* Read modem status register. */ + ASM mov dx, nModemStatusRegAddr + ASM in al, dx + ASM mov btTemp, al + + /* We only care about the modem status register if we are */ + /* using RTS/CTS flow control, and the CTS register has */ + /* changed. */ + if((btFlowControl & FLOW_RTSCTS) && (btTemp & DCTS)) + { + if(btTemp & CTS) + { + /* If CTS has gone high, then re-enable transmission. */ + bStopTrans = FALSE; + + /* Restart transmission if there is anything in the */ + /* transmit buffer. */ + if(nTXChars > 0) + { + /* Enable transmit interrupt. */ + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM or al, THRE + ASM out dx, al + } + } + else + { + /* If CTS has gone low, then stop transmitting. */ + bStopTrans = TRUE; + } + } + + break; + + case 0x02: + /* Operation: room in transmit register/FIFO. */ + /* Check whether we can send further characters to transmit. */ + if(nTXChars <= 0 || bStopTrans) + { + /* If we cannot send more characters, then turn off */ + /* transmit interrupts. */ + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM and al, 0xfd + ASM out dx, al + } + else + { + /* If we still have characters to transmit ... */ + + /* Check line status register to determine whether transmit */ + /* register/FIFO truly has room. Some UARTs trigger transmit */ + /* interrupts before the character has been tranmistted, */ + /* causing transmitted characters to be lost. */ + ASM mov dx, nLineStatusRegAddr + ASM in al, dx + ASM mov btTemp, al + + if(btTemp & TXR) + { + /* There is room in the transmit register/FIFO. */ + + /* Get next character to transmit. */ + btTemp = pbtTXQueue[nTXOutIndex++]; + + /* Write character to UART data register. */ + ASM mov dx, nDataRegAddr + ASM mov al, btTemp + ASM out dx, al + + /* Wrap-around transmit buffer pointer, if needed. */ + if (nTXOutIndex == nTXQueueSize) + { + nTXOutIndex = 0; + } + + /* Decrease count of characters in transmit buffer. */ + nTXChars--; + } + } + break; + + case 0x04: + /* Operation: Receive Data. */ + + /* Get character from receive buffer ASAP. */ + ASM mov dx, nDataRegAddr + ASM in al, dx + ASM mov btTemp, al + + /* If receive buffer is above high water mark. */ + if(nRXChars >= nRXHighWaterMark) + { + /* If we are using flow control, then stop sender from */ + /* sending. */ + if(btFlowControl & FLOW_RTSCTS) + { + /* If using RTS/CTS flow control, then lower RTS line. */ + ASM mov dx, nModemCtrlRegAddr + ASM in al, dx + ASM and al, NOT_RTS + ASM out dx, al + } + } + + /* If there is room in receive buffer. */ + if(nRXChars < nRXQueueSize) + { + /* Store the new character in the receive buffer. */ + pbtRXQueue[nRXInIndex++] = btTemp; + + /* Wrap-around buffer index, if needed. */ + if (nRXInIndex == nRXQueueSize) + nRXInIndex = 0; + + /* Increment count of characters in the buffer. */ + nRXChars++; + } + break; + + case 0x06: + /* Operation: Change in line status register. */ + + /* We just read the register to move on to further operations. */ + ASM mov dx, nLineStatusRegAddr + ASM in al, dx + break; + } + } + + /* Send end of interrupt to interrupt controller(s). */ + ASM mov dx, nI8259EndOfIntRegAddr + ASM mov al, 0x20 + ASM out dx, al + + if(nI8259MasterEndOfIntRegAddr != 0) + { + ASM mov dx, nI8259MasterEndOfIntRegAddr + ASM mov al, 0x20 + ASM out dx, al + } +} +#endif /* INCLUDE_UART_COM */ + + + +/* ========================================================================= */ +/* Win32-API base serial I/O specific functions. */ +/* ========================================================================= */ + +#ifdef INCLUDE_WIN32_COM + +/* Function prototypes. */ +static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo, + tReadTimeoutState RequiredTimeoutState); + + +/* ---------------------------------------------------------------------------- + * ODComWin32SetReadTimeouts() *** PRIVATE FUNCTION *** + * + * Ensures that read timeout state is set appropriately. + * + * Parameters: pPortInfo - Pointer to serial port handle structure. + * + * RequiredTimeoutState - Timeout state that should be set. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo, + tReadTimeoutState RequiredTimeoutState) +{ + ASSERT(pPortInfo != NULL); + + /* If timeout state must be changed ... */ + if(RequiredTimeoutState != pPortInfo->ReadTimeoutState) + { + COMMTIMEOUTS CommTimeouts; + + /* Obtain current timeout settings. */ + if(!GetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts)) + { + return(kODRCGeneralFailure); + } + + /* Setup timeout setting structure appropriately. */ + switch(RequiredTimeoutState) + { + case kBlocking: + CommTimeouts.ReadIntervalTimeout = 0; + CommTimeouts.ReadTotalTimeoutMultiplier = 0; + CommTimeouts.ReadTotalTimeoutConstant = 0; + break; + case kNonBlocking: + CommTimeouts.ReadIntervalTimeout = INFINITE; + CommTimeouts.ReadTotalTimeoutMultiplier = 0; + CommTimeouts.ReadTotalTimeoutConstant = 0; + break; + default: + ASSERT(FALSE); + } + + /* Write settings. */ + if(!SetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts)) + { + return(kODRCGeneralFailure); + } + + /* Record current read timeout setting state for subsequent */ + /* calls to this function. */ + pPortInfo->ReadTimeoutState = RequiredTimeoutState; + } + + return(kODRCSuccess); +} + +#endif /* INCLUDE_WIN32_COM */ + + + +/* ========================================================================= */ +/* Implementation of generic serial I/O functions. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODComAlloc() + * + * Allocates a serial port handle, which can be passed to other ODCom...() + * functions. + * + * Parameters: phPort - Pointer to serial port handle. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComAlloc(tPortHandle *phPort) +{ + tPortInfo *pPortInfo; + + VERIFY_CALL(phPort != NULL); + + /* Attempt to allocate a serial port information structure. */ + pPortInfo = malloc(sizeof(tPortInfo)); + + /* If memory allocation failed, return with failure. */ + if(pPortInfo == NULL) + { + *phPort = ODPTR2HANDLE(NULL, tPortInfo); + return(kODRCNoMemory); + } + + /* Initialize serial port information structure. */ + pPortInfo->bIsOpen = FALSE; + pPortInfo->bUsingClientsHandle = FALSE; + pPortInfo->btFlowControlSetting = FLOW_DEFAULT; + pPortInfo->lSpeed = SPEED_UNSPECIFIED; + pPortInfo->btWordFormat = ODPARITY_NONE | DATABITS_EIGHT | STOP_ONE; + pPortInfo->nReceiveBufferSize = 1024; + pPortInfo->nTransmitBufferSize = 1024; + pPortInfo->btFIFOSetting = FIFO_ENABLE | FIFO_TRIGGER_8; + pPortInfo->Method = kComMethodUnspecified; + pPortInfo->pfIdleCallback = NULL; + + /* Convert serial port information structure pointer to a handle. */ + *phPort = ODPTR2HANDLE(pPortInfo, tPortInfo); + + /* Set default port number. */ + ODComSetPort(*phPort, 0); + +#if defined(INCLUDE_SOCKET_COM) && defined(_WINSOCKAPI_) + WSAStartup(MAKEWORD(1,1), &WSAData); +#endif + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComFree() + * + * Deallocates a serial port handle that is no longer required. + * + * Parameters: hPort - Handle to a serial port object. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComFree(tPortHandle hPort) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + /* Deallocate port information structure. */ + free(pPortInfo); + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetIdleFunction() + * + * Sets function to call when serial I/O module is idle, or NULL for none. + * + * Parameters: hPort - Handle to a serial port object. + * + * pfCallback - Pointer to function to call when idle. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetIdleFunction(tPortHandle hPort, + void (*pfCallback)(void)) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->pfIdleCallback = pfCallback; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetFlowControl() + * + * Sets the flow control method(s) to use. If this function is not called, + * RTS/CTS flow control is used by default. This function should not be + * called while the port is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * btFlowControlSetting - One or more FLOW_* settings, joined + * by bitwise-or (|) operators. If + * FLOW_DEFAULT is included, all other + * settings are ignored, and the default + * settings for this serial I/O method + * are used. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetFlowControl(tPortHandle hPort, BYTE btFlowControlSetting) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->btFlowControlSetting = btFlowControlSetting; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetSpeed() + * + * Sets the serial port BPS (baud) rate to use. Depending upon the serial I/O + * method being used, this setting may be controlled by the user's system + * configuration, in which case the value passed to this function wil have + * no effect. A setting of SPEED_UNSPECIFIED, indicates that the serial port + * speed should not be changed, if it is possible not to do so with the serial + * I/O method being used. This function cannot be called while the port is + * open. + * + * Parameters: hPort - Handle to a serial port object. + * + * lSpeed - A valid BPS rate, or SPEED_UNSPECIFIED. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetSpeed(tPortHandle hPort, long lSpeed) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->lSpeed = lSpeed; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetPort() + * + * Sets the serial port number to be associated with this port handle. This + * function cannot be called while the port is open. Calling this function + * also sets the IRQ line number and serial port address to their defaults + * for this port number, if this values can be set for the serial I/O method + * being used. + * + * Parameters: hPort - Handle to a serial port object. + * + * btPort - Serial port identification, where 0 typically + * corresponds to COM1, 1 to COM2, and so on. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetPort(tPortHandle hPort, BYTE btPort) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + /* Store port number in port information structure. */ + pPortInfo->btPort = btPort; + + +#ifdef INCLUDE_UART_COM + /* Get default address for this port number, if possible. */ + pPortInfo->nPortAddress = 0; + + if(btPort < 4) + { + /* Get port address from BIOS data area. */ + pPortInfo->nPortAddress = *(((int far *)0x400) + btPort); + } + + /* If port address is still unknown, and we know the default */ + /* address, then use that address. */ + if(pPortInfo->nPortAddress == 0 + && btPort < DIM(anDefaultPortAddr)) + { + pPortInfo->nPortAddress = anDefaultPortAddr[btPort]; + } + + + /* Set default IRQ number for this port number. */ + + /* Ports 0 and 2 (COM1:, COM3:) default to IRQ 4, all others */ + /* default to IRQ 3. */ + if(btPort == 0 || btPort == 2) + { + pPortInfo->btIRQLevel = 4; + } + else + { + pPortInfo->btIRQLevel = 3; + } +#endif /* INCLUDE_UART_COM */ + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetPortAddress() + * + * Sets address of the serial port, if it can be set for the serial I/O method + * being used. This function cannot be called when the port is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * nPortAddress - Address of serial port. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetPortAddress(tPortHandle hPort, int nPortAddress) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->nPortAddress = nPortAddress; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetIRQ() + * + * Sets the IRQ line associated with this serial port, if applicable for the + * serial I/O method being used. This function cannot be called while the port + * is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * btIRQLevel - A number from 1 to 15, specifying the IRQ line that + * the serial port is wired to. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetIRQ(tPortHandle hPort, BYTE btIRQLevel) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->btIRQLevel = btIRQLevel; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetWordFormat() + * + * Determine the word format (number of data bits, stop bits and parity bits) + * to use, if it can be set for the serial I/O method being used. If this + * function is not called, N81 word format is used. This function can only + * be called when the port is not open. + * + * Parameters: hPort - Handle to a serial port object. + * + * btWordFormat - Bitwise-or (|) of PARITY_*, STOP_* and DATABITS_* + * settings which determine the word format to use. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetWordFormat(tPortHandle hPort, BYTE btWordFormat) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->btWordFormat = btWordFormat; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetRXBuf() + * + * Sets the desired size of the receive buffer, if possible for the + * serial I/O method being used. Note that for some serial I/O methods, this + * buffer size is fixed, controlled by the user's system configuration. + * No error is generated when this function is called when such serial I/O + * methods will be used - in this case this setting will simply have no effect. + * This function cannot be called while the port is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * nReceiveBufferSize - Number of bytes in the receive buffer. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetRXBuf(tPortHandle hPort, int nReceiveBufferSize) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->nReceiveBufferSize = nReceiveBufferSize; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetTXBuf() + * + * Sets the desired size of the transmit buffer, if possible for the + * serial I/O method being used. Note that for some serial I/O methods, this + * buffer size is fixed, controlled by the user's system configuration. + * No error is generated when this function is called when such serial I/O + * methods will be used - in this case this setting will simply have no effect. + * This function cannot be called while the port is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * nTransmitBufferSize - Number of bytes in the transmit buffer. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetTXBuf(tPortHandle hPort, int nTransmitBufferSize) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->nTransmitBufferSize = nTransmitBufferSize; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetFIFO() + * + * Enables or disables use of the UART FIFO buffers (if applicable), and also + * sets the FIFO trigger level. This function cannot be called while the port + * is open. + * + * Parameters: hPort - Handle to a serial port object. + * + * btFIFOSetting - UART FIFO setting, including FIFO_ENABLE or + * FIDO_DISABLE, and a FIFO_TRIGGER_* setting, + * joined by bitwise-or (|) operators. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetFIFO(tPortHandle hPort, BYTE btFIFOSetting) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->btFIFOSetting = btFIFOSetting; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetPreferredMethod() + * + * Sets the method to be used to perform serial I/O. + * + * Parameters: hPort - Handle to a serial port object. + * + * Method - The method to be used for peforming serial I/O, + * or kComMethodUnspecified to have the serial I/O + * routines to automatically choose the method to use. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetPreferredMethod(tPortHandle hPort, tComMethod Method) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + + pPortInfo->Method = Method; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComGetMethod() + * + * Returns the method being used to perform serial I/O, if this has been + * determined. You can only assume that this value will be set after + * ODComOpen() has been called. + * + * Parameters: hPort - Handle to a serial port object. + * + * pMethod - Pointer to a tComMethod, in which function will + * store the method of serial I/O being used, if this + * has been determined. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComGetMethod(tPortHandle hPort, tComMethod *pMethod) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pMethod != NULL); + + *pMethod = pPortInfo->Method; + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComOpen() + * + * Initializes serial I/O for appropriate serial I/O mechanism (e.g. FOSSIL + * driver, internal async I/O, etc.) + * + * Parameters: hPort - Handle to a serial port object. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComOpen(tPortHandle hPort) +{ +#if defined(INCLUDE_FOSSIL_COM) || defined(INCLUDE_UART_COM) + unsigned int uDivisor; + unsigned long ulQuotient, ulRemainder; + BYTE btTemp; +#endif /* INCLUDE_FOSSIL_COM || INCLUDE_UART_COM */ +#ifdef INCLUDE_STDIO_COM + struct termios tio_raw; +#endif + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + nPort = (int)pPortInfo->btPort; + + /* Ensure that port is not already open. */ + VERIFY_CALL(!pPortInfo->bIsOpen); + + /* The following code is used to handle FOSSIL-based serial I/O open */ + /* operations. */ +#ifdef INCLUDE_FOSSIL_COM + /* If use of FOSSIL driver has not been disabled, then first attempt to */ + /* use it. */ + if(pPortInfo->Method == kComMethodFOSSIL || + pPortInfo->Method == kComMethodUnspecified) + { + /* Attempt to open port with FOSSIL DRIVER. */ + ASM push si + ASM push di + ASM mov ah, 4 + ASM mov dx, nPort + ASM mov bx, 0 + ASM int 20 + ASM pop di + ASM pop si + ASM cmp ax, 6484 + ASM je fossil + goto no_fossil; + +fossil: + pPortInfo->Method = kComMethodFOSSIL; + + /* Enable flow control, if applicable. */ + + /* Generate flow control setting. All bits in high nibble of flow */ + /* control are set to 1, because some FOSSIL driver implementations */ + /* use the high nibble as a control mask. */ + if(pPortInfo->btFlowControlSetting & FLOW_DEFAULT) + { + btTemp = FLOW_RTSCTS | 0xf0; + } + else + { + btTemp = pPortInfo->btFlowControlSetting | 0xf0; + } + + ASM push si + ASM push di + ASM mov ah, 0x0f + ASM mov al, btTemp + ASM mov dx, nPort + ASM int 20 + ASM pop di + ASM pop si + + /* If serial port speed is not to be set, then return now. */ + if(pPortInfo->lSpeed == SPEED_UNSPECIFIED) + { + /* Set port state to open. */ + pPortInfo->bIsOpen = TRUE; + + /* Return with success. */ + return(kODRCSuccess); + } + + /* Set to current baud rate. */ + switch(pPortInfo->lSpeed) + { + case 300L: + btTemp = 0x40; + break; + case 600L: + btTemp = 0x60; + break; + case 1200L: + btTemp = 0x80; + break; + case 2400L: + btTemp = 0xa0; + break; + case 4800L: + btTemp = 0xc0; + break; + case 9600L: + btTemp = 0xe0; + break; + case 19200L: + btTemp = 0x00; + break; + case 38400L: + btTemp = 0x20; + break; + default: + /* If invalid bps rate, don't change current bps setting. */ + /* Set port state to open. */ + pPortInfo->bIsOpen = TRUE; + + /* Return with success. */ + return(kODRCSuccess); + } + + /* Add desired word format parameters to data to be passed to fossil. */ + btTemp |= pPortInfo->btWordFormat; + + /* Initialize fossil driver. */ + ASM push si + ASM push di + ASM mov al, btTemp + ASM mov ah, 0 + ASM mov dx, nPort + ASM int 20 + ASM pop di + ASM pop si + + /* Set port state to open. */ + pPortInfo->bIsOpen = TRUE; + + /* Return with success. */ + return(kODRCSuccess); + } + +no_fossil: +#endif /* INCLUDE_FOSSIL_COM */ + + /* The following code is used to carry out the serial port I/O open */ + /* operations if built-in UART-based serial I/O is being used. */ +#ifdef INCLUDE_UART_COM + if(pPortInfo->Method == kComMethodUART || + pPortInfo->Method == kComMethodUnspecified) + { + /* Set internal serial I/O flow control variable from pre-set */ + /* flow control options. */ + if(pPortInfo->btFlowControlSetting & FLOW_DEFAULT) + { + btFlowControl = FLOW_RTSCTS; + } + else + { + btFlowControl = pPortInfo->btFlowControlSetting; + } + + /* Store serial I/O method being used. */ + pPortInfo->Method = kComMethodUART; + + /* Calculate receive buffer high and low water marks for use with */ + /* flow control. */ + nRXHighWaterMark = (pPortInfo->nReceiveBufferSize * RECEIVE_HIGH_NUM) + / RECEIVE_HIGH_DENOM; + nRXLowWaterMark = (pPortInfo->nReceiveBufferSize * RECEIVE_LOW_NUM) + / RECEIVE_LOW_DENOM; + + /* Allocate transmit and receive buffers */ + pbtTXQueue = malloc(nTXQueueSize = pPortInfo->nTransmitBufferSize); + pbtRXQueue = malloc(nRXQueueSize = pPortInfo->nReceiveBufferSize); + + if(pbtTXQueue == NULL || pbtRXQueue == NULL) + { + return(kODRCNoMemory); + } + + /* If serial port address is unknown. */ + if(pPortInfo->nPortAddress == 0) + { + return(kODRCNoPortAddress); + } + + /* Initialize table of UART register port addresses. */ + nDataRegAddr = pPortInfo->nPortAddress; + nIntEnableRegAddr = nDataRegAddr + IER; + nIntIDRegAddr = nDataRegAddr + IIR; + nLineCtrlRegAddr = nDataRegAddr + LCR; + nModemCtrlRegAddr = nDataRegAddr + MCR; + nLineStatusRegAddr = nDataRegAddr + LSR; + nModemStatusRegAddr = nDataRegAddr + MSR; + + + /* Store interrupt vector number and PIC interrupt information for */ + /* the specified IRQ line. */ + if(pPortInfo->btIRQLevel <= 7) + { + btIntVector = 0x08 + (pPortInfo->btIRQLevel); + btI8259Bit = 1 << (pPortInfo->btIRQLevel); + nI8259MaskRegAddr = 0x21; + nI8259EndOfIntRegAddr = 0x20; + nI8259MasterEndOfIntRegAddr = 0x00; + } + else + { + btIntVector = 0x68 + (pPortInfo->btIRQLevel); + btI8259Bit = 1 << (pPortInfo->btIRQLevel - 8); + nI8259MaskRegAddr = 0xA1; + nI8259EndOfIntRegAddr = 0xA0; + nI8259MasterEndOfIntRegAddr = 0x20; + } + + /* Save original state of UART IER register. */ + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM mov btOldIntEnableReg, al + + /* Test that a UART is indeed installed at this port address. */ + ASM mov dx, nIntEnableRegAddr + ASM mov al, 0 + ASM out dx, al + + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM mov btTemp, al + + if (btTemp != 0) + { + return(kODRCNoUART); + } + + /* Setup for RTS/CTS flow control, if it is to be used. */ + if(btFlowControl & FLOW_RTSCTS) + { + /* Read modem status register. */ + ASM mov dx, nModemStatusRegAddr + ASM in al, dx + ASM mov btTemp, al + + /* Enable transmission only if CTS is high. */ + bStopTrans = !(btTemp & CTS); + } + + /* Save original PIC interrupt settings, and temporarily disable */ + /* interrupts on this IRQ line while we perform initialization. */ + ASM cli + + ASM mov dx, nI8259MaskRegAddr + ASM in al, dx + ASM mov btI8259Mask, al + ASM or al, btI8259Bit + ASM out dx, al + + /* Initialize transmit and recieve buffers. */ + ODComInternalResetTX(); + ODComInternalResetRX(); + + /* Re-enable interrupts. */ + ASM sti + + /* Save original interrupt vector. */ + pfOldISR = ODComGetVect(btIntVector); + + /* Set interrupt vector to point to our ISR. */ +#ifdef _MSC_VER + ODComSetVect(btIntVector, (void far *)ODComInternalISR); +#else /* !_MSC_VER */ + ODComSetVect(btIntVector, ODComInternalISR); +#endif /* !_MSC_VER */ + + /* Set line control register to 8 data bits, no parity bits, 1 stop */ + /* bit. */ + btTemp = pPortInfo->btWordFormat; + ASM mov dx, nLineCtrlRegAddr + ASM mov al, btTemp + ASM out dx, al + + /* Save original modem control register. */ + ASM cli + + ASM mov dx, nModemCtrlRegAddr + ASM in al, dx + ASM mov btOldModemCtrlReg, al + + /* Keep current DTR setting, and activate RTS. */ + btTemp = (btOldModemCtrlReg & DTR) | (OUT2 + RTS); + ASM mov dx, nModemCtrlRegAddr + ASM mov al, btTemp + ASM out dx, al + + /* Enable use of 16550A FIFOs, if available. */ + if(pPortInfo->btFIFOSetting & FIFO_ENABLE) + { + /* Set FIFO enable bit and trigger size. */ + btBaseFIFOCtrl = pPortInfo->btFIFOSetting; + + /* Attempt to enable use of FIFO buffers. */ + ASM mov al, btBaseFIFOCtrl + ASM mov dx, nIntIDRegAddr + ASM out dx, al + + /* Check whether a 16550A UART is actually present by reading */ + /* state of FIFO buffer. */ + ASM mov dx, nIntIDRegAddr + ASM in al, dx + ASM mov btTemp, al + + bUsingFIFO = btTemp & 0xc0; + } + + ASM sti + + /* Enable receive and modem status interrupts on the UART. */ + ASM mov dx, nIntEnableRegAddr + ASM mov al, DR + MS + ASM out dx, al + + ASM cli + + ASM mov dx, nI8259MaskRegAddr + ASM in al, dx + ASM mov ah, btI8259Bit + ASM not ah + ASM and al, ah + ASM out dx, al + + ASM sti + + /* Set baud rate, if possible. */ + + /* Calculate baud rate divisor. */ + if(pPortInfo->lSpeed != SPEED_UNSPECIFIED) + { + ODDWordDivide(&ulQuotient, &ulRemainder, 115200UL, pPortInfo->lSpeed); + + /* If division results in a remainder, then this is an invalid */ + /* baud rate. We only change the UART baud rate if we have a valid */ + /* rate to set it to. Otherwise, we cross our fingers and proceed */ + /* with the currently set UART baud rate. */ + if(ulRemainder == 0L) + { + uDivisor = (unsigned int)ulQuotient; + + /* Disable interrupts. */ + ASM cli + + /* Set baud rate divisor latch. */ + /* The data register now becomes the lower byte of the baud rate */ + /* divisor, and the interrupt enable register becomes the upper */ + /* byte of the divisor. */ + ASM mov dx, nLineCtrlRegAddr + ASM in al, dx + ASM or al, DLATCH + ASM out dx, al + + /* Write lower byte of baud rate divisor. */ + ASM mov dx, nDataRegAddr + ASM mov ax, uDivisor + ASM out dx, al + + /* Write upper byte of baud rate divisor. */ + ASM mov dx, nIntEnableRegAddr + ASM mov al, ah + ASM out dx, al + + /* Reset baud rate divisor latch. */ + ASM mov dx, nLineCtrlRegAddr + ASM in al, dx + ASM and al, NOT_DL + ASM out dx, al + + /* Re-enable interrupts. */ + ASM sti + } + } + + /* Remember the serial I/O method that we are using. */ + pPortInfo->Method = kComMethodUART; + + /* Store port state as open. */ + pPortInfo->bIsOpen = TRUE; + + /* Return with success. */ + return(kODRCSuccess); + } +#endif /* INCLUDE_UART_COM */ + + /* The following code is used to handle I/O using the Door32 interface. */ +#ifdef INCLUDE_DOOR32_COM + if(pPortInfo->Method == kComMethodDoor32 || + pPortInfo->Method == kComMethodUnspecified) + { + /* Attempt to load the Door32 DLL. */ + pPortInfo->hinstDoor32DLL = LoadLibrary("DOOR32.DLL"); + if(pPortInfo->hinstDoor32DLL != NULL) + { + /* Obtain pointers to required Door32 API function entry points. */ + pPortInfo->pfDoorInitialize = (BOOL (WINAPI *)(void)) + GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorInitialize"); + pPortInfo->pfDoorShutdown = (BOOL (WINAPI *)(void)) + GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorShutdown"); + pPortInfo->pfDoorWrite = (BOOL (WINAPI *)(const BYTE *, DWORD)) + GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorWrite"); + pPortInfo->pfDoorRead = (DWORD (WINAPI *)(BYTE *, DWORD)) + GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorRead"); + pPortInfo->pfDoorGetAvailableEventHandle = (HANDLE (WINAPI *)(void)) + GetProcAddress(pPortInfo->hinstDoor32DLL, + "DoorGetAvailableEventHandle"); + pPortInfo->pfDoorGetOfflineEventHandle = (HANDLE (WINAPI *)(void)) + GetProcAddress(pPortInfo->hinstDoor32DLL, + "DoorGetOfflineEventHandle"); + + /* Check whether we have successfully been able to obtain all the */ + /* required function entry points. */ + if(pPortInfo->pfDoorInitialize != NULL + && pPortInfo->pfDoorShutdown != NULL + && pPortInfo->pfDoorWrite != NULL + && pPortInfo->pfDoorRead != NULL + && pPortInfo->pfDoorGetAvailableEventHandle != NULL + && pPortInfo->pfDoorGetOfflineEventHandle != NULL) + { + if((*pPortInfo->pfDoorInitialize)()) + { + /* Set port state as open. */ + pPortInfo->bIsOpen = TRUE; + + /* Set serial I/O method. */ + pPortInfo->Method = kComMethodDoor32; + + /* Return with success. */ + return(kODRCSuccess); + } + } + + /* On failure to obtain all Door32 function entry points, unload */ + /* the Door32 DLL. */ + FreeLibrary(pPortInfo->hinstDoor32DLL); + } + + /* If our attempt to use the Door32 interface failed for any reason, */ + /* then proceed, attempting to use the Win32 serial I/O interface. */ + } +#endif /* INCLUDE_DOOR32_COM */ + + /* The following code is used to handle Win32 API-base serial I/O */ + /* open operations. */ +#ifdef INCLUDE_WIN32_COM + if(pPortInfo->Method == kComMethodWin32 || + pPortInfo->Method == kComMethodUnspecified) + { + char szDevName[7]; + DCB dcb; + + /* Generate device name. */ + sprintf(szDevName, "COM%u", (unsigned)pPortInfo->btPort + 1); + + /* Attempt to create handle for device. */ + pPortInfo->hCommDev = CreateFile(szDevName, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + /* On open failure, return with an error code. */ + if(pPortInfo->hCommDev == INVALID_HANDLE_VALUE) + { + return(kODRCGeneralFailure); + } + + /* Note that read timeout settings have not been set. */ + pPortInfo->ReadTimeoutState = kNotSet; + + /* Call SetupComm() to set queue sizes. */ + if(!SetupComm(pPortInfo->hCommDev, pPortInfo->nReceiveBufferSize, + pPortInfo->nTransmitBufferSize)) + { + CloseHandle(pPortInfo->hCommDev); + return(kODRCGeneralFailure); + } + + /* Get current port state. */ + if(!GetCommState(pPortInfo->hCommDev, &dcb)) + { + CloseHandle(pPortInfo->hCommDev); + return(kODRCGeneralFailure); + } + + /* Fill device control block. */ + + /* Set bps rate, if appropriate. */ + if(pPortInfo->lSpeed != SPEED_UNSPECIFIED) + { + dcb.BaudRate = pPortInfo->lSpeed; + } + + /* Set flow control, if appropriate. */ + if(!(pPortInfo->btFlowControlSetting & FLOW_DEFAULT)) + { + if(pPortInfo->btFlowControlSetting & FLOW_RTSCTS) + { + dcb.fOutxCtsFlow = 1; + dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + } + else + { + dcb.fOutxCtsFlow = 0; + dcb.fRtsControl = RTS_CONTROL_ENABLE; + } + } + + /* Set word size. */ + if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_FIVE) + { + dcb.ByteSize = 5; + } + else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_SIX) + { + dcb.ByteSize = 6; + } + else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_SEVEN) + { + dcb.ByteSize = 7; + } + else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_EIGHT) + { + dcb.ByteSize = 8; + } + + /* Set parity. */ + if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_NONE) + { + dcb.Parity = NOPARITY; + } + else if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_ODD) + { + dcb.Parity = ODDPARITY; + } + else if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_EVEN) + { + dcb.Parity = EVENPARITY; + } + + /* Enable DTR control. */ + dcb.fDtrControl = DTR_CONTROL_ENABLE; + + /* Set number of stop bits. */ + if((pPortInfo->btWordFormat & STOP_MASK) == STOP_ONE) + { + dcb.StopBits = ONESTOPBIT; + } + else if((pPortInfo->btWordFormat & STOP_MASK) == STOP_ONE_POINT_FIVE) + { + dcb.StopBits = ONE5STOPBITS; + } + else if((pPortInfo->btWordFormat & STOP_MASK) == STOP_TWO) + { + dcb.StopBits = TWOSTOPBITS; + } + + /* Set comm state from device control block. */ + if(!SetCommState(pPortInfo->hCommDev, &dcb)) + { + CloseHandle(pPortInfo->hCommDev); + return(kODRCGeneralFailure); + } + + /* Store port state as open. */ + pPortInfo->bIsOpen = TRUE; + + /* Set serial I/O method. */ + pPortInfo->Method = kComMethodWin32; + + /* Return with success. */ + return(kODRCSuccess); + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_STDIO_COM + if(pPortInfo->Method == kComMethodStdIO || + pPortInfo->Method == kComMethodUnspecified) + { + if (isatty(STDIN_FILENO)) { + tcgetattr(STDIN_FILENO,&tio_default); + tio_raw = tio_default; + cfmakeraw(&tio_raw); + tcsetattr(STDIN_FILENO,TCSANOW,&tio_raw); + setvbuf(stdout, NULL, _IONBF, 0); + } + + /* Set port state as open. */ + pPortInfo->bIsOpen = TRUE; + + /* Set serial I/O method. */ + pPortInfo->Method = kComMethodStdIO; + + /* Return with success. */ + return(kODRCSuccess); + + } +#endif /* INCLUDE_STDIO_COM */ + + /* If we get to this point, then no form of serial I/O could be */ + /* initialized. */ + return(kODRCGeneralFailure); +} + + +/* ---------------------------------------------------------------------------- + * ODComOpenFromExistingHandle() + * + * Initializes serial I/O using a serial port handle natvie to the current + * operating system, which has already been opened by another application. + * + * Parameters: hPort - Handle to a serial port object. + * + * dwExistingHandle - Native operating system's handle to an + * already open serial port. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComOpenFromExistingHandle(tPortHandle hPort, + DWORD dwExistingHandle) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(!pPortInfo->bIsOpen); + +#ifdef INCLUDE_SOCKET_COM + if(pPortInfo->Method == kComMethodSocket) { + socklen_t delay=FALSE; + + pPortInfo->socket = dwExistingHandle; + + getsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &(pPortInfo->old_delay), &delay); + delay=FALSE; + setsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay)); + + pPortInfo->bIsOpen = TRUE; + + return(kODRCSuccess); + } +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_WIN32_COM + + /* Store handle to the Win32 handle to the serial port. */ + pPortInfo->hCommDev = (HANDLE)dwExistingHandle; + + /* Remember that read timeout settings have not been set. */ + pPortInfo->ReadTimeoutState = kNotSet; + + /* Remember that we are using a handle provided by the client, rather */ + /* than one that we opened ourself. This flag prevents the handle from */ + /* being closed by a call to ODComClose(). */ + pPortInfo->bUsingClientsHandle = TRUE; + + /* Remember that the serial port is now open. */ + pPortInfo->bIsOpen = TRUE; + + return(kODRCSuccess); + +#else /* !INCLUDE_WIN32_COM */ + UNUSED(dwExistingHandle); + UNUSED(pPortInfo); + + /* If no form of serial I/O included in this build can use this handle, */ + /* then return with a failure. */ + return(kODRCInvalidCall); + +#endif /* !INCLUDE_WIN32_COM */ +} + + +/* ---------------------------------------------------------------------------- + * ODComClose() + * + * Closes currently open serial port. + * + * Parameters: hPort - Handle to a serial port object. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComClose(tPortHandle hPort) +{ +#ifdef INCLUDE_UART_COM + BYTE btTemp; +#endif /* INCLUDE_UART_COM */ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + /* If we are using the client's handle, then we should not close it. */ + if(pPortInfo->bUsingClientsHandle) + { + pPortInfo->bIsOpen = FALSE; + return(kODRCSuccess); + } + + nPort = (int)pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + ASM mov ah, 5 + ASM mov dx, nPort + ASM int 20 + break; +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + /* Reset UART registers to their original values. */ + ASM mov dx, nModemCtrlRegAddr + ASM mov al, btOldModemCtrlReg + ASM out dx, al + ASM mov dx, nIntEnableRegAddr + ASM mov al, btOldIntEnableReg + ASM out dx, al + + /* Disable interrupts. */ + ASM cli + + /* Reset this line's interrupt enable status on the PIC to its */ + /* original state. */ + ASM mov dx, nI8259MaskRegAddr + ASM in al, dx + ASM mov btTemp, al + + btTemp = (btTemp & ~btI8259Bit) | (btI8259Mask & btI8259Bit); + + ASM mov dx, nI8259MaskRegAddr + ASM mov al, btTemp + ASM out dx, al + + /* Re-enable interrupts. */ + ASM sti + + /* Reset vector to original interrupt handler. */ +#ifdef _MSC_VER + ODComSetVect(btIntVector, (void far *)pfOldISR); +#else /* !_MSC_VER */ + ODComSetVect(btIntVector, pfOldISR); +#endif /* !_MSC_VER */ + + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + CloseHandle(pPortInfo->hCommDev); + break; +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorShutdown != NULL); + (*pPortInfo->pfDoorShutdown)(); + ASSERT(pPortInfo->hinstDoor32DLL != NULL); + FreeLibrary(pPortInfo->hinstDoor32DLL); + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + setsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &(pPortInfo->old_delay), sizeof(pPortInfo->old_delay)); + closesocket(pPortInfo->socket); + break; +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + if(isatty(STDIN_FILENO)) + tcsetattr(STDIN_FILENO,TCSANOW,&tio_default); + break; +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Store the fact that the port is now closed. */ + pPortInfo->bIsOpen = FALSE; + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComCarrier() + * + * Determines whether or not the carrier detect signal is present. + * + * Parameters: hPort - Handle to a serial port object. + * + * pbIsCarrier - Location to store result. Set to TRUE if carrier + * detect signal is high, FALSE if it is low. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComCarrier(tPortHandle hPort, BOOL *pbIsCarrier) +{ +#ifdef ODPLAT_NIX + sigset_t sigs; +#endif + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pbIsCarrier != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + { + int to_return; + + ASM mov ah, 3 + ASM mov dx, nPort + ASM int 20 + ASM and ax, 128 + ASM mov to_return, ax + + *pbIsCarrier = to_return; + + break; + } +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + { + BYTE btMSR; + + ASM mov dx, nModemStatusRegAddr + ASM in al, dx + ASM mov btMSR, al + + *pbIsCarrier = btMSR & RLSD; + break; + } +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwModemStats; + + /* Get modem status settings. */ + if(!GetCommModemStatus(pPortInfo->hCommDev, &dwModemStats)) + { + return(kODRCGeneralFailure); + } + + *pbIsCarrier = (dwModemStats & MS_RLSD_ON) ? TRUE : FALSE; + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorGetOfflineEventHandle != NULL); + *pbIsCarrier = (WaitForSingleObject( + (*pPortInfo->pfDoorGetOfflineEventHandle)(), + 0) != WAIT_OBJECT_0); + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + int i; + char ch; + fd_set socket_set; + struct timeval tv; + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + + tv.tv_sec=0; + tv.tv_usec=0; + i=select(pPortInfo->socket+1,&socket_set,NULL,NULL,&tv); + if(i==0 + || (i==1 && recv(pPortInfo->socket,&ch,1,MSG_PEEK)==1)) + *pbIsCarrier = TRUE; + else + *pbIsCarrier = FALSE; + break; + } +#endif + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + { + sigpending(&sigs); + if(sigismember(&sigs,SIGHUP)) + *pbIsCarrier = FALSE; + else + *pbIsCarrier = TRUE; + break; + } +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComSetDTR() + * + * Raises or lowers the DTR signal on the port. + * + * Parameters: hPort - Handle to a serial port object. + * + * bHigh - TRUE to raise DTR, FALSE to lower it. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSetDTR(tPortHandle hPort, BOOL bHigh) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + ASM cmp byte ptr bHigh, 0 + ASM je lower + ASM mov al, 1 + ASM jmp set_dtr + +lower: + ASM xor al, al + +set_dtr: + ASM mov ah, 6 + ASM mov dx, nPort + ASM int 20 +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + if(bHigh) + { + ASM cli + + ASM mov dx, nModemCtrlRegAddr + ASM in al, dx + ASM or al, DTR + ASM out dx, al + + ASM sti + } + else + { + ASM cli + + ASM mov dx, nModemCtrlRegAddr + ASM in al, dx + ASM and al, NOT_DTR + ASM out dx, al + + ASM sti + } + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + /* Set DTR line appropriately. */ + if(!EscapeCommFunction(pPortInfo->hCommDev, bHigh ? SETDTR : CLRDTR)) + { + return(kODRCGeneralFailure); + } + break; +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + return(kODRCUnsupported); +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + if(bHigh) + return(kODRCUnsupported); + closesocket(pPortInfo->socket); + break; +#endif /* INCLUDE_SOCKET_CO */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + return(kODRCUnsupported); +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComOutbound() + * + * Determines the number of bytes waiting in the serial port outbound buffer. + * + * Parameters: hPort - Handle to a serial port object. + * + * pnOutboundWaiting - Location where result the number of bytes + * waiting in the outbound buffer should be + * stored. Under some I/O methods we can + * determine whether data is still in the + * buffer, but not the number of bytes in the + * buffer. In this situation, this may be set + * to SIZE_NON_ZERO. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComOutbound(tPortHandle hPort, int *pnOutboundWaiting) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pnOutboundWaiting != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + ASM mov ah, 0x03 + ASM mov dx, nPort + ASM int 20 + ASM and ah, 0x40 + ASM jz still_sending + *pnOutboundWaiting = 0; + break; + +still_sending: + *pnOutboundWaiting = SIZE_NON_ZERO; + break; +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + *pnOutboundWaiting = (int)nTXChars; + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwErrors; + COMSTAT ComStat; + + /* Use ClearCommError() to obtain device status. */ + if(!ClearCommError(pPortInfo->hCommDev, &dwErrors, &ComStat)) + { + return(kODRCGeneralFailure); + } + + /* Set pbIsInbound to TRUE if any bytes are in outbound queue. */ + *pnOutboundWaiting = (int)ComStat.cbOutQue; + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + /* Door32 doesn't currently support this functionality, so we */ + /* assume that all sent data is transmitted immediately. */ + *pnOutboundWaiting = 0; + return(kODRCUnsupported); +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + *pnOutboundWaiting = 0; + return(kODRCUnsupported); +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + *pnOutboundWaiting = 0; + return(kODRCUnsupported); +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComClearOutbound() + * + * Removes the current contents of the serial port outbound buffer. + * + * Parameters: hPort - Handle to a serial port object. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComClearOutbound(tPortHandle hPort) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + ASM mov ah, 9 + ASM mov dx, nPort + ASM int 20 +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + ODComInternalResetTX(); + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + if(!PurgeComm(pPortInfo->hCommDev, PURGE_TXCLEAR)) + { + return(kODRCGeneralFailure); + } + break; +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + return(kODRCUnsupported); +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + return(kODRCUnsupported); +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + return(kODRCUnsupported); +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComClearInbound() + * + * Removes the current contents of the serial port inbound buffer. + * + * Parameters: hPort - Handle to a serial port object. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComClearInbound(tPortHandle hPort) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + ASM mov ah, 10 + ASM mov dx, nPort + ASM int 20 +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + ODComInternalResetRX(); + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + if(!PurgeComm(pPortInfo->hCommDev, PURGE_RXCLEAR)) + { + return(kODRCGeneralFailure); + } + break; +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + return(kODRCUnsupported); +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + return(kODRCUnsupported); +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + return(kODRCUnsupported); +#endif + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComInbound() + * + * Determines the number of bytes waiting in the serial port inbound buffer. + * + * Parameters: hPort - Handle to a serial port object. + * + * pnInboundWaiting - Location in which to store number of bytes + * waiting in the inbound buffer. Under some + * I/O methods (e.g. FOSSIL driver), we can + * determine whether data is still in the + * buffer, but not the number of bytes in the + * buffer. In this situation, this may be set + * to SIZE_NON_ZERO. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComInbound(tPortHandle hPort, int *pnInboundWaiting) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pnInboundWaiting != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + { + BOOL bDataInBuffer = FALSE; + + ASM mov ah, 3 + ASM mov dx, nPort + ASM push si + ASM push di + ASM int 20 + ASM pop di + ASM pop si + ASM and ah, 1 + ASM mov bDataInBuffer, ah + + *pnInboundWaiting = bDataInBuffer ? SIZE_NON_ZERO : 0; + + break; + } +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + *pnInboundWaiting = (int)nRXChars; + + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwErrors; + COMSTAT ComStat; + + /* Use ClearCommError() to obtain device status. */ + if(!ClearCommError(pPortInfo->hCommDev, &dwErrors, &ComStat)) + { + return(kODRCGeneralFailure); + } + + /* Set pbIsInbound to TRUE if there are any bytes in inbound queue. */ + *pnInboundWaiting = (int)ComStat.cbInQue; + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorGetAvailableEventHandle != NULL); + if(WaitForSingleObject( + (*pPortInfo->pfDoorGetAvailableEventHandle)(), + 0) == WAIT_OBJECT_0) + { + *pnInboundWaiting = SIZE_NON_ZERO; + } + else + { + *pnInboundWaiting = 0; + } + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + if(ioctlsocket(pPortInfo->socket,FIONREAD,pnInboundWaiting) != 0) + *pnInboundWaiting = 0; + break; +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + if(ioctl(0,FIONREAD,pnInboundWaiting) == -1) + *pnInboundWaiting = 0; + break; +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComGetByte() + * + * Returns a single inbound byte. If there are characters waiting in the + * inbound buffer, the next character is returned immediately. If bWait is TRUE + * and no characters are waiting, this function will wait until a character is + * received (possibly forever, if no characters are ever received). + * + * Parameters: hPort - Handle to a serial port object. + * + * pbtNext - Location to store retrieved byte. + * + * bWait - If TRUE, function will only return after a character + * has been received. If FALSE, this function will return + * kODRCNothingWaiting if no characters are waiting. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComGetByte(tPortHandle hPort, char *pbtNext, BOOL bWait) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pbtNext != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + { + BYTE btToReturn; + int nInboundSize; + + /* If we should not wait for characters if inbound queue is empty. */ + if(!bWait) + { + /* Determine whether there are any inbound characterse waiting. */ + ODComInbound(hPort, &nInboundSize); + + /* If there are no inbound characters waiting, then return */ + /* without obtaining any characters. */ + if(nInboundSize == 0) return(kODRCNothingWaiting); + } + + ASM mov ah, 2 + ASM mov dx, nPort + ASM push si + ASM push di + ASM int 20 + ASM pop di + ASM pop si + ASM mov btToReturn, al + + *pbtNext = btToReturn; + + break; + } +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + /* If we should not wait for characters if inbound queue is empty. */ + if(!bWait) + { + /* If there are no inbound characters waiting, then return */ + /* without obtaining any characters. */ + if(!nRXChars) return(kODRCNothingWaiting); + } + + /* Loop, calling idle function, until next character arrives. */ + while(!nRXChars) + { + if(pPortInfo->pfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + } + + /* Disable interrupts. */ + ASM cli + + /* Get next character from receive queue. */ + *pbtNext = pbtRXQueue[nRXOutIndex++]; + + /* Wrap queue index if needed. */ + if (nRXOutIndex == nRXQueueSize) + { + nRXOutIndex = 0; + } + + /* Decrement count of total character in the receive queue. */ + nRXChars--; + + /* Re-enable interrupts. */ + ASM sti + + /* If receive buffer is below low water mark. */ + if(nRXChars <= nRXLowWaterMark) + { + /* If we are using flow control, then stop sender from */ + /* sending. */ + if(btFlowControl & FLOW_RTSCTS) + { + /* If using RTS/CTS flow control, then raise RTS line. */ + ASM mov dx, nModemCtrlRegAddr + ASM in al, dx + ASM or al, RTS + ASM out dx, al + } + } + + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwBytesRead; + DWORD dwErrors; + + /* Ensure read timeout state is set appropriately for bWait value. */ + if(bWait) + { + ODComWin32SetReadTimeouts(pPortInfo, kBlocking); + } + else + { + ODComWin32SetReadTimeouts(pPortInfo, kNonBlocking); + } + + /* Perform read operation. */ + if(!ReadFile(pPortInfo->hCommDev, pbtNext, 1, &dwBytesRead, NULL)) + { + ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL); + return(kODRCGeneralFailure); + } + + /* Determine whether or not a byte was read. */ + if(dwBytesRead == 0) + { + /* If no bytes where read, then this is a general error if bWait */ + /* is TRUE. If bWait is FALSE, then we should return */ + /* waiting kODRCNothingWaiting. */ + return(bWait ? kODRCGeneralFailure : kODRCNothingWaiting); + } + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + if(WaitForSingleObject((*pPortInfo->pfDoorGetAvailableEventHandle)(), + bWait ? INFINITE : 0) == WAIT_OBJECT_0) + { + (*pPortInfo->pfDoorRead)(pbtNext, 1); + break; + } + + return(bWait ? kODRCGeneralFailure : kODRCNothingWaiting); + + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + fd_set socket_set; + struct timeval tv; + int select_ret, recv_ret; + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + + tv.tv_sec=0; + tv.tv_usec=100; + + select_ret = select(pPortInfo->socket+1, &socket_set, NULL, NULL, bWait ? NULL : &tv); + if (select_ret == SOCKET_ERROR) + return (kODRCGeneralFailure); + if (select_ret == 0) + return (kODRCNothingWaiting); + + do { + recv_ret = recv(pPortInfo->socket, pbtNext, 1, 0); + if(recv_ret != SOCKET_ERROR) + break; + if(WSAGetLastError() != WSAEWOULDBLOCK) + return (kODRCGeneralFailure); + od_sleep(50); + } while (bWait); + + if (recv_ret == 0) + return (kODRCNothingWaiting); + + break; + } +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + { + fd_set socket_set; + struct timeval tv; + int select_ret=-1; + int recv_ret; + + while(select_ret==-1) { + FD_ZERO(&socket_set); + FD_SET(STDIN_FILENO,&socket_set); + + tv.tv_sec=0; + tv.tv_usec=100; + + select_ret = select(STDIN_FILENO+1, &socket_set, NULL, NULL, bWait ? NULL : &tv); + if (select_ret == -1) { + if(errno==EINTR) + continue; + return (kODRCGeneralFailure); + } + if (select_ret == 0) + return (kODRCNothingWaiting); + } + + recv_ret = read(STDIN_FILENO, pbtNext, 1); + if(recv_ret == 1) + break; + return (kODRCGeneralFailure); + + break; + } +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODComSendByte() + * + * Sends a single byte to the serial port outbound buffer. + * + * Parameters: hPort - Handle to a serial port object. + * + * btToSend - The byte to transmit. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComSendByte(tPortHandle hPort, BYTE btToSend) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: +try_again: + ASM mov ah, 0x0b + ASM mov dx, nPort + ASM mov al, btToSend + ASM int 20 + ASM cmp ax, 0 + ASM jne keep_going + + /* Call idle function, if any. */ + if(pPortInfo->pfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + + goto try_again; +keep_going: + break; +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + /* Loop, calling idle function, until characters are waiting in */ + /* the transmit buffer. */ + while(!ODComInternalTXReady()) + { + /* Call idle function, if any. */ + if(pPortInfo->pfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + } + + /* Disable interrupts. */ + ASM cli + + /* Place the character in the queue. */ + pbtTXQueue[nTXInIndex++] = btToSend; + + /* Wrap transmit queue index, if needed. */ + if (nTXInIndex == nTXQueueSize) + { + nTXInIndex = 0; + } + + /* Increment count of total characters in the queue. */ + nTXChars++; + + /* Enable transmit interrupt on the UART. */ + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM or al, THRE + ASM out dx, al + + ASM sti + + break; +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwErrors; + DWORD dwBytesWritten; + + /* Attempt to perform write operation. */ + if(!WriteFile(pPortInfo->hCommDev, &btToSend, 1, &dwBytesWritten, + NULL) || dwBytesWritten != 1) + { + ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL); + return(kODRCGeneralFailure); + } + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorWrite != NULL); + if(!(*pPortInfo->pfDoorWrite)(&btToSend, 1)) + { + return(kODRCGeneralFailure); + } + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + fd_set socket_set; + struct timeval tv; + int send_ret; + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + + tv.tv_sec=1; + tv.tv_usec=0; + + if(select(pPortInfo->socket+1,NULL,&socket_set,NULL,&tv) != 1) + return(kODRCGeneralFailure); + + do { + send_ret = send(pPortInfo->socket, &btToSend, 1, 0); + if (send_ret != 1) + od_sleep(50); + } while ((send_ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)); + + if (send_ret == SOCKET_ERROR) + return (kODRCGeneralFailure); + + break; + } +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + { + fd_set fdset; + struct timeval tv; + int retval=-1; + int loopcount=0; + + while(retval==-1 && loopcount < 10) { + FD_ZERO(&fdset); + FD_SET(STDOUT_FILENO,&fdset); + + tv.tv_sec=1; + tv.tv_usec=0; + + retval=select(STDOUT_FILENO+1,NULL,&fdset,NULL,&tv); + if(retval!=1) { + if(retval==0) { + retval=-1; + loopcount++; + continue; + } + if(retval==-1 && errno==EINTR) + continue; + return(kODRCGeneralFailure); + } + } + + if(fwrite(&btToSend,1,1,stdout)!=1) + return(kODRCGeneralFailure); + break; + } +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComGetBuffer() + * + * Retreives received data into a buffer, filling the buffer with as much data + * as possible that has been received, returning immediately. + * + * Parameters: hPort - Handle to a serial port object. + * + * pbtBuffer - Pointer to a contiguous array of bytes. + * + * nSize - Size of buffer, in bytes. This is the maximum + * number of characters that will be returned. + * + * pnBytesRead - Pointer to an int where function will store the + * number of bytes actually read. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComGetBuffer(tPortHandle hPort, BYTE *pbtBuffer, int nSize, + int *pnBytesRead) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + int nPort; + + VERIFY_CALL(pPortInfo != NULL); + VERIFY_CALL(pbtBuffer != NULL); + VERIFY_CALL(nSize > 0); + VERIFY_CALL(pnBytesRead != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + { + int nReceived; + + ASM push di + ASM mov cx, nSize + ASM mov dx, nPort + + +#ifdef LARGEDATA + ASM les di, pbtBuffer +#else + ASM mov ax, ds + ASM mov es, ax + ASM mov di, pbtBuffer +#endif + + ASM mov ah, 0x18 + ASM int 20 + ASM pop di + ASM mov nReceived, ax + + *pnBytesRead = nReceived; + + break; + } +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + { + int nTransferSize; + int nFirstHalfSize; + int nSecondHalfSize; + char *pbtSource; + + /* Disable interrupts. */ + ASM cli + + /* Number of bytes to transfer is minimum of buffer size, and */ + /* number of bytes in receive queue. */ + nTransferSize = MIN(nRXChars, nSize); + + /* First half of transfer is minimum of number of bytes from here */ + /* to the end of the buffer, and the total transfer size. */ + nFirstHalfSize = nRXQueueSize - nRXOutIndex; + nFirstHalfSize = MIN(nFirstHalfSize, nTransferSize); + + /* Second half of transfer is remaining bytes, if any. */ + nSecondHalfSize = nTransferSize - nFirstHalfSize; + + /* Perform first half of transfer. */ + pbtSource = pbtRXQueue + nRXOutIndex; + while(nFirstHalfSize--) + { + *pbtBuffer++ = *pbtSource++; + } + + /* If there is a second half to transfer. */ + if(nSecondHalfSize) + { + /* Copy source will begin at beginning of queue. */ + pbtSource = pbtRXQueue; + + /* Set final queue out index. */ + nRXOutIndex = nSecondHalfSize; + + /* Perform second half of transfer. */ + while(nSecondHalfSize--) + { + *pbtBuffer++ = *pbtSource++; + } + } + + /* If entire transfer was performed in first half. */ + else + { + /* Set final queue out index. */ + nRXOutIndex += nTransferSize; + + /* Wrap queue out index, if needed. */ + if(nRXOutIndex == nRXQueueSize) nRXOutIndex = 0; + } + + /* Subtract number of bytes retrieved from number of bytes in */ + /* receive queue. */ + nRXChars -= nTransferSize; + + /* Return number of bytes copied into buffer. */ + *pnBytesRead = nTransferSize; + + /* Re-enable interrupts. */ + ASM sti + + break; + } +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwBytesRead; + DWORD dwErrors; + + /* Ensure read timeout state is set for non-blocking read */ + ODComWin32SetReadTimeouts(pPortInfo, kNonBlocking); + + /* Perform read operation. */ + if(!ReadFile(pPortInfo->hCommDev, pbtBuffer, nSize, &dwBytesRead, + NULL)) + { + ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL); + return(kODRCGeneralFailure); + } + + /* Pass number of bytes read back to caller. */ + *pnBytesRead = (int)dwBytesRead; + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorRead != NULL); + *pnBytesRead = (int)((*pPortInfo->pfDoorRead)(pbtBuffer, nSize)); + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + fd_set socket_set; + struct timeval tv; + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + + tv.tv_sec=0; + tv.tv_usec=100; + + if(select(pPortInfo->socket+1,&socket_set,NULL,NULL,&tv) != 1) { + *pnBytesRead = 0; + break; + } + + *pnBytesRead = recv(pPortInfo->socket,pbtBuffer,nSize,0); + break; + } +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + { + for(*pnBytesRead=0; + *pnBytesRead= 0); + + VERIFY_CALL(pPortInfo->bIsOpen); + + nPort = pPortInfo->btPort; + + /* If there are no characters to transmit, then there is no need to */ + /* proceed further. */ + if(nSize == 0) + { + return(kODRCSuccess); + } + + switch(pPortInfo->Method) + { +#ifdef INCLUDE_FOSSIL_COM + case kComMethodFOSSIL: + { + int nCount; + +try_again: + ASM push di + ASM mov cx, nSize + ASM mov dx, nPort + + +#ifdef LARGEDATA + ASM les di, pbtBuffer +#else + ASM mov ax, ds + ASM mov es, ax + ASM mov di, pbtBuffer +#endif + + ASM mov ah, 0x19 + ASM int 20 + ASM pop di + ASM mov nCount, ax + + if(nCountpfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + + nSize-=nCount; + pbtBuffer+=nCount; + goto try_again; + } + break; + } +#endif /* INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_UART_COM + case kComMethodUART: + { + int nTransferSize; + int nFirstHalfSize; + int nSecondHalfSize; + char *pbtDest; + + /* Loop, copying as much of buffer to transmit queue as possible, */ + /* then waiting for some characters to be transmitted, and copy */ + /* more of buffer to transmit queue, until entire buffer has been */ + /* transferred. */ + for(;;) + { + /* Disable interrupts. */ + ASM cli + + /* Try to transfer all of buffer if possible. */ + nTransferSize = nSize; + + /* Adjust number of character to transfer down if there isn't */ + /* enough space in transmit queue. */ + if(nTransferSize > (nTXQueueSize - nTXChars)) + { + nTransferSize = (nTXQueueSize - nTXChars); + } + + /* Block transfer is divided into two segments - everything from */ + /* current in index to end of queue, and everything from */ + /* beginning of queue to end of free space in queue. */ + + /* Calculate size of first half of transfer. */ + nFirstHalfSize = nTXQueueSize - nTXInIndex; + if(nFirstHalfSize > nTransferSize) nFirstHalfSize = nTransferSize; + + /* Calculate size of second half of transfer. */ + nSecondHalfSize = nTransferSize - nFirstHalfSize; + + /* Transfer characters at current queue in index. */ + pbtDest = pbtTXQueue + nTXInIndex; + while(nFirstHalfSize--) + { + *pbtDest++ = *pbtBuffer++; + } + + /* If there is a second half to transfer. */ + if(nSecondHalfSize) + { + /* Copy destination will begin at beginning of queue. */ + pbtDest = pbtTXQueue; + + /* Set final queue in index. */ + nTXInIndex = nSecondHalfSize; + + /* Perform second half of transfer. */ + while(nSecondHalfSize--) + { + *pbtDest++ = *pbtBuffer++; + } + } + + /* If entire transfer was performed in first half. */ + else + { + /* Set final queue in index. */ + nTXInIndex += nTransferSize; + + /* Wrap queue in index if we just happened to fill characters */ + /* up to end of physical queue. If there was one less */ + /* character transferred, no wrap would be necessary, and if */ + /* there was one more character to be transferred, transfer */ + /* would have to be performed in two halves. */ + if(nTXInIndex == nTXQueueSize) nTXInIndex = 0; + } + + /* Update count of total characters in the queue. */ + nTXChars += nTransferSize; + + /* Enable transmit interrupt on the UART. */ + ASM mov dx, nIntEnableRegAddr + ASM in al, dx + ASM or al, THRE + ASM out dx, al + + /* Re-enable interrupts. */ + ASM sti + + /* Adjust count of characters left to transfer down by number of */ + /* characters transferred. */ + nSize -= nTransferSize; + + /* If there are no characters left to transfer, then we are */ + /* done. */ + if(nSize == 0) break; + + /* Call idle function, if any. */ + if(pPortInfo->pfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + } + break; + } +#endif /* INCLUDE_UART_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwErrors; + DWORD dwBytesWritten; + + /* Attempt to perform write operation. */ + if(!WriteFile(pPortInfo->hCommDev, pbtBuffer, nSize, &dwBytesWritten, + NULL) || dwBytesWritten != (DWORD)nSize) + { + ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL); + return(kODRCGeneralFailure); + } + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + ASSERT(pPortInfo->pfDoorWrite != NULL); + if(!(*pPortInfo->pfDoorWrite)(pbtBuffer, nSize)) + { + return(kODRCGeneralFailure); + } + break; + return(kODRCUnsupported); +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + fd_set socket_set; + struct timeval tv; + int send_ret; + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + + tv.tv_sec=1; + tv.tv_usec=0; + + if(select(pPortInfo->socket+1,NULL,&socket_set,NULL,&tv) != 1) + return(kODRCGeneralFailure); + + do { + send_ret = send(pPortInfo->socket, pbtBuffer, nSize, 0); + if (send_ret != SOCKET_ERROR) + break; + od_sleep(25); + } while (WSAGetLastError() == WSAEWOULDBLOCK); + + if (send_ret != nSize) + return (kODRCGeneralFailure); + break; + } +#endif /* INCLUDE_SOCKET_COM */ + +#ifdef INCLUDE_STDIO_COM + case kComMethodStdIO: + { + int pos=0; + fd_set fdset; + struct timeval tv; + int retval; + int loopcount=0; + + while(pos10) + return(kODRCGeneralFailure); + continue; + } + if(retval==-1 && errno==EINTR) + continue; + return(kODRCGeneralFailure); + } + + retval=fwrite(pbtBuffer+pos,1,nSize-pos,stdout); + if(retval!=nSize-pos) { + od_sleep(1); + } + + pos+=retval; + } + break; + } +#endif + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODComWaitEvent() + * + * Blocks until the specified serial I/O event occurs, or an error condition + * is encountered. + * + * Parameters: hPort - Handle to an open port. + * + * Event - Event type to wait for. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODComWaitEvent(tPortHandle hPort, tComEvent Event) +{ + tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo); + + VERIFY_CALL(pPortInfo != NULL); + + VERIFY_CALL(pPortInfo->bIsOpen); + + switch(pPortInfo->Method) + { +#if defined(INCLUDE_UART_COM) || defined(INCLUDE_FOSSIL_COM) || defined(INCLUDE_STDIO_COM) + case kComMethodFOSSIL: + case kComMethodUART: + case kComMethodStdIO: + switch(Event) + { + case kNoCarrier: + { + BOOL bCarrier; + for(;;) + { + ODComCarrier(hPort, &bCarrier); + if(!bCarrier) break; + + if(pPortInfo->pfIdleCallback != NULL) + { + (*pPortInfo->pfIdleCallback)(); + } + } + break; + } + default: + VERIFY_CALL(FALSE); + } + break; +#endif /* INCLUDE_UART_COM || INCLUDE_FOSSIL_COM */ + +#ifdef INCLUDE_WIN32_COM + case kComMethodWin32: + { + DWORD dwEvtMask; + + /* Obtain current event mask. */ + if(!GetCommMask(pPortInfo->hCommDev, &dwEvtMask)) + { + return(kODRCGeneralFailure); + } + + /* Turn on event to be waited for. */ + switch(Event) + { + case kNoCarrier: + dwEvtMask |= EV_RLSD; + break; + default: + VERIFY_CALL(FALSE); + } + + /* Write new event mask. */ + if(!SetCommMask(pPortInfo->hCommDev, dwEvtMask)) + { + return(kODRCGeneralFailure); + } + + /* Wait until event occurs. */ + for(;;) + { + /* Block until some event occurs. */ + if(!WaitCommEvent(pPortInfo->hCommDev, &dwEvtMask, NULL)) + { + return(kODRCGeneralFailure); + } + + /* Determine whether this is what we are waiting for. */ + switch(Event) + { + case kNoCarrier: + if(dwEvtMask | EV_RLSD) + { + BOOL bCarrier; + ODComCarrier(hPort, &bCarrier); + if(!bCarrier) + { + return(kODRCSuccess); + } + } + break; + } + + /* If we get here, the event we are waiting for hasn't occurred */ + /* yet, so loop and block waiting for next event. */ + } + + break; + } +#endif /* INCLUDE_WIN32_COM */ + +#ifdef INCLUDE_DOOR32_COM + case kComMethodDoor32: + switch(Event) + { + case kNoCarrier: + ASSERT(pPortInfo->pfDoorGetOfflineEventHandle != NULL); + WaitForSingleObject( + (*pPortInfo->pfDoorGetOfflineEventHandle)(), INFINITE); + break; + default: + VERIFY_CALL(FALSE); + } + break; +#endif /* INCLUDE_DOOR32_COM */ + +#ifdef INCLUDE_SOCKET_COM + case kComMethodSocket: + { + if(Event == kNoCarrier) + { + /* Wait for socket disconnect */ + fd_set socket_set; + char ch; + int recv_ret; + + while(1) + { + + FD_ZERO(&socket_set); + FD_SET(pPortInfo->socket,&socket_set); + if(select(pPortInfo->socket+1,&socket_set,NULL,NULL,NULL) + ==SOCKET_ERROR) + break; + recv_ret = recv(pPortInfo->socket, &ch, 1, MSG_PEEK); + if(recv_ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + continue; + if (recv_ret != 1) + break; + } + } + else + { + VERIFY_CALL(FALSE); + } + break; + } +#endif /* INCLUDE_SOCKET_COM */ + + + default: + /* If we get here, then the current serial I/O method is not */ + /* handled by this function. */ + ASSERT(FALSE); + } + + /* Return with success. */ + return(kODRCSuccess); +} diff --git a/utils/magiedit/odoors/ODCom.h b/utils/magiedit/odoors/ODCom.h new file mode 100644 index 0000000..95425a6 --- /dev/null +++ b/utils/magiedit/odoors/ODCom.h @@ -0,0 +1,137 @@ +/* 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: ODCom.h + * + * Description: Public definitions for serial communications module, which + * is implemented in odcom.c + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 21, 1994 6.00 BP Created. + * Jan 01, 1995 6.00 BP Added ODComWaitEvent(). + * Dec 21, 1995 6.00 BP Add ability to use already open port. + * Jan 09, 1996 6.00 BP Supply actual in/out buffer size used. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Initial support for Door32 interface. + * Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support. + */ + +#ifndef _INC_ODCOM +#define _INC_ODCOM + +/* odtypes.h is needed for definitions of tODHandle, and BOOL. */ +#include "ODTypes.h" + +/* Serial I/O handle. */ +typedef tODHandle tPortHandle; + +/* Flow Control setting manifest constants. */ +#define FLOW_NONE 0x00 +#define FLOW_RTSCTS 0x02 +#define FLOW_DEFAULT 0x80 + +/* Parity bit setting manifest constants. */ +#define ODPARITY_NONE 0x00 +#define ODPARITY_ODD 0x08 +#define ODPARITY_EVEN 0x18 + +#define ODPARITY_MASK 0x18 + +/* Stop bit setting manifest constants. */ +#define STOP_ONE 0x00 +#define STOP_ONE_POINT_FIVE 0x04 /* Only with DATABITS_FIVE. */ +#define STOP_TWO 0x04 /* Only if not using DATABITS_FIVE. */ + +#define STOP_MASK 0x04 + +/* Character length manifest constants. */ +#define DATABITS_FIVE 0x00 +#define DATABITS_SIX 0x01 +#define DATABITS_SEVEN 0x02 +#define DATABITS_EIGHT 0x03 + +#define DATABITS_MASK 0x03 + +/* FIFO setting constants. */ +#define FIFO_DISABLE 0x00 +#define FIFO_ENABLE 0x01 +#define FIFO_TRIGGER_1 0x00 +#define FIFO_TRIGGER_4 0x40 +#define FIFO_TRIGGER_8 0x80 +#define FIFO_TRIGGER_14 0xc0 + +/* Misc. manifest constants. */ +#define SPEED_UNSPECIFIED 0 +#define SIZE_NON_ZERO -1 + +/* Serial I/O method settings. */ +typedef enum +{ + kComMethodUnspecified, + kComMethodFOSSIL, + kComMethodUART, + kComMethodWin32, + kComMethodDoor32, + kComMethodSocket, + kComMethodStdIO +} tComMethod; + +/* Serial I/O event types. */ +typedef enum +{ + kNoCarrier +} tComEvent; + +/* Serial I/O function prototypes. */ +tODResult ODComAlloc(tPortHandle *phPort); +tODResult ODComFree(tPortHandle hPort); +tODResult ODComSetIdleFunction(tPortHandle hPort, + void (*pfCallback)(void)); +tODResult ODComSetFlowControl(tPortHandle hPort, BYTE btFlowControlSetting); +tODResult ODComSetSpeed(tPortHandle hPort, long lSpeed); +tODResult ODComSetPort(tPortHandle hPort, BYTE btPort); +tODResult ODComSetIRQ(tPortHandle hPort, BYTE btIRQLevel); +tODResult ODComSetPortAddress(tPortHandle hPort, int nPortAddress); +tODResult ODComSetWordFormat(tPortHandle hPort, BYTE btWordFormat); +tODResult ODComSetRXBuf(tPortHandle hPort, int nReceiveBufferSize); +tODResult ODComSetTXBuf(tPortHandle hPort, int nTransmitBufferSize); +tODResult ODComSetFIFO(tPortHandle hPort, BYTE btFIFOSetting); +tODResult ODComSetPreferredMethod(tPortHandle hPort, tComMethod Method); +tODResult ODComGetMethod(tPortHandle hPort, tComMethod *pMethod); +tODResult ODComOpen(tPortHandle hPort); +tODResult ODComOpenFromExistingHandle(tPortHandle hPort, + DWORD dwExistingHandle); +tODResult ODComClose(tPortHandle hPort); +tODResult ODComClearInbound(tPortHandle hPort); +tODResult ODComClearOutbound(tPortHandle hPort); +tODResult ODComInbound(tPortHandle hPort, int *pnInboundWaiting); +tODResult ODComOutbound(tPortHandle hPort, int *pnOutboundWaiting); +tODResult ODComCarrier(tPortHandle hPort, BOOL *pbIsCarrier); +tODResult ODComSetDTR(tPortHandle hPort, BOOL bHigh); +tODResult ODComSendByte(tPortHandle hPort, BYTE btToSend); +tODResult ODComGetByte(tPortHandle hPort, char *pbtNext, BOOL bWait); +tODResult ODComSendBuffer(tPortHandle hPort, BYTE *pbtBuffer, int nSize); +tODResult ODComGetBuffer(tPortHandle hPort, BYTE *pbtBuffer, int nSize, + int *pnBytesRead); +tODResult ODComWaitEvent(tPortHandle hPort, tComEvent Event); + +#endif /* !_INC_ODCOM */ diff --git a/utils/magiedit/odoors/ODCore.c b/utils/magiedit/odoors/ODCore.c new file mode 100644 index 0000000..f69e79c --- /dev/null +++ b/utils/magiedit/odoors/ODCore.c @@ -0,0 +1,1620 @@ +/* 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 +#include +#include +#include +#include +#include + +#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('Ä',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); +} diff --git a/utils/magiedit/odoors/ODCore.h b/utils/magiedit/odoors/ODCore.h new file mode 100644 index 0000000..4108342 --- /dev/null +++ b/utils/magiedit/odoors/ODCore.h @@ -0,0 +1,109 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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.h + * + * Description: Global functions and variables provide by the odcore.c + * module. These core facilities are used throughout OpenDoors, + * and are required regardless of what OpenDoors features that + * a given program uses. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 16, 1995 6.00 BP Created. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Dec 24, 1995 6.00 BP Added abtGreyBlock. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 01, 1996 6.00 BP Changed TEXT_SIZE to 49. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Sep 01, 1996 6.10 BP Update output area on od_set_per...(). + */ + +#ifndef _INC_ODCORE +#define _INC_ODCORE + + +/* Include other header files that have definitions neede by this one. */ +#include "ODInQue.h" +#include "ODCom.h" +#include "ODPlat.h" +#include "ODScrn.h" + + +/* OpenDoors global initialized flag. */ +extern BOOL bODInitialized; + +/* Global serial port object handle. */ +extern tPortHandle hSerialPort; + +/* Global input queue object handle. */ +extern tODInQueueHandle hODInputQueue; + +/* Reentrancy control. */ +extern BOOL bIsCallbackActive; +extern BOOL bShellChatActive; + +/* Global working space. */ +#define OD_GLOBAL_WORK_STRING_SIZE 1025 +extern char szODWorkString[OD_GLOBAL_WORK_STRING_SIZE]; + +/* Global instance of the text information structure for general use. */ +extern tODScrnTextInfo ODTextInfo; + +/* Logfile function hooks. */ +extern BOOL (*pfLogWrite)(INT); +extern void (*pfLogClose)(INT); + +/* od_colour_config() support for od_printf(). */ +extern char chColorCheck; +extern char *pchColorEndPos; + +/* Status line information. */ +extern BYTE btCurrentStatusLine; +extern OD_PERSONALITY_CALLBACK *pfCurrentPersonality; +extern char szDesiredPersonality[33]; +typedef BOOL ODCALL SET_PERSONALITY_FUNC(char *pszName); +extern SET_PERSONALITY_FUNC *pfSetPersonality; + +/* Commonly used character sequences. */ +extern char abtBlackBlock[2]; +extern char abtGreyBlock[2]; +extern char szBackspaceWithDelete[4]; + +/* Current output area on screen. */ +extern BYTE btOutputTop; +extern BYTE btOutputBottom; + + +/* Core functions used throughout OpenDoors. */ +void ODWaitDrain(tODMilliSec MaxWait); +void ODStoreTextInfo(void); +void ODRestoreTextInfo(void); +void ODStringToName(char *pszToConvert); +BOOL ODPagePrompt(BOOL *pbPausing); + + +/* Number of built-in configuration file options. */ +#define TEXT_SIZE 49 + +/* Number of user-defined info file options. */ +#define LINES_SIZE 25 + + +#endif /* _INC_ODCORE */ diff --git a/utils/magiedit/odoors/ODDrBox.c b/utils/magiedit/odoors/ODDrBox.c new file mode 100644 index 0000000..5b3e225 --- /dev/null +++ b/utils/magiedit/odoors/ODDrBox.c @@ -0,0 +1,187 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODDrBox.c + * + * Description: Implements the od_draw_box() function. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODKrnl.h" + + +/* ---------------------------------------------------------------------------- + * od_draw_box() + * + * Draws a box on the local and remote screens, using the box characters + * specified in od_control.od_box_chars. Unlike the window functions, this + * function does not store the original contents of the screen where the box + * is drawn. + * + * Parameters: btLeft - Column number of the left side of the box. + * + * btTop - Row number of the top side of the box. + * + * btRight - Column number of hte right side of the box. + * + * btBottom - Row number of the bottom side of the box. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_draw_box(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom) +{ + /* Number of current line being drawn. */ + BYTE btLine; + + /* X size of window. */ + BYTE btBetweenSize = (btRight - btLeft) - 1; + + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_draw_box()"); + + /* Ensure that OpenDoors has been initialized */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Setup od_box_chars appropriately */ + if(od_control.od_box_chars[BOX_BOTTOM] == 0) + { + od_control.od_box_chars[BOX_BOTTOM] = od_control.od_box_chars[BOX_TOP]; + } + if(od_control.od_box_chars[BOX_RIGHT] == 0) + { + od_control.od_box_chars[BOX_RIGHT] = od_control.od_box_chars[BOX_LEFT]; + } + + /* Check that required display capabilities are supported. */ + if(!(od_control.user_ansi || od_control.user_avatar)) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(FALSE); + } + + /* Check that parameters are within valid range. */ + if(btLeft<1 || btTop<1 || btRight>80 || btBottom>25) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Move to top corner, if needed. */ + od_set_cursor(btTop, btLeft); + + /* Display left corner character. */ + od_putch(od_control.od_box_chars[BOX_UPPERLEFT]); + + /* Display top line. */ + od_repeat(od_control.od_box_chars[BOX_TOP], btBetweenSize); + + /* Display right corner character. */ + od_putch(od_control.od_box_chars[BOX_UPPERRIGHT]); + + /* If AVATAR display mode is available. */ + if(od_control.user_avatar) + { + /* Display first left vertical line. */ + od_set_cursor(btTop + 1, btLeft); + od_putch(od_control.od_box_chars[BOX_LEFT]); + + /* Fill in the center of the window. */ + od_emulate(22); + od_emulate(12); + od_emulate((BYTE)od_control.od_cur_attrib); + od_emulate((BYTE)((btBottom - btTop) - 1)); + od_emulate(btBetweenSize); + + /* Display first right vertical line. */ + od_set_cursor(btTop + 1, btRight); + od_putch(od_control.od_box_chars[BOX_RIGHT]); + + /* Display remaining vertical lines. */ + for(btLine = btTop + 2; btLine < btBottom; ++btLine) + { + /* Move to the start of the line. */ + od_set_cursor(btLine, btLeft); + + /* Display left line character. */ + od_putch(od_control.od_box_chars[BOX_LEFT]); + + /* Move to line start. */ + od_set_cursor(btLine, btRight); + + /* Display right line character. */ + od_putch(od_control.od_box_chars[BOX_RIGHT]); + } + } + + /* If AVATAR mode is not available. */ + else + { + /* Loop through middle lines of window. */ + for(btLine = btTop + 1; btLine < btBottom; ++btLine) + { + /* Move to the start of the line. */ + od_set_cursor(btLine,btLeft); + + /* Display left line character. */ + od_putch(od_control.od_box_chars[BOX_LEFT]); + + /* Display the blank area. */ + od_repeat(' ', btBetweenSize); + + /* Display the right line character. */ + od_putch(od_control.od_box_chars[BOX_RIGHT]); + } + } + + /* Move to bottom corner. */ + od_set_cursor(btBottom, btLeft); + + /* Display left corner character. */ + od_putch(od_control.od_box_chars[BOX_LOWERLEFT]); + + /* Display bottom line. */ + od_repeat(od_control.od_box_chars[BOX_BOTTOM], btBetweenSize); + + /* Display right corner character. */ + od_putch(od_control.od_box_chars[BOX_LOWERRIGHT]); + + /* Return with success. */ + OD_API_EXIT(); + return(TRUE); +} diff --git a/utils/magiedit/odoors/ODEdStr.c b/utils/magiedit/odoors/ODEdStr.c new file mode 100644 index 0000000..d9f0f9d --- /dev/null +++ b/utils/magiedit/odoors/ODEdStr.c @@ -0,0 +1,1239 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODEdStr.c + * + * Description: Implementation of od_edit_str(). This is the advanced line + * editing function which requires ANSI or AVATAR graphics. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 31, 1994 6.00 BP Use ODTimerSleep() instead of loop. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 23, 1995 6.00 BP Added EDIT_FLAG_SHOW_SIZE. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 04, 1996 6.00 BP Use od_get_input(). + * Jan 12, 1996 6.00 BP Claim exclusive use of arrow keys. + * Jan 31, 1996 6.00 BP Added timeout for od_get_input(). + * Feb 10, 1996 6.00 BP Fixed ...SHOW_SIZE /w ...PERMALITERAL. + * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Apr 08, 1996 6.10 BP Make 'C' use word capitalization. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODKrnl.h" +#include "ODStat.h" + + +/* Current od_edit_str() state and settings. */ +static INT anCurrentFormatOffset[80]; +static BOOL abCurrentFormatLiteral[80]; +static char szCurrentOriginalString[81]; +static char *pszCurrentInput; +static char *pszCurrentFormat; +static unsigned char nCurrentStringLength; +static char chCurrentBlank; + + +/* Private helper functions used by od_edit_str(). */ +static BOOL ODEditIsCharValidForPos(char chEntered, INT nPosition); +static char ODEditAsCharForPos(char chEntered, INT nPosition); +static void ODEditDisplayPermaliteral(WORD nFlags); + + +/* ---------------------------------------------------------------------------- + * od_edit_str() + * + * Provides more advanced editing capabilities than od_get_str(), requiring + * ANSI, AVATAR or RIP modes. + * + * Parameters: pszInput - Pointer to string where inputted text is + * stored. + * + * pszFormat - Pointer to format string, which specifies + * the format of inputted text. + * + * nRow - The row number where the input field should + * begin. + * + * nColumn - The column number where the input field + * should begin. + * + * btNormalColour - Color of normal text. + * + * btHighlightColour - Color of highlighted text. + * + * chBlank - Character to display blanks with. + * + * nFlags - Specifies one or more flags, combined with + * the bitwise-or operator. + * + * Return: One of a number of possible EDIT_RETURN_ values, which indicate + * why the function returned. + */ +ODAPIDEF WORD ODCALL od_edit_str(char *pszInput, char *pszFormat, INT nRow, + INT nColumn, BYTE btNormalColour, BYTE btHighlightColour, + char chBlank, WORD nFlags) +{ + char chTemp; + unsigned int nCount; + unsigned char chCurrentValue; + char *pchCurrent; + unsigned int nCursorPos; + INT nKeysPressed = 0; + WORD wToReturn; + BOOL bInsertMode = TRUE; + char chAddAtEnd = '\0'; + BOOL bNormal = TRUE; + tODInputEvent InputEvent; + + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_edit_str()"); + + /* Verify that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Store pointers to current input string and current format string. */ + pszCurrentInput=(char *)pszInput; + pszCurrentFormat=(char *)pszFormat; + + /* Check that the parameters passed in are valid. */ + if(pszCurrentInput == NULL || pszCurrentFormat == NULL || nRow < 1 + || nColumn < 1) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(EDIT_RETURN_ERROR); + } + + /* Initially, the maximum length of input string is 0. */ + nCurrentStringLength = 0; + + /* The type that is being examined. */ + chCurrentValue = 0; + + /* Counter of position in format string. */ + nCount = 0; + + /* Loop until we reach the end fo the format string. */ + for(pchCurrent = pszCurrentFormat; *pchCurrent;) + { + /* Get next character from format string. */ + chTemp = *pchCurrent++; + + /* If current character is not a literal value. */ + if(chCurrentValue == '\0') + { + /* If format string has " or ' characters, then this is the */ + /* beginning of a literal string. */ + if(chTemp == 39 || chTemp == 34) + { + chCurrentValue = chTemp; + } + + /* If this is not a literal character, and not a space character... */ + else if(chTemp != 32) + { + /* Check that we haven't exceeded the maximum allowable string */ + /* length. */ + if(nCurrentStringLength >= 80) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(EDIT_RETURN_ERROR); + } + + /* Record format character's position. */ + anCurrentFormatOffset[nCurrentStringLength] = nCount; + + /* Record that this character is not a literal. */ + abCurrentFormatLiteral[nCurrentStringLength] = FALSE; + + /* Increment length of input string. */ + ++nCurrentStringLength; + } + } + + /* If this is a literal character. */ + else + { + /* Check for end of literal string. */ + if(chTemp == chCurrentValue) + { + /* If found, stop literal string processing */ + chCurrentValue = '\0'; + } + else + { + /* Check that we haven't exceeded the maximum allowable string */ + /* length. */ + if(nCurrentStringLength >= 80) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(EDIT_RETURN_ERROR); + } + + /* Record character's position. */ + anCurrentFormatOffset[nCurrentStringLength] = nCount; + + /* Record that character IS a literal value. */ + abCurrentFormatLiteral[nCurrentStringLength] = TRUE; + + /* Increment length of input string. */ + ++nCurrentStringLength; + } + } + + /* Increment format string position. */ + ++nCount; + } + + /* Check that there is at least one character permitted in the input */ + /* string. If not, return with a parameter error. */ + if(nCurrentStringLength==0) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(EDIT_RETURN_ERROR); + } + + /* If editing an existing string. */ + if(nFlags & EDIT_FLAG_EDIT_STRING) + { + /* Check for valid existing input string. */ + if(strlen(pszCurrentInput) > nCurrentStringLength) + { + pszCurrentInput[nCurrentStringLength] = '\0'; + } + + /* Start with cursor at the end of the string. */ + nCursorPos = strlen(pszCurrentInput); + } + + /* If we are not editing an existing string. */ + else + { + /* Blank-out current string contents. */ + pszCurrentInput[0] = '\0'; + + /* Set cursor to beginning of string. */ + nCursorPos = 0; + } + + /* Store original string, in case user cancels. */ + strcpy(szCurrentOriginalString,pszCurrentInput); + + /* Set appropriate text color. */ + od_set_attrib(btHighlightColour); + + /* Determine appropriate blank character */ + chCurrentBlank = (nFlags & EDIT_FLAG_PASSWORD_MODE) ? ' ' : chBlank; + + /* Turn off insert mode if the strict input or permaliteral flags were */ + /* specified. */ + if((nFlags & EDIT_FLAG_STRICT_INPUT) || (nFlags & EDIT_FLAG_PERMALITERAL)) + { + bInsertMode = FALSE; + } + + /* If the no-initial-redraw flag is not set, then do initial redraw. */ + if(!(nFlags & EDIT_FLAG_NO_REDRAW)) + { + /* Set to redraw position. */ + od_set_cursor(nRow, nColumn); + + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* If we are in password mode, then just draw password blanks. */ + od_repeat(chBlank, (BYTE)strlen(pszCurrentInput)); + } + else + { + /* Otherwise, display the actual string. */ + od_disp_str(pszCurrentInput); + } + + if(nFlags & EDIT_FLAG_PERMALITERAL) + { + /* If we are in permaliteral mode, then fill the remaining edit */ + /* field with the literal characters. */ + ODEditDisplayPermaliteral(nFlags); + } + else + { + /* Otherwise, fill the remaining edit field with the blank */ + /* character. */ + BYTE btRemaining + = (BYTE)(nCurrentStringLength - strlen(pszCurrentInput)); + if(!(nFlags & EDIT_FLAG_SHOW_SIZE)) ++btRemaining; + od_repeat(chCurrentBlank, btRemaining); + } + } + + /* Claim exclusive use of arrow keys. */ + ODStatStartArrowUse(); + + /* Set the cursor to appropriate position. */ + od_set_cursor(nRow, nColumn + nCursorPos); + + /* Normally, we start the input loop at the keep_going tag. */ + if(bNormal) goto keep_going; + + for(;;) + { + /* If auto-accept mode has been specified ... */ + if(nFlags & EDIT_FLAG_AUTO_ENTER) + { + /* ... then check whether we have reached the end of the string. */ + if(strlen(pszCurrentInput) == nCurrentStringLength) + { + /* Indicate that input has been accepted, rather than cancelled. */ + wToReturn = EDIT_RETURN_ACCEPT; + + /* Return the current string to the caller, if it is valid. */ + goto try_to_accept; + } + } + +keep_going: + /* Check whether we have reached a literal character in permaliteral */ + /* mode. If so, we will move past the permanent literal characters */ + /* automatically. */ + if((nFlags & EDIT_FLAG_PERMALITERAL) + && (nCursorPos < nCurrentStringLength)) + { + if(abCurrentFormatLiteral[nCursorPos]) + { + if(nCursorPos < strlen(pszCurrentInput)) + { + goto pressed_right_arrow; + } + chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]]; + ++nKeysPressed; + goto try_this_character; + } + } + +get_another_key: + /* Block, waiting for the next key pressed by the user. */ + + od_get_input(&InputEvent, OD_NO_TIMEOUT, GETIN_NORMAL); + + /* Increment total number of keystrokes. */ + ++nKeysPressed; + + if(InputEvent.EventType == EVENT_EXTENDED_KEY) + { + switch(InputEvent.chKeyPress) + { + case OD_KEY_UP: + case OD_KEY_SHIFTTAB: + if(nFlags & EDIT_FLAG_FIELD_MODE) + { + wToReturn = EDIT_RETURN_PREVIOUS; + goto try_to_accept; + } + break; + + case OD_KEY_DOWN: +pressed_down_arrow: + if(nFlags & EDIT_FLAG_FIELD_MODE) + { + wToReturn = EDIT_RETURN_NEXT; + goto try_to_accept; + } + break; + + case OD_KEY_RIGHT: +pressed_right_arrow: + /* If we are not at the end of the string. */ + if(nCursorPos < strlen(pszCurrentInput)) + { + /* Move input position right. */ + nCursorPos++; + + /* Move the cursor on screen. */ + od_set_cursor(nRow, nColumn + nCursorPos); + } + if(chAddAtEnd) + { + chAddAtEnd = 0; + goto add_another_key; + } + break; + + case OD_KEY_LEFT: +pressed_left_arrow: + /* If we are not at the beginning of the string. */ + if(nCursorPos > 0) + { + /* Move input position left. */ + nCursorPos--; + + /* Move cursor on screen. */ + od_set_cursor(nRow, nColumn + nCursorPos); + } + + /* If we are moving past a permanent literal character, */ + /* then continue moving further left, if possible. */ + if((nFlags & EDIT_FLAG_PERMALITERAL) + && abCurrentFormatLiteral[nCursorPos] && nCursorPos > 0) + { + goto pressed_left_arrow; + } + break; + + case OD_KEY_HOME: + /* If we are not at the beginning of the string. */ + if(nCursorPos != 0) + { + /* Move input position to the beginning of the string. */ + nCursorPos = 0; + + /* Move the cursor on the screen. */ + od_set_cursor(nRow, nColumn); + } + break; + + case OD_KEY_END: + /* If we are not at the end of the string .*/ + if(nCursorPos != strlen(pszCurrentInput)) + { + /* Set the input position to the end of the string. */ + nCursorPos=strlen(pszCurrentInput); + + /* Move cursor on screen. */ + od_set_cursor(nRow,nColumn+nCursorPos); + } + break; + + case OD_KEY_DELETE: +pressed_delete: + /* Check whether delete key is permitted at this time. */ + if(!(nFlags & EDIT_FLAG_STRICT_INPUT) + && nCursorPos < strlen(pszCurrentInput) + && !(nFlags & EDIT_FLAG_PERMALITERAL)) + { + /* Move remaining line, if any, to the left */ + chCurrentValue = strlen(pszCurrentInput) - 1; + for(nCount = nCursorPos; nCount < chCurrentValue; ++nCount) + { + od_putch( + pszCurrentInput[nCount] = pszCurrentInput[nCount + 1]); + } + + /* Erase the last character. */ + pszCurrentInput[chCurrentValue] = '\0'; + + /* Blank out last character. */ + od_putch(chCurrentBlank); + + /* Move the cursor on the screen. */ + od_set_cursor(nRow, nColumn + nCursorPos); + + /* Update changes to string. */ + goto check_cursor_char; + } + break; + + case OD_KEY_INSERT: + if(!(nFlags & EDIT_FLAG_STRICT_INPUT) + && !(nFlags & EDIT_FLAG_PERMALITERAL)) + { + /* Toggle insert setting. */ + bInsertMode = !bInsertMode; + } + break; + + } + } + else if(InputEvent.EventType == EVENT_CHARACTER) + { + chTemp = InputEvent.chKeyPress; +try_this_character: + + if(chTemp == 27) + { + /* If cancel key is allowed ... */ + if(nFlags & EDIT_FLAG_ALLOW_CANCEL) + { + /* Reset the input string to the original contents. */ + strcpy(pszCurrentInput, szCurrentOriginalString); + + /* Indicate that return reason was due to user cancelling. */ + wToReturn = EDIT_RETURN_CANCEL; + + /* Return after redrawing the original string in the input */ + /* field. */ + goto exit_and_redraw; + } + } + + + /* If user pressed [Enter] or [Ctrl]-[Z]. */ + else if(chTemp == 13 || chTemp == 26) + { + /* User has accepted input. */ + wToReturn = EDIT_RETURN_ACCEPT; + + /* Return if input string is valid. */ + goto try_to_accept; + } + + /* If the backspace key has been pressed. */ + else if(chTemp == 8) + { + backspace_again: + /* If we are not already at the beginning of the string. */ + if(nCursorPos > 0) + { + if(nFlags & EDIT_FLAG_PERMALITERAL) + { + for(nCount = 0;nCount < nCursorPos; ++nCount) + { + if(!abCurrentFormatLiteral[nCount]) goto continue_deletion; + } + goto get_another_key; + } + + continue_deletion: + /* If we are at the end of the string. */ + if(nCursorPos == strlen(pszCurrentInput)) + { + /* Erase last char in string. */ + pszCurrentInput[--nCursorPos] = '\0'; + + if((nFlags & EDIT_FLAG_PERMALITERAL) + && abCurrentFormatLiteral[nCursorPos]) + { + goto backspace_again; + } + else + { + /* Move to new cursor pos. */ + od_set_cursor(nRow,nColumn+nCursorPos); + + /* Blank old character. */ + od_putch(chCurrentBlank); + + /* Move again to cursor pos. */ + od_set_cursor(nRow,nColumn+nCursorPos); + } + } + + /* If we are in the middle of the string and we are not in */ + /* string input mode. */ + else if(!(nFlags & EDIT_FLAG_STRICT_INPUT) + && !(nFlags & EDIT_FLAG_PERMALITERAL)) + { + /* Move cursor left. */ + --nCursorPos; + + /* Move cursor on screen. */ + od_set_cursor(nRow, nColumn + nCursorPos); + + /* Goto standard delete handler. */ + goto pressed_delete; + } + } + } + + /* If this is a next field request. */ + else if(chTemp == 9) + { + /* Goto down arrow handler. */ + goto pressed_down_arrow; + } + + /* If Control-Y. */ + else if(chTemp == 25) + { + /* Erase entire contents of line. */ + goto kill_whole_line; + } + + else + { + /* If this is the first key pressed, and we are in autodelete mode. */ + if(nKeysPressed == 1 && (nFlags & EDIT_FLAG_AUTO_DELETE)) + { + kill_whole_line: + /* If string is not empty. */ + if(strlen(pszCurrentInput) != 0) + { + /* Move to beginning of string. */ + od_set_cursor(nRow,nColumn); + + /* Blank out the entire string contents. */ + od_repeat(chCurrentBlank, (BYTE)strlen(pszCurrentInput)); + } + + /* Move to new cursor position. */ + od_set_cursor(nRow,nColumn); + + /* Update insert position. */ + nCursorPos = 0; + + /* Blank out the current string contents. */ + pszCurrentInput[0] = '\0'; + } + + add_another_key: + if(!ODEditIsCharValidForPos(chTemp,nCursorPos)) + { + /* If character is not a valid input char. */ + if(abCurrentFormatLiteral[nCursorPos]) + { + if(nCursorPos < strlen(pszCurrentInput)) + { + if(pszCurrentInput[nCursorPos] == + pszCurrentFormat[anCurrentFormatOffset[nCursorPos]]) + { + chAddAtEnd = chTemp; + goto pressed_right_arrow; + } + } + chAddAtEnd = chTemp; + chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]]; + } + else + { + continue; + } + } + + /* Convert character to correct value, if applicable. */ + chTemp = ODEditAsCharForPos(chTemp, nCursorPos); + + /* If we are at end of string. */ + if(nCursorPos >= strlen(pszCurrentInput)) + { + /* Reset original cursor position */ + nCursorPos = strlen(pszCurrentInput); + + /* If there is room to add a char. */ + if(nCursorPos < nCurrentStringLength) + { + /* If password mode */ + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* Display the password character. */ + od_putch(chBlank); + } + /* If not in password mode. */ + else + { + /* Display the character. */ + od_putch(chTemp); + } + + /* Store the character. */ + pszCurrentInput[nCursorPos] = chTemp; + + /* Add a new string terminator. */ + pszCurrentInput[++nCursorPos] = '\0'; + } + } + + /* If in insert mode, but not at end of string. */ + else if(bInsertMode) + { + /* If room in string. */ + if(strlen(pszCurrentInput) < nCurrentStringLength) + { + /* If in password mode. */ + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* Move to end. */ + od_set_cursor(nRow,nColumn+strlen(pszCurrentInput)); + + /* Add another password character. */ + od_putch(chBlank); + } + + /* If not in password mode. */ + else + { + /* Display the new character. */ + od_putch(chTemp); + + /* Loop through rest of string. */ + for(nCount = nCursorPos; nCount < strlen(pszCurrentInput); + ++nCount) + { + /* Display the next remaining character. */ + od_putch(pszCurrentInput[nCount]); + } + } + + pszCurrentInput[(strlen(pszCurrentInput) + 1)] = '\0'; + + /* Sift remaining characters forward. */ + for(nCount = strlen(pszCurrentInput); nCount > nCursorPos; + --nCount) + { + pszCurrentInput[nCount] = pszCurrentInput[nCount-1]; + } + + /* Add new char in space. */ + pszCurrentInput[nCursorPos++] = chTemp; + + /* Move to new cursor position. */ + od_set_cursor(nRow, nColumn + nCursorPos); + } + else + { + goto get_another_key; + } + } + + /* If we are in overwrite mode, but not at end of string. */ + else + { + /* If password mode. */ + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* Display the password character. */ + od_putch(chBlank); + } + /* If not in password mode. */ + else + { + /* Display the character. */ + od_putch(chTemp); + } + + /* Add character to string. */ + pszCurrentInput[nCursorPos++] = chTemp; + } + + /* If not at end of possible string. */ + if(nCursorPos < nCurrentStringLength) + { + /* If the next character is literal constant. */ + if(abCurrentFormatLiteral[nCursorPos]) + { + chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]]; + goto add_another_key; + } + } + + if(chAddAtEnd) + { + chTemp = chAddAtEnd; + chAddAtEnd = 0; + goto add_another_key; + } + + + check_cursor_char: + /* If there is a character under cursor. */ + if(nCursorPos < strlen(pszCurrentInput)) + { + /* If character corresponds to the format string. */ + if(ODEditIsCharValidForPos(pszCurrentInput[nCursorPos], + nCursorPos)) + { + /* Determine correct character for this position. */ + chTemp = ODEditAsCharForPos(pszCurrentInput[nCursorPos], + nCursorPos); + + /* If actual character is not correct. */ + if(chTemp != pszCurrentInput[nCursorPos]) + { + /* Change character to correct value. */ + pszCurrentInput[nCursorPos] = chTemp; + + /* If password mode. */ + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* Display the password character. */ + od_putch(chBlank); + } + + /* If not in password mode. */ + else + { + /* Display the character. */ + od_putch(chTemp); + } + + /* Reset cursor position. */ + od_set_cursor(nRow, nColumn + nCursorPos); + } + } + } + } + } + } + + /* Accept string if it is valid. */ +try_to_accept: + /* If string must be filled. */ + if(nFlags & EDIT_FLAG_FILL_STRING) + { + /* If string is not filled, don't return. */ + if(strlen(pszCurrentInput) != nCurrentStringLength) goto keep_going; + } + + /* Loop through string .... */ + for(nCount = 0; nCount < strlen(pszCurrentInput); ++nCount) + { + /* ... testing each character for validity. */ + if(!ODEditIsCharValidForPos(pszCurrentInput[nCount], nCount)) + goto keep_going; + } + + /* Initially, assume that the string has not been changed. */ + chCurrentValue = FALSE; + + /* Loop through the string. */ + for(nCount = 0; nCount < strlen(pszCurrentInput); ++nCount) + { + /* Find correct value for each character. */ + chTemp = ODEditAsCharForPos(pszCurrentInput[nCount], nCount); + + /* If character is not correct. */ + if(chTemp != pszCurrentInput[nCount]) + { + /* Change char to correct value */ + pszCurrentInput[nCount] = chTemp; + + /* Remember that string has been changed. */ + chCurrentValue = TRUE; + } + } + + /* If permaliteral mode. */ + if(nFlags & EDIT_FLAG_LEAVE_BLANK) + { + /* Count # of literal characters. */ + nCount = 0; + while(nCount 0) + { + /* Then they shouldn't be here. */ + pszCurrentInput[0] = '\0'; + goto exit_and_redraw; + } + } + + /* Always redraw if string was changed. */ + if(chCurrentValue) goto exit_and_redraw; + + /* If no-redraw flag not set. */ + if(!(nFlags & EDIT_FLAG_NO_REDRAW)) + { +exit_and_redraw: + /* Set appropriate text colour. */ + od_set_attrib(btNormalColour); + + /* Set to redraw position. */ + od_set_cursor(nRow,nColumn); + + /* If password mode. */ + if(nFlags & EDIT_FLAG_PASSWORD_MODE) + { + /* Display blanked-out string. */ + od_repeat(chBlank, (BYTE)strlen(pszCurrentInput)); + } + else + { + /* Display actual string. */ + od_disp_str(pszCurrentInput); + } + + /* If we should keep the background. */ + if(nFlags & EDIT_FLAG_KEEP_BLANK) + { + /* Then redraw background. */ + if(nFlags & EDIT_FLAG_PERMALITERAL) + { + ODEditDisplayPermaliteral(nFlags); + } + else + { + od_repeat(chCurrentBlank, + (BYTE)(nCurrentStringLength - strlen(pszCurrentInput) + 1)); + } + } + /* If we should erase the background ... */ + else + { + /* ... then do it. */ + od_repeat(' ', + (BYTE)(nCurrentStringLength - strlen(pszCurrentInput) + 1)); + } + } + + /* Release exclusive use of arrow keys. */ + ODStatEndArrowUse(); + + /* Return with appropriate return value. */ + OD_API_EXIT(); + return(wToReturn); +} + + + +/* ---------------------------------------------------------------------------- + * ODEditIsCharValidForPos() *** PRIVATE FUNCTION *** + * + * Determines whether or not the entered character can be accepted as a valid + * character (after any possible conversion by ODEditAsCharForPos() is applied) + * for the specified position in the string. + * + * Parameters: chEntered - The character entered by the user. + * + * nPosition - The position in the string where this character + * would be inserted. + * + * Return: TRUE if this character should be accepted, FALSE if not. + */ +static BOOL ODEditIsCharValidForPos(char chEntered, INT nPosition) +{ + /* If this character is a literal. */ + if(abCurrentFormatLiteral[nPosition]) + { + /* Check required literal character. */ + if(chEntered != pszCurrentFormat[anCurrentFormatOffset[nPosition]]) + { + /* If this is not the correct literal character, then do not */ + /* permit it to be entered in this position. */ + return(FALSE); + } + return(TRUE); + } + + /* If this position has a corresponding format control character, */ + /* then check that control character. The execution path will */ + /* continue out of this switch statement (rather than returning */ + /* to the calling function) if and only if the entered character */ + /* is valid for the format character specified. */ + switch(pszCurrentFormat[anCurrentFormatOffset[nPosition]]) + { + /* Only numerical characters are to be permitted. */ + case '#': + if(chEntered < '0' || chEntered > '9') return(FALSE); + break; + + /* Only numerical and space characters are to be permitted. */ + case '%': + if((chEntered < '0' || chEntered > '9') && chEntered != ' ') + { + return(FALSE); + } + break; + + /* Only floating point number characters are to be permitted. */ + case '9': + if(chEntered >= '0' && chEntered <= '9') break; + if(chEntered == '.' || chEntered == '+' || chEntered == '-') break; + return(FALSE); + + /* Only "printable" characters are to be permitted. */ + case '*': + if(chEntered < 32) return(FALSE); + break; + + /* City name characters are to be permitted. */ + case 'C': + case 'c': + if(chEntered >= 'A' && chEntered <= 'Z') break; + if(chEntered >= 'a' && chEntered <= 'z') break; + if(chEntered == ' ' || chEntered == ',' || chEntered == '.') break; + if(chEntered == '*' || chEntered == '?') break; + return(FALSE); + + /* If only alphabetic characters are to be permitted. */ + case 'A': + case 'a': + case 'L': + case 'l': + case 'M': + case 'm': + case 'U': + case 'u': + if(chEntered>='A' && chEntered<='Z') break; + if(chEntered>='a' && chEntered<='z') break; + if(chEntered==' ') break; + return(FALSE); + + /* If only date characters are to be permitted. */ + case 'D': + case 'd': + if(chEntered>='0' && chEntered<='9') break; + if(chEntered=='-' || chEntered=='/') break; + return(FALSE); + + /* If only MS-DOS filename characters are to be permitted. */ + case 'F': + case 'f': + if(chEntered >= 'A' && chEntered <= 'Z') break; + if(chEntered >= '0' && chEntered <= '9') break; + if(chEntered >= 'a' && chEntered <= 'z') break; + switch(chEntered) + { + /* Filename separators. */ + case ':': + case '.': + case DIRSEP: + + /* Wildcard characters. */ + case '?': + case '*': + + /* Other valid symbols in filenames */ + case '#': + case '$': + case '&': + case '\'': + case '(': + case '>': + case '-': + case '@': + case '_': + case '!': + case '{': + case '}': + case '~': + return(TRUE); + } + + return(FALSE); + + /* If only hexidecimal characters are to be permitted. */ + case 'H': + case 'h': + if(chEntered>='0' && chEntered<='9') break; + if(chEntered>='A' && chEntered<='F') break; + if(chEntered>='a' && chEntered<='f') break; + return(FALSE); + + /* If only telephone number characters are to be permitted. */ + case 'T': + case 't': + if(chEntered >= '0' && chEntered <= '9') break; + if(chEntered == '-' || chEntered == '(' || chEntered == ')' + || chEntered == ' ' || chEntered == '+') + { + break; + } + return(FALSE); + + /* If filenames with wildcards are to be permitted. */ + case 'W': + case 'w': + if(chEntered >= 'A' && chEntered <= 'Z') break; + if(chEntered >= 'a' && chEntered <= 'z') break; + if(chEntered == ':' || chEntered == '.' || chEntered == DIRSEP + || chEntered == '*' || chEntered == '?') + { + break; + } + return(FALSE); + + /* If alpha-numeric characters are to be permitted. */ + case 'X': + case 'x': + if(chEntered >= 'A' && chEntered <= 'Z') break; + if(chEntered >= 'a' && chEntered <= 'z') break; + if(chEntered >= '0' && chEntered <= '9') break; + if(chEntered == ' ') break; + return(FALSE); + + /* If this is a Yes/No field. */ + case 'Y': + case 'y': + if(chEntered == 'y' || chEntered == 'n' || chEntered == 'Y' + || chEntered == 'N') + { + break; + } + return(FALSE); + } + + /* If execution gets to this point, then the character has been approved. */ + return(TRUE); +} + + + +/* ---------------------------------------------------------------------------- + * ODEditAsCharForPos() *** PRIVATE FUNCTION *** + * + * Converts the character entered by the user to a valid character for this + * position in the string. For example, for fields that are set to all + * upper case, this function converts the entered characte to its upper case + * equivalent. + * + * Parameters: chEntered - Character that was entered by the user. + * + * nPosition - Position in the string where the character is to + * be entered. + * + * Return: The actual character to add to the input string at this + * position. + */ +static char ODEditAsCharForPos(char chEntered, INT nPosition) +{ + /* If this character is a literal. */ + if(abCurrentFormatLiteral[nPosition]) + { + /* Return the only valid char for this position. */ + return(pszCurrentFormat[anCurrentFormatOffset[nPosition]]); + } + + /* If this position has a corresponding format control character, */ + /* then check that control character. */ + switch(pszCurrentFormat[anCurrentFormatOffset[nPosition]]) + { + /* If Yes/No characters are required. */ + case 'Y': + case 'y': + return(toupper(chEntered)); + + /* If filename characters are required. */ + case 'F': + case 'f': + return(toupper(chEntered)); + + /* If lower case characters are required. */ + case 'L': + case 'l': + return(tolower(chEntered)); + + /* If upper case characters are required. */ + case 'U': + case 'u': + return(toupper(chEntered)); + + /* If automatic capitalization is required. */ + case 'M': + case 'm': + case 'C': + case 'c': + /* First character is always upper case. */ + if(nPosition == 0) return(toupper(chEntered)); + + /* Check for other base cases. */ + if(abCurrentFormatLiteral[nPosition-1]) return(toupper(chEntered)); + if(toupper(pszCurrentFormat[anCurrentFormatOffset[nPosition]]) != 'M' + && toupper(pszCurrentFormat[anCurrentFormatOffset[nPosition]]) + != 'C') + { + return(toupper(chEntered)); + } + + /* If previous character is a word delimiter, then this character */ + /* should be uppper case. */ + if(pszCurrentInput[nPosition-1] == ' ' + || pszCurrentInput[nPosition-1] == '.' + || pszCurrentInput[nPosition-1] == ',' + || pszCurrentInput[nPosition-1] == '-') + { + return(toupper(chEntered)); /* Otherwise, this should be lower */ + } + + /* Otherwise, this character should be lower-case. */ + return(tolower(chEntered)); + } + + return(chEntered); +} + + +/* ---------------------------------------------------------------------------- + * ODEditDisplayPermaliteral() *** PRIVATE FUNCTION *** + * + * Displays permaliterals (characters specified in the format string that + * should be returned in the input string, but which the user may never + * change). + * + * Parameters: nFlags - Flags parameter that was passed into od_edit_str(). + * + * Return: void + */ +static void ODEditDisplayPermaliteral(WORD nFlags) +{ + INT nCount; + BYTE btRepeat = 0; + + for(nCount = strlen(pszCurrentInput); nCount <= nCurrentStringLength; + ++nCount) + { + if(nCount != nCurrentStringLength) + { + if(abCurrentFormatLiteral[nCount]) + { + if(btRepeat > 0) + { + od_repeat(chCurrentBlank, btRepeat); + btRepeat = 0; + } + od_putch(pszCurrentFormat[anCurrentFormatOffset[nCount]]); + } + else + { + ++btRepeat; + } + } + else + { + if(!(nFlags & EDIT_FLAG_SHOW_SIZE)) + { + ++btRepeat; + } + } + } + + if(btRepeat > 0) od_repeat(chCurrentBlank, btRepeat); +} diff --git a/utils/magiedit/odoors/ODEdit.c b/utils/magiedit/odoors/ODEdit.c new file mode 100644 index 0000000..cc1a5cb --- /dev/null +++ b/utils/magiedit/odoors/ODEdit.c @@ -0,0 +1,2650 @@ +/* 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: ODEdit.c + * + * Description: Implementation of the OpenDoors multi-line editor, which + * allows the user to edit strings which may span many lines. + * Provides standard text editor features, such as word wrap. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Dec 07, 1995 6.00 BP Created. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 04, 1996 6.00 BP Use od_get_input(). + * Jan 12, 1996 6.00 BP Claim exclusive use of arrow keys. + * Jan 31, 1996 6.00 BP Added timeout for od_get_input(). + * Feb 08, 1996 6.00 BP Finished implementation details. + * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter. + * Feb 16, 1996 6.00 BP New trans. size estimation heuristics. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 24, 1996 6.00 BP Fixed garbage on [Enter] after w-wrap. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 13, 1996 6.10 BP Restore cursor position after menu. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Jun 08, 1996 6.10 BP Added cast in call to alloc function. + * Oct 19, 2001 6.20 RS Eliminated MSVC 6.0 warning. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODTypes.h" +#include "ODGen.h" +#include "ODCore.h" +#include "ODKrnl.h" +#include "ODStat.h" +#include "ODCom.h" +#include "ODScrn.h" + + +/* ========================================================================= */ +/* Misc. definitions. */ +/* ========================================================================= */ + +/* Macros used by this module. */ +#define IS_EOL_CHAR(ch) ((ch) == '\n' || (ch) == '\r' || (ch) == '\0') + +/* Configurable constants. */ +#define LINE_ARRAY_GROW_SIZE 20 +#define BUFFER_GROW_SIZE 4096 +#define ANSI_SCROLL_DISTANCE 7 +#define PRE_DRAIN_TIME 10000 +#define MAX_TAB_STOP_SIZE 8 +#define DEFAULT_TAB_STOP_SIZE 8 +#define DEFAULT_LINE_BREAK "\n" + +/* Other manifest constants. */ +#define REDRAW_NO_BOUNDARY 0xffff + +/* Default editor options. */ +static tODEditOptions ODEditOptionsDefault = +{ + 1, 1, 80, 23, + FORMAT_PARAGRAPH_BREAKS, + NULL, + NULL, + EFLAG_NORMAL, +}; + + + +/* ========================================================================= */ +/* Multiline editor instance structure. */ +/* ========================================================================= */ + +typedef struct +{ + char *pszEditBuffer; + UINT unBufferSize; + tODEditOptions *pUserOptions; + UINT unCurrentLine; + UINT unCurrentColumn; + UINT unLineScrolledToTop; + UINT unAreaWidth; + UINT unAreaHeight; + char **papchStartOfLine; + UINT unLineArraySize; + UINT unLinesInBuffer; + BOOL bInsertMode; + UINT unTabStopSize; + UINT unScrollDistance; + char *pszLineBreak; + char *pszParagraphBreak; + BOOL bWordWrapLongLines; + void *pRememberBuffer; +} tEditInstance; + + + +/* ========================================================================= */ +/* Editor function prototypes. */ +/* ========================================================================= */ + +/* High level implementation. */ +static BOOL ODEditSetupInstance(tEditInstance *pEditInstance, + char *pszBufferToEdit, UINT unBufferSize, tODEditOptions *pUserOptions); +static void ODEditRedrawArea(tEditInstance *pEditInstance); +static void ODEditDrawAreaLine(tEditInstance *pEditInstance, + UINT unAreaLineToDraw); +static INT ODEditMainLoop(tEditInstance *pEditInstance); +static void ODEditGotoPreviousLine(tEditInstance *pEditInstance); +static void ODEditGotoNextLine(tEditInstance *pEditInstance); +static BOOL ODEditScrollArea(tEditInstance *pEditInstance, INT nDistance); +static BOOL ODEditRecommendFullRedraw(tEditInstance *pEditInstance, + UINT unEstPartialRedrawBytes, BOOL bDefault); +static UINT ODEditEstDrawBytes(tEditInstance *pEditInstance, + UINT unStartRedrawLine, UINT unStartRedrawColumn, UINT unFinishRedrawLine, + UINT unFinishRedrawColumn); +static UINT ODEditGetCurrentLineInArea(tEditInstance *pEditInstance); +static void ODEditUpdateCursorPos(tEditInstance *pEditInstance); +static void ODEditUpdateCursorIfMoved(tEditInstance *pEditInstance); +static tODResult ODEditEnterText(tEditInstance *pEditInstance, + char *pszEntered, BOOL bInsertMode); +static void ODEditSetBreakSequence(tEditInstance *pEditInstance, + char chFirstEOLChar, char chSecondEOLChar); +static BOOL ODEditCursorLeft(tEditInstance *pEditInstance); +static void ODEditDeleteCurrentChar(tEditInstance *pEditInstance); +static void ODEditDeleteCurrentLine(tEditInstance *pEditInstance); +static BOOL ODEditPastEndOfCurLine(tEditInstance *pEditInstance); +static size_t ODEditRememberBufferSize(tEditInstance *pEditInstance); +static void ODEditRememberArea(tEditInstance *pEditInstance, + void *pRememberedArea); +static void ODEditRedrawChanged(tEditInstance *pEditInstance, + void *pRememberedArea, UINT unUpperBoundary, UINT unLowerBoundary); +static BOOL ODEditDetermineChanged(tEditInstance *pEditInstance, + void *pRememberedArea, UINT unUpperBoundary, UINT unLowerBoundary, + UINT *punStartRedrawLine, UINT *punStartRedrawColumn, + UINT *punFinishRedrawLine, UINT *punFinishRedrawColumn); +static void ODEditRedrawSubArea(tEditInstance *pEditInstance, + UINT unStartRedrawLine, UINT unStartRedrawColumn, UINT unFinishRedrawLine, + UINT unFinishRedrawColumn); +static void ODEditGetActualCurPos(tEditInstance *pEditInstance, + UINT *punRow, UINT *punColumn); +static BOOL ODEditIsEOLForMode(tEditInstance *pEditInstance, char chToTest); + +/* Low level buffer manipulation functions. */ +static BOOL ODEditBufferFormatAndIndex(tEditInstance *pEditInstance); +static UINT ODEditBufferGetLineLength(tEditInstance *pEditInstance, + UINT unBufferLine); +static UINT ODEditBufferGetTotalLines(tEditInstance *pEditInstance); +static char *ODEditBufferGetCharacter(tEditInstance *pEditInstance, + UINT unBufferLine, UINT unBufferColumn); +static tODResult ODEditBufferMakeSpace(tEditInstance *pEditInstance, + UINT unLine, UINT unColumn, UINT unNumChars); +static tODResult ODEditTryToGrow(tEditInstance *pEditInstance, + UINT unSizeNeeded); + + + +/* ========================================================================= */ +/* High level editor implementation. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * od_multiline_edit() + * + * Multiline editor function, allows the user to enter or change text that + * spans multiple lines. + * + * Parameters: pszBufferToEdit - Pointer to '\0'-terminated buffer of text + * to edit. + * + * unBufferSize - Size of the buffer, in characters. + * + * pEditOptions - Pointer to a tODEditOptions structure, or + * NULL to use default settings. + * + * Return: An od_multiline_edit()-specific result code. + */ +ODAPIDEF INT ODCALL od_multiline_edit(char *pszBufferToEdit, UINT unBufferSize, + tODEditOptions *pEditOptions) +{ + tEditInstance EditInstance; + INT nToReturn; + + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_node_open()"); + + /* Initialize OpenDoors if not already done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Validate parameters. */ + if(pszBufferToEdit == NULL || unBufferSize == 0) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(OD_MULTIEDIT_ERROR); + } + + /* Check the user's terminal supports the required capabilities. */ + if(!(od_control.user_ansi || od_control.user_avatar)) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(OD_MULTIEDIT_ERROR); + } + + /* Initialize editor instance information structure. */ + if(!ODEditSetupInstance(&EditInstance, pszBufferToEdit, unBufferSize, + pEditOptions)) + { + OD_API_EXIT(); + return(OD_MULTIEDIT_ERROR); + } + + /* Attempt to build the buffer line index and ensure that the buffer */ + /* conforms to the format specified by the client application. */ + if(!ODEditBufferFormatAndIndex(&EditInstance)) + { + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return(OD_MULTIEDIT_ERROR); + } + + /* Claim exclusive use of arrow keys. */ + ODStatStartArrowUse(); + + /* Ensure that all information in the outbound communications buffer */ + /* has been sent before starting. This way, we can safely purge the */ + /* outbound buffer at any time without loosing anything that was sent */ + /* before od_multiline_edit() was called. */ + ODWaitDrain(PRE_DRAIN_TIME); + + /* Draw the initial edit area. */ + ODEditRedrawArea(&EditInstance); + + /* Run the main editor loop. */ + nToReturn = ODEditMainLoop(&EditInstance); + + /* Release exclusive use of arrow keys. */ + ODStatEndArrowUse(); + + /* Set final information which will be available in the user options */ + /* structure for the client application to access. */ + EditInstance.pUserOptions->pszFinalBuffer = EditInstance.pszEditBuffer; + EditInstance.pUserOptions->unFinalBufferSize = unBufferSize; + + OD_API_EXIT(); + return(nToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODEditSetupInstance() *** PRIVATE FUNCTION *** + * + * Initializes editor instance information structure. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * pszBufferToEdit - Buffer pointer provided by client. + * + * unBufferSize - Initial buffer size, as specified by the + * client. + * + * pUserOptions - Editor options specified by the client. + * + * Return: TRUE on success, FALSE on failure. In the case of failure, + * od_control.od_error is set appropriately. + */ +static BOOL ODEditSetupInstance(tEditInstance *pEditInstance, + char *pszBufferToEdit, UINT unBufferSize, tODEditOptions *pUserOptions) +{ + ASSERT(pEditInstance != NULL); + ASSERT(pszBufferToEdit != NULL); + + /* Setup editor instance structure. */ + pEditInstance->pszEditBuffer = pszBufferToEdit; + pEditInstance->unBufferSize = unBufferSize; + if(pUserOptions == NULL) + { + /* Edit options is just the defaults. */ + pEditInstance->pUserOptions = &ODEditOptionsDefault; + } + else + { + /* Edit options are supplied by the user. */ + pEditInstance->pUserOptions = pUserOptions; + + /* Initialize any edit options that the user did not setup. */ + /* Check that edit area has been initialized. */ + if(pUserOptions->nAreaLeft == 0) + { + pUserOptions->nAreaLeft = ODEditOptionsDefault.nAreaLeft; + } + if(pUserOptions->nAreaRight == 0) + { + pUserOptions->nAreaRight = ODEditOptionsDefault.nAreaRight; + } + if(pUserOptions->nAreaTop == 0) + { + pUserOptions->nAreaTop = ODEditOptionsDefault.nAreaTop; + } + if(pUserOptions->nAreaBottom == 0) + { + pUserOptions->nAreaBottom = ODEditOptionsDefault.nAreaBottom; + } + } + pEditInstance->unCurrentLine = 0; + pEditInstance->unCurrentColumn = 0; + pEditInstance->unLineScrolledToTop = 0; + pEditInstance->papchStartOfLine = NULL; + pEditInstance->unLineArraySize = 0; + pEditInstance->unLinesInBuffer = 0; + pEditInstance->unAreaWidth = (UINT)pEditInstance->pUserOptions-> + nAreaRight - (UINT)pEditInstance->pUserOptions->nAreaLeft + 1; + pEditInstance->unAreaHeight = (UINT)pEditInstance->pUserOptions-> + nAreaBottom - (UINT)pEditInstance->pUserOptions->nAreaTop + 1; + pEditInstance->bInsertMode = TRUE; + pEditInstance->unTabStopSize = DEFAULT_TAB_STOP_SIZE; + + /* Setup line break and paragraph break sequences, if they can be */ + /* determined at this point. If they can't be determined, set them */ + /* to NULL. */ + switch(pEditInstance->pUserOptions->TextFormat) + { + case FORMAT_FTSC_MESSAGE: + /* FTSC compliant messages use \r as a paragraph break, and do */ + /* not have any line break characters. */ + pEditInstance->pszLineBreak = ""; + pEditInstance->pszParagraphBreak = "\r"; + break; + + case FORMAT_PARAGRAPH_BREAKS: + /* Paragraph break mode only inserts CR/LF sequences at the end */ + /* of a paragrah, and word-wraps the text that forms a paragrah. */ + pEditInstance->pszLineBreak = ""; + pEditInstance->pszParagraphBreak = NULL; + break; + + case FORMAT_LINE_BREAKS: + case FORMAT_NO_WORDWRAP: + /* Line break mode and no word wrap mode both terminate every */ + /* line of the file with a CR/LF sequence, and have no paragrah */ + /* terminator. In line break mode, word wrap is enabled, whereas */ + /* it is not in FORMAT_NO_WORDWRAP mode. */ + pEditInstance->pszLineBreak = NULL; + pEditInstance->pszParagraphBreak = ""; + break; + + default: + /* An invalid text format was specified. */ + od_control.od_error = ERR_PARAMETER; + return(FALSE); + } + + /* Determine whether long lines sould be word wrapped or character */ + /* wrapped. */ + pEditInstance->bWordWrapLongLines = (pEditInstance->pUserOptions->TextFormat + != FORMAT_NO_WORDWRAP); + + /* Attempt to allocate abuffer for remembered data. */ + pEditInstance->pRememberBuffer = + malloc(ODEditRememberBufferSize(pEditInstance)); + + if(pEditInstance->pRememberBuffer == NULL) + { + od_control.od_error = ERR_MEMORY; + return(FALSE); + } + + /* If AVATAR mode or local mode is active, then scroll up or down one */ + /* line at a time. */ + if(od_control.user_avatar || od_control.baud == 0) + { + pEditInstance->unScrollDistance = 1; + } + /* In ANSI mode with a remote connection, scroll multiple lines at a */ + /* time. This is the minimum of the default scroll distance, and the */ + /* current height of the edit area - 1. */ + else + { + pEditInstance->unScrollDistance = MIN(ANSI_SCROLL_DISTANCE, + pEditInstance->pUserOptions->nAreaBottom + - pEditInstance->pUserOptions->nAreaTop); + } + + /* Return with success. */ + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODEditRedrawArea() *** PRIVATE FUNCTION *** + * + * Redraws the area of the screen used by the editor. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditRedrawArea(tEditInstance *pEditInstance) +{ + UINT unAreaLine; + + ASSERT(pEditInstance != NULL); + + ODScrnEnableCaret(FALSE); + + /* First, remove anything that is still in the outbound communications */ + /* buffer, since whatever it was, it will no longer be visible after */ + /* the screen redraw anyhow. */ + if(od_control.baud != 0) ODComClearOutbound(hSerialPort); + + /* Loop, drawing every line in the edit area. */ + for(unAreaLine = 0; unAreaLine < pEditInstance->unAreaHeight; ++unAreaLine) + { + ODEditDrawAreaLine(pEditInstance, unAreaLine); + } + + ODScrnEnableCaret(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODEditDrawAreaLine() *** PRIVATE FUNCTION *** + * + * Redraws the specified line in the area of the screen used by the editor. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unAreaLineToDraw - 0-based line number in the edit area to be + * redrawn. + * + * Return: void + */ +static void ODEditDrawAreaLine(tEditInstance *pEditInstance, + UINT unAreaLineToDraw) +{ + UINT unBufferLine; + UINT unLineLength; + + ASSERT(pEditInstance != NULL); + ASSERT(unAreaLineToDraw >= 0); + ASSERT(unAreaLineToDraw < pEditInstance->unAreaHeight); + + /* Determine the buffer line that is displayed on this screen line. */ + unBufferLine = unAreaLineToDraw + pEditInstance->unLineScrolledToTop; + + /* Position the cursor to the beginning of this line. */ + od_set_cursor((UINT)pEditInstance->pUserOptions->nAreaTop + + unAreaLineToDraw, (UINT)pEditInstance->pUserOptions->nAreaLeft); + + /* If this line is not beyond the end of the buffer. */ + if(unBufferLine < pEditInstance->unLinesInBuffer) + { + /* Determine the length of this buffer line. */ + unLineLength = ODEditBufferGetLineLength(pEditInstance, unBufferLine); + + od_disp(ODEditBufferGetCharacter(pEditInstance, unBufferLine, 0), + unLineLength, TRUE); + } + else + { + unLineLength = 0; + } + + /* If right edge of edit area aligns with the right edge of the screen. */ + if(pEditInstance->pUserOptions->nAreaRight == OD_SCREEN_WIDTH) + { + /* Clear the remainder of this line on the screen. */ + od_clr_line(); + } + else + { + /* Place spaces after the end of the current line, up to right edge of */ + /* the edit area. */ + od_repeat(' ', (BYTE)(pEditInstance->unAreaWidth - unLineLength)); + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditMainLoop() *** PRIVATE FUNCTION *** + * + * Implements the main editor loop, which repeatedly waits for input from the + * user, until the user chooses to exit. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: Value to be returned by od_multiline_edit. + */ +static INT ODEditMainLoop(tEditInstance *pEditInstance) +{ + tODInputEvent InputEvent; + + ASSERT(pEditInstance != NULL); + + /* Set initial cursor position. */ + ODEditUpdateCursorPos(pEditInstance); + + /* Loop, obtaining keystrokes until the user chooses to exit. */ + for(;;) + { + od_get_input(&InputEvent, OD_NO_TIMEOUT, GETIN_NORMAL); + if(InputEvent.EventType == EVENT_EXTENDED_KEY) + { + switch(InputEvent.chKeyPress) + { + case OD_KEY_UP: + /* If we aren't at the start of the file, then move to the */ + /* previous line. */ + if(pEditInstance->unCurrentLine > 0) + { + ODEditGotoPreviousLine(pEditInstance); + ODEditUpdateCursorPos(pEditInstance); + } + break; + + case OD_KEY_DOWN: + /* If we aren't at the end of the file, then move to the */ + /* next line. */ + if(pEditInstance->unCurrentLine + < ODEditBufferGetTotalLines(pEditInstance) - 1) + { + ODEditGotoNextLine(pEditInstance); + ODEditUpdateCursorPos(pEditInstance); + } + break; + + case OD_KEY_LEFT: + /* Attempt to move the cursor left. */ + if(ODEditCursorLeft(pEditInstance)) + { + /* If it was possible to move the cursor, then update the */ + /* cursor position on the screen. */ + ODEditUpdateCursorPos(pEditInstance); + } + break; + + case OD_KEY_RIGHT: + /* In word wrap mode, we allow the cursor to move up to the */ + /* end of this line, and then wrap around to the next line. */ + if(pEditInstance->bWordWrapLongLines) + { + if(pEditInstance->unCurrentColumn < ODEditBufferGetLineLength + (pEditInstance, pEditInstance->unCurrentLine)) + { + ++pEditInstance->unCurrentColumn; + ODEditUpdateCursorPos(pEditInstance); + } + else if(pEditInstance->unCurrentLine + < ODEditBufferGetTotalLines(pEditInstance) - 1) + { + ODEditGotoNextLine(pEditInstance); + pEditInstance->unCurrentColumn = 0; + ODEditUpdateCursorPos(pEditInstance); + } + } + + /* In character wrap mode, we allow the cursor to move up to */ + /* the right edge of the edit area. */ + else + { + if(pEditInstance->unCurrentColumn + < pEditInstance->unAreaWidth - 1) + { + ++pEditInstance->unCurrentColumn; + ODEditUpdateCursorPos(pEditInstance); + } + } + break; + + case OD_KEY_HOME: + pEditInstance->unCurrentColumn = 0; + ODEditUpdateCursorPos(pEditInstance); + break; + + case OD_KEY_END: + pEditInstance->unCurrentColumn = ODEditBufferGetLineLength( + pEditInstance, pEditInstance->unCurrentLine); + ODEditUpdateCursorPos(pEditInstance); + break; + + case OD_KEY_PGUP: + if(pEditInstance->unLineScrolledToTop > 0) + { + UINT unDistance = MIN(pEditInstance->unAreaHeight - 1, + pEditInstance->unLineScrolledToTop); + ODEditScrollArea(pEditInstance, -((INT)unDistance)); + pEditInstance->unCurrentLine -= unDistance; + ODEditUpdateCursorPos(pEditInstance); + } + else if(pEditInstance->unCurrentLine != 0) + { + pEditInstance->unCurrentLine = 0; + ODEditUpdateCursorPos(pEditInstance); + } + break; + + case OD_KEY_PGDN: + if(pEditInstance->unLineScrolledToTop < + pEditInstance->unLinesInBuffer - 1) + { + UINT unDistance = MIN(pEditInstance->unAreaHeight - 1, + pEditInstance->unLinesInBuffer + - pEditInstance->unLineScrolledToTop - 1); + ODEditScrollArea(pEditInstance, (INT)unDistance); + pEditInstance->unCurrentLine = MIN( + pEditInstance->unCurrentLine + unDistance, + pEditInstance->unLinesInBuffer - 1); + ODEditUpdateCursorPos(pEditInstance); + } + break; + + case OD_KEY_INSERT: + /* If the insert key is pressed, then toggle insert mode. */ + pEditInstance->bInsertMode = !pEditInstance->bInsertMode; + break; + + case OD_KEY_DELETE: + /* Delete the character at the current position. */ + + /* If we are currently past the end of this line. */ + if(ODEditPastEndOfCurLine(pEditInstance)) + { + /* Add spaces to this line to fill it up to the current */ + /* cursor position. */ + switch(ODEditBufferMakeSpace(pEditInstance, + pEditInstance->unCurrentLine, + pEditInstance->unCurrentColumn, 0)) + { + case kODRCUnrecoverableFailure: + /* If we encountered an unrecoverable failure, then */ + /* exit from the editor with a memory allocation */ + /* error. */ + od_control.od_error = ERR_MEMORY; + return(OD_MULTIEDIT_ERROR); + + case kODRCSuccess: + /* On success, delete the current character. */ + ODEditDeleteCurrentChar(pEditInstance); + break; + + default: + /* On any other failure, just beep and continue. */ + od_putch('\a'); + } + } + else + { + /* If we aren't pas the end of the line, then just do a */ + /* simple delete character operation. */ + ODEditDeleteCurrentChar(pEditInstance); + } + break; + } + } + else if(InputEvent.EventType == EVENT_CHARACTER) + { + if(InputEvent.chKeyPress == 25) + { + /* Control-Y (delete line) has been pressed. */ + ODEditDeleteCurrentLine(pEditInstance); + } + else if(InputEvent.chKeyPress == 26 + || InputEvent.chKeyPress == 27) + { + /* Escape or control-Z has been pressed. */ + + /* If a menu callback function has been provided by */ + /* the client, then call it. */ + if(pEditInstance->pUserOptions->pfMenuCallback != NULL) + { + /* Call the menu callback function. */ + switch((*pEditInstance->pUserOptions->pfMenuCallback)(NULL)) + { + case EDIT_MENU_EXIT_EDITOR: + return(OD_MULTIEDIT_SUCCESS); + + case EDIT_MENU_DO_NOTHING: + /* Continue in the editor without doing anything. */ + break; + + default: + ASSERT(FALSE); + } + + /* If we are continuing, then restore initial cursor pos. */ + ODEditUpdateCursorPos(pEditInstance); + } + else + { + /* If a menu key callback function has not been provided, */ + /* then we exit the editor unconditionally. */ + return(OD_MULTIEDIT_SUCCESS); + } + } + else if(InputEvent.chKeyPress == '\b') + { + /* Backspace key has been pressed. */ + + /* If the cursor is past the end of the line, then we just move */ + /* the cursor left, without deleting any characters. */ + BOOL bDelete = !ODEditPastEndOfCurLine(pEditInstance); + + /* Backup the cursor one space. */ + if(ODEditCursorLeft(pEditInstance)) + { + /* If there was space to move the cursor back to, then */ + /* proceed and remove the character at the current position. */ + if(bDelete) + { + ODEditDeleteCurrentChar(pEditInstance); + } + else + { + /* In this case, we must still show the new cursor */ + /* position. */ + ODEditUpdateCursorPos(pEditInstance); + } + } + } + else if(InputEvent.chKeyPress == '\t') + { + char szTextToAdd[MAX_TAB_STOP_SIZE + 1]; + UINT unTargetColumn; + UINT unTargetDistance; + + /* A tab key has been entered. */ + + /* Determine the column that this will move the cursor to. */ + ASSERT(pEditInstance->unTabStopSize <= MAX_TAB_STOP_SIZE); + unTargetColumn = ((pEditInstance->unCurrentColumn / pEditInstance-> + unTabStopSize) + 1) * pEditInstance->unTabStopSize; + + /* In insert mode, then insert spaces into the buffer. */ + if(pEditInstance->bInsertMode) + { + /* Determine the number of columns that we need to advance in */ + /* order to reach this target column. */ + unTargetDistance = unTargetColumn - + pEditInstance->unCurrentColumn; + ASSERT(unTargetDistance <= MAX_TAB_STOP_SIZE); + + /* Translate this to a string with the appropriate number of */ + /* spaces. */ + memset(szTextToAdd, ' ', unTargetDistance); + szTextToAdd[unTargetDistance] = '\0'; + + /* Add this to the buffer. */ + if(ODEditEnterText(pEditInstance, szTextToAdd, TRUE) == + kODRCUnrecoverableFailure) + { + od_control.od_error = ERR_MEMORY; + return(OD_MULTIEDIT_ERROR); + } + } + + /* In overwrite mode, then just advance the cursor position. */ + else + { + /* Determine the column where the cursor should be wrapped. */ + UINT unWrapColumn = pEditInstance->bWordWrapLongLines ? + ODEditBufferGetLineLength(pEditInstance, + pEditInstance->unCurrentLine) + : pEditInstance->unAreaWidth; + + if(unTargetColumn < unWrapColumn) + { + pEditInstance->unCurrentColumn = unTargetColumn; + ODEditUpdateCursorPos(pEditInstance); + } + else if(pEditInstance->unCurrentLine + < ODEditBufferGetTotalLines(pEditInstance) - 1) + { + ODEditGotoNextLine(pEditInstance); + pEditInstance->unCurrentColumn = 0; + ODEditUpdateCursorPos(pEditInstance); + } + } + } + else if(InputEvent.chKeyPress == '\r') + { + char *pszTextToAdd; + + /* The enter key has been pressed. In insert mode, or at the end */ + /* of the buffer in overwrite mode, this adds a new line. */ + if(pEditInstance->bInsertMode || pEditInstance->unCurrentLine + >= ODEditBufferGetTotalLines(pEditInstance) - 1) + { + if(!pEditInstance->bInsertMode) + { + /* If we are not in insert mode, begin by positioning the */ + /* cursor at the end of this line. */ + pEditInstance->unCurrentColumn = ODEditBufferGetLineLength( + pEditInstance, pEditInstance->unCurrentLine); + } + + /* Determine the line/paragraph break sequence to use. */ + if(pEditInstance->pszLineBreak != NULL + && strlen(pEditInstance->pszLineBreak) > 0) + { + pszTextToAdd = pEditInstance->pszLineBreak; + } + else if(pEditInstance->pszParagraphBreak != NULL + && strlen(pEditInstance->pszParagraphBreak) > 0) + { + pszTextToAdd = pEditInstance->pszParagraphBreak; + } + else + { + pszTextToAdd = DEFAULT_LINE_BREAK; + } + + /* Insert the sequence into the buffer. */ + if(ODEditEnterText(pEditInstance, pszTextToAdd, TRUE) == + kODRCUnrecoverableFailure) + { + od_control.od_error = ERR_MEMORY; + return(OD_MULTIEDIT_ERROR); + } + } + else + { + /* Pressing the enter key in overwrite mode just moves the */ + /* cursor to the beginning of the next line. In other words, */ + /* it is equivalent to pressing Down arrow followed by home. */ + ODEditGotoNextLine(pEditInstance); + pEditInstance->unCurrentColumn = 0; + ODEditUpdateCursorPos(pEditInstance); + } + } + else if(InputEvent.chKeyPress >= 32) + { + char szTextToAdd[2]; + szTextToAdd[0] = InputEvent.chKeyPress; + szTextToAdd[1] = '\0'; + + /* A valid buffer character has been entered. */ + if(ODEditEnterText(pEditInstance, szTextToAdd, + (BOOL)(pEditInstance->bInsertMode + || ODEditPastEndOfCurLine(pEditInstance))) + == kODRCUnrecoverableFailure) + { + od_control.od_error = ERR_MEMORY; + return(OD_MULTIEDIT_ERROR); + } + } + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditGotoPreviousLine() *** PRIVATE FUNCTION *** + * + * Moves the current cursor position to the previous line, scrolling the screen + * if necessary to keep the cursor visible. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditGotoPreviousLine(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + /* If we are already at the first line, then return without doing */ + /* anything. */ + if(pEditInstance->unCurrentLine == 0) return; + + /* If cursor is at top of edit area, then scroll area */ + /* first. */ + if(ODEditGetCurrentLineInArea(pEditInstance) == 0) + { + ODEditScrollArea(pEditInstance, + -(INT)(MIN(pEditInstance->unScrollDistance, + pEditInstance->unCurrentLine))); + } + + /* Move cursor to previous line. */ + --pEditInstance->unCurrentLine; +} + + +/* ---------------------------------------------------------------------------- + * ODEditGotoNextLine() *** PRIVATE FUNCTION *** + * + * Advances the current cursor position to the next line, scrolling the screen + * if necessary to keep the cursor visible. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditGotoNextLine(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + /* If we are already at the end of the file, then return without */ + /* doing anything. */ + if(pEditInstance->unCurrentLine + >= ODEditBufferGetTotalLines(pEditInstance) - 1) + { + return; + } + + /* If cursor is at the bottom of the edit area, then scroll area first. */ + if(ODEditGetCurrentLineInArea(pEditInstance) + == pEditInstance->unAreaHeight - 1) + { + ODEditScrollArea(pEditInstance, + (INT)MIN(pEditInstance->unScrollDistance, + ODEditBufferGetTotalLines(pEditInstance) + - pEditInstance->unCurrentLine)); + } + + /* Move cursor to next line. */ + ++pEditInstance->unCurrentLine; +} + + +/* ---------------------------------------------------------------------------- + * ODEditScrollArea() *** PRIVATE FUNCTION *** + * + * Scrolls the edit area up or down the specified distance, redrawing newly + * "exposed" lines. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * nDistance - Number of lines to scroll, where a positive + * value moves the text upwards, and a negative + * value moves the text down. + * + * Return: FALSE if a full redraw has been performed, TRUE if an efficient + * scroll command has been used. + */ +static BOOL ODEditScrollArea(tEditInstance *pEditInstance, INT nDistance) +{ + BOOL bUseScrollCommand = FALSE; + UINT unAreaLine; + UINT unBufferLine; + UINT unFirstAreaLineToDraw; + UINT unLastAreaLineToDraw; + UINT unPositiveDistance; + + ASSERT(pEditInstance); + + /* If scroll distance is zero, then we don't need to do anything at all. */ + if(nDistance == 0) + { + return(TRUE); + } + /* Otherwise, obtain the absolute value of the distance as an unsigned */ + /* integer. */ + else if(nDistance < 0) + { + unPositiveDistance = (UINT)-nDistance; + } + else + { + unPositiveDistance = (UINT)nDistance; + } + + /* In AVATAR mode, if more than one of the currently visible lines will */ + /* still be visible after scrolling, then we will consider using the */ + /* scroll operation. */ + if(od_control.user_avatar + && ((INT)pEditInstance->unAreaHeight) - ((INT)unPositiveDistance) > 1) + { + /* Even under this situation, we only want to use the scroll operation */ + /* if the amount of data still in the outbound buffer + our estimate */ + /* of the amount of data that will be sent to perform the scroll */ + /* operation is less than our estimate of the amount of data that */ + /* would be sent by a complete screen redraw. */ + UINT unEstimatedScrollData = ((pEditInstance->unAreaWidth + 4) * + unPositiveDistance) + 7; + + if(!ODEditRecommendFullRedraw(pEditInstance, unEstimatedScrollData, + TRUE)) + { + bUseScrollCommand = TRUE; + } + } + + /* In local mode, we can also use the scroll command for efficiency. */ + if(od_control.baud == 0) + { + bUseScrollCommand = TRUE; + } + + /* Area scroll is achieved by one of two means. We either use the scroll */ + /* command, and then draw just the newly visible lines, or we redraw the */ + /* entire edit area, after removing any data from the outbound */ + /* communications buffer. */ + + if(bUseScrollCommand) + { + /* Use the od_scroll() function to scroll the screen contents. */ + od_scroll(pEditInstance->pUserOptions->nAreaLeft, + pEditInstance->pUserOptions->nAreaTop, + pEditInstance->pUserOptions->nAreaRight, + pEditInstance->pUserOptions->nAreaBottom, + nDistance, SCROLL_NO_CLEAR); + + /* Fill the newly visible lines. First, the portion of the area that */ + /* requires redrawing is determined, and then a loop redraws the lines */ + /* that must be drawn. */ + + /* If we are moving text upwards, exposing new lines at the bottom of */ + /* the area: */ + if(nDistance > 0) + { + ASSERT(pEditInstance->unLineScrolledToTop + unPositiveDistance + < pEditInstance->unLinesInBuffer); + pEditInstance->unLineScrolledToTop += unPositiveDistance; + unFirstAreaLineToDraw = pEditInstance->unAreaHeight + - (UINT)unPositiveDistance; + unLastAreaLineToDraw = pEditInstance->unAreaHeight - 1; + } + /* Otherwise, we have moved text downwards, exposing new lines at the */ + /* top of the edit area. */ + else + { + ASSERT(pEditInstance->unLineScrolledToTop >= unPositiveDistance); + pEditInstance->unLineScrolledToTop -= unPositiveDistance; + unFirstAreaLineToDraw = 0; + unLastAreaLineToDraw = unPositiveDistance - 1; + } + + ODScrnEnableCaret(FALSE); + + /* Now, redraw the new lines. */ + unBufferLine = unFirstAreaLineToDraw + + pEditInstance->unLineScrolledToTop; + for(unAreaLine = unFirstAreaLineToDraw; unAreaLine <= + unLastAreaLineToDraw; ++unAreaLine, ++unBufferLine) + { + /* Draw the entire line. */ + ODEditDrawAreaLine(pEditInstance, unAreaLine); + } + + ODScrnEnableCaret(TRUE); + } + + /* Just redraw the entire edit area. */ + else + { + /* Adjust the line number that is scrolled to the top of the screen. */ + if(nDistance > 0) + { + pEditInstance->unLineScrolledToTop += unPositiveDistance; + } + else + { + pEditInstance->unLineScrolledToTop -= unPositiveDistance; + } + + /* Perform redraw, first purging outbound buffer. */ + ODEditRedrawArea(pEditInstance); + } + + return(bUseScrollCommand); +} + + +/* ---------------------------------------------------------------------------- + * ODEditRecommendFullRedraw() *** PRIVATE FUNCTION *** + * + * Determines whether it would be more efficient to add the specified number + * of bytes to the outbound buffer as part of an incremental redraw, or if + * it would be more efficient to just purge the outbound buffer and do a + * complete redraw of the edit area. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unEstPartialRedrawBytes - Estimate of the number of bytes that + * would be transmitted if an incremental + * redraw is performed. + * + * bDefault - The default action (TRUE for full + * redraw, FALSE for incremental) if the + * number of bytes in the outbound buffer + * cannot be determined. + * + * Return: TRUE if a full redraw is recommended, FALSE if an the + * incremental redraw is recommended. + */ +static BOOL ODEditRecommendFullRedraw(tEditInstance *pEditInstance, + UINT unEstPartialRedrawBytes, BOOL bDefault) +{ + int nOutboundBufferBytes; + UINT unEstFullRedrawBytes; + + /* In local mode, just return the default action. */ + if(od_control.baud == 0) + { + return(bDefault); + } + + /* Attempt to obtain the number of bytes in the communications outbound */ + /* buffer. Unfortunately, this information may not be available. For */ + /* example, FOSSIL drivers will only report whether or not there is */ + /* still data in the outbound buffer, but not a count of the number of */ + /* bytes in the buffer. Under such a situation, ODComOutbound() returns */ + /* SIZE_NON_ZERO if there is data in the buffer, and 0 if there is no */ + /* data in the buffer. This is not a problem under OpenDoor's internal */ + /* serial I/O code, nor is it a problem under Win32's communications */ + /* facilities. */ + ODComOutbound(hSerialPort, &nOutboundBufferBytes); + + if(nOutboundBufferBytes == SIZE_NON_ZERO) + { + /* We know that there is data in the outbound buffer, but we don't */ + /* know how much, and so we cannot make a recommendation. Instead, */ + /* the default course of action will be taken. */ + return(bDefault); + } + + /* Estimate the # of bytes required for a full redraw of the edit area. */ + unEstFullRedrawBytes = ODEditEstDrawBytes(pEditInstance, 0, + 0, pEditInstance->unAreaHeight - 1, pEditInstance->unAreaWidth); + + /* Recommend a full redraw if the number of bytes for an incremental */ + /* redraw plus the number of bytes already in the outbound buffer */ + /* exceed the number of bytes required for a full redraw. */ + if(unEstPartialRedrawBytes + (UINT)nOutboundBufferBytes + > unEstFullRedrawBytes) + { + return(TRUE); + } + else + { + return(FALSE); + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditEstDrawBytes() *** PRIVATE FUNCTION *** + * + * Estimates the number of bytes which will be transmitted in order to redraw + * the specified portion of the edit area. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unStartRedrawLine - Line of first character to draw. + * + * unStartRedrawColumn - Column of first character to draw. + * + * unFinishRedrawLine - Line of last character to draw. + * + * unFinishRedrawColumn - Column after last character to draw. + * + * Return: A rough estimate of the number of bytes required for the redraw. + */ +static UINT ODEditEstDrawBytes(tEditInstance *pEditInstance, + UINT unStartRedrawLine, UINT unStartRedrawColumn, UINT unFinishRedrawLine, + UINT unFinishRedrawColumn) +{ + UINT unAreaLine; + UINT unBufferLine; + UINT unLineLength; + UINT unByteTally = 0; + + /* If we are only drawing text on a single line, then estimate is just */ + /* the distance between the start and finish redraw column. This number */ + /* is precise only if the cursor is already at the location where */ + /* output is to begin, and the final cursor position is the location */ + /* where output finishes. This is in fact the situation when the user */ + /* is entering new text in the middle of the line - the most common */ + /* situation that will be encountered. */ + if(unStartRedrawLine == unFinishRedrawLine) + { + return(unFinishRedrawColumn - unStartRedrawColumn); + } + + /* If we are drawing text on multiple lines, then inspect the contents */ + /* of those lines to estimate the number of bytes to be transmitted. */ + for(unAreaLine = unStartRedrawLine, + unBufferLine = pEditInstance->unLineScrolledToTop + unStartRedrawLine; + unAreaLine <= unFinishRedrawLine; + ++unAreaLine, ++unBufferLine) + { + /* Determine the length of this line. */ + if(unBufferLine < pEditInstance->unLinesInBuffer) + { + unLineLength = ODEditBufferGetLineLength(pEditInstance, unBufferLine); + if(unAreaLine == unStartRedrawLine) + { + unLineLength -= unStartRedrawColumn; + } + } + else + { + unLineLength = 0; + } + + /* Add the number of characters on this line, along with the number of */ + /* bytes required to reposition the cursor and to clear the unused */ + /* portion of this line to the tally. This assumes that the edit area */ + /* spans the entire screen. */ + unByteTally += unLineLength + 7; + } + + return(unByteTally); +} + + +/* ---------------------------------------------------------------------------- + * ODEditGetCurrentLineInArea() *** PRIVATE FUNCTION *** + * + * Determines which line of the edit area the cursor is currently located in. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: 0-based index of the distance from the top of the edit area + * (as specified in the user options structure) where the + * cursor is currently located. + */ +static UINT ODEditGetCurrentLineInArea(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + return(pEditInstance->unCurrentLine - pEditInstance->unLineScrolledToTop); +} + + +/* ---------------------------------------------------------------------------- + * ODEditUpdateCursorPos() *** PRIVATE FUNCTION *** + * + * Unconditionally updates the position of the cursor on the screen to + * reflect its actual position. Compare with ODEditUpdateCursorIfMoved(). + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditUpdateCursorPos(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + /* Reposition the cursor on the screen. */ + od_set_cursor(ODEditGetCurrentLineInArea(pEditInstance) + + pEditInstance->pUserOptions->nAreaTop, + pEditInstance->unCurrentColumn + pEditInstance->pUserOptions->nAreaLeft); +} + + +/* ---------------------------------------------------------------------------- + * ODEditUpdateCursorIfMoved() *** PRIVATE FUNCTION *** + * + * Updates the position of the cursor on the screen to reflec its actual + * position only if we belive it isn't already there. Compare with + * ODEditUpdateCursorPos(). + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditUpdateCursorIfMoved(tEditInstance *pEditInstance) +{ + UINT unActualRow; + UINT unActualColumn; + ODEditGetActualCurPos(pEditInstance, &unActualRow, &unActualColumn); + + if(!(unActualRow == ODEditGetCurrentLineInArea(pEditInstance) + + pEditInstance->pUserOptions->nAreaTop + && unActualColumn == pEditInstance->unCurrentColumn + + pEditInstance->pUserOptions->nAreaLeft)) + { + ODEditUpdateCursorPos(pEditInstance); + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditEnterText() *** PRIVATE FUNCTION *** + * + * Inserts new text at the current cursor position, updating the cursor + * position accordingly. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * pszEntered - The character(s) to be inserted. + * + * Return: kODRCSuccess on success, kODRCSafeFailure if we were unable to + * obtain enough buffer space before making any changes, or + * kODRCUnrecoverableFailure if the buffer has been changed, but + * there was insufficient memory to re-index the buffer. + */ +static tODResult ODEditEnterText(tEditInstance *pEditInstance, + char *pszEntered, BOOL bInsertMode) +{ + UINT unNumCharsToAdd; + char *pch; + tODResult Result; + + ASSERT(pEditInstance != NULL); + ASSERT(pszEntered != NULL); + + /* Remember initial edit area contents, to permit selective redraw. */ + ODEditRememberArea(pEditInstance, pEditInstance->pRememberBuffer); + + /* Determine the number of characters that are to be added to the buffer. */ + unNumCharsToAdd = strlen(pszEntered); + + /* Make room in the buffer for the new characters, if needed. */ + if(bInsertMode) + { + Result = ODEditBufferMakeSpace(pEditInstance, + pEditInstance->unCurrentLine, pEditInstance->unCurrentColumn, + unNumCharsToAdd); + + if(Result != kODRCSuccess) + { + /* Beep on failure. */ + od_putch('\a'); + return(Result); + } + } + + /* Copy the new characters to the buffer. */ + pch = ODEditBufferGetCharacter(pEditInstance, + pEditInstance->unCurrentLine, pEditInstance->unCurrentColumn); + memcpy(pch, pszEntered, unNumCharsToAdd); + + /* Move the cursor position to the end of the newly added text. The */ + /* cursor position may be temporarily assigned to a position that is */ + /* past the end of the edit area or past the end of the buffer. */ + for(pch = pszEntered; *pch != '\0'; ++pch) + { + if(IS_EOL_CHAR(*pch)) + { + /* A carriage return character advances the cursor to the */ + /* leftmost column on the next line. */ + pEditInstance->unCurrentColumn = 0; + pEditInstance->unCurrentLine++; + + /* If the next character is a different EOL character, and is */ + /* not the end of the string, then skip that character. */ + if(IS_EOL_CHAR(pch[1]) && pch[1] != '\0' && pch[1] != *pch) + { + ++pch; + } + } + else + { + /* All other characters move the cursor ahead one column. */ + pEditInstance->unCurrentColumn++; + } + } + + /* Reindex and reformat the buffer based on its new contents. */ + if(!ODEditBufferFormatAndIndex(pEditInstance)) + { + return(kODRCUnrecoverableFailure); + } + + /* Check whether the cursor is now positioned past the end of the edit */ + /* area, requiring the edit area to be scrolled up. */ + if(ODEditGetCurrentLineInArea(pEditInstance) + >= pEditInstance->unAreaHeight) + { + /* We need to scroll the area accordingly. */ + + /* Distance to scroll is maximum of the current single-step scroll */ + /* distance, and the distance that the cursor is positioned below */ + /* the bottom of the current edit area. */ + UINT unScrollDistance = MAX(pEditInstance->unScrollDistance, + ODEditGetCurrentLineInArea(pEditInstance) - + pEditInstance->unAreaHeight + 1); + + /* Perform actual scroll operation. */ + if(ODEditScrollArea(pEditInstance, (INT)unScrollDistance)) + { + /* Entire area wasn't redrawn by operation, so some redrawing */ + /* may still be required, within the area of text that was */ + /* visible before the scroll operation. */ + ODEditRedrawChanged(pEditInstance, pEditInstance->pRememberBuffer, + 0, pEditInstance->unAreaHeight - unScrollDistance); + } + } + + /* Perform necessary redrawing and reposition the cursor if needed. */ + ODEditRedrawChanged(pEditInstance, pEditInstance->pRememberBuffer, + REDRAW_NO_BOUNDARY, REDRAW_NO_BOUNDARY); + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODEditSetBreakSequence() *** PRIVATE FUNCTION *** + * + * If the default line or paragraph break sequence has not yet been set, then + * this function sets it based on the break sequence that was encountered in + * the buffer supplied by the client application. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * chFirstEOLChar - First character in the encountered sequence. + * + * chSecondEOLChar - Second character in the encountered sequence. + * + * Return: void + */ +static void ODEditSetBreakSequence(tEditInstance *pEditInstance, + char chFirstEOLChar, char chSecondEOLChar) +{ + char *pszSequence; + + ASSERT(pEditInstance != NULL); + + if(pEditInstance->pszParagraphBreak != NULL + && pEditInstance->pszLineBreak != NULL) + { + /* In this situation, both the default line break sequence and default */ + /* paragraph break sequence have been set, so there is nothing for us */ + /* to do. */ + return; + } + + /* Obtain a pointer to the encountered sequence. We want to use a static */ + /* string constant for this, so that the string will continue to exist, */ + /* in unchanged form. */ + if(chFirstEOLChar == '\r' && chSecondEOLChar == '\0') + { + pszSequence = "\r"; + } + else if(chFirstEOLChar == '\n' && chSecondEOLChar == '\0') + { + pszSequence = "\n"; + } + else if(chFirstEOLChar == '\n' && chSecondEOLChar == '\r') + { + pszSequence = "\n\r"; + } + else if(chFirstEOLChar == '\r' && chSecondEOLChar == '\n') + { + pszSequence = "\r\n"; + } + else + { + /* This should never happen: an invalid end of line sequence was */ + /* passed in. */ + pszSequence = NULL; + ASSERT(FALSE); + } + + /* Set the as yet undetermined line/paragraph terminators. */ + if(pEditInstance->pszParagraphBreak == NULL) + { + pEditInstance->pszParagraphBreak = pszSequence; + } + + if(pEditInstance->pszLineBreak == NULL) + { + pEditInstance->pszLineBreak = pszSequence; + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditCursorLeft() *** PRIVATE FUNCTION *** + * + * Attempts to move the cursor left. Called when the user presses the left + * arrow key, and is also called as part of the process of handling the + * backspace key. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: TRUE on success, or FALSE if the cursor cannot be moved left any + * further. + */ +static BOOL ODEditCursorLeft(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + /* In word wrap mode, pressing the left key when the cursor */ + /* is past the end of the line jumps the cursor to the end */ + /* of the line. */ + if(pEditInstance->bWordWrapLongLines && + pEditInstance->unCurrentColumn > ODEditBufferGetLineLength + (pEditInstance, pEditInstance->unCurrentLine)) + { + pEditInstance->unCurrentColumn = ODEditBufferGetLineLength + (pEditInstance, pEditInstance->unCurrentLine); + return(TRUE); + } + + /* If we are not already at the leftmost column. */ + else if(pEditInstance->unCurrentColumn > 0) + { + /* Move left one column. */ + --pEditInstance->unCurrentColumn; + return(TRUE); + } + else if(pEditInstance->bWordWrapLongLines) + { + /* In word wrap mode, this will move us up to the end of */ + /* the previous line. */ + if(pEditInstance->unCurrentLine > 0) + { + ODEditGotoPreviousLine(pEditInstance); + pEditInstance->unCurrentColumn = ODEditBufferGetLineLength( + pEditInstance, pEditInstance->unCurrentLine); + return(TRUE); + } + } + + /* It wasn't possible to move the cursor. */ + return(FALSE); +} + + +/* ---------------------------------------------------------------------------- + * ODEditDeleteCurrentChar() *** PRIVATE FUNCTION *** + * + * Deletes the character at the current cursor position, performing necessary + * redraw. Pressing the delete key causes just this function to be called. + * Pressing the backspace key causes ODEditCursorLeft() to be called to first + * move the cursor left before calling ODEditDeleteCurrentChar(). + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditDeleteCurrentChar(tEditInstance *pEditInstance) +{ + char *pch; + + ASSERT(pEditInstance != NULL); + + /* Remember initial edit area contents, to permit selective redraw. */ + ODEditRememberArea(pEditInstance, pEditInstance->pRememberBuffer); + + /* Backup the entire buffer contents by one character. */ + pch = ODEditBufferGetCharacter(pEditInstance, + pEditInstance->unCurrentLine, pEditInstance->unCurrentColumn); + memmove(pch, pch + 1, strlen(pch + 1) + 1); + + /* Reindex and reformat the buffer based on its new contents. */ + ODEditBufferFormatAndIndex(pEditInstance); + + /* Perform necessary redrawing and reposition the cursor if needed. */ + ODEditRedrawChanged(pEditInstance, pEditInstance->pRememberBuffer, + REDRAW_NO_BOUNDARY, REDRAW_NO_BOUNDARY); +} + + +/* ---------------------------------------------------------------------------- + * ODEditDeleteCurrentLine() *** PRIVATE FUNCTION *** + * + * Removes the entire current line from the buffer. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: void + */ +static void ODEditDeleteCurrentLine(tEditInstance *pEditInstance) +{ + char *pszStartOfThisLine; + char *pszStartOfNextLine; + + ASSERT(pEditInstance != NULL); + + /* Remember initial edit area contents, to permit selective redraw. */ + ODEditRememberArea(pEditInstance, pEditInstance->pRememberBuffer); + + /* Determine start of this line. */ + pszStartOfThisLine = ODEditBufferGetCharacter(pEditInstance, + pEditInstance->unCurrentLine, 0); + + if(pEditInstance->unLinesInBuffer == pEditInstance->unCurrentLine + 1) + { + /* If this is the last line of the buffer, then we just remove */ + /* everything from this line, without actually removing the line. */ + *pszStartOfThisLine = '\0'; + } + else + { + /* If this is not the last line of the buffer, then remove this */ + /* entire line, so that the next line will become the current */ + /* line. */ + pszStartOfNextLine = ODEditBufferGetCharacter(pEditInstance, + pEditInstance->unCurrentLine + 1, 0); + memmove(pszStartOfThisLine, pszStartOfNextLine, + strlen(pszStartOfNextLine) + 1); + } + + /* Reset the cursor position to the beginning of the current line. */ + pEditInstance->unCurrentColumn = 0; + + /* Reindex and reformat the buffer based on its new contents. */ + ODEditBufferFormatAndIndex(pEditInstance); + + /* Perform necessary redrawing and reposition the cursor if needed. */ + ODEditRedrawChanged(pEditInstance, pEditInstance->pRememberBuffer, + REDRAW_NO_BOUNDARY, REDRAW_NO_BOUNDARY); +} + + +/* ---------------------------------------------------------------------------- + * ODEditPastEndOfCurLine() *** PRIVATE FUNCTION *** + * + * Determines whether the cursor is currently past the end of the current line. + * The end of the line is considered to be the first column after the last + * character on the line. So, on a blank line, a cursor is considered to be + * past the end if it is in or past the second column (column 0). + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: TRUE if the cursor is past the end of the current line, + * FALSE if it is not. + */ +static BOOL ODEditPastEndOfCurLine(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + return(pEditInstance->unCurrentColumn > + ODEditBufferGetLineLength(pEditInstance, pEditInstance->unCurrentLine)); +} + + +/* ---------------------------------------------------------------------------- + * ODEditRememberBufferSize() *** PRIVATE FUNCTION *** + * + * Determines the buffer size required by ODEditRememberArea(). + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: the required buffer size, in size_t units (bytes). + */ +static size_t ODEditRememberBufferSize(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + + return((pEditInstance->unAreaWidth + 1) + * pEditInstance->unAreaHeight); +} + + +/* ---------------------------------------------------------------------------- + * ODEditRememberArea() *** PRIVATE FUNCTION *** + * + * Stores a copy of the text currently displayed in the edit area in the + * provided buffer, so that it can later be reused to redraw only the portion + * of the edit area which has been changed by an operation. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * pRememberedArea - Pointer to a buffer, which is at least + * the number of bytes specified by + * ODEditRememberBufferSize() in size. + * + * Return: void + */ +static void ODEditRememberArea(tEditInstance *pEditInstance, + void *pRememberedArea) +{ + UINT unDataLineOffset = 0; + UINT unDataLineSize; + UINT unAreaLine; + UINT unBufferLine; + UINT unLineLength; + char *pchStartOfLine; + char *pchDataLocation; + + ASSERT(pEditInstance != NULL); + ASSERT(pRememberedArea != NULL); + + /* Determine the length of a single line in the remember buffer. */ + unDataLineSize = pEditInstance->unAreaWidth + 1; + + pchDataLocation = (char *)pRememberedArea + unDataLineOffset; + for(unBufferLine = pEditInstance->unLineScrolledToTop, unAreaLine = 0; + unAreaLine < pEditInstance->unAreaHeight; + ++unAreaLine, ++unBufferLine) + { + /* If this line is not beyond the end of the buffer. */ + if(unBufferLine < pEditInstance->unLinesInBuffer) + { + /* Determine the length of this buffer line. */ + unLineLength = ODEditBufferGetLineLength(pEditInstance, unBufferLine); + + /* Determine the start location of this buffer line. */ + pchStartOfLine = ODEditBufferGetCharacter(pEditInstance, unBufferLine, + 0); + } + else + { + /* If this line is beyond the end of the buffer, then it is empty. */ + unLineLength = 0; + pchStartOfLine = ""; + } + + /* Copy the contents of this line to the data buffer. */ + memcpy(pchDataLocation, pchStartOfLine, unLineLength); + pchDataLocation[unLineLength] = '\0'; + + /* Update the location where data is being stored in the buffer. */ + pchDataLocation += unDataLineSize; + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditRedrawChanged() *** PRIVATE FUNCTION *** + * + * Redraws the portion of the edit area which has been changed by an operation, + * based on the original edit area contents as stored in a buffer by the + * ODEditRememberArea() function. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * pRememberedArea - Pointer to a buffer that was filled by a + * previous call to ODEditRememberArea(). + * + * unUpperBoundary - The first line in the edit area to consider + * redrawing, or REDRAW_NO_BOUNDARY to specify + * the top of the edit area. + * + * unLowerBoundary - The last line in the edit area to consider + * redrawing, or REDRAW_NO_BOUNDARY to specify + * the bottom of the edit area. + * + * Return: void + */ +static void ODEditRedrawChanged(tEditInstance *pEditInstance, + void *pRememberedArea, UINT unUpperBoundary, UINT unLowerBoundary) +{ + UINT unStartRedrawLine; + UINT unStartRedrawColumn; + UINT unFinishRedrawLine; + UINT unFinishRedrawColumn; + UINT unEstPartialRedrawBytes; + + ASSERT(pEditInstance != NULL); + ASSERT(pRememberedArea != NULL); + + /* Determine what portion of the edit area, within the specified upper */ + /* and lower boundaries, has been changed. */ + if(!ODEditDetermineChanged(pEditInstance, pRememberedArea, unUpperBoundary, + unLowerBoundary, &unStartRedrawLine, &unStartRedrawColumn, + &unFinishRedrawLine, &unFinishRedrawColumn)) + { + /* Nothing has changed in the edit area. */ + ODEditUpdateCursorIfMoved(pEditInstance); + return; + } + + /* Now that we have determined the portion of the edit area that would */ + /* be redraw by a partial (incremental) redraw, we compare the amount */ + /* of data involved + the amount of data still in the outbound buffer */ + /* with the amount of data involved in a full redraw. If the amount of */ + /* data in the outbound buffer cannot be determined, we default to */ + /* using an incremental redraw. */ + unEstPartialRedrawBytes = ODEditEstDrawBytes(pEditInstance, + unStartRedrawLine, unStartRedrawColumn, unFinishRedrawLine, + unFinishRedrawColumn); + if(ODEditRecommendFullRedraw(pEditInstance, unEstPartialRedrawBytes, + FALSE)) + { + /* Purge the outbound buffer and do a full redraw. */ + ODEditRedrawArea(pEditInstance); + + /* Move the cursor back to its appropriate position. */ + ODEditUpdateCursorPos(pEditInstance); + } + else + { + /* Perform a partial (incremental) redraw. */ + + /* Now, redraw the portion of the edit area that has been determined to */ + /* require redrawing. */ + ODEditRedrawSubArea(pEditInstance, unStartRedrawLine, unStartRedrawColumn, + unFinishRedrawLine, unFinishRedrawColumn); + + /* Now, move the cursor back to its appropriate position, if it isn't */ + /* already there. */ + ODEditUpdateCursorIfMoved(pEditInstance); + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditDetermineChanged() *** PRIVATE FUNCTION *** + * + * Determines what portion of the edit area, within the specifiede upper and + * lower boundary, has been changed. Area is specified as row and column + * position of the first changed characer between boundaries, and the row + * and column position past the last changed character between the boundaries. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * pRememberedArea - Pointer to a buffer that was filled by a + * previous call to ODEditRememberArea(). + * + * unUpperBoundary - The first line in the edit area to + * consider redrawing, or + * REDRAW_NO_BOUNDARY to specify the top of + * the edit area. + * + * unLowerBoundary - The last line in the edit area to + * consider redrawing, or + * REDRAW_NO_BOUNDARY to specify the bottom + * of the edit area. + * + * punStartRedrawLine - Output: Line of first changed character. + * + * punStartRedrawColumn - Output: Column of first changed char. + * + * punFinishRedrawLine - Output: Line of last changed character. + * + * punFinishRedrawColumn - Output: Column after last changed char. + * + * Return: TRUE if some text in the edit area has been changed, FALSE + * if there is no change. + */ +static BOOL ODEditDetermineChanged(tEditInstance *pEditInstance, + void *pRememberedArea, UINT unUpperBoundary, UINT unLowerBoundary, + UINT *punStartRedrawLine, UINT *punStartRedrawColumn, + UINT *punFinishRedrawLine, UINT *punFinishRedrawColumn) +{ + BOOL bFoundStart = FALSE; + BOOL bFoundFinish = FALSE; + UINT unDataLineOffset = 0; + UINT unDataLineSize; + UINT unAreaLine; + UINT unLineLength; + UINT unColumn; + UINT unBufferLine; + char *pchCurrent; + char *pchRemembered; + + /* Determine the length of a single line in the remember buffer. */ + unDataLineSize = pEditInstance->unAreaWidth + 1; + + /* If caller specified no upper boundary, then reset upper boundary */ + /* to 0. */ + if(unUpperBoundary == REDRAW_NO_BOUNDARY) unUpperBoundary = 0; + + /* Likewise, iff caller specified no lower boundary, then reset the */ + /* lower boundary to the bottom of the edit area. */ + if(unLowerBoundary == REDRAW_NO_BOUNDARY) + { + unLowerBoundary = pEditInstance->unAreaHeight; + } + + /* Loop through the area within boundaries, determining which */ + /* portion of the edit area has changed. */ + for(unBufferLine = pEditInstance->unLineScrolledToTop + unUpperBoundary, + unAreaLine = unUpperBoundary; unAreaLine < unLowerBoundary; + ++unAreaLine, ++unBufferLine) + { + /* Determine location of corresponding line in remembered data. */ + pchRemembered = (char *)pRememberedArea + unDataLineOffset + + unDataLineSize * unAreaLine; + + /* If this line is not beyond the end of the buffer. */ + if(unBufferLine < pEditInstance->unLinesInBuffer) + { + /* Determine the start location of this buffer line. */ + pchCurrent = ODEditBufferGetCharacter(pEditInstance, unBufferLine, 0); + + /* Determine the length of this buffer line. */ + unLineLength = ODEditBufferGetLineLength(pEditInstance, unBufferLine); + } + else + { + pchCurrent = ""; + unLineLength = 0; + } + + /* Start at the first column on this line. */ + unColumn = 0; + + /* Look for any characters that differ. */ + for(;; ++unColumn, ++pchCurrent, ++pchRemembered) + { + /* Determine if we are at the end of the remembered line. */ + BOOL bEndOfRemembered = (*pchRemembered == '\0'); + + /* Determine if we are at the end of the current buffer line. */ + BOOL bEndOfCurrent = (unColumn == unLineLength); + + /* If we are at the end of either of the buffers (but not both), */ + /* or if these two characters differ, then we have found the */ + /* start of the area that must be redrawn. */ + if(!(bEndOfRemembered && bEndOfCurrent)) + { + if(bEndOfRemembered || bEndOfCurrent + || *pchCurrent != *pchRemembered) + { + if(bFoundStart) + { + bFoundFinish = FALSE; + } + else + { + /* We have found a character that differs. */ + bFoundStart = TRUE; + *punStartRedrawLine = unAreaLine; + *punStartRedrawColumn = unColumn; + } + } + } + + /* If we have found the first changed text in the buffer, then we */ + /* are now looking for the last changed text in the buffer. */ + if(bFoundStart && !bFoundFinish) + { + if(*pchCurrent == *pchRemembered) + { + bFoundFinish = TRUE; + *punFinishRedrawLine = unAreaLine; + *punFinishRedrawColumn = unColumn; + } + else if(bEndOfRemembered) + { + bFoundFinish = TRUE; + *punFinishRedrawLine = unAreaLine; + *punFinishRedrawColumn = unLineLength; + } + else if(bEndOfCurrent) + { + bFoundFinish = TRUE; + *punFinishRedrawLine = unAreaLine; + *punFinishRedrawColumn = unColumn + strlen(pchRemembered); + } + } + + /* If we are at the end of either buffers. */ + if(bEndOfRemembered || bEndOfCurrent) + { + /* Now, proceed to processing the next line in the edit area. */ + break; + } + } + } + + /* If we haven't found any text in the edit area that has changed. */ + if(!bFoundStart) + { + /* Then return indicating no change. */ + return(FALSE); + } + + /* If we haven't found an end to the portion of the area that has */ + /* changed, then we must redraw up to the end of the edit area. */ + if(!bFoundFinish) + { + *punFinishRedrawLine = unLowerBoundary; + *punFinishRedrawColumn = unColumn; + } + + /* Return indicating that ther has been some change. */ + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODEditRedrawSubArea() *** PRIVATE FUNCTION *** + * + * Redraws the portion of the edit area within the specified range. Redrawing + * is performed from the location of the start redraw row and column, up to + * but not includin gthe finish redraw row and column. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unStartRedrawLine - Line of first character to draw. + * + * unStartRedrawColumn - Column of first character to draw. + * + * unFinishRedrawLine - Line of last character to draw. + * + * unFinishRedrawColumn - Column after last character to draw. + * + * Return: void + */ +static void ODEditRedrawSubArea(tEditInstance *pEditInstance, + UINT unStartRedrawLine, UINT unStartRedrawColumn, UINT unFinishRedrawLine, + UINT unFinishRedrawColumn) +{ + UINT unAreaLine; + UINT unLineLength; + UINT unBufferLine; + char *pchCurrent; + UINT unStartColumn; + UINT unFinishColumn; + UINT unScrnStartColumn; + UINT unTextLength; + + /* Now, perform actual redraw in area that requires redrawing. */ + for(unBufferLine = pEditInstance->unLineScrolledToTop + unStartRedrawLine, + unAreaLine = unStartRedrawLine; unAreaLine <= unFinishRedrawLine; + ++unBufferLine, ++unAreaLine) + { + BOOL bFirstLine = (unAreaLine == unStartRedrawLine); + BOOL bLastLine = (unAreaLine == unFinishRedrawLine); + UINT unScrnRow = (UINT)pEditInstance->pUserOptions->nAreaTop + + unAreaLine; + + /* If this line is not beyond the end of the buffer. */ + if(unBufferLine < pEditInstance->unLinesInBuffer) + { + pchCurrent = ODEditBufferGetCharacter(pEditInstance, unBufferLine, 0); + unTextLength = unLineLength = + ODEditBufferGetLineLength(pEditInstance, unBufferLine); + } + else + { + pchCurrent = ""; + unTextLength = unLineLength = 0; + } + + /* Move to the position on the first line to begin redraw. */ + if(bFirstLine) + { + UINT unActualRow; + UINT unActualColumn; + ODEditGetActualCurPos(pEditInstance, &unActualRow, &unActualColumn); + + unStartColumn = unStartRedrawColumn; + unScrnStartColumn = (UINT)pEditInstance->pUserOptions->nAreaLeft + + unStartColumn; + + if(unScrnRow != unActualRow || unScrnStartColumn != unActualColumn) + { + od_set_cursor(unScrnRow, unScrnStartColumn); + } + + pchCurrent += unStartRedrawColumn; + unTextLength -= unStartRedrawColumn; + } + else + { + unStartColumn = 0; + unScrnStartColumn = (UINT)pEditInstance->pUserOptions->nAreaLeft; + od_set_cursor(unScrnRow, unScrnStartColumn); + } + + /* If this is the last line to redraw, then adjust accordingly. */ + if(bLastLine) + { + if(unFinishRedrawColumn < unLineLength) + { + unTextLength -= unLineLength - unFinishRedrawColumn; + } + unFinishColumn = unFinishRedrawColumn; + } + else + { + unFinishColumn = pEditInstance->unAreaWidth; + } + + /* Output changed text. */ + if(unStartColumn < unLineLength) + { + od_disp(pchCurrent, unTextLength, TRUE); + unStartColumn += unTextLength; + } + + /* If we need to clear the rest of the line. */ + if(unFinishColumn == pEditInstance->unAreaWidth) + { + /* If right edge of edit area aligns with the right edge of the */ + /* screen. */ + if(pEditInstance->pUserOptions->nAreaRight == OD_SCREEN_WIDTH) + { + /* Clear the remainder of this line on the screen. */ + od_clr_line(); + } + else + { + /* Place spaces after the end of the current line, up to right */ + /* edge of the edit area. */ + od_repeat(' ', (BYTE)(pEditInstance->unAreaWidth - unLineLength)); + } + } + else if(unStartColumn < unFinishColumn) + { + od_repeat(' ', (BYTE)(unFinishColumn - unStartColumn)); + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditGetActualCurPos() *** PRIVATE FUNCTION *** + * + * Estimates the actual position of the cursor on the screen. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * punRow - Pointer to location where cursor row number + * should be stored. + * + * punColumn - Pointer to location where cursor column number + * should be stored. + * + * Return: void + */ +static void ODEditGetActualCurPos(tEditInstance *pEditInstance, + UINT *punRow, UINT *punColumn) +{ + tODScrnTextInfo TextInfo; + + ASSERT(pEditInstance != NULL); + ASSERT(punRow != NULL); + ASSERT(punColumn != NULL); + + UNUSED(pEditInstance); + + /* Obtain current cursor position information from the ODScrn module. */ + ODScrnGetTextInfo(&TextInfo); + *punRow = (UINT)TextInfo.cury; + *punColumn = (UINT)TextInfo.curx; +} + + +/* ---------------------------------------------------------------------------- + * ODEditIsEOLForMode() *** PRIVATE FUNCTION *** + * + * Determines whether the specified character should be treated as an EOL + * character for the current mode. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: TRUE if this is an EOL character, FALSE otherwise. + */ +static BOOL ODEditIsEOLForMode(tEditInstance *pEditInstance, char chToTest) +{ + switch(pEditInstance->pUserOptions->TextFormat) + { + case FORMAT_FTSC_MESSAGE: + return(chToTest == '\r' || chToTest == '\0'); + + default: + return(IS_EOL_CHAR(chToTest)); + } +} + + + +/* ========================================================================= */ +/* Low level buffer manipulation functions. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODEditBufferFormatAndIndex() *** PRIVATE FUNCTION *** + * + * Regenerates the count of lines in the buffer, and the array of pointers to + * the start of each line. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: TRUE on success, or FALSE if there is not enough memory + * available to complete this operation. + */ +static BOOL ODEditBufferFormatAndIndex(tEditInstance *pEditInstance) +{ + char *pch; + char *pchLastSpace; + UINT unProcessingColumn; + UINT unProcessingLine; + BOOL bAtEndOfBuffer = FALSE; + BOOL bLineEndedByBreak; + BOOL bFTSCMode = + (pEditInstance->pUserOptions->TextFormat == FORMAT_FTSC_MESSAGE); + + ASSERT(pEditInstance != NULL); + + /* Reset current line count. */ + unProcessingLine = 0; + + /* Begin at the beginning of the buffer to edit. */ + pch = pEditInstance->pszEditBuffer; + ASSERT(pch != NULL); + + /* Loop for each line in the buffer. */ + while(!bAtEndOfBuffer) + { + /* In FTSC mode, skip a line if it begins with a ^A ("kludge lines"). */ + if(bFTSCMode) + { + /* Loop while the current line begins with a ^A. */ + while(*pch == 0x01) + { + /* Loop until the end of the line is found. */ + while(!ODEditIsEOLForMode(pEditInstance, *pch)) ++pch; + + if(*pch == '\0') + { + /* If the line was ended by a null character, then note that */ + /* the end of the buffer has been reached. */ + bAtEndOfBuffer = TRUE; + } + else + { + /* If the line was not ended by a null character, then skip */ + /* the end of line character. */ + ++pch; + } + } + + continue; + } + + /* Add the address of the start of this line to the line array. */ + + /* If the line array is full, then attempt to grow it. */ + ASSERT(unProcessingLine <= pEditInstance->unLineArraySize); + if(unProcessingLine == pEditInstance->unLineArraySize) + { + /* Determine the size to grow the array to. */ + UINT unNewArraySize = pEditInstance->unLineArraySize + + LINE_ARRAY_GROW_SIZE; + + /* Attempt to reallocate this memory block. */ + char **papchNewLineArray = (char **)realloc( + pEditInstance->papchStartOfLine, unNewArraySize * sizeof(char *)); + + /* If reallocation failed, then return with failure. */ + if(papchNewLineArray == NULL) + { + return(FALSE); + } + + /* Otherwise, update the editor instance information with the new */ + /* array address and array size information. */ + pEditInstance->papchStartOfLine = papchNewLineArray; + pEditInstance->unLineArraySize = unNewArraySize; + } + + /* Add the address of the start of this line to the array. */ + pEditInstance->papchStartOfLine[unProcessingLine] = pch; + + /* Reset word wrap information. */ + pchLastSpace = NULL; + + /* Now, find the end of this line. */ + bLineEndedByBreak = TRUE; + unProcessingColumn = 0; + while(!ODEditIsEOLForMode(pEditInstance, *pch)) + { + /* If this character is a space, then record the location of the */ + /* last space characters. */ + if(*pch == ' ') pchLastSpace = pch; + + /* Check for characters which must be filtered from the buffer */ + /* in FTSC message mode. */ + if(bFTSCMode) + { + if(*pch == 0x0a || ((unsigned char)*pch) == 0x8d) + { + /* If this character must be removed, then move rest of */ + /* buffer up by one character, and proceed to next loop */ + /* iteration. */ + memmove(pch, pch + 1, strlen(pch + 1) + 1); + continue; + } + } + + /* Increment count of characters on this line. */ + ++unProcessingColumn; + + /* Check whether we have reached the maximum number of characters */ + /* that will fit on this line. */ + if(unProcessingColumn >= pEditInstance->unAreaWidth - 1) + { + if(pEditInstance->bWordWrapLongLines) + { + /* If we are to word wrap long lines, then back up to the */ + /* beginning of the last word, if we have encountered any */ + /* space characters. */ + if(pchLastSpace != NULL && pchLastSpace < pch) + { + /* Update current column number accordingly. */ + unProcessingColumn -= (UINT)(pch - pchLastSpace); + + /* Back up to position to perform word wrap at. */ + pch = pchLastSpace; + } + } + + /* If we are wrapping text where the cursor is located, then we */ + /* will have to reposition the cursor accordingly. */ + if(unProcessingLine == pEditInstance->unCurrentLine + && unProcessingColumn < pEditInstance->unCurrentColumn) + { + /* Move the cursor to the next line. */ + pEditInstance->unCurrentLine++; + + /* Adjust the cursor column number to the position where the */ + /* corresponding wrapped text will appear. */ + pEditInstance->unCurrentColumn -= unProcessingColumn; + } + + /* Note that line was not ended by en explicit line break. */ + bLineEndedByBreak = FALSE; + + break; + } + + /* Move to the next character in the buffer. */ + ++pch; + } + + /* If we the line was terminated by a '\0', then note that the end of */ + /* the buffer has been reached. */ + if(*pch == '\0') + { + bAtEndOfBuffer = TRUE; + } + + /* If the line was not terminated by a '\0', then find the first */ + /* character of the next line. */ + else + { + char chFirstEOLChar = *pch; + char chSecondEOLChar = '\0'; + + /* Move to the next character in the buffer. */ + ++pch; + + /* If this character is a different EOL sequence character from the */ + /* already encountered EOL character, then skip past it too. */ + if(ODEditIsEOLForMode(pEditInstance, chFirstEOLChar) && *pch != '\0' + && ODEditIsEOLForMode(pEditInstance, *pch) + && *pch != chFirstEOLChar) + { + chSecondEOLChar = *pch; + ++pch; + } + + /* If we don't already know what form of line/paragraph break to */ + /* use (just a CR, just a LF, a CR/LF sequence or a LF/CR */ + /* sequence), then use this line termination as an example of */ + /* what should be used. */ + if(bLineEndedByBreak) + { + ODEditSetBreakSequence(pEditInstance, chFirstEOLChar, + chSecondEOLChar); + } + } + + /* Increment the count of the current line number. */ + unProcessingLine++; + } + + /* Update count of number of lines in the buffer, based on the number */ + /* that we have found. */ + pEditInstance->unLinesInBuffer = unProcessingLine; + + /* Return with success. */ + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODEditBufferGetLineLength() *** PRIVATE FUNCTION *** + * + * Determines the length of the specified line in the buffer, not including + * any line terminator characters. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unBufferLine - 0-based index of the line in question. + * + * Return: The number of characters on this line. + */ +static UINT ODEditBufferGetLineLength(tEditInstance *pEditInstance, + UINT unBufferLine) +{ + char *pch; + char *pchStartOfLine; + UINT unCharsBeforeEOL; + + ASSERT(pEditInstance != NULL); + ASSERT(unBufferLine < pEditInstance->unLinesInBuffer); + ASSERT(pEditInstance->unLinesInBuffer <= pEditInstance->unLineArraySize); + + /* Get the address of the start of this line in the buffer. */ + pchStartOfLine + = ODEditBufferGetCharacter(pEditInstance, unBufferLine, 0); + + /* Count the number of characters before the next end of line character. */ + for(pch = pchStartOfLine, unCharsBeforeEOL = 0; + !ODEditIsEOLForMode(pEditInstance, *pch); + ++unCharsBeforeEOL, ++pch); + + /* If this is the last line in the buffer, then the number of characers */ + /* before the next end of line character is the length of this line. */ + if(unBufferLine >= pEditInstance->unLinesInBuffer - 1) + { + return(unCharsBeforeEOL); + } + + /* If this is not the last line in the buffer, then the length of this */ + /* line is the minimum of the number of characters before the next end */ + /* of line character and the number of characters before the next line, */ + /* according to the line index information. This is because all lines */ + /* do not necessarily end with an end-of-line character. */ + else + { + return(MIN(unCharsBeforeEOL, (UINT)(ODEditBufferGetCharacter( + pEditInstance, unBufferLine + 1, 0) - pchStartOfLine))); + } +} + + +/* ---------------------------------------------------------------------------- + * ODEditBufferGetTotalLines() *** PRIVATE FUNCTION *** + * + * Determines the number of lines in the current edit buffer. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * Return: The total number of lines in the buffer. + */ +static UINT ODEditBufferGetTotalLines(tEditInstance *pEditInstance) +{ + ASSERT(pEditInstance != NULL); + ASSERT(pEditInstance->unLinesInBuffer <= pEditInstance->unLineArraySize); + + /* Return the total number of lines in the buffer. */ + return(pEditInstance->unLinesInBuffer); +} + + +/* ---------------------------------------------------------------------------- + * ODEditBufferGetCharacter() *** PRIVATE FUNCTION *** + * + * Obtains the character at the specified position in the buffer. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unBufferLine - 0-based index of the line in question. + * + * unBufferColumn - The position in the line of the required + * character. + * + * Return: A pointer to the character at the specified position in the + * specified line. The caller can assume that any remaining + * character(s) in the line follow this character, but should + * not assume that the pointer can be used to access following + * lines in the buffer. + */ +static char *ODEditBufferGetCharacter(tEditInstance *pEditInstance, + UINT unBufferLine, UINT unBufferColumn) +{ + ASSERT(pEditInstance != NULL); + ASSERT(unBufferLine < pEditInstance->unLinesInBuffer); + ASSERT(pEditInstance->unLinesInBuffer <= pEditInstance->unLineArraySize); + ASSERT(unBufferColumn <= ODEditBufferGetLineLength(pEditInstance, unBufferLine)); + + /* The position of this character is the position of this line, plus */ + /* the number of characters into the line. */ + return(pEditInstance->papchStartOfLine[unBufferLine] + unBufferColumn); +} + + +/* ---------------------------------------------------------------------------- + * ODEditBufferMakeSpace() *** PRIVATE FUNCTION *** + * + * Moves the remaining buffer contents by the specified distance to make room + * for new text. The new space is filled by space (' ') characters. Does not + * necessarily reindex the buffer before returning, and so this should be done + * by the caller after the new buffer space has been filled. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unLine - Line number to make more room on. + * + * unColumn - Column number to insert the space. + * + * unNumChars - Number of characters to make room for. + * + * Return: kODRCSuccess on success, kODRCSafeFailure if we were unable to + * obtain enough buffer space before making any changes, or + * kODRCUnrecoverableFailure if the buffer has been changed, but + * there was insufficient memory to re-index the buffer. + */ +static tODResult ODEditBufferMakeSpace(tEditInstance *pEditInstance, + UINT unLine, UINT unColumn, UINT unNumChars) +{ + UINT unLineLength; + UINT unBufferUsed; + UINT unBufferUnused; + UINT unRemainingBufferBytes; + UINT unCount; + char *pchBufferPos; + tODResult Result; + + ASSERT(pEditInstance != NULL); + ASSERT(unLine < pEditInstance->unLinesInBuffer); + + /* Determine the current length of the specified line. */ + unLineLength = ODEditBufferGetLineLength(pEditInstance, unLine); + + /* If a column past the current end of this line was specified, then */ + /* adjust column and number of characters in order to extend the line */ + /* up to the specified column as well as adding space beginning at that */ + /* column. */ + if(unColumn > unLineLength) + { + UINT unExtendLineBy = unColumn - unLineLength; + unColumn -= unExtendLineBy; + unNumChars += unExtendLineBy; + } + + /* Now, determine whether the buffer is large enough for the additional */ + /* space that will be added. */ + unBufferUsed = strlen(pEditInstance->pszEditBuffer) + 1; + unBufferUnused = pEditInstance->unBufferSize - unBufferUsed; + if(unBufferUnused < unNumChars) + { + /* There is not currently sufficient room in the buffer for the new */ + /* characters, then attempt to grow the buffer to make more room. */ + Result = ODEditTryToGrow(pEditInstance, unBufferUsed + unNumChars); + if(Result != kODRCSuccess) + { + /* On failure, return the result code that indicates the nature */ + /* of the failure. */ + return(Result); + } + } + + /* Now, shift the buffer contents from this location forward by */ + /* unNumChars characters. */ + pchBufferPos = ODEditBufferGetCharacter(pEditInstance, unLine, unColumn); + unRemainingBufferBytes = strlen(pchBufferPos) + 1; + memmove(pchBufferPos + unNumChars, pchBufferPos, unRemainingBufferBytes); + + /* Next, we fill the new buffer area with space characters. */ + for(unCount = 0; unCount < unNumChars; ++unCount) + { + *pchBufferPos++ = ' '; + } + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODEditTryToGrow() *** PRIVATE FUNCTION *** + * + * Attempts to reallocate the buffer to a larger size. This function is called + * if it is found that the current buffer isn't large enough to complete some + * operation. If the client application has setup the editor to permit buffer + * reallocation, then this function will call the realloc callback function + * supplied by the client application. If buffer growing is not possible, then + * this function automatically fails. + * + * Parameters: pEditInstance - Editor instance information structure. + * + * unSizeNeeded - The minimum buffer size that is needed. + * + * Return: kODRCSuccess on success, kODRCSafeFailure if we were unable to + * obtain enough buffer space before making any changes, or + * kODRCUnrecoverableFailure if the buffer has been changed, but + * there was insufficient memory to re-index the buffer. + */ +static tODResult ODEditTryToGrow(tEditInstance *pEditInstance, + UINT unSizeNeeded) +{ + BOOL bFullReIndexRequired = FALSE; + + ASSERT(pEditInstance != NULL); + ASSERT(unSizeNeeded > pEditInstance->unBufferSize); + + if(pEditInstance->pUserOptions->pfBufferRealloc != NULL) + { + /* If the buffer is growable, then attempt to grow it using the */ + /* realloc function provided by the client application. */ + UINT unNewBufferSize = MAX(pEditInstance->unBufferSize + + BUFFER_GROW_SIZE, unSizeNeeded); + char *pszNewBuffer = (char *)((*pEditInstance->pUserOptions-> + pfBufferRealloc)(pEditInstance->pszEditBuffer, unNewBufferSize)); + + /* If we were unable to grow the buffer, then fail now. At this */ + /* point, nothing has changed, and so the buffer information */ + /* is still intact and valid. */ + if(pszNewBuffer == NULL) + { + return(kODRCSafeFailure); + } + + /* Otherwise, determine whether the entire buffer will now have to */ + /* be reindexed. This is necessary if the reallocated buffer is at */ + /* a new location than the original was. */ + if(pszNewBuffer != pEditInstance->pszEditBuffer) + { + bFullReIndexRequired = TRUE; + } + + /* Now, store the new buffer pointer and buffer size information. */ + pEditInstance->pszEditBuffer = pszNewBuffer; + pEditInstance->unBufferSize = unNewBufferSize; + } + else + { + /* If the buffer is not growable, then fail right away. */ + return(kODRCSafeFailure); + } + + /* If a full reindex is required due to buffer reallocation, then do so. */ + if(bFullReIndexRequired) + { + if(!ODEditBufferFormatAndIndex(pEditInstance)) + { + /* If this fails, then return with failure. */ + return(kODRCUnrecoverableFailure); + } + bFullReIndexRequired = FALSE; + } + + /* If we get to this point, we suceeded in growing the buffer to the */ + /* required size, so return with success. */ + return(kODRCSuccess); +} diff --git a/utils/magiedit/odoors/ODEmu.c b/utils/magiedit/odoors/ODEmu.c new file mode 100644 index 0000000..a754161 --- /dev/null +++ b/utils/magiedit/odoors/ODEmu.c @@ -0,0 +1,2212 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODEmu.c + * + * Description: Code for the TTY/ANSI/AVATAR terminal emulation routines, + * including .ASC/.ANS/.AVT/.RIP file display functions. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Jun 07, 1995 6.00 BP Added od_emu_simulate_modem. + * Jul 18, 1995 6.00 BP Fixed warning in call to _ulongdiv(). + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 15, 1995 6.00 BP Terminal emulation speed optimization. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 24, 1995 6.00 BP Use od_connect_speed for modem sim. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 21, 1996 6.00 BP Use ODScrnShowMessage(). + * Jan 09, 1996 6.00 BP ODComOutbound() returns actual size. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Prevent TC generated N_LXMUL@ call. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Oct 18, 2001 6.11 MD Added od_send_file_section() + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODCom.h" +#include "ODTypes.h" +#include "ODScrn.h" +#include "ODKrnl.h" +#include "ODUtil.h" + + +/* Manifest constants. */ +#define MODEM_SIMULATOR_TICK 54L + +#define LEVEL_NONE 0 +#define LEVEL_ASCII 1 +#define LEVEL_ANSI 2 +#define LEVEL_AVATAR 3 +#define LEVEL_RIP 4 + + +/* Local helper function prototypes. */ +static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho); +static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel); +static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom, char chToFillWith); + + +/* Current terminal emulator state variables. */ +static BYTE btANSISeqLevel = 0; +static INT anANSIParams[10]; +static char szCurrentParam[4] = ""; +static BYTE btCurrentParamLength; +static BYTE btSavedColumn=1; +static BYTE btSavedRow = 1; +static char szToRepeat[129]; +static BYTE btRepeatCount; +static BYTE btAvatarSeqLevel = 0; +static char chPrevParam; +static BYTE btNumParams; +static BYTE btDefaultAttrib = 7; +static BOOL bAvatarInsertMode = FALSE; +static INT8 btScrollLines; +static BYTE btScrollLeft, btScrollTop, btScrollRight, btScrollBottom; + +/* Variables for tracking hotkeys while displaying a menu file. */ +static char *pszCurrentHotkeys=NULL; +static char chHotkeyPressed; + +/* Lookup table to map colors from ANSI values to PC color values. */ +static BYTE abtANSIToPCColorTable[8] = {0, 4, 2, 6, 1, 5, 3, 7}; + + +/* ---------------------------------------------------------------------------- + * od_hotkey_menu() + * + * Displays a .ASC/.ANS/.AVT/.RIP file, just as od_send_file() does. However, + * unlike od_send_file(), od_hotkey_menu() also allows checks for keypresses + * by the user. If any of the hotkeys listed in pszHotKeys are pressed while + * the file is being displayed, or after the file has finished being displayed, + * od_hotkey_menu() will return this value to the caller. This allows menu + * screens to be easily displayed from on-disk files, while permitting the user + * to choose a menu item at any time. + * + * Parameters: pszFileName - Pointer to the filename to display. + * + * pszHotKeys - Pointer to a string listing the valid keys. + * Keys are not case sensitive. + * + * bWait - If TRUE, od_hotkey_menu() will not return until + * the user presses one of the valid keys. If FALSE, + * then od_hotkey_menu() will return as soon as it + * has finished displaying the file, even if the + * user has not pressed any key;. + * + * Return: The key pressed by the user, or '\0' if no key was pressed. + */ +ODAPIDEF char ODCALL od_hotkey_menu(char *pszFileName, char *pszHotKeys, + BOOL bWait) +{ + char chPressed; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_hotkey_menu()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + if(!pszHotKeys) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return('\0'); + } + + /* Store pointer to string of hotkeys in global hotkey array for access */ + /* from od_send_file(). */ + pszCurrentHotkeys = (char *)pszHotKeys; + + /* Clear the hotkey status variable. */ + chHotkeyPressed = '\0'; + + /* Display the menu file using od_send_file() primitive. */ + if(!od_send_file(pszFileName)) + { + OD_API_EXIT(); + return('\0'); + } + + /* Clear the global hotkey array. */ + pszCurrentHotkeys = NULL; + + /* If the file display was interrupted by the pressing of one of the */ + /* hotkeys, return the pressed hotkey immediately. */ + if(chHotkeyPressed != '\0') + { + OD_API_EXIT(); + return(chHotkeyPressed); + } + + /* If no hotkey has been pressed key, and the wait flag has been set, */ + /* wait for the user to press a valid hotkey. */ + if(bWait) + { + /* Wait for a valid hotkey using the od_get_answer() primitive. */ + chPressed = od_get_answer(pszHotKeys); + + /* If a remote user is connected on this node. */ + if(od_control.baud) + { + /* Clear the outbound buffer. */ + ODComClearOutbound(hSerialPort); + } + + /* Return the hotkey pressed by the user. */ + OD_API_EXIT(); + return(chPressed); + } + + /* No hotkey has been pressed, so return 0. */ + /* (Since 0 is used to terminate the string of valid hotkeys, it can */ + /* never be a valid hotkey itself, and is therefore a safe value to */ + /* indicate the "no key press" state.) */ + OD_API_EXIT(); + return(0); +} + + +/* ---------------------------------------------------------------------------- + * od_send_file() + * + * Displays a .ASC/.ANS/.AVT/.RIP file to the local and remote screens. If + * OpenDoors is unable to display the required file format locally, an + * equivalent file that is locally displayable is selected. If no such + * equivalent file can be found, then a message box is displayed, indicating + * that the file is being transmitted to the remote system. + * + * Parameters: pszFileName - The name of the file to send. This parameter may + * explicitly specify the full filename and + * extension, or the extension may be omitted. In the + * case that the extension is omitted, this function + * automatically selects the appropriate file type + * for the current display mode (RIP, ANSI, etc.). + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_send_file(const char *pszFileName) +{ + FILE *pfRemoteFile; + FILE *pfLocalFile = NULL; + BOOL bAnythingLocal = TRUE; + void *pWindow; + INT nFileLevel; + BYTE btCount; + BOOL bPausing; + char chKey; + char *pchParsing; + char szMessage[74]; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_send_file()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + if(!pszFileName) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Initialize local variables. */ + btCount = 2; + + /* Turn on page pausing, if available. */ + bPausing = od_control.od_page_pausing; + + /* If operating in auto-filename mode (no extension specified). */ + if(strchr(pszFileName, '.') == NULL) + { + /* Begin by searching for a .RIP file. */ + nFileLevel = LEVEL_RIP; + + /* If no .ASC/.ANS/.AVT/.RIP file. */ + if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel)) + == NULL) + { + /* Then return with an error. */ + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + /* If the file found was a .RIP. */ + if(nFileLevel == LEVEL_RIP) + { + /* Search for file to display locally. */ + nFileLevel = LEVEL_AVATAR; + + /* No page pausing with .RIP display. */ + bPausing = FALSE; + + if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel)) + == NULL) + { + /* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */ + /* local display. */ + bAnythingLocal = FALSE; + } + } + else if(nFileLevel == LEVEL_NONE) + { + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + /* Get filename of remote file. */ + strcpy(szODWorkString, pszFileName); + strcat(szODWorkString, ".rip"); + strupr(szODWorkString); + } + else + { + /* If the full filename was specified, then attempt to open that file. */ + if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL) + { + /* If unable to open file, then return. */ + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + strcpy(szODWorkString, pszFileName); + strupr(szODWorkString); + + if(strstr(szODWorkString, ".rip")) + { + /* No page pausing during .RIP display. */ + bPausing = FALSE; + + /* Disable local display. */ + bAnythingLocal = FALSE; + } + } + + /* Set default colour to grey on black. */ + btDefaultAttrib = 0x07; + + /* Reset all terminal emulation. */ + btAvatarSeqLevel = 0; + btANSISeqLevel = 0; + + /* Turn off AVATAR insert mode. */ + bAvatarInsertMode = FALSE; + + /* Reset [S]top/[P]ause control key status. */ + chLastControlKey = 0; + + if(!bAnythingLocal) + { + strcpy(szODWorkString, od_control.od_sending_rip); + strcat(szODWorkString, pszFileName); + ODStringCopy(szMessage, szODWorkString, sizeof(szMessage)); + + pWindow = ODScrnShowMessage(szMessage, 0); + } + + /* Loop to display each line in the file(s) with page pausing, etc. */ + for(;;) + { + /* Call the OpenDoors kernel routine. */ + CALL_KERNEL_IF_NEEDED(); + + /* If hotkeys are active. */ + if(pszCurrentHotkeys != NULL) + { + /* If a key is waiting in buffer. */ + while((chKey = (char)tolower(od_get_key(FALSE))) != 0) + { + /* Check for key in hotkey string. */ + pchParsing = (char *)pszCurrentHotkeys; + while(*pchParsing) + { + /* If key is found. */ + if(tolower(*pchParsing) == chKey) + { + /* Return, indicating that hotkey was pressed. */ + chHotkeyPressed = *pchParsing; + goto abort_send; + } + ++pchParsing; + } + } + } + + /* If a control key has been pressed. */ + if(chLastControlKey) + { + switch(chLastControlKey) + { + /* If it was a stop control key. */ + case 's': + if(od_control.od_list_stop) + { + /* If enabled, clear keyboard buffer. */ +abort_send: + /* If operating in remote mode. */ + if(od_control.baud) + { + /* Clear the outbound FOSSIL buffer. */ + ODComClearOutbound(hSerialPort); + } + + /* Return from function. */ + goto end_transmission; + } + break; + + /* If control key was "pause". */ + case 'p': + /* If pause is enabled. */ + if(od_control.od_list_pause) + { + /* Clear keyboard buffer. */ + od_clear_keybuffer(); + + /* Wait for any keypress. */ + od_get_key(TRUE); + } + } + + /* Clear control key status. */ + chLastControlKey = 0; + } + + /* Get next line, if any. */ + if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL) + { + /* If different local file. */ + if(pfLocalFile) + { + /* Display rest of it. */ + while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile)) + { + /* Pass each line to terminal emulator. */ + ODEmulateFromBuffer(szODWorkString, FALSE); + } + } + + /* Return from od_send_file(). */ + goto end_transmission; + } + + /* Set parsepos = last char in globworkstr. */ + pchParsing = (char *)&szODWorkString; + while(*++pchParsing) ; + --pchParsing; + + /* Check for end of page state. */ + if((*pchParsing == '\r' || *pchParsing == '\n') && + ++btCount >= od_control.user_screen_length && bPausing) + { + /* Display page pause prompt. */ + if(ODPagePrompt(&bPausing)) + { + /* If user chose to abort, then return from od_send_file(). */ + goto end_transmission; + } + + /* Reset line count. */ + btCount = 2; + } + + + /* If the file is also to be displayed locally. */ + if(bAnythingLocal) + { + /* If the local file is different from the remote file, then obtain */ + /* the next line from the local file. */ + if(pfLocalFile) + { + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + + if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL) + { + while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile)) + { + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + } + + /* Return from od_send_file(). */ + goto end_transmission; + } + + ODEmulateFromBuffer(szODWorkString, FALSE); + } + else + { + /* Pass the string through the local terminal emulation */ + /* system, and send a copy to the remote system. */ + if(od_control.od_no_ra_codes) + { + ODEmulateFromBuffer(szODWorkString, FALSE); + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + } + else + { + ODEmulateFromBuffer(szODWorkString,TRUE); + } + } + } + else + { + /* If the file is not being displayed locally, then just send the */ + /* entire line to the remote system (if any). */ + od_disp(szODWorkString,strlen(szODWorkString),FALSE); + } + } + +end_transmission: + + /* Close remote file. */ + fclose(pfRemoteFile); + + /* If there is a different local file, then close it too. */ + if(pfLocalFile) + { + fclose(pfLocalFile); + } + + /* If we are not displaying anything on the local system. */ + if(!bAnythingLocal) + { + /* Wait while file is being sent. */ + if(od_control.baud != 0) + { + int nOutboundSize; + do + { + CALL_KERNEL_IF_NEEDED(); + ODComOutbound(hSerialPort, &nOutboundSize); + } while(nOutboundSize != 0); + } + + /* Get rid of the window. */ + ODScrnRemoveMessage(pWindow); + } + + OD_API_EXIT(); + return(TRUE); +} + + + +/* ---------------------------------------------------------------------------- + * od_send_file_section() + * + * Displays a .ASC/.ANS/.AVT/.RIP multi-section file to the local and remote + * screens. If OpenDoors is unable to display the required file format locally, + * an equivalent file that is locally displayable is selected. If no such + * equivalent file can be found, then a message box is displayed, incdicating + * that the file is being transmitted to the remote system. + * + * Note: This function works virtually identical to od_send_file() except it + * checks for the section headers (if found). + * + * Parameters: pszFileName - The name of the file to send. This parameter may + * explicitly specify the full filename and + * extension, or the extension may be omitted. In the + * case that the extension is omitted, this function + * automatically selects the appropriate file type + * for the current display mode (RIP, ANSI, etc.). + * pszSectionname - Name of the section in which to send. This + * parameter must include only the section name + * and not the @# delimiter. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_send_file_section(char *pszFileName, char *pszSectionName) +{ + FILE *pfRemoteFile; + FILE *pfLocalFile = NULL; + BOOL bAnythingLocal = TRUE; + void *pWindow; + INT nFileLevel; + BYTE btCount; + BOOL bPausing; + char chKey; + char *pchParsing; + char szMessage[74]; + char szFullSectionName[256]; + BOOL bSectionFound = FALSE; + UINT uSectionNameLength; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_send_file_section()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + if(!pszFileName || !pszSectionName) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Initialize local variables. */ + btCount = 2; + + /* Turn on page pausing, if available. */ + bPausing = od_control.od_page_pausing; + + /* If operating in auto-filename mode (no extension specified). */ + if(strchr(pszFileName, '.') == NULL) + { + /* Begin by searching for a .RIP file. */ + nFileLevel = LEVEL_RIP; + + /* If no .ASC/.ANS/.AVT/.RIP file. */ + if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel)) + == NULL) + { + /* Then return with an error. */ + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + /* If the file found was a .RIP. */ + if(nFileLevel == LEVEL_RIP) + { + /* Search for file to display locally. */ + nFileLevel = LEVEL_AVATAR; + + /* No page pausing with .RIP display. */ + bPausing = FALSE; + + if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel)) + == NULL) + { + /* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */ + /* local display. */ + bAnythingLocal = FALSE; + } + } + else if(nFileLevel == LEVEL_NONE) + { + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + /* Get filename of remote file. */ + strcpy(szODWorkString, pszFileName); + strcat(szODWorkString, ".rip"); + strupr(szODWorkString); + } + else + { + /* If the full filename was specified, then attempt to open that file. */ + if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL) + { + /* If unable to open file, then return. */ + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + strcpy(szODWorkString, pszFileName); + strupr(szODWorkString); + + if(strstr(szODWorkString, ".rip")) + { + /* No page pausing during .RIP display. */ + bPausing = FALSE; + + /* Disable local display. */ + bAnythingLocal = FALSE; + } + } + + /* Set default colour to grey on black. */ + btDefaultAttrib = 0x07; + + /* Reset all terminal emulation. */ + btAvatarSeqLevel = 0; + btANSISeqLevel = 0; + + /* Turn off AVATAR insert mode. */ + bAvatarInsertMode = FALSE; + + /* Reset [S]top/[P]ause control key status. */ + chLastControlKey = 0; + + if(!bAnythingLocal) + { + strcpy(szODWorkString, od_control.od_sending_rip); + strcat(szODWorkString, pszFileName); + ODStringCopy(szMessage, szODWorkString, sizeof(szMessage)); + + pWindow = ODScrnShowMessage(szMessage, 0); + } + + /* Create section name information */ + strcpy(szFullSectionName, "@#"); + strncat(szFullSectionName, pszSectionName, 254); + + /* Get the length of the section name in it's full form */ + uSectionNameLength = strlen(szFullSectionName); + + /* Loop to display each line in the file(s) with page pausing, etc. */ + for(;;) + { + /* Call the OpenDoors kernel routine. */ + CALL_KERNEL_IF_NEEDED(); + + /* If hotkeys are active. */ + if(pszCurrentHotkeys != NULL) + { + /* If a key is waiting in buffer. */ + while((chKey = (char)tolower(od_get_key(FALSE))) != 0) + { + /* Check for key in hotkey string. */ + pchParsing = (char *)pszCurrentHotkeys; + while(*pchParsing) + { + /* If key is found. */ + if(tolower(*pchParsing) == chKey) + { + /* Return, indicating that hotkey was pressed. */ + chHotkeyPressed = *pchParsing; + goto abort_send; + } + ++pchParsing; + } + } + } + + /* If a control key has been pressed. */ + if(chLastControlKey) + { + switch(chLastControlKey) + { + /* If it was a stop control key. */ + case 's': + if(od_control.od_list_stop) + { + /* If enabled, clear keyboard buffer. */ +abort_send: + /* If operating in remote mode. */ + if(od_control.baud) + { + /* Clear the outbound FOSSIL buffer. */ + ODComClearOutbound(hSerialPort); + } + + /* Return from function. */ + goto end_transmission; + } + break; + + /* If control key was "pause". */ + case 'p': + /* If pause is enabled. */ + if(od_control.od_list_pause) + { + /* Clear keyboard buffer. */ + od_clear_keybuffer(); + + /* Wait for any keypress. */ + od_get_key(TRUE); + } + } + + /* Clear control key status. */ + chLastControlKey = 0; + } + + /* Get next line, if any. */ + if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL) + { + /* If different local file. */ + if(pfLocalFile) + { + /* Display rest of it. */ + while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile)) + { + if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0) + { + /* Section Found, allow all lines up to EOF or new section to be displayed */ + bSectionFound = TRUE; + /* Read next line, ignore the section line */ + continue; + } + else if (!bSectionFound) + { + /* Section not found yet, continue loop */ + continue; + } + else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0) + { + /* New Section Intercepted */ + goto end_transmission; + } + /* Pass each line to terminal emulator. */ + ODEmulateFromBuffer(szODWorkString, FALSE); + } + } + + /* Return from od_send_file(). */ + goto end_transmission; + } + + /* Check for section header @# + pszSectionName */ + if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0) + { + /* Flag the section as found */ + bSectionFound = TRUE; + /* Read next line, ignore section line */ + continue; + } + else if (!bSectionFound) + { + /* Section hasn't been found yet */ + continue; + } + else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0) + { + /* New section found, terminate send */ + goto end_transmission; + } + + /* Set parsepos = last char in globworkstr. */ + pchParsing = (char *)&szODWorkString; + while(*++pchParsing) ; + --pchParsing; + + /* Check for end of page state. */ + if((*pchParsing == '\r' || *pchParsing == '\n') && + ++btCount >= od_control.user_screen_length && bPausing) + { + /* Display page pause prompt. */ + if(ODPagePrompt(&bPausing)) + { + /* If user chose to abort, then return from od_send_file(). */ + goto end_transmission; + } + + /* Reset line count. */ + btCount = 2; + } + + + /* If the file is also to be displayed locally. */ + if(bAnythingLocal) + { + /* If the local file is different from the remote file, then obtain */ + /* the next line from the local file. */ + if(pfLocalFile) + { + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + + if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL) + { + while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile)) + { + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + } + + /* Return from od_send_file(). */ + goto end_transmission; + } + + ODEmulateFromBuffer(szODWorkString, FALSE); + } + else + { + /* Pass the string through the local terminal emulation */ + /* system, and send a copy to the remote system. */ + if(od_control.od_no_ra_codes) + { + ODEmulateFromBuffer(szODWorkString, FALSE); + od_disp(szODWorkString, strlen(szODWorkString), FALSE); + } + else + { + ODEmulateFromBuffer(szODWorkString,TRUE); + } + } + } + else + { + /* If the file is not being displayed locally, then just send the */ + /* entire line to the remote system (if any). */ + od_disp(szODWorkString,strlen(szODWorkString),FALSE); + } + } + +end_transmission: + + /* Close remote file. */ + fclose(pfRemoteFile); + + /* If there is a different local file, then close it too. */ + if(pfLocalFile) + { + fclose(pfLocalFile); + } + + /* If we are not displaying anything on the local system. */ + if(!bAnythingLocal) + { + /* Wait while file is being sent. */ + if(od_control.baud != 0) + { + int nOutboundSize; + do + { + CALL_KERNEL_IF_NEEDED(); + ODComOutbound(hSerialPort, &nOutboundSize); + } while(nOutboundSize != 0); + } + + /* Get rid of the window. */ + ODScrnRemoveMessage(pWindow); + } + + /* If the section was not found, return FALSE for error */ + if (!bSectionFound) + { + OD_API_EXIT(); + return (FALSE); + } + + OD_API_EXIT(); + return(TRUE); +} + + + +/* ---------------------------------------------------------------------------- + * ODEmulateFindCompatFile() *** PRIVATE FUNCTION *** + * + * Searches for an .ASC/.ANS/.AVT/.RIP file that is compatible with the + * specified display capabilities level. + * + * Parameters: pszBaseName - Base filename to use. + * + * pnLevel - Highest file level to search for. This value is + * updated to indicate the type of file found. + * + * Return: A pointer to a now-open file of the required type, or NULL if + * no match was found. + */ +static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel) +{ + FILE *pfCompatibleFile; + + ASSERT(pszBaseName != NULL); + ASSERT(pnLevel != NULL); + ASSERT(*pnLevel >= 0 && *pnLevel <= 4); + + /* Loop though .RIP/.AVT/.ANS/.ASC extensions. */ + for(;*pnLevel > LEVEL_NONE; --*pnLevel) + { + /* Get base-filename passed in. */ + strcpy(szODWorkString, pszBaseName); + + /* Try current extension. */ + switch(*pnLevel) + { + case LEVEL_RIP: + if(!od_control.user_rip) continue; + strcat(szODWorkString, ".rip"); + break; + + case LEVEL_AVATAR: + if(!od_control.user_avatar) continue; + strcat(szODWorkString, ".avt"); + break; + + case LEVEL_ANSI: + if(!od_control.user_ansi) continue; + strcat(szODWorkString, ".ans"); + break; + + case LEVEL_ASCII: + strcat(szODWorkString, ".asc"); + break; + } + + /* If we are able to open this file, then return a pointer to */ + /* the file. */ + if((pfCompatibleFile = fopen(szODWorkString,"rb")) != NULL) + return(pfCompatibleFile); + } + + /* Return NULL if no file was found. */ + return(NULL); +} + + +/* ---------------------------------------------------------------------------- + * od_disp_emu() + * + * Sends an entire string to both local and remote systems. The characters + * displayed locally are fed through the local terminal emulation sub-system, + * allowing aribtrary ANSI/AVATAR control sequences to be displayed both + * locally and remotely. + * + * Parameters: pszToDisplay - Pointer to string to display. + * + * bRemoteEcho - TRUE if characters should also be transmitted + * to the remote system. + * + * Return: void + */ +ODAPIDEF void ODCALL od_disp_emu(const char *pszToDisplay, BOOL bRemoteEcho) +{ + BOOL bTranslateRemote; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_disp_emu()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Send pszToDisplay to remote system. */ + if(bRemoteEcho) + { + if(od_control.od_no_ra_codes) + { + od_disp(pszToDisplay, strlen(pszToDisplay), FALSE); + bTranslateRemote = FALSE; + } + else + { + bTranslateRemote = TRUE; + } + } + else + { + bTranslateRemote = FALSE; + } + + /* Pass string to be emulated to local terminal emulation function. */ + ODEmulateFromBuffer(pszToDisplay, bTranslateRemote); + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * od_emulate() + * + * Sends a single character to both local and remote systems. The characters + * displayed locally are fed through the local terminal emulation sub-system, + * allowing aribtrary ANSII/AVATAR control sequences to be displayed both + * locally and remotely. + * + * Parameters: chToEmulate - Character to feed through the terminal emulator. + * + * Return: void + */ +ODAPIDEF void ODCALL od_emulate(char chToEmulate) +{ + static char szBuffer[2]; + + *szBuffer = chToEmulate; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_emulate()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Pass character to be emulated to local terminal emulation function. */ + ODEmulateFromBuffer(szBuffer, TRUE); + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * ODEmulateFromBuffer() *** PRIVATE FUNCTION *** + * + * Displays a string on the local screen, interpreting any terminal emulation + * control sequences. The string may also be sent to the remote system at the + * same time. + * + * Parameters: pszBuffer - Pointer to the string to transmit. + * + * bRemoteEcho - TRUE if string should also be sent to the remote + * system, FALSE if it should not be. + * + * Return: void + */ +static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho) +{ + char chCurrent; + static tODScrnTextInfo TextInfo; + INT nTemp; + BOOL bEchoThisChar; + INT nCharsPerTick; + INT nCharsThisTick; + tODTimer ModemSimTimer; + + ASSERT(pszBuffer != NULL); + + /* If we should simulate modem transmission speed. */ + if(od_control.od_emu_simulate_modem) + { + DWORD lCharsPerSecond; + + /* Determine character per second rate to simulate. */ + if(od_control.baud == 0) + { + lCharsPerSecond = 960L; + } + else + { + ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL, + od_control.od_connect_speed, 10L); + } + + /* Determine number of characters to send per timer tick. */ + lCharsPerSecond = ODDWordMultiply(lCharsPerSecond, MODEM_SIMULATOR_TICK); + ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL, lCharsPerSecond, 1000L); + nCharsPerTick = (INT)lCharsPerSecond; + + /* Start tick timer. */ + ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK); + + /* Reset number of characters that we have sent during this tick. */ + nCharsThisTick = 0; + } + + while(*pszBuffer) + { + /* Read the next character from the buffer into local variable for */ + /* access speed efficiency. */ + chCurrent = *pszBuffer; + + /* If we should simulate modem transmission speed. */ + if(od_control.od_emu_simulate_modem) + { + /* If we have now sent all of the characters that should be sent */ + /* during this tick. */ + if(nCharsThisTick++ >= nCharsPerTick) + { + /* Wait for timer to elapse. */ + ODTimerWaitForElapse(&ModemSimTimer); + + /* Restart tick timer. */ + ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK); + + /* Reset characters sent in this tick. */ + nCharsThisTick = 0; + } + } + + bEchoThisChar = bRemoteEcho; + + /* Switch according to ANSI emulator state. */ + switch(btANSISeqLevel) + { + /* If we are not in the middle of an ANSI command string. */ + case 0: + /* Switch according to current character. */ + switch(chCurrent) + { + /* If this is the escape character. */ + case 27: + /* If we are not in the middle of an AVATAR sequence. */ + if(btAvatarSeqLevel == 0) + { + /* Then treat this as the start an ANSI sequence. */ + btANSISeqLevel = 1; + break; + } + + /* Deliberate fallthrough to default case. */ + + /* If not start of an ANSI sequence. */ + default: + /* Check our position in AVATAR sequence. */ + switch(btAvatarSeqLevel) + { + /* If not in middle of an AVATAR command. */ + case 0: + /* Check the character we've been sent. */ + switch(chCurrent) + { + /* Check for QBBS/RA pause for keypress code. */ + case 0x01: + if(od_control.od_no_ra_codes) + { + goto output_next_char; + } + + /* Wait for user to press [ENTER] key. */ + od_get_answer("\n\r"); + bEchoThisChar = FALSE; + break; + + /* QBBS/RA ^F user parameters. */ + case 0x06: + if(od_control.od_no_ra_codes) + { + goto output_next_char; + } + btAvatarSeqLevel = 21; + bEchoThisChar = FALSE; + break; + + /* QBBS/RA ^K user parameters. */ + case 0x0b: + if(od_control.od_no_ra_codes) + { + goto output_next_char; + } + btAvatarSeqLevel = 22; + bEchoThisChar = FALSE; + break; + + case 0x0c: + bAvatarInsertMode = FALSE; + ODScrnSetAttribute((BYTE)( + od_control.od_cur_attrib = btDefaultAttrib)); + ODScrnClear(); + break; + + case 0x19: + bAvatarInsertMode = FALSE; + btAvatarSeqLevel = 1; + break; + + case 0x16: /* ^V */ + btAvatarSeqLevel = 3; + break; + + default: + output_next_char: + /* Output next character. */ + if(bAvatarInsertMode) + { + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.curx < 80) + { + ODScrnCopyText(TextInfo.curx, + TextInfo.cury, 79, TextInfo.cury, + (BYTE)(TextInfo.curx + 1), + TextInfo.cury); + } + ODScrnDisplayChar(chCurrent); + } + + else + { + ODScrnDisplayChar(chCurrent); + } + } + break; + + case 1: + bAvatarInsertMode = FALSE; + chPrevParam = chCurrent; + btAvatarSeqLevel = 2; + break; + + case 2: + for(nTemp = 0; nTemp < (INT)chCurrent; + ++nTemp) + { + ODScrnDisplayChar(chPrevParam); + } + btAvatarSeqLevel = 0; + break; + + case 3: + switch(chCurrent) + { + case 0x01: + bAvatarInsertMode = FALSE; + btAvatarSeqLevel = 4; + break; + + case 0x02: + bAvatarInsertMode = FALSE; + ODScrnGetTextInfo(&TextInfo); + ODScrnSetAttribute((BYTE) + (od_control.od_cur_attrib = + TextInfo.attribute | 0x80)); + btAvatarSeqLevel = 0; + break; + + case 0x03: + bAvatarInsertMode = FALSE; + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.cury > 1) + { + ODScrnSetCursorPos(TextInfo.curx, + (BYTE)(TextInfo.cury - 1)); + } + btAvatarSeqLevel = 0; + break; + + case 0x04: + bAvatarInsertMode = FALSE; + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.cury < 25) + { + ODScrnSetCursorPos(TextInfo.curx, + (BYTE)(TextInfo.cury + 1)); + } + btAvatarSeqLevel = 0; + break; + + case 0x05: + bAvatarInsertMode = FALSE; + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.curx > 1) + { + ODScrnSetCursorPos((BYTE)(TextInfo.curx - 1), + TextInfo.cury); + } + btAvatarSeqLevel = 0; + break; + + case 0x06: + bAvatarInsertMode = FALSE; + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.curx < 80) + { + ODScrnSetCursorPos((BYTE)(TextInfo.curx + 1), + TextInfo.cury); + } + btAvatarSeqLevel = 0; + break; + + case 0x07: + bAvatarInsertMode = FALSE; + ODScrnClearToEndOfLine(); + btAvatarSeqLevel = 0; + break; + + case 0x08: + bAvatarInsertMode = FALSE; + btAvatarSeqLevel = 5; + break; + + case 0x09: /* ^I */ + bAvatarInsertMode = TRUE; + btAvatarSeqLevel = 0; + break; + + case 0x0a: /* ^J */ + btScrollLines = -1; + btAvatarSeqLevel = 7; + break; + + case 0x0b: /* ^K */ + btScrollLines = 1; + btAvatarSeqLevel = 7; + break; + + case 0x0c: /* ^L */ + btAvatarSeqLevel = 14; + break; + + case 0x0d: /* ^M */ + btAvatarSeqLevel = 15; + break; + + case 0x0e: /* ^N */ + ODScrnGetTextInfo(&TextInfo); + if(TextInfo.curx < 80) + { + ODScrnCopyText((BYTE)(TextInfo.curx + 1), + TextInfo.cury, 80, TextInfo.cury, + TextInfo.curx, TextInfo.cury); + } + + ODScrnEnableScrolling(FALSE); + ODScrnSetCursorPos(80, TextInfo.cury); + ODScrnDisplayChar(' '); + ODScrnEnableScrolling(TRUE); + ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury); + + btAvatarSeqLevel = 0; + break; + + case 0x19: /* ^Y */ + btAvatarSeqLevel = 19; + break; + + default: + btAvatarSeqLevel = 0; + } + break; + + case 4: + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = chCurrent)); + btAvatarSeqLevel = 0; + break; + + case 5: + chPrevParam = chCurrent; + btAvatarSeqLevel = 6; + break; + + case 6: + ODScrnSetCursorPos(chCurrent, chPrevParam); + btAvatarSeqLevel = 0; + break; + + case 7: + if(btScrollLines < 1) + { + btScrollLines = chCurrent; + } + else + { + btScrollLines = -chCurrent; + } + btAvatarSeqLevel = 8; + break; + + case 8: + btScrollTop = chCurrent; + btAvatarSeqLevel = 9; + break; + + case 9: + btScrollLeft = chCurrent; + btAvatarSeqLevel = 10; + break; + + case 10: + btScrollBottom = chCurrent; + btAvatarSeqLevel = 11; + break; + + case 11: + btScrollRight = chCurrent; + btAvatarSeqLevel = 12; + break; + + case 12: + if(btScrollLines == 0 + || abs(btScrollLines) > + (btScrollBottom - btScrollTop)) + { + ODEmulateFillArea(btScrollLeft, btScrollTop, + btScrollRight, btScrollBottom, ' '); + } + + else if(btScrollLines < 0) + { + ODScrnCopyText(btScrollLeft, btScrollTop, + btScrollRight, + (BYTE)(btScrollBottom + btScrollLines), + btScrollLeft, + (BYTE)(btScrollTop - btScrollLines)); + ODEmulateFillArea(btScrollLeft, btScrollTop, + btScrollRight, + (BYTE)(btScrollTop - (btScrollLines - 1)), ' '); + } + + else + { + ODScrnCopyText(btScrollLeft, + (BYTE)(btScrollTop + btScrollLines), + btScrollRight, btScrollBottom, + btScrollLeft, btScrollTop); + ODEmulateFillArea(btScrollLeft, + (BYTE)(btScrollBottom - (btScrollLines - 1)), + btScrollRight, btScrollBottom, ' '); + } + btAvatarSeqLevel = 0; + break; + + case 14: + btScrollLines = (chCurrent & 0x7f); + btScrollRight = ' '; + btAvatarSeqLevel = 17; + break; + + case 15: + btScrollLines = (chCurrent & 0x7f); + btAvatarSeqLevel = 16; + break; + + case 16: + btScrollRight = chCurrent; + btAvatarSeqLevel = 17; + break; + + case 17: + btScrollTop = chCurrent; + btAvatarSeqLevel = 18; + break; + + case 18: + ODScrnGetTextInfo(&TextInfo); + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = btScrollLines)); + ODEmulateFillArea(TextInfo.curx, TextInfo.cury, + (BYTE)(TextInfo.curx + chCurrent), + (BYTE)(TextInfo.cury + btScrollTop), btScrollRight); + btAvatarSeqLevel = 0; + break; + + case 19: + btScrollLines = (chCurrent & 0x7f); + szToRepeat[btRepeatCount = 0] = '\0'; + btAvatarSeqLevel = 20; + break; + + case 20: + if(btRepeatCount < btScrollLines) + { + szToRepeat[btRepeatCount] = chCurrent; + szToRepeat[++btRepeatCount] = '\0'; + } + else + { + for(btRepeatCount = 0; btRepeatCount < + (BYTE)chCurrent;++btRepeatCount) + { + ODScrnDisplayString(szToRepeat); + } + btAvatarSeqLevel = 0; + } + break; + + /* RA/QBBS ^F control codes. */ + case 21: + bEchoThisChar = FALSE; + switch(chCurrent) + { + case 'A': + od_disp_str(od_control.user_name); + break; + case 'B': + od_disp_str(od_control.user_location); + break; + case 'C': + od_disp_str(od_control.user_password); + break; + case 'D': + od_disp_str(od_control.user_dataphone); + break; + case 'E': + od_disp_str(od_control.user_homephone); + break; + case 'F': + od_disp_str(od_control.user_lastdate); + break; + case 'G': + od_disp_str(od_control.user_lasttime); + break; + case 'H': + btScrollLines = 0; + goto show_flags; + case 'I': + btScrollLines = 1; + goto show_flags; + case 'J': + btScrollLines = 2; + goto show_flags; + case 'K': + btScrollLines = 3; + show_flags: for(btRepeatCount = 0; btRepeatCount < 8; + ++btRepeatCount) + { + if((od_control.user_flags[btScrollLines] >> + btRepeatCount) & 0x01) + { + szToRepeat[btRepeatCount] = 'X'; + } + else + { + szToRepeat[btRepeatCount] = '-'; + } + } + szToRepeat[btRepeatCount] = '\0'; + od_disp_str(szToRepeat); + break; + case 'L': + od_printf("%lu", od_control.user_net_credit); + break; + case 'M': + od_printf("%u", od_control.user_messages); + break; + case 'N': + od_printf("%u", od_control.user_lastread); + break; + case 'O': + od_printf("%u", od_control.user_security); + break; + case 'P': + od_printf("%u", od_control.user_numcalls); + break; + case 'Q': + od_printf("%ul", od_control.user_uploads); + break; + case 'R': + od_printf("%ul", od_control.user_upk); + break; + case 'S': + od_printf("%ul", od_control.user_downloads); + break; + case 'T': + od_printf("%ul", od_control.user_downk); + break; + case 'U': + od_printf("%d", od_control.user_time_used); + break; + case 'V': + od_printf("%d", od_control.user_screen_length); + break; + case 'W': + btRepeatCount = 0; + while(od_control.user_name[btRepeatCount]) + { + if((szToRepeat[btRepeatCount] + = od_control.user_name[btRepeatCount]) + == ' ') + { + szToRepeat[btRepeatCount] = '\0'; + break; + } + ++btRepeatCount; + } + od_disp_str(szToRepeat); + break; + case 'X': + if(od_control.user_ansi) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case 'Y': + if(od_control.user_attribute & 0x04) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case 'Z': + if(od_control.user_attribute & 0x02) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case '0': + if(od_control.user_attribute & 0x40) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case '1': + if(od_control.user_attribute & 0x80) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case '2': + if(od_control.user_attrib2 & 0x01) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case '3': + od_disp_str(od_control.user_handle); + break; + case '4': + od_disp_str(od_control.user_firstcall); + break; + case '5': + od_disp_str(od_control.user_birthday); + break; + case '6': + od_disp_str(od_control.user_subdate); + break; + case '7': + /* days until subscrption expiry */ + break; + case '8': + if(od_control.user_attrib2 & 0x02) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + break; + case '9': + od_printf("%lu:%lu", + od_control.user_uploads, + od_control.user_downloads); + break; + case ':': + od_printf("%lu:%lu", + od_control.user_upk, + od_control.user_downk); + break; + case ';': + if(od_control.user_attrib2 & 0x04) + { + od_disp_str("ON"); + } + else + { + od_disp_str("OFF"); + } + } + btAvatarSeqLevel=0; + break; + + /* QBBS/RA ^K control codes. */ + case 22: + bEchoThisChar = FALSE; + switch(chCurrent) + { + case 'A': + od_printf("%lu", od_control.system_calls); + break; + case 'B': + od_disp_str(od_control.system_last_caller); + break; + case 'C': + /* number of active messages */ + break; + case 'D': + /* system starting message number */ + break; + case 'E': + /* system ending message number */ + break; + case 'F': + /* number of times user has paged sysop */ + break; + case 'G': + /* day of the week (Monday, Tuesday, etc.) */ + break; + case 'H': + /* number of users in user file */ + break; + case 'I': + /* Time in 24 hour format */ + break; + case 'J': + /* today's date */ + break; + case 'K': + /* minutes connected this call */ + break; + case 'L': + /* Seconds connected (0) */ + break; + case 'M': + od_printf("%d", od_control.user_time_used); + break; + case 'N': + od_disp_str("00"); + break; + case 'O': + /* Minutes remaining today */ + od_printf("%d", od_control.user_timelimit); + break; + case 'P': + /* seconds remaining today (0) */ + break; + case 'Q': + od_printf("0", od_control.user_timelimit); + break; + case 'R': /* current baud rate */ + od_printf("0", od_control.baud); + break; + case 'S': + /* day of the week (MON, TUE) */ + break; + case 'T': + /* Daily download limit (in K) */ + break; + case 'U': + /* Minutes until next system event */ + break; + case 'V': + ODScrnDisplayString(od_control.event_starttime); + break; + case 'W': + /* line number (from command line) */ + break; + case 'X': + od_exit(2, TRUE); + break; + case 'Y': + /* Name of current msg area */ + break; + case 'Z': + /* name of current file area */ + break; + case '0': + /* # of messages in area */ + break; + case '1': + /* # of message area */ + break; + case '2': + /* # of file area */ + break; + } + btAvatarSeqLevel = 0; + } + } + break; + + case 1: + switch(chCurrent) + { + case '[': + btANSISeqLevel = 2; + btCurrentParamLength = 0; + btNumParams = 0; + break; + + default: + btANSISeqLevel = 0; + ODScrnDisplayChar(27); + ODScrnDisplayChar(chCurrent); + } + break; + + default: + if((chCurrent >= '0' && chCurrent <= '9') || chCurrent == '?') + { + if(btCurrentParamLength < 3) + { + szCurrentParam[btCurrentParamLength] = chCurrent; + szCurrentParam[++btCurrentParamLength] = '\0'; + } + else + { + btANSISeqLevel = 0; + } + } + + else if(chCurrent == ';') + { + if(btNumParams < 10) + { + if(btCurrentParamLength != 0) + { + if(strcmp(szCurrentParam, "?9") == 0) + { + anANSIParams[btNumParams] = -2; + } + else + { + anANSIParams[btNumParams] = atoi(szCurrentParam); + } + szCurrentParam[0] = '\0'; + btCurrentParamLength = 0; + ++btNumParams; + } + else + { + anANSIParams[btNumParams++] = -1; + } + } + else + { + btANSISeqLevel = 0; + } + } + + else + { + btANSISeqLevel = 0; + + if(btCurrentParamLength != 0 && btNumParams < 10) + { + if(strcmp(szCurrentParam,"?9") == 0) + { + anANSIParams[btNumParams] = -2; + } + else + { + anANSIParams[btNumParams] = atoi(szCurrentParam); + } + szCurrentParam[0] = '\0'; + btCurrentParamLength = 0; + ++btNumParams; + } + + ODScrnGetTextInfo(&TextInfo); + + switch(chCurrent) + { + case 'A': + if(btNumParams == 0) anANSIParams[0] = 1; + if((nTemp = TextInfo.cury - anANSIParams[0]) < 1) + { + nTemp = 1; + } + if(nTemp > 25) nTemp=25; + ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp); + break; + + case 'B': + if(btNumParams == 0) anANSIParams[0] = 1; + if((nTemp = TextInfo.cury + anANSIParams[0]) > 25) + { + nTemp = 25; + } + if(nTemp < 1) nTemp = 1; + ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp); + break; + + case 'C': + if(btNumParams == 0) anANSIParams[0] = 1; + if((nTemp=TextInfo.curx + anANSIParams[0]) > 80) + { + nTemp = 80; + } + if(nTemp < 1) nTemp = 1; + ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury); + break; + + case 'D': + if(btNumParams == 0) anANSIParams[0] = 1; + if((nTemp = TextInfo.curx - anANSIParams[0]) < 1) + { + nTemp = 1; + } + if(nTemp > 80) nTemp = 80; + ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury); + break; + + case 'H': + case 'f': + if(btNumParams >= 2) + { + if(anANSIParams[0] == -1) + { + ODScrnSetCursorPos((BYTE)anANSIParams[1], 1); + } + else + { + ODScrnSetCursorPos((BYTE)anANSIParams[1], + (BYTE)anANSIParams[0]); + } + } + else if(btNumParams == 1) + { + if(anANSIParams[0] <= 0) + { + ODScrnSetCursorPos(1, TextInfo.cury); + } + else + { + ODScrnSetCursorPos(1, (BYTE)anANSIParams[0]); + } + } + else /* if(num_params==0) */ + { + ODScrnSetCursorPos(1, 1); + } + break; + + case 'J': + if(btNumParams >= 1 && anANSIParams[0] == 2) + { + /* Clear entire screen. */ + ODScrnClear(); + } + else if(btNumParams == 0 || anANSIParams[0] == 0) + { + /* Not supported - Clears from cursor to end of */ + /* screen. */ + } + else if(btNumParams>=1 && anANSIParams[0]==1) + { + /* Not supported - Clears from beginning of screen to */ + /* cursor. */ + } + break; + + case 'K': + if(btNumParams == 0 || anANSIParams[0] == 0) + { + /* Clear to end of line. */ + ODScrnClearToEndOfLine(); + } + else if(btNumParams >= 1 && anANSIParams[0] == 1) + { + /* Not supported - should clear to beginning of line. */ + } + else if(btNumParams >= 1 && anANSIParams[0] == 2) + { + /* Not supported - should clear entire line. */ + } + break; + + case 'm': + for(nTemp = 0; nTemp < btNumParams; ++nTemp) + { + if(anANSIParams[nTemp] == 0) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute = 0x07)); + } + else if(anANSIParams[nTemp] == 1) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = TextInfo.attribute | 0x08)); + } + else if(anANSIParams[nTemp] == 2) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = TextInfo.attribute & (~0x08))); + } + else if(anANSIParams[nTemp] == 4) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = (TextInfo.attribute & 0xf8) | (1))); + } + else if(anANSIParams[nTemp] == 5) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = TextInfo.attribute | 0x80)); + } + else if(anANSIParams[nTemp] == 7) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = (TextInfo.attribute << 4) + | (TextInfo.attribute >> 4))); + } + else if(anANSIParams[nTemp] == 8) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = (TextInfo.attribute & 0xf0) + | ((TextInfo.attribute >> 4) & 0x07))); + } + else if(anANSIParams[nTemp] >= 30 + && anANSIParams[nTemp] <= 37) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = (TextInfo.attribute & 0xf8) + + abtANSIToPCColorTable[ + (anANSIParams[nTemp] - 30)])); + } + else if(anANSIParams[nTemp] >= 40 + && anANSIParams[nTemp]<=47) + { + ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib + = TextInfo.attribute + = (TextInfo.attribute & 0x8f) + + (abtANSIToPCColorTable[ + anANSIParams[nTemp] - 40] << 4))); + } + } + break; + + case 's': + btSavedColumn = TextInfo.curx; + btSavedRow = TextInfo.cury; + break; + + case 'u': + ODScrnSetCursorPos(btSavedColumn, btSavedRow); + break; + + case '@': + /* Not supported - inserts spaces at cursor. */ + break; + + case 'P': + /* Not supported - deletes characters at cursor. */ + break; + + case 'L': + /* Not supported - inserts lines at cursor. */ + break; + + case 'M': + /* Not supported - deletes lines at cursor. */ + break; + + case 'r': + /* Not supported - sets scrolling zone - 1st param is */ + /* top row, 2nd param is bottom row. Cursor may go */ + /* outside zone, but no scrolling occurs there. */ + /* Also resets cursor to row 1, column 1. */ + /* If only one param, bottom row is bottom of screen. */ + break; + + case 'h': + if(btNumParams >= 1 && anANSIParams[0] == 4) + { + /* Not suppored - turn insert mode on. */ + } + else if(btNumParams >= 1 && anANSIParams[0] == -2) + { + /* Home cursor. */ + ODScrnSetCursorPos(1, 1); + } + break; + + case 'l': + if(btNumParams >= 1 && anANSIParams[0] == 4) + { + /* Not suppored - turn insert mode off. */ + } + break; + + case 'E': + /* Not supported - repeat CRLF specified # of times. */ + break; + + case 'F': + /* Not supported - repeat reverse CRLF specified # */ + /* of times. Also not suppored ESC M - reverse */ + /* linefeed, ESC D - LF, ESC E - CRLF */ + break; + } + } + } + + if(bEchoThisChar && od_control.baud != 0) + { + ODComSendByte(hSerialPort, chCurrent); + } + + ++pszBuffer; + } +} + + +/* ---------------------------------------------------------------------------- + * ODEmulateFillArea() *** PRIVATE FUNCTION *** + * + * Fills an area of the local screen with the specified character, in the + * current display color. + * + * Parameters: btLeft - The left column of the area to fill. + * + * btTop - The top row of the area to fill. + * + * btRight - The right column of the area to fill. + * + * btBottom - The bottom row of the area to fill. + * + * chToFillWith - Character to fill in the specified area with. + * + * Return: void + */ +static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom, char chToFillWith) +{ + BYTE btCount; + BYTE btLast; + static char szTemp[81]; + static tODScrnTextInfo TextInfo; + + ODScrnGetTextInfo(&TextInfo); + + btLast = btRight - btLeft; + + for(btCount=0; btCount <= btLast; ++btCount) + { + szTemp[btCount] = chToFillWith; + } + szTemp[btCount] = 0; + + ODScrnEnableScrolling(FALSE); + + for(btCount = btTop; btCount <= btBottom; ++btCount) + { + ODScrnSetCursorPos(btLeft, btCount); + ODScrnDisplayString(szTemp); + } + + ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury); + + ODScrnEnableScrolling(TRUE); +} diff --git a/utils/magiedit/odoors/ODFrame.c b/utils/magiedit/odoors/ODFrame.c new file mode 100644 index 0000000..4a97857 --- /dev/null +++ b/utils/magiedit/odoors/ODFrame.c @@ -0,0 +1,1759 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODFrame.c + * + * Description: Implements the OpenDoors frame window which provides the + * menu, toolbar, and status bar. The frame window's client + * area contains the display window which shows the door's + * output as the remote user would see it. This file should + * not be built into non-Windows versions of OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Aug 20, 1995 6.00 BP Created. + * Dec 20, 1995 6.00 BP Remember toolbar & statusbar settings. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Jan 20, 1996 6.00 BP Made ODFrameCenter...() shared. + * Jan 21, 1996 6.00 BP Added ODScrnShowMessage() and related. + * Feb 17, 1996 6.00 BP Add ...Accelerator() return value. + * Feb 17, 1996 6.00 BP Pass WM_MENUSELECT to DefWindowProc(). + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 21, 1996 6.00 BP Fixed user keyboard off command. + * Feb 22, 1996 6.00 BP Allow escape to close Help About box. + * Feb 23, 1996 6.00 BP Properly update when toolbar turned on + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 14, 1996 6.10 BP Added configuration menu option. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include + +#include "windows.h" +#include "commctrl.h" + +#include "OpenDoor.h" +#include "ODRes.h" +#include "ODFrame.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODKrnl.h" + +#ifdef ODPLAT_WIN32 + +/* Frame window information structure. */ +typedef struct +{ + HINSTANCE hInstance; + BOOL bToolbarOn; + HWND hwndToolbar; + BOOL bStatusBarOn; + HWND hwndStatusBar; + HWND hwndTimeEdit; + HWND hwndTimeUpDown; + BOOL bWantsChatIndicator; + HACCEL hacclFrameCommands; + HWND hwndMessageWindow; + char *pszCurrentMessage; + int nCurrentMessageFlags; +} tODFrameWindowInfo; + +/* Toolbar button information. */ +TBBUTTON atbButtons[] = +{ + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {0, ID_DOOR_CHATMODE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {1, ID_DOOR_USERKEYBOARDOFF, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, + {2, ID_DOOR_SYSOPNEXT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0}, + {3, ID_DOOR_HANGUP, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, + {4, ID_DOOR_LOCKOUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, + {5, ID_DOOR_EXIT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, +}; + +/* Other toolbar settings. */ +#define NUM_TOOLBAR_BITMAPS 6 +#define MIN_TIME 0 +#define MAX_TIME 1440 + +/* Pointer to default edit box window procedure. */ +WNDPROC pfnDefEditProc = NULL; +WNDPROC pfnDefToolbarProc = NULL; + +/* Global frame window handle. */ +static HWND hwndCurrentFrame; + +/* Status bar settings. */ +#define NUM_STATUS_PARTS 2 +#define NODE_PART_WIDTH 65 + +/* Child window IDs. */ +#define ID_TOOLBAR 1000 +#define ID_TIME_EDIT 1001 +#define ID_TIME_UPDOWN 1002 +#define ID_STATUSBAR 1003 + + +/* Private function prototypes. */ +static HWND ODFrameCreateToolbar(HWND hwndParent, HANDLE hInstance, + tODFrameWindowInfo *pWindowInfo); +static void ODFrameDestroyToolbar(HWND hwndToolbar, + tODFrameWindowInfo *pWindowInfo); +static HWND ODFrameCreateStatusBar(HWND hwndParent, HANDLE hInstance); +static void ODFrameSetMainStatusText(HWND hwndStatusBar); +static void ODFrameDestroyStatusBar(HWND hwndStatusBar); +static void ODFrameSizeStatusBar(HWND hwndStatusBar); +LRESULT CALLBACK ODFrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +LRESULT CALLBACK ODFrameToolbarProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +static void ODFrameUpdateTimeLeft(tODFrameWindowInfo *pWindowInfo); +LRESULT CALLBACK ODFrameTimeEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +BOOL CALLBACK ODFrameAboutDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam); +static HWND ODFrameCreateWindow(HANDLE hInstance); +static void ODFrameDestroyWindow(HWND hwndFrame); +static void ODFrameMessageLoop(HANDLE hInstance, HWND hwndFrame); +DWORD OD_THREAD_FUNC ODFrameThreadProc(void *pParam); +BOOL CALLBACK ODFrameMessageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam); + + +/* ---------------------------------------------------------------------------- + * ODFrameCreateWindow() *** PRIVATE FUNCTION *** + * + * Creates the OpenDoors frame window and its children. + * + * Parameters: hInstance - Handle to application instance. + * + * Return: A handle to the newly created window, or NULL on failure. + */ +static HWND ODFrameCreateWindow(HANDLE hInstance) +{ + HWND hwndFrameWindow = NULL; + WNDCLASS wcFrameWindow; + tODFrameWindowInfo *pWindowInfo = NULL; + tODThreadHandle hScreenThread; + HKEY hOpenDoorsKey; + DWORD cbData; + + /* Register the main frame window's window class. */ + memset(&wcFrameWindow, 0, sizeof(wcFrameWindow)); + wcFrameWindow.style = CS_HREDRAW | CS_VREDRAW; + wcFrameWindow.lpfnWndProc = ODFrameWindowProc; + wcFrameWindow.cbClsExtra = 0; + wcFrameWindow.cbWndExtra = 0; + wcFrameWindow.hInstance = hInstance; + if(od_control.od_app_icon != NULL) + { + wcFrameWindow.hIcon = od_control.od_app_icon; + } + else + { + wcFrameWindow.hIcon + = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OPENDOORS)); + } + wcFrameWindow.hCursor = LoadCursor(NULL, IDC_ARROW); + wcFrameWindow.hbrBackground = NULL; + wcFrameWindow.lpszMenuName = MAKEINTRESOURCE(IDR_FRAME_MENU); + wcFrameWindow.lpszClassName = "ODFrame"; + + RegisterClass(&wcFrameWindow); + + /* Setup window information structure. */ + pWindowInfo = malloc(sizeof(tODFrameWindowInfo)); + if(!pWindowInfo) + { + return(NULL); + } + pWindowInfo->hInstance = hInstance; + pWindowInfo->hwndTimeEdit = NULL; + pWindowInfo->hwndTimeUpDown = NULL; + pWindowInfo->bWantsChatIndicator = FALSE; + pWindowInfo->hwndMessageWindow = NULL; + + /* Determine whether or not the toolbar and status bar are on. */ + RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors", + &hOpenDoorsKey); + + cbData = sizeof(pWindowInfo->bToolbarOn); + if(RegQueryValueEx(hOpenDoorsKey, "ToolBarOn", NULL, NULL, + (LPBYTE)&pWindowInfo->bToolbarOn, + &cbData) != ERROR_SUCCESS) + { + pWindowInfo->bToolbarOn = TRUE; + RegSetValueEx(hOpenDoorsKey, "ToolBarOn", 0, REG_DWORD, + (LPBYTE)&pWindowInfo->bToolbarOn, + sizeof(pWindowInfo->bToolbarOn)); + } + + cbData = sizeof(pWindowInfo->bStatusBarOn); + if(RegQueryValueEx(hOpenDoorsKey, "StatusBarOn", NULL, NULL, + (LPBYTE)&pWindowInfo->bStatusBarOn, + &cbData) != ERROR_SUCCESS) + { + pWindowInfo->bStatusBarOn = TRUE; + RegSetValueEx(hOpenDoorsKey, "StatusBarOn", 0, REG_DWORD, + (LPBYTE)&pWindowInfo->bStatusBarOn, + sizeof(pWindowInfo->bStatusBarOn)); + } + + RegCloseKey(hOpenDoorsKey); + + /* Create the main frame window. */ + if((hwndFrameWindow = CreateWindowEx( + 0L, + wcFrameWindow.lpszClassName, + od_control.od_prog_name, + WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, + CW_USEDEFAULT, + 0, + 0, + 0, + NULL, + NULL, + hInstance, + pWindowInfo)) == NULL) + { + /* On window creation failure, return NULL. */ + return(NULL); + } + + /* Load accelerator table for the frame window. */ + pWindowInfo->hacclFrameCommands + = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_FRAME)); + + /* Create the OpenDoors toolbar. On failure, we will continue anyhow. */ + if(pWindowInfo->bToolbarOn) + { + pWindowInfo->hwndToolbar = + ODFrameCreateToolbar(hwndFrameWindow, hInstance, pWindowInfo); + } + + /* Create the status bar. On failure, we will continue anyhow. */ + if(pWindowInfo->bStatusBarOn) + { + pWindowInfo->hwndStatusBar = + ODFrameCreateStatusBar(hwndFrameWindow, hInstance); + } + + /* Updates state of the window from whether or not the user has */ + /* requested a chat with the sysop. */ + ODFrameUpdateWantChat(); + + /* Create the local screen window, which occupies the remaining */ + /* client area of the frame window. */ + ODScrnStartWindow(hInstance, &hScreenThread, hwndFrameWindow); + + return(hwndFrameWindow); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameCreateToolbar() *** PRIVATE FUNCTION *** + * + * Creates the OpenDoors toolbar. + * + * Parameters: hwndParent - Handle to the parent window. + * + * hInstance - Handle to the executable file's module instance. + * + * pWindowInfo - Pointer to frame window information structure. + * + * Return: A handle to the toolbar on success, or NULL on failure. + */ +static HWND ODFrameCreateToolbar(HWND hwndParent, HANDLE hInstance, + tODFrameWindowInfo *pWindowInfo) +{ + HWND hwndToolbar = NULL; + HWND hwndTimeEdit = NULL; + HWND hwndTimeUpDown = NULL; + HWND hwndToolTip; + BOOL bSuccess = FALSE; + + ASSERT(hwndParent != NULL); + ASSERT(hInstance != NULL); + ASSERT(pWindowInfo != NULL); + + /* First, attempt to create the toolbar window. */ + hwndToolbar = CreateToolbarEx(hwndParent, + WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS, + ID_TOOLBAR, NUM_TOOLBAR_BITMAPS, hInstance, IDB_TOOLBAR, + atbButtons, DIM(atbButtons), 0, 0, 0, 0, sizeof(TBBUTTON)); + + if(hwndToolbar == NULL) + { + goto CleanUp; + } + + /* Change the window proc for the toolbar window to our own, keeping a */ + /* pointer to the original window proc. */ + pfnDefToolbarProc = (WNDPROC)GetWindowLong(hwndToolbar, GWL_WNDPROC); + SetWindowLong(hwndToolbar, GWL_WNDPROC, (LONG)ODFrameToolbarProc); + + /* Next, create an edit control on the toolbar, to allow the user's */ + /* time remaining online to be adjusted. */ + hwndTimeEdit = CreateWindowEx(WS_EX_STATICEDGE, "EDIT", "", + WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT, + 0, 0, 70, 22, hwndToolbar, (HMENU)ID_TIME_EDIT, hInstance, NULL); + + if(hwndTimeEdit == NULL) + { + goto CleanUp; + } + + /* Now that the edit window has the appropriate parent, we set its */ + /* position accordingly. */ + SetWindowPos(hwndTimeEdit, NULL, 2, 2, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + + /* Set font of the edit control to be the standard non-bold font. */ + SendMessage(hwndTimeEdit, WM_SETFONT, + (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(FALSE, 0)); + + /* Change the window proc for the edit window to our own, keeping a */ + /* pointer to the original window proc. */ + pfnDefEditProc = (WNDPROC)GetWindowLong(hwndTimeEdit, GWL_WNDPROC); + SetWindowLong(hwndTimeEdit, GWL_WNDPROC, (LONG)ODFrameTimeEditProc); + + /* Add the time edit control to the tooltip control. */ + + /* Obtain a handle to the toolbar's tooltip control. */ + hwndToolTip = (HWND)SendMessage(hwndToolbar, TB_GETTOOLTIPS, 0, 0); + if(hwndToolTip) + { + TOOLINFO ToolInfo; + + /* Fill TOOLINFO structure. */ + ToolInfo.cbSize = sizeof(ToolInfo); + ToolInfo.uFlags = TTF_IDISHWND | TTF_CENTERTIP; + ToolInfo.lpszText = "User's Time Remaining"; + ToolInfo.hwnd = hwndParent; + ToolInfo.uId = (UINT)hwndTimeEdit; + ToolInfo.hinst = hInstance; + + /* Setup tooltips for the time edit box. */ + SendMessage(hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ToolInfo); + } + + /* Now, we create an up-down control to buddy with the edit control. */ + hwndTimeUpDown = CreateWindowEx(0L, UPDOWN_CLASS, "", + WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_ARROWKEYS | + UDS_ALIGNRIGHT, 0, 0, 8, 8, + hwndToolbar, (HMENU)ID_TIME_UPDOWN, hInstance, NULL); + + if(hwndTimeUpDown == NULL) + { + goto CleanUp; + } + + /* Set the up-down control's buddy control to be the edit control that */ + /* we just created. */ + SendMessage(hwndTimeUpDown, UDM_SETBUDDY, (LONG)hwndTimeEdit, 0L); + + /* Set the valid range of values for the edit control. */ + SendMessage(hwndTimeUpDown, UDM_SETRANGE, 0L, MAKELONG(MAX_TIME, MIN_TIME)); + + /* Store handles to time limit edit and up-down controls. */ + pWindowInfo->hwndTimeEdit = hwndTimeEdit; + pWindowInfo->hwndTimeUpDown = hwndTimeUpDown; + + /* Next, we set the default text for the edit control. */ + ODFrameUpdateTimeLeft(pWindowInfo); + + /* Return with success. */ + bSuccess = TRUE; + +CleanUp: + if(!bSuccess) + { + /* On failure, free any allocated resources. */ + if(hwndTimeUpDown != NULL) + { + DestroyWindow(hwndTimeUpDown); + } + if(hwndTimeEdit != NULL) + { + DestroyWindow(hwndTimeUpDown); + } + if(hwndToolbar != NULL) + { + DestroyWindow(hwndToolbar); + hwndToolbar = NULL; + } + } + + /* Return handle to newly created toolbar, or NULL on failure. */ + return(hwndToolbar); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameDestroyToolbar() *** PRIVATE FUNCTION *** + * + * Destroys the OpenDoors toolbar. + * + * Parameters: hwndToolbar - Handle to previously created toolbar. + * + * pWindowInfo - Pointer to frame window information structure. + * + * Return: void. + */ +static void ODFrameDestroyToolbar(HWND hwndToolbar, + tODFrameWindowInfo *pWindowInfo) +{ + ASSERT(hwndToolbar != NULL); + ASSERT(pWindowInfo != NULL); + + /* Destroy the time up-down control, and NULL its handle in the frame */ + /* window information structure. */ + DestroyWindow(pWindowInfo->hwndTimeUpDown); + pWindowInfo->hwndTimeUpDown = NULL; + + /* Destroy the time edit control, and NULL its handle in the frame window */ + /* information structure. */ + DestroyWindow(pWindowInfo->hwndTimeEdit); + pWindowInfo->hwndTimeEdit = NULL; + + /* Now, destroy the toolbar itself. */ + DestroyWindow(hwndToolbar); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameCreateStatusBar() *** PRIVATE FUNCTION *** + * + * Creates the OpenDoors status bar. + * + * Parameters: hwndParent - Handle to the parent window. + * + * hInstance - Handle to the executable file's module instance. + * + * Return: A handle to the status bar on success, or NULL on failure. + */ +static HWND ODFrameCreateStatusBar(HWND hwndParent, HANDLE hInstance) +{ + HWND hwndStatusBar = NULL; + char szStatusText[20]; + + ASSERT(hwndParent != NULL); + + /* Create the status bar window. */ + hwndStatusBar = CreateWindowEx(0L, STATUSCLASSNAME, "", + WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, + hwndParent, (HMENU)ID_STATUSBAR, hInstance, NULL); + + if(hwndStatusBar == NULL) + { + return(NULL); + } + + /* Set the size of the status bar parts from the size of the frame */ + /* window. */ + ODFrameSizeStatusBar(hwndStatusBar); + + /* Add the user's name, location and connection info string. */ + ODFrameSetMainStatusText(hwndStatusBar); + + /* Add the node number string. */ + sprintf(szStatusText, "Node %d", od_control.od_node); + SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)1, (LPARAM)szStatusText); + + return(hwndStatusBar); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameSetMainStatusText() *** PRIVATE FUNCTION *** + * + * Updates the text that is displayed in the main pane of the status bar. + * + * Parameters: hwndStatusBar - Handle to the status bar. + * + * Return: void. + */ +static void ODFrameSetMainStatusText(HWND hwndStatusBar) +{ + char szStatusText[160]; + + ASSERT(hwndStatusBar != NULL); + + /* Generate base status bar text, with the user's name, location and */ + /* connection information. */ + if(od_control.baud == 0) + { + sprintf(szStatusText, "%s of %s in local mode", + od_control.user_name, + od_control.user_location); + } + else + { + sprintf(szStatusText, "%s of %s at %ldbps", + od_control.user_name, + od_control.user_location, + od_control.od_connect_speed); + } + + /* If the user has paged the sysop, then include reason for chat if */ + /* it is available. */ + if(od_control.user_wantchat && strlen(od_control.user_reasonforchat) > 0) + { + strcat(szStatusText, " (Reason for chat: \""); + strcat(szStatusText, od_control.user_reasonforchat); + strcat(szStatusText, "\")"); + } + + /* Update status bar text in the main status bar pane with the newly */ + /* generated string. */ + SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)0, (LPARAM)szStatusText); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameDestroyStatusBar() *** PRIVATE FUNCTION *** + * + * Destroys the OpenDoors status bar. + * + * Parameters: hwndStatusBar - Handle to previously created status bar. + * + * Return: void. + */ +static void ODFrameDestroyStatusBar(HWND hwndStatusBar) +{ + DestroyWindow(hwndStatusBar); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameSizeStatusBar() *** PRIVATE FUNCTION *** + * + * Creates the OpenDoors status bar. + * + * Parameters: hwndStatusBar - Handle to existing status bar window. + * + * Return: void. + */ +static void ODFrameSizeStatusBar(HWND hwndStatusBar) +{ + int anWidths[NUM_STATUS_PARTS]; + int nStatusWidth; + RECT rcStatusBar; + + /* Determine the total width of the status bar. */ + GetWindowRect(hwndStatusBar, &rcStatusBar); + nStatusWidth = rcStatusBar.right - rcStatusBar.left; + + /* Calculate the width of the parts from the total width. */ + anWidths[0] = nStatusWidth - NODE_PART_WIDTH; + anWidths[1] = -1; + + /* Update the status bar part settings. */ + SendMessage(hwndStatusBar, SB_SETPARTS, NUM_STATUS_PARTS, + (LPARAM)anWidths); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameGetUsedClientAtTop() + * + * Determines height in pixels of the space used at the top of the + * frame window's client area, by the toolbar, etc. + * + * Parameters: hwndFrame - Handle to the OpenDoors frame window. + * + * Return: The height of the used space, in pixels. + */ +INT ODFrameGetUsedClientAtTop(HWND hwndFrame) +{ + tODFrameWindowInfo *pWindowInfo; + RECT rcWindow; + + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA); + + if(!pWindowInfo->bToolbarOn) return(0); + + GetWindowRect(pWindowInfo->hwndToolbar, &rcWindow); + + return(rcWindow.bottom - rcWindow.top - 2); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameGetUsedClientAtBottom() + * + * Determines height in pixels of the space used at the bottom of the + * frame window's client area, by the status bar, etc. + * + * Parameters: hwndFrame - Handle to the OpenDoors frame window. + * + * Return: The height of the used space, in pixels. + */ +INT ODFrameGetUsedClientAtBottom(HWND hwndFrame) +{ + tODFrameWindowInfo *pWindowInfo; + RECT rcWindow; + + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA); + + if(!pWindowInfo->bStatusBarOn) return(0); + + GetWindowRect(pWindowInfo->hwndStatusBar, &rcWindow); + + return(rcWindow.bottom - rcWindow.top - 1); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameWindowProc() *** PRIVATE FUNCTION *** + * + * The OpenDoors frame window proceedure. + * + * Parameters: hwnd - Handle to the OpenDoors frame window. + * + * uMsg - Specifies the message. + * + * wParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * lParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * Return: The return value is the result of the message processing and + * depends on the message. + */ +LRESULT CALLBACK ODFrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + tODFrameWindowInfo *pWindowInfo; + + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwnd, GWL_USERDATA); + + switch(uMsg) + { + case WM_CREATE: + { + /* At window creation time, store a pointer to the window */ + /* information structure in window's user data. */ + CREATESTRUCT *pCreateStruct = (CREATESTRUCT *)lParam; + pWindowInfo = (tODFrameWindowInfo *)pCreateStruct->lpCreateParams; + SetWindowLong(hwnd, GWL_USERDATA, (LONG)pWindowInfo); + + /* Update the enabled and checked states of frame window commands. */ + ODFrameUpdateCmdUI(); + + /* If the client has not provided a help callback function, then */ + /* remove the Contents item from the help menu. */ + if(od_control.od_help_callback == NULL) + { + RemoveMenu(GetMenu(hwnd), ID_HELP_CONTENTS, MF_BYCOMMAND); + } + + if(od_control.od_config_callback == NULL) + { + RemoveMenu(GetMenu(hwnd), ID_DOOR_CONFIG, MF_BYCOMMAND); + } + break; + } + + case WM_CLOSE: + /* If door exit has been chosen, confirm with local user. */ + if(MessageBox(hwnd, + "You are about to terminate this session and return the user to the BBS.\nDo you wish to proceed?", + od_control.od_prog_name, + MB_ICONQUESTION | MB_YESNO) == IDYES) + { + /* Normal door exit (drop to BBS) is implemented by the */ + /* WM_DESTROY handler. */ + ODFrameDestroyWindow(hwnd); + } + break; + + case WM_DESTROY: + /* If toolbar is on, then it must be destroyed when the frame */ + /* window is destroyed. */ + if(pWindowInfo->bToolbarOn) + { + ODFrameDestroyToolbar(GetDlgItem(hwnd, ID_TOOLBAR), pWindowInfo); + } + + /* If status bar is on, then it must be destroyed when the frame */ + /* window is destroyed. */ + if(pWindowInfo->bStatusBarOn) + { + ODFrameDestroyStatusBar(GetDlgItem(hwnd, ID_STATUSBAR)); + } + + /* Now, force OpenDoors to shutdown. */ + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_DROPTOBBS); + + /* When the frame window is destroyed, it is the window proc's */ + /* responsiblity to deallocate the window information structure. */ + free(pWindowInfo); + SetWindowLong(hwnd, GWL_USERDATA, (LONG)NULL); + + /* Reset current frame window handle. */ + hwndCurrentFrame = NULL; + break; + + case WM_SETFOCUS: + /* Whenver input focus is set to the frame window, pass the input */ + /* focus on to the screen window, which fills most of our client */ + /* area. */ + ODScrnSetFocusToWindow(); + break; + + case WM_TIMER: + /* If the window flash timer has elapsed, then flash the window. */ + FlashWindow(hwnd, TRUE); + break; + + case WM_COMMAND: + /* An OpenDoors-defined command has been selected, so switch on */ + /* the command ID. */ + switch(LOWORD(wParam)) + { + case ID_HELP_ABOUT: + /* Display the OpenDoors default about box. */ + DialogBox(pWindowInfo->hInstance, MAKEINTRESOURCE(IDD_ABOUT), + hwnd, ODFrameAboutDlgProc); + break; + + case ID_HELP_CONTENTS: + /* Call the client's help callback function, if one was */ + /* provided. */ + if(od_control.od_help_callback != NULL) + { + (*od_control.od_help_callback)(); + } + break; + + case ID_DOOR_CONFIG: + if(od_control.od_config_callback != NULL) + { + (*od_control.od_config_callback)(); + } + break; + + case ID_DOOR_EXIT: + /* On request for normal door exit (drop to BBS), just send */ + /* a close message to this window. This will prompt to */ + /* confirm exit, and then shutdown OpenDoors if appropriate. */ + PostMessage(hwnd, WM_CLOSE, 0, 0L); + break; + + case ID_DOOR_CHATMODE: + /* If chat mode is currently active, then end it. */ + if(od_control.od_chat_active) + { + ODKrnlEndChatMode(); + } + /* If chat mode is not currently active, then start it. */ + else + { + ODKrnlStartChatThread(TRUE); + } + break; + + case ID_DOOR_USERKEYBOARDOFF: + /* If user keyboard off command has been chosen, then toggle */ + /* keyboard off mode on or off. */ + od_control.od_user_keyboard_on + = !od_control.od_user_keyboard_on; + + /* Update the keyboard off menu item and toolbar button. */ + CheckMenuItem(GetMenu(hwnd), ID_DOOR_USERKEYBOARDOFF, + MF_BYCOMMAND | (od_control.od_user_keyboard_on + ? MF_UNCHECKED : MF_CHECKED)); + SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), TB_CHECKBUTTON, + ID_DOOR_USERKEYBOARDOFF, + MAKELONG(!od_control.od_user_keyboard_on, 0)); + break; + + case ID_DOOR_SYSOPNEXT: + /* If sysop next command has been chosen, then toggle the */ + /* sysop next flag on or off. */ + od_control.sysop_next = !od_control.sysop_next; + + /* Update the sysop next menu item and toolbar button. */ + CheckMenuItem(GetMenu(hwnd), ID_DOOR_SYSOPNEXT, MF_BYCOMMAND | + (od_control.sysop_next ? MF_CHECKED : MF_UNCHECKED)); + SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), TB_CHECKBUTTON, + ID_DOOR_SYSOPNEXT, MAKELONG(od_control.sysop_next, 0)); + break; + + case ID_DOOR_HANGUP: + /* If hangup command has been chosen, then confirm with the */ + /* local user. */ + if(MessageBox(hwnd, + "You are about to disconnect this user. Do you wish to proceed?", + od_control.od_prog_name, + MB_ICONQUESTION | MB_YESNO) == IDYES) + { + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP); + } + break; + + case ID_DOOR_LOCKOUT: + /* If lockout command has been chosen, the confirm with the */ + /* local user. */ + if(MessageBox(hwnd, + "You are about to lock out this user. Do you wish to proceed?", + od_control.od_prog_name, + MB_ICONQUESTION | MB_YESNO) == IDYES) + { + /* Set the user's access security level to 0. */ + od_control.user_security = 0; + + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP); + } + break; + + case ID_VIEW_TOOL_BAR: + { + HKEY hOpenDoorsKey; + + /* If toolbar on/off command has been chosen ... */ + if(pWindowInfo->bToolbarOn) + { + /* If the toolbar is on, then turn it off. */ + ODFrameDestroyToolbar(GetDlgItem(hwnd, ID_TOOLBAR), + pWindowInfo); + pWindowInfo->bToolbarOn = FALSE; + CheckMenuItem(GetMenu(hwnd), ID_VIEW_TOOL_BAR, + MF_BYCOMMAND | MF_UNCHECKED); + } + else + { + /* If the toolbar is off, then turn it on. */ + pWindowInfo->hwndToolbar = ODFrameCreateToolbar(hwnd, + pWindowInfo->hInstance, pWindowInfo); + pWindowInfo->bToolbarOn = TRUE; + CheckMenuItem(GetMenu(hwnd), ID_VIEW_TOOL_BAR, + MF_BYCOMMAND | MF_CHECKED); + ODFrameUpdateCmdUI(); + } + + /* Adjust window sizes accordingly. */ + ODScrnAdjustWindows(); + + /* Update the toolbar setting in the registry. */ + RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors", + &hOpenDoorsKey); + RegSetValueEx(hOpenDoorsKey, "ToolBarOn", 0, REG_DWORD, + (LPBYTE)&pWindowInfo->bToolbarOn, + sizeof(pWindowInfo->bToolbarOn)); + RegCloseKey(hOpenDoorsKey); + break; + } + + case ID_VIEW_STAT_BAR: + { + HKEY hOpenDoorsKey; + + /* If the status bar on/off command has been chosen ... */ + if(pWindowInfo->bStatusBarOn) + { + /* If the status bar is on, then turn it off. */ + pWindowInfo->bStatusBarOn = FALSE; + CheckMenuItem(GetMenu(hwnd), ID_VIEW_STAT_BAR, + MF_BYCOMMAND | MF_UNCHECKED); + ODFrameDestroyStatusBar(GetDlgItem(hwnd, ID_STATUSBAR)); + } + else + { + /* If the status bar is off, then turn it on. */ + pWindowInfo->bStatusBarOn = TRUE; + CheckMenuItem(GetMenu(hwnd), ID_VIEW_STAT_BAR, + MF_BYCOMMAND | MF_CHECKED); + pWindowInfo->hwndStatusBar = + ODFrameCreateStatusBar(hwnd, pWindowInfo->hInstance); + } + + /* Adjust window sizes accordingly. */ + ODScrnAdjustWindows(); + + /* Update the status bar setting in the registry. */ + RegCreateKey(HKEY_CURRENT_USER, "Software\\Pirie\\OpenDoors", + &hOpenDoorsKey); + RegSetValueEx(hOpenDoorsKey, "StatusBarOn", 0, REG_DWORD, + (LPBYTE)&pWindowInfo->bStatusBarOn, + sizeof(pWindowInfo->bStatusBarOn)); + RegCloseKey(hOpenDoorsKey); + break; + } + + case ID_USER_ADDONEMINUTE: + /* If add one minute command has been chosen, then */ + /* increment the user's time, up to the maximum allowable */ + /* time. */ + if(od_control.user_timelimit < MAX_TIME) + { + od_control.user_timelimit++; + ODFrameUpdateTimeLeft(pWindowInfo); + } + break; + + case ID_USER_ADDFIVEMINUTES: + /* If add five minutes command has been chosen, then */ + /* adjust the user's time accordingly. */ + od_control.user_timelimit = + MIN(od_control.user_timelimit + 5, MAX_TIME); + ODFrameUpdateTimeLeft(pWindowInfo); + break; + + case ID_USER_SUBTRACTONEMINUTE: + /* If subtract one minute command has been chosen, then */ + /* adjust the user's time accordingly. */ + if(od_control.user_timelimit > MIN_TIME) + { + od_control.user_timelimit--; + ODFrameUpdateTimeLeft(pWindowInfo); + } + break; + + case ID_USER_SUBTRACTFIVEMINUTES: + /* If the subtract five mintues command has been chosen, */ + /* then adjust the user's time accordingly. */ + od_control.user_timelimit = + MAX(od_control.user_timelimit - 5, MIN_TIME); + ODFrameUpdateTimeLeft(pWindowInfo); + break; + + case ID_USER_INACTIVITYTIMER: + /* If the user inactivity timer command has been chosen, */ + /* then toggle the timer on or off. */ + od_control.od_disable_inactivity = + !od_control.od_disable_inactivity; + CheckMenuItem(GetMenu(hwnd), ID_USER_INACTIVITYTIMER, + MF_BYCOMMAND | (od_control.od_disable_inactivity ? + MF_UNCHECKED : MF_CHECKED)); + break; + + case ID_TIME_EDIT: + { + /* If the user's time remaining has been directly edited, */ + /* then adjust the time limit accordingly. */ + if(HIWORD(wParam) == EN_CHANGE) + { + char szTimeText[40]; + GetWindowText((HWND)lParam, szTimeText, sizeof(szTimeText)); + od_control.user_timelimit = atoi(szTimeText); + + /* Do not allow the time limit to fall outside of the */ + /* valid range. */ + od_control.user_timelimit = + MAX(MIN_TIME, od_control.user_timelimit); + od_control.user_timelimit = + MIN(MAX_TIME, od_control.user_timelimit); + + /* Update the position of the up-down control. */ + SendMessage(pWindowInfo->hwndTimeUpDown, UDM_SETPOS, 0, + (LPARAM)MAKELONG(od_control.user_timelimit, 0)); + } + } + + default: + return(TRUE); + } + return(FALSE); + + case WM_NOTIFY: + /* A control parent notification message has been sent. */ + switch(((LPNMHDR)lParam)->code) + { + case TTN_NEEDTEXT: + { + /* This is the message from the tool tip control, requesting */ + /* the appropriate string to display for the current toolbar */ + /* item. */ + LPTOOLTIPTEXT lpToolTipText = (LPTOOLTIPTEXT)lParam; + switch(lpToolTipText->hdr.idFrom) + { + case ID_DOOR_EXIT: + lpToolTipText->lpszText = "Exit To BBS"; + break; + case ID_DOOR_CHATMODE: + lpToolTipText->lpszText = "Chat Mode"; + break; + case ID_DOOR_USERKEYBOARDOFF: + lpToolTipText->lpszText = "User Keyboard Off"; + break; + case ID_DOOR_SYSOPNEXT: + lpToolTipText->lpszText = "Sysop Next"; + break; + case ID_DOOR_HANGUP: + lpToolTipText->lpszText = "Hangup"; + break; + case ID_DOOR_LOCKOUT: + lpToolTipText->lpszText = "Lockout"; + break; + } + break; + } + } + break; + + case WM_VSCROLL: + /* A scrolling action has taken place. */ + + /* If it is the time limit up-down control that has scrolled. */ + if((HWND)lParam == pWindowInfo->hwndTimeUpDown) + { + int nPos = HIWORD(wParam); + + /* Adjust the user's time limit. */ + od_control.user_timelimit = MAX(MIN(nPos, MAX_TIME), MIN_TIME); + + /* Update the time left displayed in the edit box. */ + ODFrameUpdateTimeLeft(pWindowInfo); + } + break; + + case WM_SIZE: + /* The OpenDoors frame window has been resized, so its contents */ + /* must now be resized accordingly. */ + + /* Pass the message on to the status bar window, so that it will */ + /* automatically adjust its own position and overall size. */ + SendMessage(GetDlgItem(hwnd, ID_STATUSBAR), WM_SIZE, wParam, lParam); + + /* Now, adjust the size of each part of the status bar. */ + ODFrameSizeStatusBar(GetDlgItem(hwnd, ID_STATUSBAR)); + + /* Pass the message on to the toolbar, so that it will resize */ + /* iteself. */ + SendMessage(GetDlgItem(hwnd, ID_TOOLBAR), WM_SIZE, wParam, lParam); + break; + + case WM_MENUSELECT: + /* If the user has selected an item on the menu, then we should */ + /* update the status bar accordingly. */ + if(HIWORD(wParam) == 0xFFFF) + { + /* If menu is being exited, then turn off the status bar simple */ + /* mode. */ + HWND hwndStatusBar = GetDlgItem(hwnd, ID_STATUSBAR); + + SendMessage(hwndStatusBar, SB_SIMPLE, (WPARAM)FALSE, 0L); + } + else + { + char szCommandString[160] = ""; + HWND hwndStatusBar = GetDlgItem(hwnd, ID_STATUSBAR); + + /* A new menu item is being selected. */ + + /* If this item is on the system menu, then provide the strings */ + /* for any of those menu items. */ + if(HIWORD(wParam) & MF_SYSMENU) + { + switch(LOWORD(wParam)) + { + case SC_SIZE: + strcpy(szCommandString, + "Resizes this window."); + break; + case SC_MOVE: + strcpy(szCommandString, + "Moves this window."); + break; + case SC_MINIMIZE: + strcpy(szCommandString, + "Collapses this window to an icon."); + break; + case SC_MAXIMIZE: + strcpy(szCommandString, + "Expands this window to fill the screen."); + break; + case SC_CLOSE: + strcpy(szCommandString, + "Closes this window, and returns the user to the BBS."); + break; + case SC_RESTORE: + strcpy(szCommandString, + "Restores this window to normal size."); + break; + case SC_TASKLIST: + strcpy(szCommandString, + ""); + break; + } + } + else + { + /* If this item is on the window menu provided by OpenDoors, */ + /* then load the status bar string for this command ID. */ + LoadString(pWindowInfo->hInstance, LOWORD(wParam), + szCommandString, sizeof(szCommandString)); + } + + /* Switch the status bar into simple (single-paned) mode. */ + SendMessage(hwndStatusBar, SB_SIMPLE, (WPARAM)TRUE, 0L); + + /* Set the text for the status bar. */ + SendMessage(hwndStatusBar, SB_SETTEXT, (WPARAM)255 | SBT_NOBORDERS, + (LPARAM)szCommandString); + } + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + + case WM_SHOW_MESSAGE: + if(pWindowInfo->hwndMessageWindow == NULL) + { + pWindowInfo->pszCurrentMessage = (char *)lParam; + pWindowInfo->nCurrentMessageFlags = (int)wParam; + + /* Create the message window. */ + DialogBoxParam(pWindowInfo->hInstance, + MAKEINTRESOURCE(IDD_MESSAGE), hwnd, ODFrameMessageDlgProc, + (LPARAM)pWindowInfo); + } + break; + + case WM_REMOVE_MESSAGE: + if(pWindowInfo->hwndMessageWindow != NULL) + { + PostMessage(pWindowInfo->hwndMessageWindow, WM_COMMAND, + MAKELONG(IDOK, 0), 0L); + pWindowInfo->hwndMessageWindow = NULL; + } + break; + + default: + /* Pass messages that we don't explicitly handle on to the */ + /* default window proc. */ + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameUpdateCmdUI() + * + * Updates the enabled and checked state of OpenDoors commands that may change. + * + * Parameters: None. + * + * Return: void. + */ +void ODFrameUpdateCmdUI(void) +{ + HWND hwndFrame = hwndCurrentFrame; + HMENU hMenu = GetMenu(hwndFrame); + HWND hwndToolbar = GetDlgItem(hwndFrame, ID_TOOLBAR); + tODFrameWindowInfo *pWindowInfo; + + if(hwndFrame == NULL) return; + + /* Obtain window information structure. */ + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA); + if(pWindowInfo == NULL) return; + + /* Check or uncheck the toolbar and status bar menu items. */ + CheckMenuItem(hMenu, ID_VIEW_TOOL_BAR, MF_BYCOMMAND | + (pWindowInfo->bToolbarOn ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hMenu, ID_VIEW_STAT_BAR, MF_BYCOMMAND | + (pWindowInfo->bStatusBarOn ? MF_CHECKED : MF_UNCHECKED)); + + /* Check or uncheck the inactivity timer menu item. */ + CheckMenuItem(hMenu, ID_USER_INACTIVITYTIMER, MF_BYCOMMAND | + (od_control.od_disable_inactivity ? MF_UNCHECKED : MF_CHECKED)); + + /* Check or uncheck the sysop next menu item and toolbar button. */ + CheckMenuItem(hMenu, ID_DOOR_SYSOPNEXT, MF_BYCOMMAND | + (od_control.sysop_next ? MF_CHECKED : MF_UNCHECKED)); + SendMessage(hwndToolbar, TB_CHECKBUTTON, + ID_DOOR_SYSOPNEXT, MAKELONG(od_control.sysop_next, 0)); + + /* Check or uncheck the keyboard off menu item and toolbar button. */ + CheckMenuItem(hMenu, ID_DOOR_USERKEYBOARDOFF, MF_BYCOMMAND | + (od_control.od_user_keyboard_on ? MF_UNCHECKED : MF_CHECKED)); + SendMessage(hwndToolbar, TB_CHECKBUTTON, + ID_DOOR_USERKEYBOARDOFF, + MAKELONG(!od_control.od_user_keyboard_on, 0)); + + /* Update the chat mode menu item and toolbar button. */ + CheckMenuItem(hMenu, ID_DOOR_CHATMODE, MF_BYCOMMAND | + (od_control.od_chat_active ? MF_CHECKED : MF_UNCHECKED)); + SendMessage(hwndToolbar, TB_CHECKBUTTON, ID_DOOR_CHATMODE, + MAKELONG(od_control.od_chat_active, 0)); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameUpdateTimeDisplay() + * + * Updates the remaining time online that is displayed anywhere by the frame + * window. Uses ODFrameUpdateTimeLeft(). + * + * Parameters: None. + * + * Return: void. + */ +void ODFrameUpdateTimeDisplay(void) +{ + tODFrameWindowInfo *pWindowInfo; + + /* If there is no current frame window, then return without doing */ + /* anything. */ + if(hwndCurrentFrame == NULL) return; + + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndCurrentFrame, + GWL_USERDATA); + ASSERT(pWindowInfo != NULL); + + ODFrameUpdateTimeLeft(pWindowInfo); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameUpdateWantChat() + * + * Updates the state of the flashing wants-chat indicator on the frame window. + * + * Parameters: None. + * + * Return: void. + */ +void ODFrameUpdateWantChat(void) +{ + tODFrameWindowInfo *pWindowInfo; + + /* If there is no current frame window, then return without doing */ + /* anything. */ + if(hwndCurrentFrame == NULL) return; + + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndCurrentFrame, + GWL_USERDATA); + ASSERT(pWindowInfo != NULL); + + /* If the status bar is on, then update the text displayed in the */ + /* status bar's main pane. */ + if(pWindowInfo->bStatusBarOn) + { + ODFrameSetMainStatusText(pWindowInfo->hwndStatusBar); + } + + /* Toggle the state of the wants-chat indicator, of needed. */ + if(pWindowInfo->bWantsChatIndicator && !od_control.user_wantchat) + { + /* Restore original window text. */ + SetWindowText(hwndCurrentFrame, od_control.od_prog_name); + + /* Restore the window flash to its original state. */ + FlashWindow(hwndCurrentFrame, FALSE); + + /* Destroy the Windows timer. */ + KillTimer(hwndCurrentFrame, 1); + + /* Record that wants chat indicator is now off. */ + pWindowInfo->bWantsChatIndicator = FALSE; + } + else if (!pWindowInfo->bWantsChatIndicator && od_control.user_wantchat) + { + /* Set window title to include the wants chat indicator. */ + char szNewWindowTitle[sizeof(od_control.od_prog_name) + 20]; + sprintf(szNewWindowTitle, "%s - User Wants Chat", + od_control.od_prog_name); + SetWindowText(hwndCurrentFrame, szNewWindowTitle); + + /* Start the flashing the window. */ + SetTimer(hwndCurrentFrame, 1, + GetCaretBlinkTime(), NULL); + + /* Record that wants chat indicator is now on. */ + pWindowInfo->bWantsChatIndicator = TRUE; + } +} + + +/* ---------------------------------------------------------------------------- + * ODFrameDestroyWindow() *** PRIVATE FUNCTION *** + * + * Destroys the OpenDoors frame window and its children. + * + * Parameters: hwndFrame - Handle to the window previously created by + * ODFrameCreateWindow(). + * + * Return: void. + */ +static void ODFrameDestroyWindow(HWND hwndFrame) +{ + tODFrameWindowInfo *pWindowInfo; + + ASSERT(hwndFrame != NULL); + + /* Obtain a pointer to the frame window information structure. */ + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA); + + /* At this point, deallocate the accelerator table. */ + if(pWindowInfo->hacclFrameCommands != NULL) + { + DestroyAcceleratorTable(pWindowInfo->hacclFrameCommands); + } + + /* Destroying the main frame window will automatically cause its */ + /* children to be destroyed. */ + DestroyWindow(hwndFrame); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameToolbarProc() *** PRIVATE FUNCTION *** + * + * The toolbar window proceedure. + * + * Parameters: hwnd - Handle to the toolbar window. + * + * uMsg - Specifies the message. + * + * wParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * lParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * Return: The return value is the result of the message processing and + * depends on the message. + */ +LRESULT CALLBACK ODFrameToolbarProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + /* Forward needed message to the main frame window proceedure. */ + case WM_VSCROLL: + case WM_COMMAND: + SendMessage(GetParent(hwnd), uMsg, wParam, lParam); + break; + } + + /* Pass all messages on to the default toolbar window proceedure. */ + return(CallWindowProc(pfnDefToolbarProc, hwnd, uMsg, wParam, lParam)); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameUpdateTimeLeft() *** PRIVATE FUNCTION *** + * + * Updates the displayed time remaining from od_control.user_timelimit. + * + * Parameters: pWindowInfo - Pointer to frame window information structure. + * + * Return: void. + */ +static void ODFrameUpdateTimeLeft(tODFrameWindowInfo *pWindowInfo) +{ + char szTimeLeft[12]; + RECT rcWindow; + + if(pWindowInfo->hwndTimeEdit == NULL) + { + /* If the time limit edit control does not exist (i.e., if the */ + /* toolbar is not currently on), then there is nothing for us to do. */ + return; + } + + /* Generate the string to be displayed in the edit control. */ + sprintf(szTimeLeft, "%d min.", od_control.user_timelimit); + + /* Set the edit control's text to the new string. */ + SetWindowText(pWindowInfo->hwndTimeEdit, szTimeLeft); + + /* Force edit control to be redrawn. (Except for rightmost pixel */ + /* column.) */ + GetWindowRect(pWindowInfo->hwndTimeEdit, &rcWindow); + rcWindow.right--; + InvalidateRect(pWindowInfo->hwndTimeEdit, &rcWindow, TRUE); + + /* Set the position of the up-down control to match. */ + SendMessage(pWindowInfo->hwndTimeUpDown, UDM_SETPOS, 0, + (LPARAM)MAKELONG(od_control.user_timelimit, 0)); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameTimeEditProc() *** PRIVATE FUNCTION *** + * + * The time edit window proceedure. Relays mouse messages from the edit box + * to the tooltip control, and then passes all messages on to the standard + * edit box window proceedure. + * + * Parameters: hwnd - Handle to the time edit window. + * + * uMsg - Specifies the message. + * + * wParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * lParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * Return: The return value is the result of the message processing and + * depends on the message. + */ +LRESULT CALLBACK ODFrameTimeEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + { + MSG msg; + HWND hwndToolTip; + + /* Setup message structure. */ + msg.lParam = lParam; + msg.wParam = wParam; + msg.message = uMsg; + msg.hwnd = hwnd; + + /* Obtain handle to the tooltip window. */ + hwndToolTip = (HWND)SendMessage(GetParent(hwnd), TB_GETTOOLTIPS, + 0, 0); + + /* Relay the message to the tooltip window. */ + SendMessage(hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg); + + break; + } + } + + /* Pass all messages on to the default edit box window proceedure. */ + return(CallWindowProc(pfnDefEditProc, hwnd, uMsg, wParam, lParam)); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameAboutDlgProc() + * + * DialogProc for the OpenDoors default Help About dialog box. + * + * Parameters: hwndDlg - Window handle to the dialog box. + * + * uMsg - Message ID. + * + * wParam - First message parameter. + * + * lParam - Second message parameter. + * + * Return: TRUE if message is processed, FALSE otherwise. + */ +BOOL CALLBACK ODFrameAboutDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + /* At dialog box creation time, update the text in the about */ + /* box with any information provided by the OpenDoors programmer. */ + + /* If a program name has been provided, then display it. */ + if(strcmp(od_control.od_prog_name, OD_VER_SHORTNAME) != 0) + { + SetWindowText(GetDlgItem(hwndDlg, IDC_DOORNAME), + od_control.od_prog_name); + } + + /* If copyright information has been provided, then display it. */ + if(strlen(od_control.od_prog_copyright) > 0) + { + SetWindowText(GetDlgItem(hwndDlg, IDC_COPYRIGHT), + od_control.od_prog_copyright); + } + + /* If program version information has been provided, then display */ + /* it. */ + if(strlen(od_control.od_prog_version) > 0) + { + SetWindowText(GetDlgItem(hwndDlg, IDC_VERSION), + od_control.od_prog_version); + } + + /* Center the about dialog box in the area occupied by the */ + /* main frame window. */ + ODFrameCenterWindowInParent(hwndDlg); + + return(TRUE); + + case WM_COMMAND: + /* If a command has been chosen. */ + switch(LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + /* If the OK button has been pressed, then close the dialog. */ + EndDialog(hwndDlg, IDOK); + break; + } + return(TRUE); + + default: + /* Otherwise, indicate that this message has not been processed. */ + return(FALSE); + } +} + + +/* ---------------------------------------------------------------------------- + * ODFrameCenterWindowInParent() *** PRIVATE FUNCTION *** + * + * Repositions the specified window so that it is centered in its parent. + * + * Parameters: hwndChild - The window to reposition. + * + * Return: void. + */ +void ODFrameCenterWindowInParent(HWND hwndChild) +{ + HWND hwndParent; + RECT rcParent; + RECT rcChild; + INT nChildWidth; + INT nChildHeight; + INT nParentWidth; + INT nParentHeight; + + ASSERT(hwndChild != NULL); + + /* Obtain a handle to the parent window. */ + hwndParent = GetParent(hwndChild); + ASSERT(hwndParent != NULL); + + /* Obtain the bounding boxes of both windows. */ + GetWindowRect(hwndChild, &rcChild); + GetWindowRect(hwndParent, &rcParent); + + /* Determine the height and width of both windows. */ + nChildWidth = rcChild.right - rcChild.left; + nChildHeight = rcChild.bottom - rcChild.top; + nParentWidth = rcParent.right - rcParent.left; + nParentHeight = rcParent.bottom - rcParent.top; + + /* Move the child to the center of the parent. */ + SetWindowPos(hwndChild, NULL, + rcParent.left + (nParentWidth - nChildWidth) / 2, + rcParent.top + (nParentHeight - nChildHeight) / 2, + 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameMessageLoop() *** PRIVATE FUNCTION *** + * + * Message loop for OpenDoors local UI thread (frame window handling). + * + * Parameters: hInstance - Handle to current instance. + * + * hwndFrame - Handle to the frame window. + * + * Return: void. + */ +static void ODFrameMessageLoop(HANDLE hInstance, HWND hwndFrame) +{ + MSG msg; + + ASSERT(hInstance != NULL); + ASSERT(hwndFrame != NULL); + + /* Loop, fetching, translating and dispatching messages for any windows */ + /* created by this thread. (GetMessage() blocks when no messages are */ + /* available.) */ + while(GetMessage(&msg, NULL, 0, 0)) + { + if(!ODFrameTranslateAccelerator(hwndFrame, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODFrameTranslateAccelerator() + * + * Translates WM_KEYDOWN or WM_SYSKEYDOWN messages to frame window commands, + * if needed, based on the frame window's accelerator table. + * + * Parameters: hwndFrame - Handle to the OpenDoors main frame window. + * + * pMsg - Pointer to the message that may require + * translation. + * + * Return: TRUE if message was translated, FALSE if not. + */ +BOOL ODFrameTranslateAccelerator(HWND hwndFrame, LPMSG pMsg) +{ + tODFrameWindowInfo *pWindowInfo; + + ASSERT(hwndFrame != NULL); + ASSERT(pMsg != NULL); + + /* Obtain a pointer to the frame window information structure. */ + pWindowInfo = (tODFrameWindowInfo *)GetWindowLong(hwndFrame, GWL_USERDATA); + ASSERT(pWindowInfo != NULL); + + /* Perform accelerator translation, based on the frame window's */ + /* accelerator table, sending any resulting WM_COMMAND messages */ + /* to the frame window. */ + return(TranslateAccelerator(hwndFrame, pWindowInfo->hacclFrameCommands, + pMsg) != 0); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameThreadProc() *** PRIVATE FUNCTION *** + * + * Function that execute the OpenDoors frame window thread. + * + * Parameters: pParam - The thread parameter, which must be the handle to the + * current application instance. + * + * Return: TRUE on success, or FALSE on failure. + */ +DWORD OD_THREAD_FUNC ODFrameThreadProc(void *pParam) +{ + HWND hwndFrame; + HANDLE hInstance = (HANDLE)pParam; + + /* Create the frame window. */ + hwndFrame = ODFrameCreateWindow(hInstance); + + if(hwndFrame == NULL) + { + return(FALSE); + } + + /* Store a pointer to the frame window. */ + hwndCurrentFrame = hwndFrame; + + /* Loop, processing messages for the frame window. */ + ODFrameMessageLoop(hInstance, hwndFrame); + + /* Destroy the frame window. */ + ODFrameDestroyWindow(hwndFrame); + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameStart() + * + * Function that starts up the frame window. + * + * Parameters: hInstance - Handle to the current application instance. + * + * phFrameThread - Pointer to the frame thread handle. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODFrameStart(HANDLE hInstance, tODThreadHandle *phFrameThread) +{ + return(ODThreadCreate(phFrameThread, ODFrameThreadProc, + (void *)hInstance)); +} + + +/* ---------------------------------------------------------------------------- + * ODFrameMessageDlgProc() + * + * Dialog proceedure for the OpenDoors message window. + * + * Parameters: hwndDlg - Window handle to the dialog box. + * + * uMsg - Message ID. + * + * wParam - First message parameter. + * + * lParam - Second message parameter. + * + * Return: TRUE if message is processed, FALSE otherwise. + */ +BOOL CALLBACK ODFrameMessageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + { + tODFrameWindowInfo *pWindowInfo; + + pWindowInfo = (tODFrameWindowInfo *)lParam; + + ASSERT(pWindowInfo != NULL); + + pWindowInfo->hwndMessageWindow = hwndDlg; + + /* Set the message window title. */ + SetWindowText(hwndDlg, od_control.od_prog_name); + + /* Change the text displayed in the message window. */ + SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE_TEXT1), + (char *)pWindowInfo->pszCurrentMessage); + + /* Center window in parent window. */ + ODFrameCenterWindowInParent(hwndDlg); + + return(FALSE); + } + + case WM_COMMAND: + /* If a command has been chosen. */ + switch(LOWORD(wParam)) + { + case IDOK: + /* If the OK button has been pressed, then close the dialog. */ + EndDialog(hwndDlg, IDOK); + break; + } + return(TRUE); + + default: + /* Indicate that this message has not been processed. */ + return(FALSE); + } + + return(TRUE); +} + + +#endif /* ODPLAT_WIN32 */ diff --git a/utils/magiedit/odoors/ODFrame.h b/utils/magiedit/odoors/ODFrame.h new file mode 100644 index 0000000..d10a41d --- /dev/null +++ b/utils/magiedit/odoors/ODFrame.h @@ -0,0 +1,58 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODFrame.h + * + * Description: Defines the public interface to the OpenDoors frame window. + * This file is only applicable when building the Win32 version + * of OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Aug 20, 1995 6.00 BP Created. + * Jan 20, 1996 6.00 BP Made ODFrameCenter...() shared. + * Feb 17, 1996 6.00 BP Add ...Accelerator() return value. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODFRAME +#define _INC_ODFRAME + +#include "ODPlat.h" +#include "ODGen.h" + +#ifdef ODPLAT_WIN32 + +/* Public frame window functions. */ +tODResult ODFrameStart(HANDLE hInstance, tODThreadHandle *phFrameThread); +INT ODFrameGetUsedClientAtTop(HWND hwndFrame); +INT ODFrameGetUsedClientAtBottom(HWND hwndFrame); +BOOL ODFrameTranslateAccelerator(HWND hwndFrame, LPMSG pMsg); +void ODFrameUpdateCmdUI(void); +void ODFrameUpdateTimeDisplay(void); +void ODFrameUpdateWantChat(void); +void ODFrameCenterWindowInParent(HWND hwndChild); + +/* User defined messages that are handled by the frame window. */ +#define WM_SHOW_MESSAGE (WM_USER + 1) +#define WM_REMOVE_MESSAGE (WM_USER + 2) + +#endif /* ODPLAT_WIN32 */ + +#endif /* _INC_ODFRAME */ diff --git a/utils/magiedit/odoors/ODGen.h b/utils/magiedit/odoors/ODGen.h new file mode 100644 index 0000000..196c17c --- /dev/null +++ b/utils/magiedit/odoors/ODGen.h @@ -0,0 +1,199 @@ +/* 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: ODGen.h + * + * Description: Contains general definitions used throughout OpenDoors, + * including: - version information manifest constants + * - debugging macros + * - compiler-dependent definitions + * - internally used macros + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP Created. + * Oct 20, 1994 6.00 BP Added DIM macro. + * Dec 31, 1994 6.00 BP Remove USEINLINE option. + * Dec 12, 1995 6.00 BP Moved ODPLAT_??? to OpenDoor.h. + * Dec 19, 1995 6.00 BP Implement ASSERT() for Win32. + * Jan 23, 1996 6.00 BP Added OD_TEXTMODE. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 24, 1996 6.00 BP Turn off OD_DIAGNOSTICS. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 03, 1996 6.10 BP Moved ODFAR to OpenDoor.h. + * Oct 19, 2001 6.20 RS Incremented version for socket support. + */ + +#ifndef _INC_ODGEN +#define _INC_ODGEN + + +/* PLATFORM-SPECIFIC DEFINITIONS. */ + +/* DLL specific defintions. */ +#ifdef OD_DLL +#ifdef ODPLAT_WIN32 +#define OD_DLL_NAME "ODOORS62" +#endif /* ODPLAT_WIN32 */ +#endif /* OD_DLL */ + +/* Mutlithreading specific definitions. */ +#ifdef ODPLAT_WIN32 +#define OD_MULTITHREADED +#endif /* ODPLAT_WIN32 */ + +/* Text mode specific definitions. */ +#if defined(ODPLAT_DOS) || defined(ODPLAT_NIX) +#define OD_TEXTMODE +#endif /* ODPLAT_DOS */ + +/* DOS specific definitions. */ +#ifdef ODPLAT_DOS + +/* Keyword to flag ISR functions. */ +#define INTERRUPT interrupt + +/* Inline assembly keyword varies from compiler to compiler. */ +#ifdef _MSC_VER +#define ASM __asm +#else +#define ASM asm +#endif + +/* Memory model information. */ +#ifdef __TINY__ +#define SMALLDATA +#define SMALLCODE +#endif +#ifdef __SMALL__ +#define SMALLDATA +#define SMALLCODE +#endif +#ifdef __COMPACT__ +#define LARGEDATA +#define SMALLCODE +#endif +#ifdef __MEDIUM__ +#define SMALLDATA +#define LARGECODE +#endif +#ifdef __LARGE__ +#define LARGEDATA +#define LARGECODE +#endif +#ifdef __HUGE__ +#define LARGEDATA +#define LARGECODE +#endif +#endif /* ODPLAT_DOS */ + + +/* VERSION INFORMATION CONSTANTS. */ +#define OD_VER_SHORTNAME "OpenDoors" +#define OD_VER_STATUSLINE " OpenDoors 6.24 - (C) Copyright 1991-2001" \ + " by Brian Pirie " +#define OD_VER_UNREG_STAT " OpenDoors 6.24 *WARNING* Unregistered Version" \ + " - Limit 1 month trial period! " + +#ifdef ODPLAT_DOS +#define OD_VER_SIGNON "[OpenDoors 6.24/DOS - " \ + "(C) Copyright 1991-2001 by Brian Pirie]\n\r" +#define OD_VER_FULLNAME "OpenDoors 6.24/DOS" +#endif /* ODPLAT_DOS */ +#ifdef ODPLAT_WIN32 +#define OD_VER_SIGNON "[OpenDoors 6.24/Win32 - " \ + "(C) Copyright 1991-2001 by Brian Pirie]\n\r" +#define OD_VER_FULLNAME "OpenDoors 6.24/Win32" +#endif /* ODPLAT_WIN32 */ +#ifdef ODPLAT_NIX +#define OD_VER_SIGNON "[OpenDoors 6.24/*nix - " \ + "(C) Copyright 1991-2001 by Brian Pirie]\n\r" +#define OD_VER_FULLNAME "OpenDoors 6.24/*nix" +#endif /* ODPLAT_NIX */ + + +/* COMPILER DEPENDENT DEFINITIONS. */ + +/* Some compilers don't like const keyword on parameters. */ +#define CONST const + + +/* DEBUG MACROS. */ + +/* OD_DEBUG is defined for debug version of the library. */ +/* #define OD_DEBUG */ + +/* OD_DIAGNOSTICS is defined to enable od_internal_debug. */ +/* #define OD_DIAGNOSTICS */ + +/* ASSERTion macro - terminates if test condition fails. */ +#ifdef OD_DEBUG +#define __STR(x) __VAL(x) +#define __VAL(x) #x +#ifdef ODPLAT_WIN32 +#define ASSERT(x) if(!(x)) { MessageBox(NULL, __FILE__ ":" \ + __STR(__LINE__) "\n" #x, OD_VER_FULLNAME " - Test condition failed", \ + MB_ICONSTOP | MB_OK); exit(1); } +#else /* !ODPLAT_WIN32 */ +#define ASSERT(x) if(!(x)) { puts(OD_VER_FULLNAME \ + " - Test condition failed:\n" __FILE__ ":" __STR(__LINE__) "\n" #x); \ + exit(1); } +#endif /* !ODPLAT_WIN32 */ +#else /* !OD_DEBUG */ +#define ASSERT(x) +#endif /* !OD_DEBUG */ + +/* TRACE() macro - used to generate debug output. */ +#ifdef OD_TRACE +#include +#define TRACE_API 1 +#define TRACE(x, y) printf("[%s]", y); +#else +#define TRACE(x, y) +#endif + + +/* SCREEN SIZE. */ +#define OD_SCREEN_WIDTH 80 +#define OD_SCREEN_HEIGHT 25 + + +/* INTERNALLY USED MACROS. */ + +/* MIN() and MAX() macros. Note that expressions passed to macros may be */ +/* evaluated more than once. For this reason, it is best to only pass */ +/* constants or variables to these macros. */ +#ifndef MIN +#define MIN(x, y) ((x) > (y)) ? (y) : (x) +#endif /* !MIN */ +#ifndef MAX +#define MAX(x, y) ((x) > (y)) ? (x) : (y) +#endif /* !MAX */ + +/* DIM() macro. Returns the number of elements in an array. */ +#ifndef DIM +#define DIM(x) (sizeof(x) / sizeof(*x)) +#endif /* !DIM */ + +/* UNUSED() macro. Used to flag that a function parameter is intentionally */ +/* not used, thus preventing a compile-time warning. */ +#define UNUSED(x) ((void)(x)) + +#endif /* !_INC_ODGEN */ diff --git a/utils/magiedit/odoors/ODGetIn.c b/utils/magiedit/odoors/ODGetIn.c new file mode 100644 index 0000000..66c1593 --- /dev/null +++ b/utils/magiedit/odoors/ODGetIn.c @@ -0,0 +1,511 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODGetIn.c + * + * Description: Implements the od_get_input() function, which obtains the + * next input event of any type, optionally performing + * translation. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Jan 04, 1996 6.00 BP Created. + * Jan 30, 1996 6.00 BP Tweaked TREAT_ESC_AS_ANSI_TIMEOUT. + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout. + * Jan 31, 1996 6.00 BP Added timeout for od_get_input(). + * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 19, 1996 6.00 BP Switched to table implementation. + * Feb 25, 1996 6.00 BP Added new control sequences to table. + * Feb 27, 1996 6.00 BP Added od_max_key_latency. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + * Apr 11, 2005 6.23 SH Fix hang forver on ESC press and latency timeout. + */ + +#define BUILDING_OPENDOORS + +#include +#include + +#include "OpenDoor.h" +#include "ODInQue.h" +#include "ODCore.h" +#include "ODKrnl.h" + +/* Control sequence table definitions. */ +typedef struct +{ + char *pszSequence; + char chExtendedKey; + BOOL bIsControlKey; +} tODKeySequence; + +tODKeySequence aKeySequences[] = +{ + /* VT-52 control sequences. */ + {"\033A", OD_KEY_UP, FALSE}, + {"\033B", OD_KEY_DOWN, FALSE}, + {"\033C", OD_KEY_RIGHT, FALSE}, + {"\033D", OD_KEY_LEFT, FALSE}, + {"\033H", OD_KEY_HOME, FALSE}, + {"\033K", OD_KEY_END, FALSE}, + {"\033P", OD_KEY_F1, FALSE}, + {"\033Q", OD_KEY_F2, FALSE}, + {"\033?w", OD_KEY_F3, FALSE}, + {"\033?x", OD_KEY_F4, FALSE}, + {"\033?t", OD_KEY_F5, FALSE}, + {"\033?u", OD_KEY_F6, FALSE}, + {"\033?q", OD_KEY_F7, FALSE}, + {"\033?r", OD_KEY_F8, FALSE}, + {"\033?p", OD_KEY_F9, FALSE}, + + /* Control sequences common to VT-100/VT-102/VT-220/VT-320/ANSI. */ + {"\033[A", OD_KEY_UP, FALSE}, + {"\033[B", OD_KEY_DOWN, FALSE}, + {"\033[C", OD_KEY_RIGHT, FALSE}, + {"\033[D", OD_KEY_LEFT, FALSE}, + {"\033[M", OD_KEY_PGUP, FALSE}, + {"\033[H\x1b[2J", OD_KEY_PGDN, FALSE}, + {"\033[H", OD_KEY_HOME, FALSE}, + {"\033[K", OD_KEY_END, FALSE}, + {"\033OP", OD_KEY_F1, FALSE}, + {"\033OQ", OD_KEY_F2, FALSE}, + {"\033OR", OD_KEY_F3, FALSE}, + {"\033OS", OD_KEY_F4, FALSE}, + + /* VT-220/VT-320 specific control sequences. */ + {"\033[1~", OD_KEY_HOME, FALSE}, /* Windows XP telnet.exe. Is actually FIND */ + {"\033[2~", OD_KEY_INSERT, FALSE}, + {"\033[3~", OD_KEY_DELETE, FALSE}, + {"\033[4~", OD_KEY_END, FALSE}, /* Windows XP telnet.exe. Is actually SELECT */ + {"\033[5~", OD_KEY_PGUP, FALSE}, + {"\033[6~", OD_KEY_PGDN, FALSE}, + {"\033[17~", OD_KEY_F6, FALSE}, + {"\033[18~", OD_KEY_F7, FALSE}, + {"\033[19~", OD_KEY_F8, FALSE}, + {"\033[20~", OD_KEY_F9, FALSE}, + {"\033[21~", OD_KEY_F10, FALSE}, + {"\033[23~", OD_KEY_F11, FALSE}, + {"\033[24~", OD_KEY_F12, FALSE}, + + /* ANSI-specific control sequences. */ + {"\033[L", OD_KEY_HOME, FALSE}, + {"\033Ow", OD_KEY_F3, FALSE}, + {"\033Ox", OD_KEY_F4, FALSE}, + {"\033Ot", OD_KEY_F5, FALSE}, + {"\033Ou", OD_KEY_F6, FALSE}, + {"\033Oq", OD_KEY_F7, FALSE}, + {"\033Or", OD_KEY_F8, FALSE}, + {"\033Op", OD_KEY_F9, FALSE}, + + /* PROCOMM-specific control sequences (non-keypad alternatives). */ + {"\033OA", OD_KEY_UP, FALSE}, + {"\033OB", OD_KEY_DOWN, FALSE}, + {"\033OC", OD_KEY_RIGHT, FALSE}, + {"\033OD", OD_KEY_LEFT, FALSE}, + {"\033OH", OD_KEY_HOME, FALSE}, + {"\033OK", OD_KEY_END, FALSE}, + + /* Other standard control sequences. */ + {"\x16\t", OD_KEY_INSERT, TRUE}, + + /* OpenDoors-specific alternatives. */ + {"\x7f", OD_KEY_DELETE, FALSE}, + {"\x5", OD_KEY_UP, TRUE}, + {"\x18", OD_KEY_DOWN, TRUE}, + {"\x13", OD_KEY_LEFT, TRUE}, + {"\x4", OD_KEY_RIGHT, TRUE}, + {"\x7", OD_KEY_DELETE, TRUE}, + {"\x16", OD_KEY_INSERT, TRUE}, +}; + +/* Constant that indicates no match has been found. */ +#define NO_MATCH DIM(aKeySequences) + +/* Configurable constants. */ + +/* The time, in milliseconds, to wait for a second character in a control */ +/* sequence, before deciding that none is going to come. */ +#define MAX_CHARACTER_LATENCY 250 + +/* Size of inbound sequence buffer. */ +#define SEQUENCE_BUFFER_SIZE 10 + +/* Current control sequence received state. */ +static char szCurrentSequence[SEQUENCE_BUFFER_SIZE] = ""; +#if 0 // Unused... +static tODTimer SequenceFailTimer; +static BOOL bSequenceFromRemote; +static int nMatchedSequence = NO_MATCH; +static BOOL bTimerActive = FALSE; +#endif +static BOOL bDoorwaySequence = FALSE; +static BOOL bDoorwaySequencePending = FALSE; + +/* Local private function prototypes. */ +static int ODGetCodeIfLongest(WORD wFlags); +static int ODHaveStartOfSequence(WORD wFlags); +static int ODLongestFullCode(WORD wFlags); +static void ODShiftSeq(int chars); + +/* ---------------------------------------------------------------------------- + * od_get_input() + * + * Obtains the next input event of any type, optionally performing + * translation on input events. + * + * Parameters: pInputEvent - Pointer to a tODInputEvent structure, which + * will be filled by information on the next input + * event, if any is obtained. + * + * TimeToWait - Number of milliseconds to wait for input to be + * available. A value of 0 causes od_get_input() + * to return immediately if no input is waiting, + * while a value of OD_NO_TIMEOUT causes the + * function to never return unless input has been + * obtained. + * + * wFlags - Flags which customize od_get_input()'s behaviour. + * + * Return: TRUE if an input event was obtained, FALSE if not. + */ +ODAPIDEF BOOL ODCALL od_get_input(tODInputEvent *pInputEvent, + tODMilliSec TimeToWait, WORD wFlags) +{ + tODInputEvent LastInputEvent; + int nSequence; + int nSequenceLen; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_get_input()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check for parameter validity. */ + if(pInputEvent == NULL) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Call the OpenDoors kernel, if applicable */ + CALL_KERNEL_IF_NEEDED(); + + /* If you don't know better, it's a remote char */ + /* Local chars are always correctly received (no ANSI sequences) */ + LastInputEvent.bFromRemote = TRUE; + + if((!bDoorwaySequence) && bDoorwaySequencePending && (!szCurrentSequence[0])) { + bDoorwaySequencePending=FALSE; + bDoorwaySequence=TRUE; + } + + /* If no pending input string, wait for the first keystroke */ + if((!szCurrentSequence[0]) && (!bDoorwaySequence)) { + if(ODInQueueGetNextEvent(hODInputQueue, &LastInputEvent, TimeToWait) + != kODRCSuccess) { + OD_API_EXIT(); + return(FALSE); + } + + /* If you have a *local* char, send it immediately */ + if((!LastInputEvent.bFromRemote) && (LastInputEvent.chKeyPress != 0) +#if 0 + && (LastInputEvent.EventType == EVENT_EXTENDED_KEY)) { +#else + ) { +#endif + memcpy(pInputEvent, &LastInputEvent, sizeof(tODInputEvent)); + OD_API_EXIT(); + return(TRUE); + } + + /* IF the received char is a NULL, this is the start of a doorway char */ + if(!LastInputEvent.chKeyPress) + bDoorwaySequence = TRUE; + else { + szCurrentSequence[0]=LastInputEvent.chKeyPress; + szCurrentSequence[1]=0; + } + } + + nSequenceLen=strlen(szCurrentSequence); + + CALL_KERNEL_IF_NEEDED(); + + /* If you don't have the start of a sequence, and it's not doorway mode, you have + * a char. It's that simple. + */ + if((!bDoorwaySequence) && (!ODHaveStartOfSequence(wFlags))) { + pInputEvent->chKeyPress = szCurrentSequence[0]; + pInputEvent->EventType = EVENT_CHARACTER; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + /* Shift the sequence buffer over one */ + ODShiftSeq(1); + OD_API_EXIT(); + return(TRUE); + } + + /* Now... if the current sequence IS the longest valid one, return it + * immediately. If it's sequence leftovers, it HAS to be a remote key + * since local chars are #1 always doorway mode and #2 have no delay + * betwixt them. + */ + if((nSequence = ODGetCodeIfLongest(wFlags)) != NO_MATCH) { + pInputEvent->chKeyPress = aKeySequences[nSequence].chExtendedKey; + pInputEvent->EventType = EVENT_EXTENDED_KEY; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + /* Shift the sequence buffer... being sure to copy the terminator */ + ODShiftSeq(strlen(aKeySequences[nSequence].pszSequence)); + OD_API_EXIT(); + return(TRUE); + } + + /* Now, continue adding chars, waiting at MOST MAX_CHARACTER_LATENCY between them */ + CALL_KERNEL_IF_NEEDED(); + while((!bDoorwaySequencePending) + && (ODInQueueGetNextEvent(hODInputQueue, &LastInputEvent, MAX_CHARACTER_LATENCY) + == kODRCSuccess)) { + /* If you are looking for a doorway sequence, any char completes it (honest!) */ + /* Further, thanks to some lack of planning, it's EXACTLY THE SAME as the char, + * only it's extended. + */ + if(bDoorwaySequence) { + memcpy(pInputEvent, &LastInputEvent, sizeof(tODInputEvent)); + pInputEvent->EventType = EVENT_EXTENDED_KEY; + bDoorwaySequence=FALSE; + OD_API_EXIT(); + return(TRUE); + } + + /* If we get a 0, we *WILL BE* looking for a doorway sequence. But NOT + * until the current sequence buffer is drained! + */ + if(LastInputEvent.chKeyPress == 0) { + bDoorwaySequencePending=TRUE; + break; + } + + /* If you have a *local* char, send it immediately */ + if((!LastInputEvent.bFromRemote) && (LastInputEvent.chKeyPress != 0) +#if 0 + && (LastInputEvent.EventType == EVENT_EXTENDED_KEY)) { +#else + ) { +#endif + memcpy(pInputEvent, &LastInputEvent, sizeof(tODInputEvent)); + OD_API_EXIT(); + return(TRUE); + } + + /* Put this char into the sequence buffer */ + szCurrentSequence[nSequenceLen++]=LastInputEvent.chKeyPress; + szCurrentSequence[nSequenceLen]=0; + + /* When you have the longest possible sequence, you ARE done */ + if((nSequence = ODGetCodeIfLongest(wFlags)) != NO_MATCH) { + pInputEvent->chKeyPress = aKeySequences[nSequence].chExtendedKey; + pInputEvent->EventType = EVENT_EXTENDED_KEY; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + /* Shift the sequence buffer... being sure to copy the terminator */ + ODShiftSeq(strlen(aKeySequences[nSequence].pszSequence)); + OD_API_EXIT(); + return(TRUE); + } + CALL_KERNEL_IF_NEEDED(); + } + + /* If we were looking for a doorway sequence, tough, we didn't get it. */ + if(bDoorwaySequence) { + pInputEvent->chKeyPress = 0; + pInputEvent->EventType = EVENT_CHARACTER; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + bDoorwaySequence=FALSE; + OD_API_EXIT(); + return(TRUE); + } + + /* Now, if we have any kind of sequence, we'll settle for it. */ + if((nSequence = ODLongestFullCode(wFlags)) != NO_MATCH) { + pInputEvent->chKeyPress = aKeySequences[nSequence].chExtendedKey; + pInputEvent->EventType = EVENT_EXTENDED_KEY; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + /* Shift the sequence buffer... being sure to copy the terminator */ + ODShiftSeq(strlen(aKeySequences[nSequence].pszSequence)); + OD_API_EXIT(); + return(TRUE); + } + + /* If we don't have a complete sequence, send a single char */ + pInputEvent->chKeyPress = szCurrentSequence[0]; + if(szCurrentSequence[0]) { + pInputEvent->EventType = EVENT_CHARACTER; + pInputEvent->bFromRemote = LastInputEvent.bFromRemote; + /* Shift the sequence buffer over one */ + ODShiftSeq(1); + } + OD_API_EXIT(); + /* Return false if something broke */ + return(pInputEvent->chKeyPress); +} + +/* ---------------------------------------------------------------------------- + * ODLongestFullCode() *** PRIVATE FUNCTION *** + * + * Return the index of the longest full code that matches the start of the + * sequence buffer + * + * Parameters: wFlags from od_get_input() + * + * Return: void + */ +static int ODLongestFullCode(WORD wFlags) +{ + int CurrLen=0; + int seqlen; + int i; + int retval=NO_MATCH;; + + if(wFlags & GETIN_RAW) + return(NO_MATCH); + for(i = 0; i < DIM(aKeySequences); ++i) { + if((wFlags & GETIN_RAWCTRL) && aKeySequences[i].bIsControlKey) { + continue; + } + seqlen=strlen(aKeySequences[i].pszSequence); + if(seqlen>CurrLen) { + if(strncmp(aKeySequences[i].pszSequence, szCurrentSequence, seqlen)==0) { + retval=i; + CurrLen=seqlen; + } + } + } + + return(retval); +} + +/* ---------------------------------------------------------------------------- + * ODHaveStartOfSequence() *** PRIVATE FUNCTION *** + * + * If the current sequence buffer is the start of a valid sequence, return TRUE + * + * Parameters: wFlags from od_get_input() + * + * Return: void + */ +static int ODHaveStartOfSequence(WORD wFlags) +{ + int seqlen1; + int seqlen2; + int i; + + if(wFlags & GETIN_RAW) + return(FALSE); + seqlen1=strlen(szCurrentSequence); + for(i = 0; i < DIM(aKeySequences); ++i) { + if((wFlags & GETIN_RAWCTRL) && aKeySequences[i].bIsControlKey) { + continue; + } + seqlen2=strlen(aKeySequences[i].pszSequence); + if(seqlen1CurrLen) { + if(seqlen2<=seqlen1) { /* The sequence would be completed in buffer */ + if(strncmp(aKeySequences[i].pszSequence, szCurrentSequence, seqlen2)==0) { + retval=i; + CurrLen=seqlen2; + } + } + else { /* Possible partial sequence */ + if(strncmp(aKeySequences[i].pszSequence, szCurrentSequence, seqlen1)==0) { + return(NO_MATCH); + } + } + } + } + + return(retval); +} + +/* ---------------------------------------------------------------------------- + * ODShiftSeq() *** PRIVATE FUNCTION *** + * + * Shifts szCurrentSequence left the specified number of chars + * + * Parameters: int chars to shift + * + * Return: void + */ +static void ODShiftSeq(int chars) +{ + char *in; + char *out; + + if(!chars) + return; + out=szCurrentSequence; + in=out+chars; + + if(in>strchr(szCurrentSequence,0)) + return; + while(*in) { + *(out++)=*(in++); + } + *out=*in; +} + diff --git a/utils/magiedit/odoors/ODGraph.c b/utils/magiedit/odoors/ODGraph.c new file mode 100644 index 0000000..6d251c3 --- /dev/null +++ b/utils/magiedit/odoors/ODGraph.c @@ -0,0 +1,247 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODGraph.c + * + * Description: Implements special ANSI/AVATAR control functions. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Aug 19, 1995 6.00 BP 32-bit portability. + * 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 Removed oddoor.h, added odcore.h. + * Nov 16, 1995 6.00 BP Moved local vars here from odcore.c. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 13, 1996 6.10 BP Added od_get_cursor(). + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODKrnl.h" + + +/* Local private variables. */ +static char szANSIClearLine[3] = {27, '[', 'K'}; +static char szAvatarClearLine[2] = {22, 7}; + + +/* ---------------------------------------------------------------------------- + * od_clr_line() + * + * Clears the contents of the current line, from the current cursor position + * to the end of the line. This function affects both local and remote + * screens. + * + * Parameters: None. + * + * Return: void + */ +ODAPIDEF void ODCALL od_clr_line(void) +{ + char *pchLine; + INT nCharsLeft; + INT nCount; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_clr_line()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Obtain the current cursor position. */ + ODScrnGetTextInfo(&ODTextInfo); + + /* Calculate the number of columns that are to be erased. */ + nCharsLeft = 80 - ODTextInfo.curx; + + /* If either ANSI or AVATAR mode is available, then we first */ + /* clear the line on the local screen without affecting the */ + /* remote screen. */ + if(od_control.user_avatar || od_control.user_ansi) + { + pchLine = (char *)szODWorkString; + for(nCount = 0; nCount <= nCharsLeft; ++nCount) *pchLine++ = ' '; + *pchLine = '\0'; + ODScrnEnableScrolling(0); + ODScrnDisplayString(szODWorkString); + ODScrnEnableScrolling(1); + ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury); + } + + /* If AVATAR mode is active. */ + if(od_control.user_avatar) + { + /* Transmit the two-character AVATAR clear to end of line sequence. */ + od_disp(szAvatarClearLine, 2, FALSE); + } + + /* If ANSI mode is active. */ + else if(od_control.user_ansi) + { + /* Transmit the three-character ANSI clear to end of line sequence. */ + od_disp(szANSIClearLine, 3, FALSE); + } + + /* If we are operating in plain-ASCII mode. */ + else + { + /* Generate a sequence of space characters followed by backspace */ + /* characters. */ + pchLine = (char *)szODWorkString; + for(nCount = 0; nCount < nCharsLeft; ++nCount) *pchLine++ = ' '; + for(nCount = 0; nCount < nCharsLeft; ++nCount) *pchLine++ = 8; + *pchLine='\0'; + + /* Send this sequence to both the local and remote screens. */ + od_disp(szODWorkString, strlen(szODWorkString), TRUE); + } + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * od_set_cursor() + * + * Moves the position of the cursor on both local and remote screens. This + * function is available in all display modes other than plain-ASCII. + * + * Parameters: nRow - 1-based index of the row to position the cursor in. + * + * nColumn - Index of the column to position the cursor in. + * + * Return: void + */ +ODAPIDEF void ODCALL od_set_cursor(INT nRow, INT nColumn) +{ + static char szControlSequence[40]; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_set_cursor()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check validity of parameters. */ + if(nRow < 1 || nColumn < 1) + { + od_control.od_error = ERR_PARAMETER; + return; + } + + /* If AVATAR mode is on. */ + if(od_control.user_avatar) + { + /* Position the local cursor. */ + ODScrnSetCursorPos((BYTE)nColumn, (BYTE)nRow); + + /* Generate the AVATAR control sequence to position the remote cursor. */ + szControlSequence[0] = 22; + szControlSequence[1] = 8; + szControlSequence[2] = nRow; + szControlSequence[3] = nColumn; + + /* Transmit the AVATAR control sequence to the remote terminal. */ + od_disp(szControlSequence, 4, FALSE); + } + + /* If ANSI mode is on. */ + else if(od_control.user_ansi) + { + /* Generate the ANSI control sequence to position the remote cursor. */ + sprintf(szControlSequence, "x[%d;%dH", nRow, nColumn); + szControlSequence[0] = 27; + + /* Transmit the ANSI control seequence to the remote terminal. */ + od_disp(szControlSequence, strlen(szControlSequence), FALSE); + + /* Position the cursor on the local screen. */ + ODScrnSetCursorPos((BYTE)nColumn, (BYTE)nRow); + } + else + { + /* If neither ANSI nor AVATAR modes are available, indicate this */ + /* in the error code in od_control. */ + od_control.od_error = ERR_NOGRAPHICS; + } + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * od_get_cursor() + * + * Returns our best estimate of the current position of the cursor on the + * remote screen. + * + * Parameters: pnRow - 1-based index of the row to position the cursor in. + * + * pnColumn - Index of the column to position the cursor in. + * + * Return: void + */ +ODAPIDEF void ODCALL od_get_cursor(INT *pnRow, INT *pnColumn) +{ + tODScrnTextInfo TextInfo; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_get_cursor()"); + + /* Ensure that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check for parameter validity. */ + if(pnRow == NULL && pnColumn == NULL) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return; + } + + /* Obtain current state of local screen. */ + ODScrnGetTextInfo(&TextInfo); + + /* Set the caller's parameters to the current row and column, if each */ + /* of these parameters were supplied. */ + if(pnRow != NULL) *pnRow = (INT)TextInfo.cury; + if(pnColumn != NULL) *pnColumn = (INT)TextInfo.curx; + + OD_API_EXIT(); +} diff --git a/utils/magiedit/odoors/ODInEx.h b/utils/magiedit/odoors/ODInEx.h new file mode 100644 index 0000000..ce5f447 --- /dev/null +++ b/utils/magiedit/odoors/ODInEx.h @@ -0,0 +1,450 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODInEx.h + * + * Description: OpenDoors initialization and shutdown operations + * (od_init() and od_exit()), including drop file I/O. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 22, 1995 6.00 BP Created. + * Nov 23, 1995 6.00 BP 32-bit portability. + * Dec 03, 1995 6.00 BP Win32 port. + * Jan 19, 1996 6.00 BP Don't use atexit() under Win32. + * Jan 19, 1996 6.00 BP Make ODInitError() a shared function. + * Jan 20, 1996 6.00 BP Prompt for user name if force_local. + * Feb 02, 1996 6.00 BP Added RA 2.50 EXITINFO.BBS support. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 20, 1996 6.00 BP Added bParsedCmdLine. + * Feb 21, 1996 6.00 BP Don't override command line options. + * Feb 21, 1996 6.00 BP Force single-byte structure alignment. + * Feb 23, 1996 6.00 BP Make DTR disable code shared. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODINEX +#define _INC_ODINEX + +#include "ODPlat.h" + +/* Drop file structures. */ + +/* Force byte alignment, if possible */ +#ifdef __TURBOC__ +#if(__TURBOC__ >= 0x295) +#pragma option -a- +#endif /* __TURBOC__ >= 0x295 */ +#endif /* __TURBOC__ */ +#ifdef _MSC_VER +#pragma pack(1) +#endif /* _MSC_VER */ + +typedef struct +{ + WORD baud; + DWORD num_calls; + char last_caller[36]; + char sLastHandle[36]; /* New to RA 2.50 */ + char extra1[92]; + char start_date[9]; + WORD busyperhour[24]; + WORD busyperday[7]; + char name[36]; + char location[26]; + char organisation[51]; + char address[3][51]; + char handle[36]; + char comment[81]; + DWORD password_crc; + char dataphone[16]; + char homephone[16]; + char lasttime[6]; + char lastdate[9]; + BYTE attrib; + BYTE attrib2; + char flags[4]; + DWORD credit; + DWORD pending; + WORD posted; + WORD sec; + DWORD lastread; + DWORD nocalls; + DWORD ups; + DWORD downs; + DWORD upk; + DWORD downk; + DWORD todayk; + INT16 elapsed; + WORD screenlen; + char lastpwdchange; + WORD group; + WORD combinedrecord[200]; + char firstcall[9]; + char birthday[9]; + char subdate[9]; + BYTE screenwidth; + BYTE language; + BYTE dateformat; + char forwardto[36]; + WORD msgarea; + WORD filearea; + BYTE default_protocol; + WORD file_group; + BYTE last_dob_check; + BYTE sex; + DWORD xirecord; + WORD msg_group; + BYTE btAttribute3; /* New to RA 2.50. */ + char sPassword[16]; /* New to RA 2.50. */ + BYTE extra2[31]; + char status; + char starttime[6]; + char errorlevel; + char days; + char forced; + char lasttimerun[9]; + char netmailentered; + char echomailentered; + char logintime[6]; + char logindate[9]; + INT16 timelimit; + DWORD loginsec; + WORD userrecord; + WORD readthru; + WORD numberpages; + WORD downloadlimit; + char timeofcreation[6]; + DWORD logonpasswordcrc; + BYTE wantchat; + INT16 deducted_time; + char menustack[50][9]; + BYTE menustackpointer; + char extra3[200]; + BYTE error_free; + BYTE sysop_next; + char emsi_session; + char emsi_crtdef[41]; + char emsi_protocols[41]; + char emsi_capabilities[41]; + char emsi_requests[41]; + char emsi_software[41]; + BYTE hold_attr1; + BYTE hold_attr2; + BYTE hold_len; + char page_reason[81]; + BYTE status_line; + char last_cost_menu[9]; + WORD menu_cost_per_min; + BYTE has_avatar; + BYTE has_rip; + BYTE btRIPVersion; /* New to RA 2.50. */ + BYTE btExtraSpace[85]; +} tRA2ExitInfoRecord; + + +typedef struct +{ + WORD baud; + DWORD num_calls; + char last_caller[36]; + char extraspace[128]; + char start_date[9]; + WORD busyperhour[24]; + WORD busyperday[7]; + char uname[36]; + char uloc[26]; + char password[16]; + char dataphone[13]; + char homephone[13]; + char lasttime[6]; + char lastdate[9]; + BYTE attrib; + BYTE flags[4]; + WORD credit; + WORD pending; + WORD posted; + WORD lastread; + WORD sec; + WORD nocalls; + WORD ups; + WORD downs; + WORD upk; + WORD downk; + WORD todayk; + WORD elapsed; + WORD screenlen; + BYTE lastpwdchange; + BYTE attrib2; + BYTE group; + WORD xirecord; + char extra2[3]; + char status; + char starttime[6]; + char errorlevel; + char days; + char forced; + char lasttimerun[9]; + char netmailentered; + char echomailentered; + char logintime[6]; + char logindate[9]; + WORD timelimit; + DWORD loginsec; + DWORD net_credit; + WORD userrecord; + WORD readthru; + WORD numberpages; + WORD downloadlimint; + union + { + struct + { + char timeofcreation[6]; + char logonpassword[16]; + char wantchat; + } ra; + struct + { + char qwantchat; + char gosublevel; + char menustack[20][9]; + char menu[9]; + BYTE screenclear; + BYTE moreprompts; + BYTE graphicsmode; + BYTE externedit; + INT16 screenlength; + BYTE mnpconnect; + char chatreason[49]; + BYTE externlogoff; + BYTE ansicapable; + BYTE ripactive; + BYTE extraspace[199]; + } qbbs; + } bbs; +} tExitInfoRecord; + +typedef struct +{ + INT16 deducted_time; + char menustack[50][9]; + char menustackpointer; + char userhandle[36]; + char comment[81]; + char firstcall[9]; + char combinedrecord[25]; + char birthday[9]; + char subdate[9]; + BYTE screenwidth; + BYTE msgarea; + BYTE filearea; + BYTE language; + BYTE dateformat; + char forwardto[36]; + char extra_space[43]; + char error_free; + char sysop_next; + char emsi_session; + char emsi_crtdef[41]; + char emsi_protocols[41]; + char emsi_capabilities[41]; + char emsi_requests[41]; + char emsi_software[41]; + char hold_attr1; + char hold_attr2; + char hold_len; + char extr_space[100]; +} tExtendedExitInfo; + +struct _pcbsys +{ + char display[2]; /* "-1" = On, " 0" = Off */ + char printer[2]; + char pagebell[2]; + char calleralarm[2]; + char sysopflag; /* ' ', 'N'=sysop next, 'X'=exit to dos */ + char errorcorrection[2]; + char graphicsmode; /* 'Y'=Yes, 'N'=No, '7'=7E1 */ + char nodechat; /* 'A'=available, 'U'=unavailable */ + char dteportspeed[5]; + char connectspeed[5]; /* "Local"=local mode */ + WORD recordnum; + char firstname[15]; + char password[15]; + INT16 logontimeval; /* minutes since midnight */ + INT16 todayused; /* -ve # of minutes */ + char logontime[5]; + INT16 timeallowed; + WORD kallowed; + char conference; + char joined[5]; + char scanned[5]; + INT16 conferenceaddtime; + INT16 creditminutes; + char languageext[4]; + char fullname[25]; + INT16 minutesremaining; + char node; /* ' ' if no network */ + char eventtime[5]; + char eventactive[2]; + char slideevent[2]; + DWORD memmessage; + char comport; /* 0=none, 1-8 */ + char reserved1[2]; + char useansi; /* 1 = yes, 0 = no */ + char lasteventdate[8]; + WORD lasteventminute; + char dosexit; + char eventupcoming; + char stopuploads; + WORD conferencearea; +}; + +struct _userssyshdr +{ + WORD Version; /* PCBoard version number (i.e. 145) */ + DWORD RecNo; /* Record number from USER's file */ + WORD SizeOfRec; /* Size of "fixed" user record */ + WORD NumOfAreas; /* Number of conference areas (Main=1) */ + WORD NumOfBitFields; /* Number of Bit Map fields for conferences */ + WORD SizeOfBitFields; /* Size of each Bit Map field */ + char AppName[15]; /* Name of the Third Party Application */ + WORD AppVersion; /* Version number for the application */ + WORD AppSizeOfRec; /* Size of a "fixed length" record (if any) */ + WORD AppSizeOfConfRec; /* Size of each conference record (if any) */ + DWORD AppRecOffset; /* Offset of AppRec into USERS.INF record */ + char Updated; /* TRUE if USERS.SYS has been updated */ +}; + +struct _pcbflags +{ + int Dirty :1; /* Dirty Flag (meaning file has been updated) */ + int MsgClear :1; /* User's choice for screen clear after messages */ + int HasMail :1; /* Indicates if NEW mail has been left for user */ + int Reserved :5; +}; + +struct _pcbdate +{ + int Day :5; /* 5 bit integer representing the Day */ + int Month :4; /* 4 bit integer representing the Month */ + int Year :7; /* 7 bit integer representing the Year MINUS 80 */ +}; + +struct _userssysrec +{ + char Name[26]; /* Name (NULL terminated) */ + char City[25]; /* City (NULL terminated) */ + char Password[13]; /* Password (NULL terminated) */ + char BusDataPhone[14]; /* Business or Data Phone (NULL terminated) */ + char HomeVoicePhone[14];/* Home or Voice Phone (NULL terminated) */ + WORD LastDateOn; /* Julian date for the Last Date On */ + char LastTimeOn[6]; /* Last Time On (NULL Terminated) */ + char ExpertMode; /* 1=Expert, 0=Novice */ + char Protocol; /* Protocol (A thru Z) */ + struct _pcbflags PackedFlags; + struct _pcbdate DateLastDirRead; + INT16 SecurityLevel; /* Security Level */ + WORD NumTimesOn; /* Number of times the caller has connected */ + char PageLen; /* Page Length when display data on the screen */ + WORD NumUploads; /* Total number of FILES uploaded */ + WORD NumDownloads; /* Total number of FILES downloaded */ + DWORD DailyDnldBytes; /* Number of BYTES downloaded so far today */ + char UserComment[31]; /* Comment field #1 (NULL terminated) */ + char SysopComment[31]; /* Comment field #1 (NULL terminated) */ + INT16 ElapsedTimeOn; /* Number of minutes online */ + WORD RegExpDate; /* Julian date for Registration Expiration Date */ + INT16 ExpSecurityLevel; /* Expired Security Level */ + WORD LastConference; /* Number of the conference the caller was in */ + DWORD TotDnldBytes; /* Total number of BYTES downloaded */ + DWORD TotUpldBytes; /* Total number of BYTES uploaded */ + char DeleteFlag; /* 1=delete this record, 0=keep */ + DWORD RecNum; /* Record Number in USERS.INF file */ + char Reserved[9]; /* Bytes 391-399 from the USERS file */ + DWORD MsgsRead; /* Number of messages the user has read in PCB */ + DWORD MsgsLeft; /* Number of messages the user has left in PCB */ +}; + +/* Restore original structure alignment, if possible. */ +#ifdef _MSC_VER +#pragma pack() +#endif /* _MSC_VER */ + + +/* od_init() and od_exit() global helper functons. */ +#ifndef ODPLAT_WIN32 +void ODAtExitCallback(void); +#endif /* !ODPLAT_WIN32 */ +INT ODWriteExitInfoPrimitive(FILE *pfDropFile, INT nCount); +BOOL ODReadExitInfoPrimitive(FILE *pfDropFile, INT nCount); +INT ODSearchForDropFile(char **papszFileNames, INT nNumFileNames, + char *pszFound, char *pszDirectory); +void ODInitError(char *pszErrorText); +#ifdef ODPLAT_WIN32 +BOOL CALLBACK ODInitLoginDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam); +void ODInExDisableDTR(void); +#endif /* ODPLAT_WIN32 */ + + +/* Global variables. */ +extern WORD wODNodeNumber; +extern BOOL bIsCoSysop; +extern BOOL bIsSysop; +extern char *apszDropFileInfo[25]; +extern BYTE btExitReason; +extern DWORD dwForcedBPS; +extern INT nForcedPort; +extern DWORD dwFileBPS; +extern char szDropFilePath[120]; +extern char szExitinfoBBSPath[120]; +extern INT16 nInitialElapsed; +extern char *szOriginalDir; +extern BYTE btDoorSYSLock; +extern time_t nStartupUnixTime; +extern INT16 nInitialRemaining; +extern BOOL bSysopNameSet; +extern char szForcedSysopName[40]; +extern BOOL bSystemNameSet; +extern char szForcedSystemName[40]; +extern BOOL bUserFull; +extern BOOL bCalledFromConfig; +extern tRA2ExitInfoRecord *pRA2ExitInfoRecord; +extern tExitInfoRecord *pExitInfoRecord; +extern tExtendedExitInfo *pExtendedExitInfo; +extern struct _pcbsys *pPCBoardSysRecord; +extern struct _userssyshdr *pUserSysHeader; +extern struct _userssysrec *pUserSysRecord; +extern BOOL bPreOrExit; +extern BOOL bRAStatus; +extern BOOL bPromptForUserName; +extern BOOL bParsedCmdLine; +extern WORD wPreSetInfo; +#ifdef ODPLAT_WIN32 +extern tODThreadHandle hFrameThread; +#endif /* ODPLAT_WIN32 */ + + +/* wPreSetInfo flags. */ +#define PRESET_BPS 0x0001 +#define PRESET_PORT 0x0002 +#define PRESET_REQUIRED (PRESET_BPS | PRESET_PORT) + + +#endif /* _INC_ODINEX */ diff --git a/utils/magiedit/odoors/ODInEx1.c b/utils/magiedit/odoors/ODInEx1.c new file mode 100644 index 0000000..41722cf --- /dev/null +++ b/utils/magiedit/odoors/ODInEx1.c @@ -0,0 +1,2519 @@ +/* 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: ODInEx1.c + * + * Description: Performs OpenDoors initialization and shutdown operations + * (od_init() and od_exit()), including drop file I/O. This + * module is broken into two files, ODInEx1.c and ODInEx2.c. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 19, 1994 6.00 BP Default paging hours 8:00-22:00. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Oct 29, 1994 6.00 BP Properly read dorinfo?.def BBS name. + * Oct 31, 1994 6.00 BP Only use dorinfo?.def /w exitinfo.bbs. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 31, 1994 6.00 BP Remove call to _mt_init(). + * Dec 31, 1994 6.00 BP Add call to ODPlatInit(). + * Jul 30, 1995 6.00 BP Split up od_init(). + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 14, 1995 6.00 BP New default for od_colour_char is 0. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Nov 23, 1995 6.00 BP Moved Pascal conversion to odutil.c. + * Dec 21, 1995 6.00 BP Add ability to use already open port. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Dec 30, 1995 6.00 BP Only use comm idle func under DOS. + * Jan 01, 1996 6.00 BP Added od_disable_dtr. + * Jan 01, 1996 6.00 BP Raise DTR after opening serial port. + * Jan 02, 1996 6.00 BP Use printf() in ODInitError(). + * Jan 03, 1996 6.00 BP Display connect speed with %lu. + * Jan 19, 1996 6.00 BP Don't use atexit() under Win32. + * Jan 19, 1996 6.00 BP Make ODInitError() a shared function. + * Jan 20, 1996 6.00 BP Prompt for user name if force_local. + * Jan 23, 1996 6.00 BP Added od_exiting and OD_TEXTMODE. + * Jan 31, 1996 6.00 BP Added DIS_NAME_PROMPT. + * Jan 31, 1996 6.00 BP Support new SFDOORS.DAT format. + * Feb 02, 1996 6.00 BP Added RA 2.50 EXITINFO.BBS support. + * Feb 06, 1996 6.00 BP Added od_silent_mode. + * Feb 08, 1996 6.00 BP Recognize SFSYSOP.DAT. + * Feb 09, 1996 6.00 BP Correctly translate RA 2.x sex field. + * Feb 09, 1996 6.00 BP Made default outbound buffer 3072. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 20, 1996 6.00 BP Added bParsedCmdLine. + * Feb 21, 1996 6.00 BP Don't override command line options. + * Feb 21, 1996 6.00 BP Change od_always_clear default to on. + * Feb 23, 1996 6.00 BP Changed default DTR disable string. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Added TRIBBS.SYS support. + * Mar 06, 1996 6.10 BP Initial support for Door32 interface. + * Mar 13, 1996 6.10 BP Added od_local_win_col. + * Mar 17, 1996 6.10 BP Reset text color after local login. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Apr 08, 1996 6.10 BP Store local login name in user_handle. + * Jan 13, 1997 6.10 BP Fixes for Door32 support. + * Oct 19, 2001 6.20 RS Added door32.sys and socket support. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#ifdef ODPLAT_NIX +#include +#include +#include +#include +#endif +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODInQue.h" +#include "ODKrnl.h" +#include "ODInEx.h" +#include "ODUtil.h" +#ifdef ODPLAT_WIN32 +#include "ODFrame.h" +#include "ODRes.h" +#endif /* ODPLAT_WIN32 */ + +/* Default size of local/remote combined keyboard buffer. */ +#define DEFAULT_EVENT_QUEUE_SIZE 128 + + +/* Local private helper functions. */ +static void ODInitReadExitInfo(void); +static void ODInitPartTwo(void); +static BOOL ODInitReadSFDoorsDAT(void); +static void ODInitPartTwo(void); + + +/* Private variables. */ +static BYTE btRAStatusToSet = 0; +#ifndef ODPLAT_WIN32 +static BOOL bPreset = TRUE; +#endif /* !ODPLAT_WIN32 */ +static char szIFTemp[256]; + +/* Configuration file keywords. */ +static char *apszConfigText[] = +{ + "Node", + "BBSDir", + "DoorDir", + "LogFileName", + "DisableLogging", + "SundayPagingHours", + "MondayPagingHours", + "TuesdayPagingHours", + "WednesdayPagingHours", + "ThursdayPagingHours", + "FridayPagingHours", + "SaturdayPagingHours", + "MaximumDoorTime", + "SysopName", + "SystemName", + "SwappingDisable", + "SwappingDir", + "SwappingNoEMS", + "LockedBPS", + "SerialPort", + "CustomFileName", + "CustomFileLine", + "InactivityTimeout", + "PageDuration", + "ChatUserColour", + "ChatSysopColour", + "FileListTitleColour", + "FileListNameColour", + "FileListSizeColour", + "FileListDescriptionColour", + "FileListOfflineColour", + "Personality", + "NoFossil", + "PortAddress", + "PortIRQ", + "ReceiveBuffer", + "TransmitBuffer", + "PagePromptColour", + "LocalMode", + "PopupMenuTitleColour", + "PopupMenuBorderColour", + "PopupMenuTextColour", + "PopupMenuKeyColour", + "PopupMenuHighlightColour", + "PopupMenuHighKeyColour", + "NoFIFO", + "FIFOTriggerSize", + "DisableDTR", + "NoDTRDisable", +}; + +/* Custom drop file keywords. */ +static char *apszConfigLines[] = +{ + "Ignore", + "ComPort", + "FossilPort", + "ModemBPS", + "LocalMode", + "UserName", + "UserFirstName", + "UserLastName", + "Alias", + "HoursLeft", + "MinutesLeft", + "SecondsLeft", + "ANSI", + "AVATAR", + "PagePausing", + "ScreenLength", + "ScreenClearing", + "Security", + "City", + "Node", + "SysopName", + "SysopFirstName", + "SysopLastName", + "SystemName", + "RIP", +}; + +/* Logfile messages. */ +static char *apszLogMessages[] = +{ + "Carrier lost, exiting door", + "System operator terminating call, exiting door", + "User's time limit expired, exiting door", + "User keyboard inactivity time limit exceeded, exiting door", + "System operator returning user to BBS, exiting door", + "Exiting door with errorlevel %d", + "Invoking operating system shell", + "Returning from operating system shell", + "User paging system operator", + "Entering sysop chat mode", + "Terminating sysop chat mode", + "%s entering door", + "Reason for chat: %s", + "Exiting door", +}; + +/* Color name strings. */ +static char *apszColorNames[] = +{ + "BLACK", + "BLUE", + "GREEN", + "CYAN", + "RED", + "MAGENTA", + "YELLOW", + "WHITE", + "BROWN", + "GREY", + "BRIGHT", + "FLASHING", +}; + +/* Array of door information (drop) file names to search for. */ +static char *apszDropFileNames[] = +{ + "exitinfo.bbs", + "dorinfo1.def", + "chain.txt", + "sfdoors.dat", + "door.sys", + "callinfo.bbs", + "sfmain.dat", + "sffile.dat", + "sfmess.dat", + "sfsysop.dat", + "tribbs.sys", + "door32.sys", +}; + +/* Array of door information (drop) file numbers + * (corresponding to apszDropFileNames) + */ +enum { + FOUND_EXITINFO_BBS, + FOUND_DORINFO1_DEF, + FOUND_CHAIN_TXT, + FOUND_SFDOORS_DAT, + FOUND_DOOR_SYS, + FOUND_CALLINFO_BBS, + FOUND_SFMAIN_DAT, + FOUND_SFFILE_DAT, + FOUND_SFMESS_DAT, + FOUND_SFSYSOP_DAT, + FOUND_TRIBBS_SYS, + FOUND_DOOR32_SYS, +}; + +#define FOUND_NONE -1 + + +/* Global variables. */ +WORD wODNodeNumber = 65535U; +BOOL bIsCoSysop; +BOOL bIsSysop; +char *apszDropFileInfo[25]; +BYTE btExitReason = 0; +DWORD dwForcedBPS = 1; +INT nForcedPort = -1; +DWORD dwFileBPS; +char szDropFilePath[120]; +char szExitinfoBBSPath[120]; +INT16 nInitialElapsed; +char *szOriginalDir = NULL; +BYTE btDoorSYSLock = 0; +time_t nStartupUnixTime; +INT16 nInitialRemaining; +BOOL bSysopNameSet = FALSE; +char szForcedSysopName[40]; +BOOL bSystemNameSet = FALSE; +char szForcedSystemName[40]; +BOOL bUserFull = FALSE; +BOOL bCalledFromConfig = FALSE; +tRA2ExitInfoRecord *pRA2ExitInfoRecord = NULL; +tExitInfoRecord *pExitInfoRecord = NULL; +tExtendedExitInfo *pExtendedExitInfo = NULL; +struct _pcbsys *pPCBoardSysRecord = NULL; +struct _userssyshdr *pUserSysHeader = NULL; +struct _userssysrec *pUserSysRecord = NULL; +BOOL bPreOrExit = FALSE; +BOOL bRAStatus; +BOOL bPromptForUserName = FALSE; +BOOL bParsedCmdLine = FALSE; +WORD wPreSetInfo = 0; +#ifdef ODPLAT_WIN32 +tODThreadHandle hFrameThread; +#endif /* ODPLAT_WIN32 */ + + +/* ---------------------------------------------------------------------------- + * od_init() + * + * Starts up OpenDoors. Initializes various members of od_control, reads the + * BBS door information (drop file), initializes the serial port and carries + * out other operations that must be done at initialization time. May be + * explicitly called by the user, or called as a result of the first call to + * some other OpenDoors API function. + * + * Parameters: none + * + * Return: void + */ +ODAPIDEF void ODCALL od_init(void) +{ + BYTE btCount; + FILE *pfDropFile=NULL; + char *pointer; + INT nFound = FOUND_NONE; +#ifdef _WIN32 + float forcefloats; + + forcefloats=1.1; +#endif + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_init()"); + + /* If a callback function is active, then don't do anything. */ + if(bIsCallbackActive) return; + + /* If we are not being called from within ODConfigInit(). */ + if(!bCalledFromConfig) + { + /* If OpenDoors has already been initialized, then return without */ + /* doing anything. */ + if(bODInitialized) return; + + /* Otherwise, set the initialized flag so that od_init() won't be */ + /* run again. */ + bODInitialized = TRUE; + + /* Initialize program name string. */ + if(od_control.od_prog_name[0] == '\0') + { + strcpy(od_control.od_prog_name, OD_VER_SHORTNAME); + } + + /* Initialize color name strings in od_control. */ + for(btCount = 0; btCount < DIM(apszColorNames); ++btCount) + { + if(!*od_control.od_color_names[btCount]) + { + strcpy(od_control.od_color_names[btCount], + apszColorNames[btCount]); + } + } + + /* Initialize custom drop file strings in od_control. */ + for(btCount = 0; btCount < LINES_SIZE; ++btCount) + { + if(!*od_control.od_cfg_lines[btCount]) + { + strcpy(od_control.od_cfg_lines[btCount], apszConfigLines[btCount]); + } + } + + /* Initialize configuration keyword strings in od_control. */ + for(btCount = 0; btCount < TEXT_SIZE; ++btCount) + { + if(!*od_control.od_cfg_text[btCount]) + { + strcpy(od_control.od_cfg_text[btCount], apszConfigText[btCount]); + } + } + + /* Enable multiple personality system if it has been installed. */ +#ifdef OD_TEXTMODE + if(od_control.od_mps != NULL) + { + (*(OD_COMPONENT_CALLBACK *)od_control.od_mps)(); + } +#endif /* !OD_TEXTMODE */ + + /* If baud rate has been set in od_control, then remember the forced */ + /* rate for later use. */ + if(od_control.baud != 0) + { + dwForcedBPS = od_control.baud; + } + + /* If the serial port number has already been set in od_control, then */ + /* remember the forced port number for later use. */ + if(od_control.port != 0) + { + nForcedPort = od_control.port; + } + + /* If the configuration file system has been installed, then allow */ + /* the configuration file initialization routine take over */ + /* initialization from here. Once it has read the configuration file */ + /* it will call od_init() again, at which time od_init() will carry */ + /* on from this point in the code. */ + if(od_control.config_file != NULL) + { + (*(OD_COMPONENT_CALLBACK *)od_control.config_file)(); + return; + } + } + + /* Initialize the OpenDoors platform-specific utility functions. */ + ODPlatInit(); + + /* Store the time of door startup. */ + time(&nStartupUnixTime); + + /* Allocate the set of strings that are used to store certain parts */ + /* of drop files for rewriting at od_exit() time. */ + for(btCount = 0; btCount < DIM(apszDropFileInfo); ++btCount) + { + if((apszDropFileInfo[btCount] = (char *)malloc(81)) == NULL) + { +malloc_error: + ODInitError("Insufficient memory available to start up program."); + exit(od_control.od_errorlevel[1]); + } + } + + /* Determine the current node number. */ + if((pointer=getenv("TASK")) != NULL) + { + od_control.od_node = atoi(pointer); + } + else if((pointer=getenv("SBBSNNUM")) != NULL) + { + od_control.od_node = atoi(pointer); + } + else if(wODNodeNumber != 65535U) + { + od_control.od_node = wODNodeNumber; + } + else if(od_control.od_node == 0) + { + od_control.od_node = 1; + } + + /* If a custom drop file format is not being used, then set certain */ + /* od_control members to their default values. In the case where */ + /* a custom drop file format is being used, these values will already */ + /* have been set, and so we don't want to touch them. */ + if(od_control.od_info_type != CUSTOM) + { + od_control.user_avatar = FALSE; + od_control.user_rip = FALSE; + od_control.user_attribute = 0x06; + od_control.user_screen_length = 23; + od_control.user_screenwidth = 80; + od_control.od_page_pausing = TRUE; + od_control.od_page_len = 15; + } + else + { + /* When a custom drop file is being used, there are certain */ + /* variables that we must initialize if they weren't already set */ + /* when the custom drop file was read. */ + if(od_control.user_timelimit == 0) od_control.user_timelimit = 60; +#ifdef ODPLAT_NIX + if(od_control.port == -1) od_control.baud = 1L; +#else + if(od_control.port == -1) od_control.baud = 0L; +#endif + } + + /* Setup inbound local/remote buffer. */ + if(ODInQueueAlloc(&hODInputQueue, od_control.od_in_buf_size == 0 ? + DEFAULT_EVENT_QUEUE_SIZE : od_control.od_in_buf_size) != kODRCSuccess) + { + goto malloc_error; + } + + /* Enable user's keyboard by default. */ + od_control.od_user_keyboard_on = TRUE; + + /* If door information (drop) file reading has been disabled, then */ + /* don't attempt to read any drop file. */ + if(od_control.od_disable & DIS_INFOFILE) + { + od_control.od_info_type = NO_DOOR_FILE; + } + + /* Otherwise, if the local mode override has been explicitly asked for, */ + /* setup od_control for default local mode operation. */ + else if(od_control.od_force_local) + { +force_local: + /* No door information file is being used. */ + od_control.od_info_type = NO_DOOR_FILE; + + /* Operate in local mode. */ +#ifdef ODPLAT_NIX + od_control.baud = 1L; +#else + od_control.baud = 0L; +#endif + + if(!bParsedCmdLine) + { + /* Enable ANSI mode. */ + od_control.user_ansi = TRUE; + + /* Default to 60 minutes of time available. */ + od_control.user_timelimit = 60; + } + + /* Choose the appropriate system name. */ + if(bSystemNameSet) + { + strcpy(od_control.user_location, szForcedSystemName); + } + else if(od_control.system_name[0] != '\0') + { + strcpy(od_control.user_location, od_control.system_name); + } + else + { + strcpy(od_control.user_location, "Unknown Location"); + } + } + + /* If drop file reading isn't disable, if a custom format drop file */ + /* hasn't already been read and automatic local mode hasn't been */ + /* specified, then attempt to find and read a standard drop file. */ + else if(od_control.od_info_type != CUSTOM) + { + /* Generate the name of the dorinfox.def file for this node. */ + if(od_control.od_node > 35) + { + apszDropFileNames[1] = (char *)"dorinfo1.def"; + } + else if(od_control.od_node > 9) + { + sprintf(szIFTemp, "dorinfo%c.def", od_control.od_node + 55); + apszDropFileNames[1] = (char *)szIFTemp; + } + else + { + sprintf(szIFTemp, "dorinfo%d.def", od_control.od_node); + apszDropFileNames[1] = (char *)szIFTemp; + } + + nFound = FOUND_NONE; + + if(!ODFileAccessMode(od_control.info_path, 4)) + { + /* Check for a DORINFOx.DEF filename. */ + if(ODStringHasTail(od_control.info_path, ".def") && + strlen(od_control.info_path) >= strlen(apszDropFileNames[2]) && + strnicmp((char *)&od_control.info_path + + (strlen(od_control.info_path) - 12), "dorinfo", 7) == 0) + { + nFound = FOUND_DORINFO1_DEF; + strcpy(szDropFilePath, od_control.info_path); + } + else + { + /* Check filenames other than DORINFOx.DEF */ + for(btCount = 0; btCount < DIM(apszDropFileNames); ++btCount) + { + if(ODStringHasTail(od_control.info_path, + apszDropFileNames[btCount])) + { + strcpy(szDropFilePath, od_control.info_path); + nFound = btCount; + break; + } + } + } + } + + /* Search for a door information file. */ + if(nFound == FOUND_NONE) + { + nFound = ODSearchForDropFile((char **)&apszDropFileNames, + DIM(apszDropFileNames), (char *)&szDropFilePath, + (char *)&szExitinfoBBSPath); + } + + if(nFound == FOUND_EXITINFO_BBS) + { + od_control.od_info_type = NO_DOOR_FILE; + ODInitReadExitInfo(); + if(od_control.od_info_type == NO_DOOR_FILE) + { + goto DropFileFail; + } + + ODMakeFilename(szODWorkString, szExitinfoBBSPath, "dorinfo1.def", + sizeof(szExitinfoBBSPath)); + if((pfDropFile = fopen(szODWorkString, "r")) == NULL) + { + goto DropFileFail; + } + + goto read_dorinfox; + } + + else if(nFound==FOUND_DORINFO1_DEF) + { + /* Open DORINFO?.DEF. */ + if((pfDropFile = fopen(szDropFilePath, "r")) == NULL) goto DropFileFail; + + /* Set door type to DORINFO. */ + od_control.od_info_type = DORINFO1; + +read_dorinfox: + /* If not able to read first line. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) + { + goto DropFileFail; + } + + if(szIFTemp[strlen(szIFTemp) - 1] == '\n') + { + szIFTemp[strlen(szIFTemp) - 1] = '\0'; + } + if(szIFTemp[strlen(szIFTemp) - 1] == '\r') + { + szIFTemp[strlen(szIFTemp) - 1] = '\0'; + } + strncpy(od_control.system_name, szIFTemp, 39); + od_control.system_name[39] = '\0'; + + /* get sysop name from DORINFO1.DEF */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + ODStringToName(szIFTemp); + strncpy(od_control.sysop_name, szIFTemp, 19); + + /* get sysop's last name */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(szIFTemp); + if(strlen(szIFTemp)) + { + strcat(od_control.sysop_name," "); + strncat(od_control.sysop_name,szIFTemp,19); + } + /* get com port that modem is connected to */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.port=szIFTemp[3]-'1'; + /* determine BPS rate of connection */ + if(fgets((char *)apszDropFileInfo[0],255,pfDropFile)==NULL) goto DropFileFail; +#ifdef ODPLAT_NIX + od_control.baud= (od_control.port == -1) ? 1 : atol((char *)apszDropFileInfo[0]); +#else + od_control.baud= (od_control.port == -1) ? 0 : atol((char *)apszDropFileInfo[0]); +#endif + + if(fgets((char *)apszDropFileInfo[1],80,pfDropFile)==NULL) goto DropFileFail; + + /* get user's first name */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(szIFTemp); + strncpy(od_control.user_name,szIFTemp,17); + /* get user's last name */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(szIFTemp); + if(strlen(szIFTemp)) + { + strcat(od_control.user_name," "); + strncat(od_control.user_name,szIFTemp,17); + } + /* get user's location */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(szIFTemp); + strncpy(od_control.user_location,szIFTemp,25); + /* get ANSI mode settings */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(szIFTemp[0]=='0') od_control.user_ansi=FALSE; + else od_control.user_ansi=TRUE; + /* get user security level */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_security=atoi(szIFTemp); + /* get time left in door */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_timelimit=atoi(szIFTemp); + fclose(pfDropFile); + } + /* Read CHAIN.TXT */ + else if(nFound==FOUND_CHAIN_TXT) + { + if((pfDropFile=fopen(szDropFilePath,"r"))==NULL) goto DropFileFail; + + od_control.od_info_type=CHAINTXT; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_num=atoi(szIFTemp); + + if(fgets((char *)&od_control.user_handle,35,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(od_control.user_handle); + + if(fgets((char *)&od_control.user_name,35,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(od_control.user_name); + + if(fgets((char *)&od_control.user_callsign,12,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(od_control.user_callsign); + + if(fgets((char *)apszDropFileInfo[0],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_sex=szIFTemp[0]; + + if(fgets((char *)apszDropFileInfo[1],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + strncpy(od_control.user_lastdate,szIFTemp,8); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_screenwidth=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_screen_length=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_security=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + bIsSysop=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + bIsCoSysop=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_ansi=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; /* non-zero if remote */ + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_timelimit=atoi(szIFTemp); + od_control.user_timelimit/=60; + + if(fgets((char *)apszDropFileInfo[3],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets((char *)apszDropFileInfo[4],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets((char *)apszDropFileInfo[5],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(strcmp(szIFTemp,"KB")==0) + { +#ifdef ODPLAT_NIX + od_control.baud=1; +#else + od_control.baud=0; +#endif + } + else + { + od_control.baud=atol(szIFTemp); + } + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.port=atoi(szIFTemp)-1; + + if(fgets((char *)apszDropFileInfo[6],80,pfDropFile)==NULL) goto DropFileFail; + + if(fgets((char *)&od_control.user_password,15,pfDropFile)==NULL) goto DropFileFail; + ODStringToName(od_control.user_password); + + if(fgets((char *)apszDropFileInfo[2],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[7],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[8],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[9],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[10],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[11],80,pfDropFile)==NULL) goto DropFileFail; + if(fgets((char *)apszDropFileInfo[12],80,pfDropFile)==NULL) goto DropFileFail; + + fclose(pfDropFile); + } + + else if(nFound == FOUND_SFDOORS_DAT + || nFound == FOUND_SFMAIN_DAT + || nFound == FOUND_SFFILE_DAT + || nFound == FOUND_SFMESS_DAT + || nFound == FOUND_SFSYSOP_DAT) + { + od_control.od_info_type = SFDOORSDAT; + + if(!ODInitReadSFDoorsDAT()) + { + goto DropFileFail; + } + } + + else if(nFound==FOUND_DOOR_SYS) + { + if((pfDropFile=fopen(szDropFilePath,"r"))==NULL) goto DropFileFail; + + /* Read line 1. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(szIFTemp[0]=='C' && szIFTemp[1]=='O' && szIFTemp[2]=='M' && szIFTemp[4]==':') + { /* GAP style DOOR.SYS */ + od_control.od_info_type=DOORSYS_GAP; + + od_control.port=szIFTemp[3]-'1'; + + /* Check for COM0:STDIO */ + if(!strncmp(szIFTemp,"COM0:STDIO",10)) + od_control.od_com_method=COM_STDIO; + + /* Check for COM0:SOCKET### */ + if(!strncmp(szIFTemp,"COM0:SOCKET",11)) { + od_control.od_com_method=COM_SOCKET; + od_control.od_use_socket = TRUE; + od_control.od_open_handle=atoi(szIFTemp+11); + } + + /* Check for COM0:HANDLE### */ + if(!strncmp(szIFTemp,"COM0:HANDLE",11)) { + od_control.od_com_method=COM_WIN32; + od_control.od_open_handle=atoi(szIFTemp+11); + } + + /* Read line 2. */ + if(fgets((char *)apszDropFileInfo[0], 80, pfDropFile) == NULL) + { + goto DropFileFail; + } + od_control.od_connect_speed = atol(apszDropFileInfo[0]); + + /* Read line 3. */ + if(fgets((char *)apszDropFileInfo[1],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 4. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_node = atoi(szIFTemp); + + /* Read line 5. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + strupr(szIFTemp); + if(strchr(szIFTemp, 'N') != NULL) + { + btDoorSYSLock = 1; + od_control.baud = atol(apszDropFileInfo[0]); + } + else if(strchr(szIFTemp, 'Y') != NULL) + { + btDoorSYSLock = 2; + od_control.baud = 19200; + } + else + { + od_control.baud = atol(szIFTemp); + } + +#ifdef ODPLAT_NIX + if(od_control.port == -1) od_control.baud = 1L; +#else + if(od_control.port == -1) od_control.baud = 0L; +#endif + + /* Read line 6. */ + if(fgets((char *)apszDropFileInfo[3],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 7. */ + if(fgets((char *)apszDropFileInfo[4],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 8. */ + if(fgets((char *)apszDropFileInfo[5],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 9. */ + if(fgets((char *)apszDropFileInfo[22],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 10. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[35]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_name,szIFTemp); + + /* Read line 11. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[25]='\0'; + if(szIFTemp[strlen(szIFTemp)-1]=='\n') szIFTemp[strlen(szIFTemp)-1]='\0'; + if(szIFTemp[strlen(szIFTemp)-1]=='\r') szIFTemp[strlen(szIFTemp)-1]='\0'; + strcpy(od_control.user_location,szIFTemp); + + /* Read line 12. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_homephone,szIFTemp); + + /* Read line 13. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_dataphone,szIFTemp); + + /* Read line 14. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + if(szIFTemp[strlen(szIFTemp)-1]=='\n') szIFTemp[strlen(szIFTemp)-1]='\0'; + if(szIFTemp[strlen(szIFTemp)-1]=='\r') szIFTemp[strlen(szIFTemp)-1]='\0'; + strcpy(od_control.user_password,szIFTemp); + + /* Read line 15. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_security=atoi(szIFTemp); + + /* Read line 16. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_numcalls=atoi(szIFTemp); + + /* Read line 17. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_lastdate,szIFTemp); + + /* Read line 18. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 19. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_timelimit=atoi(szIFTemp); + + /* Read line 20. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + strupr(szIFTemp); + if(!strcmp(szIFTemp,"RIP")) + { + od_control.user_rip=TRUE; + od_control.user_ansi=TRUE; + } + else if(szIFTemp[0]=='G') + { + od_control.user_rip=FALSE; + od_control.user_ansi=TRUE; + } + else + { + od_control.user_rip=FALSE; + od_control.user_ansi=FALSE; + } + + /* Read line 21. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_screen_length=atoi(szIFTemp); + + /* Read line 22. */ + if(fgets((char *)apszDropFileInfo[8],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 23. */ + if(fgets((char *)apszDropFileInfo[9],80,pfDropFile)==NULL) goto DropFileFail; + if(apszDropFileInfo[9][strlen(apszDropFileInfo[9])-1]!='\n') + { + int ch; + apszDropFileInfo[9][strlen(apszDropFileInfo[9])-1]='\n'; + do + { + ch = fgetc(pfDropFile); + } while(ch != '\n' && ch != EOF); + } + + /* Read line 24. */ +again: + if(fgets((char *)apszDropFileInfo[10],80,pfDropFile)==NULL) goto DropFileFail; + if(strchr(apszDropFileInfo[10],',')!=NULL) goto again; + + /* Read line 25. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_subdate,szIFTemp); + + /* Read line 26. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_num=atoi(szIFTemp); + + /* Read line 27. */ + if(fgets((char *)apszDropFileInfo[6],80,pfDropFile)==NULL) goto DropFileFail; + + /* Read line 28. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_uploads=atoi(szIFTemp); + + /* Read line 29. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_downloads=atoi(szIFTemp); + + /* Read line 30. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_todayk=atoi(szIFTemp); + + /* Read line 31. */ + if(fgets((char *)apszDropFileInfo[21],80,pfDropFile)==NULL) goto DropFileFail; + + + /* Beginning of extending DOOR.SYS data */ + /* Read line 32. */ + fgets((char *)apszDropFileInfo[7],80,pfDropFile); + /* Read line 33. */ + fgets((char *)apszDropFileInfo[11],80,pfDropFile); + /* Read line 34. */ + fgets((char *)apszDropFileInfo[12],80,pfDropFile); + /* Read line 35. */ + fgets((char *)apszDropFileInfo[13],80,pfDropFile); + /* Read line 36. */ + if(fgets((char *)apszDropFileInfo[14],80,pfDropFile)!=NULL) + { + /* Read line 37. */ + strncpy(od_control.user_birthday,apszDropFileInfo[7],8); + od_control.user_birthday[8]='\0'; + + /* Read line 38. */ + strncpy(od_control.sysop_name,apszDropFileInfo[13],39); + od_control.sysop_name[39]='\0'; + ODStringToName(od_control.sysop_name); + + /* Read line 39. */ + strncpy(od_control.user_handle,apszDropFileInfo[14],35); + od_control.user_handle[35]='\0'; + ODStringToName(od_control.user_handle); + + /* Read line 40. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + strncpy(od_control.event_starttime, szIFTemp, 5); + od_control.event_starttime[5] = '\0'; + + /* Read line 41. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + if(szIFTemp[0]=='y' || szIFTemp[0]=='Y') + od_control.user_error_free=TRUE; + else + od_control.user_error_free=FALSE; + + /* Read line 42. */ + if(fgets((char *)apszDropFileInfo[7],80,pfDropFile)==NULL) goto finished; + /* Read line 43. */ + if(fgets((char *)apszDropFileInfo[13],80,pfDropFile)==NULL) goto finished; + /* Read line 44. */ + if(fgets((char *)apszDropFileInfo[14],80,pfDropFile)==NULL) goto finished; + /* Read line 45. */ + if(fgets((char *)apszDropFileInfo[15],80,pfDropFile)==NULL) goto finished; + /* Read line 46. */ + if(fgets((char *)apszDropFileInfo[16],80,pfDropFile)==NULL) goto finished; + + /* Read line 47. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + strncpy(od_control.user_logintime,szIFTemp,5); + od_control.user_logintime[5]='\0'; + + /* Read line 48. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + strncpy(od_control.user_lasttime,szIFTemp,5); + od_control.user_lasttime[5]='\0'; + + /* Read line 49. */ + if(fgets((char *)apszDropFileInfo[18],80,pfDropFile)==NULL) goto finished; + + /* Read line 50. */ + if(fgets((char *)apszDropFileInfo[19],80,pfDropFile)==NULL) goto finished; + + /* Read line 51. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + od_control.user_upk=atoi(szIFTemp); + + /* Read line 52. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + od_control.user_downk=atoi(szIFTemp); + + /* Read line 53. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + strncpy(od_control.user_comment,szIFTemp,79); + od_control.user_comment[79]='\0'; + if(od_control.user_comment[strlen(od_control.user_comment)-1]=='\n') + od_control.user_comment[strlen(od_control.user_comment)-1]='\0'; + if(od_control.user_comment[strlen(od_control.user_comment)-1]=='\r') + od_control.user_comment[strlen(od_control.user_comment)-1]='\0'; + + /* Read line 54. */ + if(fgets((char *)apszDropFileInfo[20],80,pfDropFile)==NULL) goto finished; + + /* Read line 55. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto finished; + od_control.user_messages=atoi(szIFTemp); + + + od_control.od_info_type=DOORSYS_WILDCAT; + } + } + + else /* DoorWay style DOOR.SYS */ + { + od_control.od_info_type=DOORSYS_DRWY; + + szIFTemp[35]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_name,szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.port=szIFTemp[0]-'1'; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(od_control.port==-1) + { +#ifdef ODPLAT_NIX + od_control.baud=1L; +#else + od_control.baud=0L; +#endif + } + else + { + od_control.baud=atol(szIFTemp); + } + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_timelimit=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(szIFTemp[0]=='G') + { + od_control.user_ansi=TRUE; + } + else + { + od_control.user_ansi=FALSE; + } + } +finished: + fclose(pfDropFile); + } + + else if(nFound==FOUND_CALLINFO_BBS) + { + if((pfDropFile=fopen(szDropFilePath,"r"))==NULL) goto DropFileFail; + + od_control.od_info_type=CALLINFO; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[35]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_name,szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[25]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_location,szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_security=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_timelimit=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(szIFTemp[0]=='M') + { + od_control.user_ansi=FALSE; + } + else + { + od_control.user_ansi=TRUE; + } + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_password,szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_homephone,szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_screen_length=atoi(szIFTemp); + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.port=szIFTemp[3]-'1'; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.baud=atol(szIFTemp); + + fclose(pfDropFile); + } + else if(nFound == FOUND_TRIBBS_SYS) + { + /* We have found reading a TRIBBS.SYS file. */ + + /* Attempt to open the file. */ + if((pfDropFile = fopen(szDropFilePath, "r")) == NULL) + { + goto DropFileFail; + } + + /* Record the drop file type being used. */ + od_control.od_info_type = TRIBBSSYS; + + /* Read line 1: User's number. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_num = atoi(szIFTemp); + + /* Read line 2: User's name. */ + if(fgets((char *)&od_control.user_name, 35, pfDropFile) == NULL) + { + goto DropFileFail; + } + ODStringToName(od_control.user_name); + + /* Read line 3: User's password. */ + if(fgets((char *)&od_control.user_password, 15, pfDropFile) == NULL) + { + goto DropFileFail; + } + + /* Read line 4: User's security level. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_security = atoi(szIFTemp); + + /* Read line 5: "Y" for expert mode, "N" for novice mode. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_expert = (szIFTemp[0] == 'Y'); + + /* Read line 6: "Y" for ANSI, "N" for TTY. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_ansi = (szIFTemp[0] == 'Y'); + + /* Read line 7: Minutes remaining for this call. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_timelimit = atoi(szIFTemp); + + /* Read line 8: User's phone number. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + szIFTemp[15] = '\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_homephone, szIFTemp); + + /* Read line 9: User's location. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + ODStringToName(szIFTemp); + strncpy(od_control.user_location, szIFTemp, 25); + + /* Read line 10: User's birthday. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + strncpy(od_control.user_birthday, szIFTemp, 8); + od_control.user_birthday[8] = '\0'; + od_control.user_birthday[2] = '-'; + od_control.user_birthday[5] = '-'; + + /* Read line 11: Node number. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_node = atoi(szIFTemp); + + /* Read line 12: Serial port. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.port = atoi(szIFTemp) - 1; + + /* Read line 13: Baud rate. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_connect_speed = + (od_control.port == -1) ? 0 : atol(szIFTemp); + + /* Read line 14: Locked baud rate or 0 for unlocked port. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.baud = atol(szIFTemp); + if(od_control.baud == 0) + { + od_control.baud = od_control.od_connect_speed; + } + + /* Read line 15: "Y" for RTS/CTS handshaking, "N" for none. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_com_flow_control = (szIFTemp[0] == 'Y') + ? COM_RTSCTS_FLOW : COM_NO_FLOW; + + /* Read line 16: "Y" for error free connection, "N" otherwise. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_error_free = (szIFTemp[0] == 'Y'); + + /* Read line 17: BBS name. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + ODStringCopy(od_control.system_name, szIFTemp, 40); + ODStringToName(od_control.system_name); + + /* Read line 18: Sysop's name. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + ODStringCopy(od_control.sysop_name, szIFTemp, 40); + ODStringToName(od_control.sysop_name); + + /* Read line 19: User's alias. */ + if(fgets((char *)&od_control.user_handle, 35, pfDropFile) == NULL) + { + goto DropFileFail; + } + ODStringToName(od_control.user_handle); + + /* Read line 20: "Y" for RIP mode, "N" for no RIP mode. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_rip = (szIFTemp[0] == 'Y'); + + /* Now, close the TRIBBS.SYS file. */ + fclose(pfDropFile); + } + else if(nFound == FOUND_DOOR32_SYS) + { + /* We have found a DOOR32.SYS file. */ + + /* Attempt to open the file. */ + if((pfDropFile = fopen(szDropFilePath, "r")) == NULL) + { + goto DropFileFail; + } + + /* Record the drop file type being used. */ + od_control.od_info_type = DOOR32SYS; + + /* Read line 1: Comm type. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + switch(atoi(szIFTemp)) { + case 0: /* local */ + od_control.od_force_local = TRUE; /* Is this the right way? */ + break; + case 1: /* serial */ + break; + case 2: /* telnet */ + od_control.od_use_socket = TRUE; + break; + } + /* Read line 2: Comm or Socket handle. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_open_handle = atoi(szIFTemp); + + /* Read line 3: Baud rate */ + if(fgets((char *)apszDropFileInfo[0],255,pfDropFile)==NULL) goto DropFileFail; +#ifdef ODPLAT_NIX + od_control.baud= (od_control.port == -1) ? 1 : atol((char *)apszDropFileInfo[0]); +#else + od_control.baud= (od_control.port == -1) ? 0 : atol((char *)apszDropFileInfo[0]); +#endif + + /* Read line 4: BBS Software name and version - unused. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + + /* Read line 5: User's number. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_num = atoi(szIFTemp); + + /* Read line 6: User's real name. */ + if(fgets((char *)&od_control.user_name, 35, pfDropFile) == NULL) + { + goto DropFileFail; + } + ODStringToName(od_control.user_name); + + /* Read line 7: User's alias. */ + if(fgets((char *)&od_control.user_handle, 35, pfDropFile) == NULL) + { + goto DropFileFail; + } + ODStringToName(od_control.user_handle); + + /* Read line 8: User's security level */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_security=atoi(szIFTemp); + + /* Read line 9: Minutes remaining for this call. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.user_timelimit = atoi(szIFTemp); + + /* Read line 10: User's Terminal type */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) goto DropFileFail; + od_control.user_ansi=TRUE; + switch(atoi(szIFTemp)) { + case 0: /* ASCII */ + od_control.user_ansi=FALSE; + break; + case 1: /* ANSI */ + od_control.user_ansi=TRUE; + break; + case 2: /* AVATAR */ + od_control.user_avatar=TRUE; + break; + case 3: /* RIP */ + od_control.user_rip=TRUE; + break; + } + + /* Read line 11: Current Node number. */ + if(fgets(szIFTemp, 255, pfDropFile) == NULL) goto DropFileFail; + od_control.od_node = atoi(szIFTemp); + + /* Now, close the DOOR32.SYS file. */ + fclose(pfDropFile); + } + else + { +DropFileFail: + if(pfDropFile!=NULL) /* Let's not leave the file open */ + fclose(pfDropFile); + + od_control.od_info_type = NO_DOOR_FILE; + + if(od_control.od_no_file_func != NULL) + { + (*od_control.od_no_file_func)(); + } + + /* Check whether force local has been turned on by the no */ + /* file function. */ + if(od_control.od_force_local) + { + goto force_local; + } + + /* Exit with failure if the no file function has not read a */ + /* door information file itself. */ + if(od_control.od_info_type == NO_DOOR_FILE + && (wPreSetInfo & PRESET_REQUIRED) != PRESET_REQUIRED) + { + ODInitError("Unable to read door information (drop) file."); + exit(od_control.od_errorlevel[1]); + } + } + } + + ODInitPartTwo(); +} + + +/* ---------------------------------------------------------------------------- + * ODInitReadSFDoorsDAT() *** PRIVATE FUNCTION *** + * + * Reads an SFDOORS.DAT format drop file. + * + * Parameters: none + * + * Return: TRUE on success or FALSE on failure. + */ +static BOOL ODInitReadSFDoorsDAT(void) +{ + FILE *pfDropFile; + + if((pfDropFile=fopen(szDropFilePath,"r"))==NULL) return(FALSE); + + /* Line 1: User number. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_num=atoi(szIFTemp); + + /* Line 2: User name. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + szIFTemp[35]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_name,szIFTemp); + + /* Line 3: User password. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_password,szIFTemp); + + /* Line 4: Unused. */ + if(fgets((char *)apszDropFileInfo[0],80,pfDropFile)==NULL) return(FALSE); + + /* Line 5: Modem <-> Serial port bps rate. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.baud=atol(szIFTemp); + + /* Line 6: Serial port number. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.port=atoi(szIFTemp)-1; + + /* Line 7: User's time remaining. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_timelimit=atoi(szIFTemp); + + /* Line 8: Unused. */ + if(fgets((char *)apszDropFileInfo[13],80,pfDropFile)==NULL) return(FALSE); + + /* Line 9: Unused. */ + if(fgets((char *)apszDropFileInfo[14],80,pfDropFile)==NULL) return(FALSE); + + /* Line 10: User's ANSI mode setting. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + strupr(szIFTemp); + od_control.user_ansi=(szIFTemp[0]=='T'); + + /* Line 11: User's security level. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_security=atoi(szIFTemp); + + /* Line 12: User's upload count. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_uploads=atoi(szIFTemp); + + /* Line 13: User's download count. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_downloads=atoi(szIFTemp); + + /* Line 14: Unused. */ + if(fgets((char *)apszDropFileInfo[1],80,pfDropFile)==NULL) return(FALSE); + + /* Line 15: User's login time. */ + if(fgets((char *)apszDropFileInfo[2],255,pfDropFile)==NULL) return(FALSE); + sprintf(od_control.user_logintime, "%02d:%02d", + atoi((char *)apszDropFileInfo[2]) % 60, + atoi((char *)apszDropFileInfo[2]) / 60); + + /* Line 16: Unused. */ + if(fgets((char *)apszDropFileInfo[3],80,pfDropFile)==NULL) return(FALSE); + + /* Line 17: Sysop next flag. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + strupr(szIFTemp); + od_control.sysop_next=(szIFTemp[0]=='T'); + + /* Line 18: Unused. */ + if(fgets((char *)apszDropFileInfo[4],80,pfDropFile)==NULL) return(FALSE); + + /* Line 19: Unused. */ + if(fgets((char *)apszDropFileInfo[5],80,pfDropFile)==NULL) return(FALSE); + + /* Line 20: Unused. */ + if(fgets((char *)apszDropFileInfo[6],80,pfDropFile)==NULL) return(FALSE); + + /* Line 21: Error free connection flag. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + strupr(szIFTemp); + od_control.user_error_free=(szIFTemp[0]=='T'); + + /* Line 22: Current message area. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_msg_area=atoi(szIFTemp); + + /* Line 23: Current file area. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_file_area=atoi(szIFTemp); + + /* Line 24: Current node number. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.od_node=atoi(szIFTemp); + + /* Line 25: Unused. */ + if(fgets((char *)apszDropFileInfo[10],80,pfDropFile)==NULL) return(FALSE); + + /* Line 26: Unused. */ + if(fgets((char *)apszDropFileInfo[11],80,pfDropFile)==NULL) return(FALSE); + + /* Line 27: Unused. */ + if(fgets((char *)apszDropFileInfo[12],80,pfDropFile)==NULL) return(FALSE); + + /* Line 28: Kilobytes downloaded today. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_todayk=atoi(szIFTemp); + + /* Line 29: Kilobytes uploaded in total. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_upk=atoi(szIFTemp); + + /* Line 30: Kilobytes downloaded in total. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + od_control.user_downk=atoi(szIFTemp); + + /* Line 31: User's home phone number. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + szIFTemp[15]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_homephone,szIFTemp); + + /* Line 32: User's home location. */ + if(fgets(szIFTemp,255,pfDropFile)==NULL) return(FALSE); + szIFTemp[25]='\0'; + ODStringToName(szIFTemp); + strcpy(od_control.user_location,szIFTemp); + + /* Line 33: Unused. */ + if(fgets((char *)apszDropFileInfo[15],80,pfDropFile)==NULL) + { + apszDropFileInfo[15][0]='\0'; + } + + /* Line 34: RIP mode. */ + if(fgets(szIFTemp,255,pfDropFile) != NULL) + { + strupr(szIFTemp); + od_control.user_rip = (szIFTemp[0] == 'T'); + } + + /* line 35: User wants chat. */ + if(fgets(szIFTemp,255,pfDropFile) != NULL) + { + strupr(szIFTemp); + od_control.user_wantchat = (szIFTemp[0] == 'T'); + } + + /* Line 36: Unused. */ + if(fgets((char *)apszDropFileInfo[17],80,pfDropFile)==NULL) + { + apszDropFileInfo[17][0]='\0'; + } + + /* Line 37: IRQ number. */ + if(fgets(szIFTemp,255,pfDropFile) != NULL) + { + od_control.od_com_irq = atoi(szIFTemp); + } + + /* Line 38: Serial port address. */ + if(fgets(szIFTemp,255,pfDropFile) != NULL) + { + od_control.od_com_address = atoi(szIFTemp); + } + + /* Line 39: Unused. */ + if(fgets((char *)apszDropFileInfo[18],80,pfDropFile)==NULL) + { + apszDropFileInfo[18][0]='\0'; + } + + fclose(pfDropFile); + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODInitReadExitInfo() *** PRIVATE FUNCTION *** + * + * Reads an EXITINFO.BBS format drop file. + * + * Parameters: none + * + * Return: void + */ +static void ODInitReadExitInfo(void) +{ + DWORD dwFileSize; + FILE *pfDropFile; + BYTE btCount; + + od_control.od_extended_info=FALSE; + od_control.od_ra_info=FALSE; + + /* Try to open EXITINFO.BBS. */ + ODMakeFilename(szODWorkString, szExitinfoBBSPath, "exitinfo.bbs", + sizeof(szExitinfoBBSPath)); + if((pfDropFile = fopen(szODWorkString, "rb")) != NULL) + { + dwFileSize = ODFileSize(pfDropFile); + + if(dwFileSize >= 2363) + { + if((pRA2ExitInfoRecord=malloc(sizeof(tRA2ExitInfoRecord)))!=NULL) + { + if(fread(pRA2ExitInfoRecord,1,2363,pfDropFile)==2363) + { + od_control.od_ra_info=TRUE; + od_control.od_extended_info=TRUE; + od_control.od_info_type=RA2EXITINFO; + + od_control.baud=(long)pRA2ExitInfoRecord->baud; + od_control.system_calls=pRA2ExitInfoRecord->num_calls; + ODStringPascalToC(od_control.system_last_caller,pRA2ExitInfoRecord->last_caller,35); + ODStringPascalToC(od_control.system_last_handle,pRA2ExitInfoRecord->sLastHandle,35); + ODStringPascalToC(od_control.timelog_start_date,pRA2ExitInfoRecord->start_date,8); + memcpy(&od_control.timelog_busyperhour,&pRA2ExitInfoRecord->busyperhour,62); + ODStringPascalToC(od_control.user_name,pRA2ExitInfoRecord->name,35); + ODStringPascalToC(od_control.user_location,pRA2ExitInfoRecord->location,25); + ODStringPascalToC(od_control.user_org,pRA2ExitInfoRecord->organisation,50); + for(btCount=0;btCount<3;++btCount) + ODStringPascalToC(od_control.user_address[btCount],pRA2ExitInfoRecord->address[btCount],50); + ODStringPascalToC(od_control.user_handle,pRA2ExitInfoRecord->handle,35); + ODStringPascalToC(od_control.user_comment,pRA2ExitInfoRecord->comment,80); + od_control.user_pwd_crc=pRA2ExitInfoRecord->password_crc; + ODStringPascalToC(od_control.user_dataphone,pRA2ExitInfoRecord->dataphone,15); + ODStringPascalToC(od_control.user_homephone,pRA2ExitInfoRecord->homephone,15); + ODStringPascalToC(od_control.user_lasttime,pRA2ExitInfoRecord->lasttime,5); + ODStringPascalToC(od_control.user_lastdate,pRA2ExitInfoRecord->lastdate,8); + od_control.user_attribute=pRA2ExitInfoRecord->attrib; + od_control.user_attrib2=pRA2ExitInfoRecord->attrib2; + memcpy(&od_control.user_flags,&pRA2ExitInfoRecord->flags,14); + od_control.user_security=pRA2ExitInfoRecord->sec; + od_control.user_lastread=pRA2ExitInfoRecord->lastread; + memcpy(&od_control.user_numcalls,&pRA2ExitInfoRecord->nocalls,29); + od_control.user_group=pRA2ExitInfoRecord->group; + memcpy(&od_control.user_combinedrecord,&pRA2ExitInfoRecord->combinedrecord,200); + ODStringPascalToC(od_control.user_firstcall,pRA2ExitInfoRecord->firstcall,8); + ODStringPascalToC(od_control.user_birthday,pRA2ExitInfoRecord->birthday,8); + ODStringPascalToC(od_control.user_subdate,pRA2ExitInfoRecord->subdate,8); + od_control.user_screenwidth=pRA2ExitInfoRecord->screenwidth; + od_control.user_language=pRA2ExitInfoRecord->language; + od_control.user_date_format=pRA2ExitInfoRecord->dateformat; + ODStringPascalToC(od_control.user_forward_to,pRA2ExitInfoRecord->forwardto,35); + memcpy(&od_control.user_msg_area,&pRA2ExitInfoRecord->msgarea,15); + od_control.user_sex = (pRA2ExitInfoRecord->sex == 1) ? 'M' : 'F'; + od_control.user_attrib3=pRA2ExitInfoRecord->btAttribute3; + ODStringPascalToC(od_control.user_password,pRA2ExitInfoRecord->sPassword,15); + od_control.event_status=pRA2ExitInfoRecord->status; + ODStringPascalToC(od_control.event_starttime,pRA2ExitInfoRecord->starttime,5); + memcpy(&od_control.event_errorlevel,&pRA2ExitInfoRecord->errorlevel,3); + ODStringPascalToC(od_control.event_last_run,pRA2ExitInfoRecord->lasttimerun,8); + memcpy(&od_control.user_netmailentered,&pRA2ExitInfoRecord->netmailentered,2); + ODStringPascalToC(od_control.user_logintime,pRA2ExitInfoRecord->logintime,5); + ODStringPascalToC(od_control.user_logindate,pRA2ExitInfoRecord->logindate,8); + memcpy(&od_control.user_timelimit,&pRA2ExitInfoRecord->timelimit,6); + memcpy(&od_control.user_num,&pRA2ExitInfoRecord->userrecord,8); + ODStringPascalToC(od_control.user_timeofcreation,pRA2ExitInfoRecord->timeofcreation,5); + od_control.user_logon_pwd_crc=pRA2ExitInfoRecord->logonpasswordcrc; + od_control.user_wantchat=pRA2ExitInfoRecord->wantchat; + od_control.user_deducted_time=pRA2ExitInfoRecord->deducted_time; + for(btCount=0;btCount<50;++btCount) + ODStringPascalToC(od_control.user_menustack[btCount],pRA2ExitInfoRecord->menustack[btCount],8); + od_control.user_menustackpointer=pRA2ExitInfoRecord->menustackpointer; + memcpy(&od_control.user_error_free,&pRA2ExitInfoRecord->error_free,3); + ODStringPascalToC(od_control.user_emsi_crtdef,pRA2ExitInfoRecord->emsi_crtdef,40); + ODStringPascalToC(od_control.user_emsi_protocols,pRA2ExitInfoRecord->emsi_protocols,40); + ODStringPascalToC(od_control.user_emsi_capabilities,pRA2ExitInfoRecord->emsi_capabilities,40); + ODStringPascalToC(od_control.user_emsi_requests,pRA2ExitInfoRecord->emsi_requests,40); + ODStringPascalToC(od_control.user_emsi_software,pRA2ExitInfoRecord->emsi_software,40); + memcpy(&od_control.user_hold_attr1,&pRA2ExitInfoRecord->hold_attr1,3); + ODStringPascalToC(od_control.user_reasonforchat,pRA2ExitInfoRecord->page_reason,77); + btRAStatusToSet = pRA2ExitInfoRecord->status_line-1; + ODStringPascalToC(od_control.user_last_cost_menu,pRA2ExitInfoRecord->last_cost_menu,8); + od_control.user_menu_cost=pRA2ExitInfoRecord->menu_cost_per_min; + od_control.user_rip=pRA2ExitInfoRecord->has_rip; + od_control.user_rip_ver=pRA2ExitInfoRecord->btRIPVersion; + + od_control.user_ansi=od_control.user_attribute&8; + od_control.user_avatar=od_control.user_attrib2&2; + } + + else + { + free(pRA2ExitInfoRecord); + } + } + } + + else if(dwFileSize>=1493) + { + if(ODReadExitInfoPrimitive(pfDropFile,476)) + { + if((pExtendedExitInfo=malloc(sizeof(tExtendedExitInfo)))!=NULL) + { + if(fread(pExtendedExitInfo,1,sizeof(tExtendedExitInfo), pfDropFile)==sizeof(tExtendedExitInfo)) + { /* transfer info into od_control struct */ + ODStringPascalToC(od_control.user_timeofcreation,pExitInfoRecord->bbs.ra.timeofcreation,5); + ODStringPascalToC(od_control.user_logonpassword,pExitInfoRecord->bbs.ra.logonpassword,15); + od_control.user_wantchat=pExitInfoRecord->bbs.ra.wantchat; + + od_control.user_deducted_time=pExtendedExitInfo->deducted_time; + for(btCount=0;btCount<50;++btCount) + { + ODStringPascalToC(od_control.user_menustack[btCount],pExtendedExitInfo->menustack[btCount],8); + } + od_control.user_menustackpointer=pExtendedExitInfo->menustackpointer; + ODStringPascalToC(od_control.user_handle,pExtendedExitInfo->userhandle,35); + ODStringPascalToC(od_control.user_comment,pExtendedExitInfo->comment,80); + ODStringPascalToC(od_control.user_firstcall,pExtendedExitInfo->firstcall,8); + memcpy(od_control.user_combinedrecord,pExtendedExitInfo->combinedrecord,25); + ODStringPascalToC(od_control.user_birthday,pExtendedExitInfo->birthday,8); + ODStringPascalToC(od_control.user_subdate,pExtendedExitInfo->subdate,8); + od_control.user_screenwidth=pExtendedExitInfo->screenwidth; + od_control.user_msg_area=pExtendedExitInfo->msgarea; + od_control.user_file_area=pExtendedExitInfo->filearea; + od_control.user_language=pExtendedExitInfo->language; + od_control.user_date_format=pExtendedExitInfo->dateformat; + ODStringPascalToC(od_control.user_forward_to,pExtendedExitInfo->forwardto,35); + memcpy(&od_control.user_error_free,&pExtendedExitInfo->error_free,3); + ODStringPascalToC(od_control.user_emsi_crtdef,pExtendedExitInfo->emsi_crtdef,40); + ODStringPascalToC(od_control.user_emsi_protocols,pExtendedExitInfo->emsi_protocols,40); + ODStringPascalToC(od_control.user_emsi_capabilities,pExtendedExitInfo->emsi_capabilities,40); + ODStringPascalToC(od_control.user_emsi_requests,pExtendedExitInfo->emsi_requests,40); + ODStringPascalToC(od_control.user_emsi_software,pExtendedExitInfo->emsi_software,40); + memcpy(&od_control.user_hold_attr1,&pExtendedExitInfo->hold_attr1,3); + + od_control.od_ra_info=TRUE; + od_control.od_extended_info=TRUE; + od_control.od_info_type=RA1EXITINFO; + } + } + } + } + + else if(dwFileSize>476) + { + if(dwFileSize > sizeof(tExitInfoRecord)) + { + dwFileSize = sizeof(tExitInfoRecord); + } + + if(ODReadExitInfoPrimitive(pfDropFile,(int)dwFileSize)) + { + od_control.user_wantchat=pExitInfoRecord->bbs.qbbs.qwantchat; + for(btCount=0;btCountbbs.qbbs.gosublevel;++btCount) + { + ODStringPascalToC(od_control.user_menustack[btCount],pExitInfoRecord->bbs.qbbs.menustack[btCount],8); + } + od_control.user_menustackpointer=pExitInfoRecord->bbs.qbbs.gosublevel; + ODStringPascalToC(od_control.user_menustack[od_control.user_menustackpointer],pExitInfoRecord->bbs.qbbs.menu,8); + + od_control.od_extended_info=TRUE; + od_control.od_info_type=QBBS275EXITINFO; + nInitialElapsed=pExitInfoRecord->elapsed; + + od_control.user_rip = pExitInfoRecord->bbs.qbbs.ripactive; + } + } + + else if(dwFileSize>=452) + { + if(ODReadExitInfoPrimitive(pfDropFile,(int)dwFileSize)) + { + ODStringPascalToC(od_control.user_timeofcreation,pExitInfoRecord->bbs.ra.timeofcreation,5); + ODStringPascalToC(od_control.user_logonpassword,pExitInfoRecord->bbs.ra.logonpassword,15); + od_control.user_wantchat=pExitInfoRecord->bbs.ra.wantchat; + + od_control.od_extended_info=TRUE; + od_control.od_info_type=EXITINFO; + } + } + + od_control.od_page_pausing=od_control.user_attribute&0x04; + + fclose(pfDropFile); + } +} + + +/* ---------------------------------------------------------------------------- + * ODInitPartTwo() *** PRIVATE FUNCTION *** + * + * Called by od_init() to carry on with second stage of OpenDoors + * initialization. The sole reason that this function exists is because some + * compilers were unable to compile this file with a huge od_init() function + * that had this code in the main od_init() body. + * + * Parameters: none + * + * Return: void + */ +static void ODInitPartTwo(void) +{ + BYTE btCount; +#ifdef ODPLAT_NIX + struct termios term; + struct passwd *uinfo; +#endif + + /* Initialize any colors that haven't already been set. */ + if(!od_control.od_list_title_col) od_control.od_list_title_col = 0x0f; + if(!od_control.od_continue_col) od_control.od_continue_col = 0x0f; + if(!od_control.od_list_name_col) od_control.od_list_name_col = 0x0e; + if(!od_control.od_list_size_col) od_control.od_list_size_col = 0x0d; + if(!od_control.od_list_comment_col) od_control.od_list_comment_col = 0x03; + if(!od_control.od_list_offline_col) od_control.od_list_offline_col = 0x0c; + if(!od_control.od_local_win_col) od_control.od_local_win_col = 0x19; + if(!od_control.od_menu_title_col) od_control.od_menu_title_col = 0x74; + if(!od_control.od_menu_border_col) od_control.od_menu_border_col = 0x70; + if(!od_control.od_menu_text_col) od_control.od_menu_text_col = 0x70; + if(!od_control.od_menu_key_col) od_control.od_menu_key_col = 0x7f; + if(!od_control.od_menu_highkey_col) od_control.od_menu_highkey_col = 0x0f; + if(!od_control.od_menu_highlight_col) + { + od_control.od_menu_highlight_col = 0x07; + } + + /* Color sequence delimiter characters. */ + od_control.od_color_char = '\0'; + od_control.od_color_delimiter = '`'; + + /* Enable sysop paging between the hours of 8:00am and 10:00pm. */ + od_control.od_okaytopage = PAGE_USE_HOURS; + od_control.od_pagestartmin = 480; + od_control.od_pageendmin = 1320; + + /* Default maximum user inactivity is 200 seconds. */ + od_control.od_inactivity = 200; + + /* Screen clearing is on by default. */ + od_control.od_always_clear = TRUE; + + od_control.od_inactive_warning = 10; + od_control.od_cur_attrib = -1; + + /* Enable screen clearing on door exit. */ + od_control.od_clear_on_exit = TRUE; + + /* RA/QBBS control codes are now disabled by default. */ + od_control.od_no_ra_codes = TRUE; + + if(od_control.od_chat_color1 == 0) od_control.od_chat_color1 = 0x0c; + if(od_control.od_chat_color2 == 0) od_control.od_chat_color2 = 0x0f; + + /* Set default messages and prompts. */ + od_control.od_before_shell = "\n\rPlease wait a moment...\n\r"; + od_control.od_after_shell = "\n\r...Thanks for waiting\n\r\n\r"; + od_control.od_help_text = " Alt: [C]hat [H]angup [L]ockout [J]Dos [K]eyboard-Off [D]rop to BBS "; + od_control.od_before_chat = "\n\rThe system operator has placed you in chat mode to talk with you:\n\r\n\r"; + od_control.od_after_chat = "\n\rChat mode ended.\n\r\n\r"; + od_control.od_inactivity_timeout = "\n\rMaximum user inactivity time has elapsed, please call again.\n\r\n\r"; + od_control.od_inactivity_warning = "\n\rWARNING: Inactivity timeout in 10 seconds, press a key now to remain online.\n\r\n\r"; + od_control.od_time_warning = "\n\rWARNING: You only have %d minute(s) remaining for this session.\n\r\n\r"; + od_control.od_time_left = "%d mins "; + od_control.od_sysop_next = "[SN] "; + od_control.od_no_keyboard = "[Keyboard]"; + od_control.od_want_chat = "[Want-Chat]"; + od_control.od_no_time = "\n\rSorry, you have used up of your time for this session.\n\r\n\r"; + od_control.od_no_sysop = "\n\rSorry, the system operator is not available at this time.\n\r"; + od_control.od_press_key = "Press [Enter] to continue"; + od_control.od_chat_reason = " Why would you like to chat? (Blank line to cancel)\n\r"; + od_control.od_paging = "\n\rPaging system operator for chat"; + od_control.od_no_response = " No response.\n\r\n\r"; + od_control.od_status_line[0] = " [Node: "; + od_control.od_status_line[1] = "%s of %s at %lu BPS"; + od_control.od_status_line[2] = "Security: Time: [F9]=Help "; + od_control.od_month[0] = "Jan"; + od_control.od_month[1] = "Feb"; + od_control.od_month[2] = "Mar"; + od_control.od_month[3] = "Apr"; + od_control.od_month[4] = "May"; + od_control.od_month[5] = "Jun"; + od_control.od_month[6] = "Jul"; + od_control.od_month[7] = "Aug"; + od_control.od_month[8] = "Sep"; + od_control.od_month[9] = "Oct"; + od_control.od_month[10] = "Nov"; + od_control.od_month[11] = "Dec"; + od_control.od_day[0] = "Sun"; + od_control.od_day[1] = "Mon"; + od_control.od_day[2] = "Tue"; + od_control.od_day[3] = "Wed"; + od_control.od_day[4] = "Thu"; + od_control.od_day[5] = "Fri"; + od_control.od_day[6] = "Sat"; + od_control.od_offline = "[OFFLINE] "; + od_control.od_continue = "Continue? [Y/n/=]"; + od_control.od_continue_yes = 'y'; + od_control.od_continue_no = 'n'; + od_control.od_continue_nonstop = '='; + od_control.od_help_text2 = OD_VER_STATUSLINE; + od_control.od_sending_rip = "Sending RIP file: "; + od_control.od_hanging_up = "Ending call..."; + od_control.od_exiting = "Program is exiting..."; + if(strlen(od_control.od_disable_dtr) == 0) + { + strcpy(od_control.od_disable_dtr, "~+++~ AT&D0| ATO|"); + } + + nInitialRemaining = od_control.user_timelimit; + + if(od_control.od_maxtime > 0 && od_control.od_maxtime <= 1440) + { + if(od_control.user_timelimit > (INT)od_control.od_maxtime) + { + od_control.od_maxtime_deduction + = od_control.user_timelimit-od_control.od_maxtime; + od_control.user_timelimit + = od_control.od_maxtime; + } + } + + /* If sysop name is unkown, then use the word "Sysop". */ + if(strlen(od_control.sysop_name) == 0) + { + strcpy(od_control.sysop_name, "Sysop"); + } + + /* If in foced local mode and user name has not yet been set. */ + if(od_control.od_force_local && od_control.user_name[0] == '\0') + { + /* If name prompting is not disabled, then turn on flag to prompt for */ + /* user's name. */ + if(!(od_control.od_disable & DIS_NAME_PROMPT)) + { + bPromptForUserName = TRUE; + } + + /* Use sysop's name as default user name. */ + if(bSysopNameSet) + { + strcpy(od_control.user_name, szForcedSysopName); + } + else + { + strcpy(od_control.user_name, od_control.sysop_name); + } + } + + dwFileBPS = od_control.baud; + + /* Determine desired BPS rate. */ + if(dwForcedBPS != 1) + { + if(od_control.od_disable & DIS_LOCAL_OVERRIDE || od_control.baud != 0) + { + od_control.baud = dwForcedBPS; + } + } + + /* If we are not operating in local mode, then setup for serial I/O. */ +#ifndef ODPLAT_NIX + if(od_control.baud != 0) +#endif + { + tComMethod ComMethod; + + /* Attempt to allocate an OpenDoors port object. */ + if(ODComAlloc(&hSerialPort) != kODRCSuccess) + { +malloc_error: + ODInitError("Insufficient memory available to start up program."); + exit(od_control.od_errorlevel[1]); + } + + /* Set socket I/O method, if specified by user. */ + if(od_control.od_use_socket) + { + ODComSetPreferredMethod(hSerialPort, kComMethodSocket); + } + +#if defined ODPLAT_WIN32 || defined ODPLAT_NIX + /* Check whether a handle has been provided by the caller. */ + if(od_control.od_open_handle != 0) + { + if(ODComOpenFromExistingHandle(hSerialPort, od_control.od_open_handle) + != kODRCSuccess) + { + ODInitError("Unable to use provided serial port handle."); + exit(od_control.od_errorlevel[1]); + } + } + else +#endif /* ODPLAT_WIN32 */ + { + /* Set flow control type. */ + switch(od_control.od_com_flow_control) + { + case COM_NO_FLOW: + ODComSetFlowControl(hSerialPort, FLOW_NONE); + break; + case COM_RTSCTS_FLOW: + ODComSetFlowControl(hSerialPort, FLOW_RTSCTS); + break; + case COM_DEFAULT_FLOW: + /* Don't say anything to the serial I/O module about flow */ + /* control. */ + break; + default: + /* We should never get here. */ + ASSERT(FALSE); + } + + /* Determine desired port. */ + if(nForcedPort != -1) od_control.port=nForcedPort; + + /* Set port number. */ + ODComSetPort(hSerialPort, (BYTE)od_control.port); + + /* If serial port address has been explicitly set, then set user's */ + /* port address in serial port object. */ + if(od_control.od_com_address != 0) + { + ODComSetPortAddress(hSerialPort, od_control.od_com_address); + } + + /* If serial port IRQ line number has been explicitly set, then */ + /* set user's setting in serial port object. */ + if(od_control.od_com_irq >= 1 && od_control.od_com_irq < 15) + { + ODComSetIRQ(hSerialPort, od_control.od_com_irq); + } + + /* Set BPS rate, if this is not disabled. */ + if(!(od_control.od_disable&DIS_BPS_SETTING)) + { + ODComSetSpeed(hSerialPort, od_control.baud); + } + else + { + ODComSetSpeed(hSerialPort, SPEED_UNSPECIFIED); + } + + /* Set serial I/O method, if specified by user. */ + if(od_control.od_no_fossil) + { + ODComSetPreferredMethod(hSerialPort, kComMethodUART); + } + + /* Establish default buffer sizes */ + if(od_control.od_com_rx_buf == 0) + od_control.od_com_rx_buf = 256; + if(od_control.od_com_tx_buf == 0) + od_control.od_com_tx_buf = 3072; + + /* Set buffer sizes for serial port. */ + ODComSetRXBuf(hSerialPort, od_control.od_com_rx_buf); + ODComSetTXBuf(hSerialPort, od_control.od_com_tx_buf); + + /* Set FIFO enabled/disabled and trigger size */ + if(od_control.od_com_no_fifo) + { + /* Disable UART FIFO buffers. */ + ODComSetFIFO(hSerialPort, FIFO_DISABLE); + } + else + { + /* Enable FIFO, setting size of FIFO trigger. */ + switch(od_control.od_com_fifo_trigger) + { + case 1: + ODComSetFIFO(hSerialPort, FIFO_ENABLE | FIFO_TRIGGER_1); + break; + case 4: + ODComSetFIFO(hSerialPort, FIFO_ENABLE | FIFO_TRIGGER_4); + break; + case 8: + ODComSetFIFO(hSerialPort, FIFO_ENABLE | FIFO_TRIGGER_8); + break; + case 14: + ODComSetFIFO(hSerialPort, FIFO_ENABLE | FIFO_TRIGGER_14); + break; + default: + od_control.od_com_fifo_trigger = 4; + ODComSetFIFO(hSerialPort, FIFO_ENABLE | FIFO_TRIGGER_4); + } + } + +#ifdef ODPLAT_DOS + /* Set od_kernel() to be idle function. */ + ODComSetIdleFunction(hSerialPort, od_kernel); +#endif /* ODPLAT_DOS */ + + /* Open serial port. */ + switch(ODComOpen(hSerialPort)) + { + case kODRCSuccess: + /* Serial port open succeeded, so proceed with OpenDoors */ + /* initialization. */ + break; + case kODRCNoMemory: + goto malloc_error; + case kODRCNoPortAddress: + ODInitError("Serial port address is unknown, cannot continue."); + exit(od_control.od_errorlevel[1]); + break; + case kODRCNoUART: + ODInitError("No UART at specified port address, cannot continue.\n"); + exit(od_control.od_errorlevel[1]); + break; + default: + ODInitError("Unable to access serial port, cannot continue.\n"); + exit(od_control.od_errorlevel[1]); + break; + } + } + + /* Raise DTR signal. */ + ODComSetDTR(hSerialPort, TRUE); + + /* Get serial I/O method actually being used. */ + ODComGetMethod(hSerialPort, (tComMethod *)&ComMethod); + switch(ComMethod) + { + case kComMethodFOSSIL: + od_control.od_com_method = COM_FOSSIL; + break; + case kComMethodUART: + od_control.od_com_method = COM_INTERNAL; + break; + case kComMethodWin32: + od_control.od_com_method = COM_WIN32; + break; + case kComMethodDoor32: + od_control.od_com_method = COM_DOOR32; + break; + case kComMethodSocket: + od_control.od_com_method = COM_SOCKET; /* Why are using doubling up constants here? */ + break; + case kComMethodStdIO: + od_control.od_com_method = COM_STDIO; + break; + default: + ODInitError("No method of accessing serial port, cannot continue.\n"); + exit(od_control.od_errorlevel[1]); + break; + } + } + + /* If we are operating in local mode, then disable silent mode. */ + if(od_control.baud == 0) + { + od_control.od_silent_mode = FALSE; + } + + /* Setup local screen. */ + ODScrnInitialize(); +#ifdef OD_TEXTMODE + ODScrnSetBoundary(1, 1, 80, 23); +#else /* !OD_TEXTMODE */ + ODScrnSetBoundary(1, 1, 80, 25); +#endif /* !OD_TEXTMODE */ + +#ifndef ODPLAT_WIN32 + if(bPreset) + { + atexit(ODAtExitCallback); + bPreset = FALSE; + } +#endif /* !ODPLAT_WIN32 */ + + /* Setup remote terminal for ANSI graphics if operating in RIP mode. */ + if(od_control.user_rip) + { + od_clr_scr(); + } + +#ifdef ODPLAT_WIN32 + /* Startup the OpenDoors frame window, if we are not operating in silent */ + /* mode. */ + if(!od_control.od_silent_mode) + { +#ifdef OD_DLL + ODFrameStart(GetModuleHandle(OD_DLL_NAME), &hFrameThread); +#else /* !OD_DLL */ + ODFrameStart(GetModuleHandle(NULL), &hFrameThread); +#endif /* !OD_DLL */ + } +#endif /* ODPLAT_WIN32 */ + + /* Initialize the OpenDoors kernel. */ + ODKrnlInitialize(); + +#ifndef ODPLAT_WIN32 +#ifdef ODPLAT_NIX + if(bPromptForUserName) + { + od_control.od_com_method=COM_STDIO; + od_control.baud=19200; + gethostname(od_control.system_name,sizeof(od_control.system_name)); + od_control.system_name[sizeof(od_control.system_name)-1]=0; + if (isatty(STDIN_FILENO)) { + tcgetattr(STDIN_FILENO,&term); + od_control.baud=cfgetispeed(&term); + if(!od_control.baud) + od_control.baud=cfgetispeed(&term); + if(!od_control.baud) + od_control.baud=19200; + } + uinfo=getpwuid(getuid()); + ODStringCopy(od_control.user_handle, uinfo->pw_name,sizeof(od_control.user_handle)); + ODStringCopy(od_control.user_name, uinfo->pw_gecos,sizeof(od_control.user_name)); + } +#else + if(bPromptForUserName) + { + void *pWindow = ODScrnCreateWindow(10, 8, 70, 15, + od_control.od_local_win_col, od_control.od_prog_name, + od_control.od_local_win_col); + + if(pWindow != NULL) + { + ODScrnSetCursorPos(12, 9); + ODScrnDisplayString("This program has been started in local mode,"); + ODScrnSetCursorPos(12, 10); + ODScrnDisplayString("independently of a BBS system. When operating in this"); + ODScrnSetCursorPos(12, 11); + ODScrnDisplayString("mode, you may specify what name you should be known to"); + ODScrnSetCursorPos(12, 12); + ODScrnDisplayString("the program by."); + ODScrnSetCursorPos(12, 14); + ODScrnDisplayString("Your name:"); + ODScrnLocalInput(23, 14, od_control.user_name, 35); + ODStringCopy(od_control.user_handle, od_control.user_name, + sizeof(od_control.user_name)); + ODScrnDestroyWindow(pWindow); + ODScrnSetCursorPos(1, 1); + ODScrnSetAttribute(0x07); + } + } +#endif /* !ODPLAT_NIX */ +#endif /* !ODPLAT_WIN32 */ + +#ifdef OD_TEXTMODE + /* Setup sysop status line/function key personality. */ + if(pfSetPersonality == NULL) + { +no_default: + if (od_control.od_default_personality == NULL) + { + pfCurrentPersonality = pdef_opendoors; + } + else + { + pfCurrentPersonality = od_control.od_default_personality; + } + (*pfCurrentPersonality)(20); + if(bRAStatus) + { + od_set_statusline(btRAStatusToSet); + } + else + { + od_set_statusline(0); + } + } + else + { + if(!((*pfSetPersonality)(szDesiredPersonality))) + { + goto no_default; + } + } +#endif /* OD_TEXTMODE */ + + /* If connect speed has not been set yet, then set it to the */ + /* serial port speed. */ + if(od_control.od_connect_speed == 0) + { + od_control.od_connect_speed = od_control.baud; + } + + /* Initialize the array of characters to use for drawing boxes, */ + /* window and menu boarders, etc. */ + od_control.od_box_chars[0] = 218U; + od_control.od_box_chars[1] = 196U; + od_control.od_box_chars[2] = 191U; + od_control.od_box_chars[3] = 179U; + od_control.od_box_chars[4] = 192U; + od_control.od_box_chars[5] = 217U; + + /* Enable pausing and stoping of listing. */ + od_control.od_list_stop = TRUE; + od_control.od_list_pause = TRUE; + + /* Initialize array of logfile messages. */ + for(btCount = 0; btCount < DIM(apszLogMessages); ++btCount) + { + if(od_control.od_logfile_messages[btCount] == NULL) + { + od_control.od_logfile_messages[btCount] + = apszLogMessages[btCount]; + } + } + + /* Set log file name to default, if none has been specified already. */ + if(strlen(od_control.od_logfile_name) == 0) + { + strcpy(od_control.od_logfile_name, "DOOR.LOG"); + } + + /* If OpenDoors log file system is installed, then start it up. */ + if(od_control.od_logfile != NULL) + { + (*(OD_COMPONENT_CALLBACK *)od_control.od_logfile)(); + } +} + + +/* ---------------------------------------------------------------------------- + * ODInitError() + * + * Called to display an error message when OpenDoors initialization fails, + * forcing the program to exit. + * + * Parameters: pszErrorText - Pointer to the error message explaining the + * reason for failure. + * + * Return: void + */ +void ODInitError(char *pszErrorText) +{ +#ifdef ODPLAT_DOS + printf("%s: %s\n", od_control.od_prog_name, pszErrorText); + if(bParsedCmdLine) + { + printf("Use the -HELP command line option for help, or -LOCAL for local mode.\n"); + } +#endif +#ifdef ODPLAT_WIN32 + char *pszMessage; + if(!bParsedCmdLine || + (pszMessage = malloc(strlen(pszErrorText) + 80)) == NULL) + { + MessageBox(NULL, pszErrorText, od_control.od_prog_name, + MB_ICONSTOP | MB_OK | MB_TASKMODAL); + } + else + { + sprintf(pszMessage, + "%s\nUse the -HELP command line option for help, or -LOCAL for local mode.", + pszErrorText); + MessageBox(NULL, pszMessage, od_control.od_prog_name, + MB_ICONSTOP | MB_OK | MB_TASKMODAL); + free(pszMessage); + } +#endif +#ifdef ODPLAT_NIX + fwrite(pszErrorText,strlen(pszErrorText),1,stderr); +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODInitLoginDlgProc() + * + * Dialog box proceedure for the local mode login dialog box. + * + * Parameters: hwndDlg - Window handle to the dialog box. + * + * uMsg - Message ID. + * + * wParam - First message parameter. + * + * lParam - Second message parameter. + * + * Return: TRUE if message is processed, FALSE otherwise. + */ +#ifdef ODPLAT_WIN32 +BOOL CALLBACK ODInitLoginDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + ODFrameCenterWindowInParent(hwndDlg); + + /* Set the title of the dialog box to the name of this program. */ + SetWindowText(hwndDlg, od_control.od_prog_name); + + /* The initial text in the user name dialog box should be the */ + /* default user name. */ + SetWindowText(GetDlgItem(hwndDlg, IDC_USER_NAME), + od_control.user_name); + + /* Limit the number of characters that may be entered as the */ + /* user's name to the maximum size of the string. */ + SendMessage(GetDlgItem(hwndDlg, IDC_USER_NAME), EM_LIMITTEXT, + sizeof(od_control.user_name), 0L); + + return(TRUE); + + case WM_COMMAND: + /* If a command has been chosen. */ + switch(LOWORD(wParam)) + { + case IDOK: + /* If the OK button has been pressed, obtain the entered */ + /* user name. */ + GetWindowText(GetDlgItem(hwndDlg, IDC_USER_NAME), + od_control.user_name, sizeof(od_control.user_name)); + ODStringCopy(od_control.user_handle, od_control.user_name, + sizeof(od_control.user_name)); + + /* Now close the dialog. */ + EndDialog(hwndDlg, IDOK); + break; + + case IDCANCEL: + /* If the Cancel button has benn pressed, close the dialog. */ + EndDialog(hwndDlg, IDCANCEL); + break; + } + return(TRUE); + + default: + /* Otherwise, indicate that this message has not been processed. */ + return(FALSE); + } +} +#endif /* ODPLAT_WIN32 */ diff --git a/utils/magiedit/odoors/ODInEx2.c b/utils/magiedit/odoors/ODInEx2.c new file mode 100644 index 0000000..a8379bb --- /dev/null +++ b/utils/magiedit/odoors/ODInEx2.c @@ -0,0 +1,1434 @@ +/* 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: ODInEx2.c + * + * Description: Performs OpenDoors initialization and shutdown operations + * (od_init() and od_exit()), including drop file I/O. This + * module is broken into two files, ODInEx1.c and ODInEx2.c. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Oct 29, 1994 6.00 BP New EXITINFO.BBS timelimit writing. + * Nov 01, 1994 6.00 BP New directory access functions. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 13, 1994 6.00 BP Remove include of dir.h. + * Dec 31, 1994 6.00 BP Add DIR_ATTRIB_ARCH in file search. + * Dec 31, 1994 6.00 BP Move _mt_init to new func in odplat.c + * Jan 01, 1995 6.00 BP _waitdrain() -> ODWaitDrain(). + * Aug 19, 1995 6.00 BP 32-bit portability. + * 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 Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 01, 1996 6.00 BP Added od_disable_dtr, DIS_DTR_DISABLE. + * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent. + * Jan 19, 1996 6.00 BP Don't use atexit() under Win32. + * Jan 21, 1996 6.00 BP Try DTR disable sequence twice. + * Jan 21, 1996 6.00 BP Use ODScrnShowMessage(). + * Jan 23, 1996 6.00 BP Added od_exiting. + * Jan 23, 1996 6.00 BP Use ODProcessExit() instead of exit(). + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout. + * Jan 31, 1996 6.00 BP Support new SFDOORS.DAT format. + * Feb 02, 1996 6.00 BP Added RA 2.50 EXITINFO.BBS support. + * Feb 09, 1996 6.00 BP Correctly translate RA 2.x sex field. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 23, 1996 6.00 BP Make DTR disable code shared. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Added TRIBBS.SYS support. + * Mar 27, 1996 6.10 BP Added WCNODEID to + * Jan 13, 1997 6.10 BP Fixes for Door32 support. + * Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODCom.h" +#include "ODPlat.h" +#include "ODTypes.h" +#include "ODScrn.h" +#include "ODInQue.h" +#include "ODKrnl.h" +#include "ODInEx.h" +#include "ODUtil.h" + + +/* Time difference leeway for door information files to be considered to */ +/* have been written during the same exit (door execution session). */ +#define DROPFILE_TIME_LEEWAY 10 + +/* Maximum length of modem response string. */ +#define MAX_RESPONSE_LEN 40 + +/* Maximum time to wait for modem response string, in milliseconds. */ +#define RESPONSE_TIMEOUT 2000 + + +/* Environment variables that specify directories where drop files may be */ +/* found. */ +static char *apszEnvVarNames[] = +{ + "RA", + "QUICK", + "PCB", + "BBS", + "WCNODEID", + "SBBSNODE", +}; +#define NUM_DIR_ENV_VARS DIM(apszEnvVarNames) + + +/* Local helper functions. */ +static INT ODSearchInDir(char **papszFileNames, INT nNumFileNames, + char *pszFound, char *pszDirectory); + +/* Currently, the following functions are only used in the Win32 version. */ +#ifdef ODPLAT_WIN32 +static BOOL ODSendModemCommand(char *pszCommand, int nRetries); +static BOOL ODSendModemCommandOnce(char *pszCommand); +static BOOL ODWaitForString(char *pszResponse, tODMilliSec ResponseTimeout); +#endif /* ODPLAT_WIN32 */ + +#ifdef OD_DIAGNOSTICS +static char szDebugWorkString[500] = ""; +#endif /* OD_DIAGNOSTICS */ + + + +/* ---------------------------------------------------------------------------- + * od_exit() + * + * Shuts down OpenDoors operations. Normally, the program is exited as soon + * as OpenDoors is shutdown. + * + * Parameters: nErrorLevel - Result code to exit program with. + * + * bTermCall - TRUE to disconnect the user before exiting, + * FALSE to leave the user connected. + * + * Return: void + */ +ODAPIDEF void ODCALL od_exit(INT nErrorLevel, BOOL bTermCall) +{ + BYTE btCount; + FILE *pfDropFile; + time_t nMaxTime; + time_t nDoorEndTime; + void *pWindow = NULL; + DWORD dwActiveMinutes; + static BOOL bExiting = FALSE; + + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_exit()"); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Starting up od_exit()", "OpenDoors Diagnostics", + MB_OK); + } +#endif + + /* If this is a recursive od_exit() call, then ignore it. */ + if(bExiting) + { + return; + } + bExiting = TRUE; + + /* If user called od_exit() before doing anything else, then we first */ + /* initialize OpenDoors in order to shutdown and exit. */ + if(!bODInitialized) od_init(); + + /* Update remaining time. */ + od_control.user_timelimit += od_control.od_maxtime_deduction; + + /* Calculate deducted time */ + time(&nDoorEndTime); + ODDWordDivide(&dwActiveMinutes, NULL, nDoorEndTime - nStartupUnixTime, 60L); + od_control.user_time_used += ((nInitialRemaining + - od_control.user_timelimit) - (int)dwActiveMinutes); + + /* Reset to original bps rate that was stored in drop file */ + od_control.baud = dwFileBPS; + + /* If function hook is defined. */ + if(od_control.od_before_exit != NULL) + { + /* Then call it. */ + (*od_control.od_before_exit)(); + } + + if(bTermCall && od_control.od_hanging_up != NULL) + { + pWindow = ODScrnShowMessage(od_control.od_hanging_up, 0); + } + else if(!bTermCall) + { + pWindow = ODScrnShowMessage(od_control.od_exiting, 0); + } + + if(szOriginalDir != NULL) + { + ODDirChangeCurrent(szOriginalDir); + free(szOriginalDir); + szOriginalDir=NULL; + } + + if(od_control.od_extended_info) /* Update EXITINFO.BBS, if applicable */ + { + ODMakeFilename(szExitinfoBBSPath, szExitinfoBBSPath, "EXITINFO.BBS", + sizeof(szExitinfoBBSPath)); + if((pfDropFile = fopen(szExitinfoBBSPath, "r+b")) != NULL) + { + switch(od_control.od_info_type) + { + case RA2EXITINFO: + pRA2ExitInfoRecord->baud = (unsigned int)od_control.baud; + pRA2ExitInfoRecord->num_calls = od_control.system_calls; + ODStringCToPascal(pRA2ExitInfoRecord->last_caller,35,od_control.system_last_caller); + ODStringCToPascal(pRA2ExitInfoRecord->sLastHandle,35,od_control.system_last_handle); + ODStringCToPascal(pRA2ExitInfoRecord->start_date,8,od_control.timelog_start_date); + memcpy(&pRA2ExitInfoRecord->busyperhour,&od_control.timelog_busyperhour,62); + ODStringCToPascal(pRA2ExitInfoRecord->name,35,od_control.user_name); + ODStringCToPascal(pRA2ExitInfoRecord->location,25,od_control.user_location); + ODStringCToPascal(pRA2ExitInfoRecord->organisation,50,od_control.user_org); + for(btCount=0;btCount<3;++btCount) + ODStringCToPascal(pRA2ExitInfoRecord->address[btCount],50,od_control.user_address[btCount]); + ODStringCToPascal(pRA2ExitInfoRecord->handle,35,od_control.user_handle); + ODStringCToPascal(pRA2ExitInfoRecord->comment,80,od_control.user_comment); + pRA2ExitInfoRecord->password_crc=od_control.user_pwd_crc; + ODStringCToPascal(pRA2ExitInfoRecord->dataphone,15,od_control.user_dataphone); + ODStringCToPascal(pRA2ExitInfoRecord->homephone,15,od_control.user_homephone); + ODStringCToPascal(pRA2ExitInfoRecord->lasttime,5,od_control.user_lasttime); + ODStringCToPascal(pRA2ExitInfoRecord->lastdate,8,od_control.user_lastdate); + pRA2ExitInfoRecord->attrib=od_control.user_attribute; + pRA2ExitInfoRecord->attrib2=od_control.user_attrib2; + memcpy(&pRA2ExitInfoRecord->flags,&od_control.user_flags,14); + pRA2ExitInfoRecord->sec=od_control.user_security; + pRA2ExitInfoRecord->lastread=od_control.user_lastread; + memcpy(&pRA2ExitInfoRecord->nocalls,&od_control.user_numcalls,29); + pRA2ExitInfoRecord->group=od_control.user_group; + memcpy(&pRA2ExitInfoRecord->combinedrecord,&od_control.user_combinedrecord,200); + ODStringCToPascal(pRA2ExitInfoRecord->firstcall,8,od_control.user_firstcall); + ODStringCToPascal(pRA2ExitInfoRecord->birthday,8,od_control.user_birthday); + ODStringCToPascal(pRA2ExitInfoRecord->subdate,8,od_control.user_subdate); + pRA2ExitInfoRecord->screenwidth=od_control.user_screenwidth; + pRA2ExitInfoRecord->language=od_control.user_language; + pRA2ExitInfoRecord->dateformat=od_control.user_date_format; + ODStringCToPascal(pRA2ExitInfoRecord->forwardto,35,od_control.user_forward_to); + memcpy(&pRA2ExitInfoRecord->msgarea,&od_control.user_msg_area,15); + pRA2ExitInfoRecord->sex = (od_control.user_sex == 'M') ? 1 : 2; + pRA2ExitInfoRecord->btAttribute3=od_control.user_attrib3; + ODStringCToPascal(pRA2ExitInfoRecord->sPassword,15,od_control.user_password); + pRA2ExitInfoRecord->status=od_control.event_status; + ODStringCToPascal(pRA2ExitInfoRecord->starttime,5,od_control.event_starttime); + memcpy(&pRA2ExitInfoRecord->errorlevel,&od_control.event_errorlevel,3); + ODStringCToPascal(pRA2ExitInfoRecord->lasttimerun,8,od_control.event_last_run); + memcpy(&pRA2ExitInfoRecord->netmailentered,&od_control.user_netmailentered,2); + ODStringCToPascal(pRA2ExitInfoRecord->logintime,5,od_control.user_logintime); + ODStringCToPascal(pRA2ExitInfoRecord->logindate,8,od_control.user_logindate); + memcpy(&pRA2ExitInfoRecord->timelimit,&od_control.user_timelimit,6); + memcpy(&pRA2ExitInfoRecord->userrecord,&od_control.user_num,8); + ODStringCToPascal(pRA2ExitInfoRecord->timeofcreation,5,od_control.user_timeofcreation); + pRA2ExitInfoRecord->logonpasswordcrc=od_control.user_logon_pwd_crc; + pRA2ExitInfoRecord->wantchat=od_control.user_wantchat; + pRA2ExitInfoRecord->deducted_time=od_control.user_deducted_time; + for(btCount=0;btCount<50;++btCount) + ODStringCToPascal(pRA2ExitInfoRecord->menustack[btCount],8,od_control.user_menustack[btCount]); + pRA2ExitInfoRecord->menustackpointer=od_control.user_menustackpointer; + memcpy(&pRA2ExitInfoRecord->error_free,&od_control.user_error_free,3); + ODStringCToPascal(pRA2ExitInfoRecord->emsi_crtdef,40,od_control.user_emsi_crtdef); + ODStringCToPascal(pRA2ExitInfoRecord->emsi_protocols,40,od_control.user_emsi_protocols); + ODStringCToPascal(pRA2ExitInfoRecord->emsi_capabilities,40,od_control.user_emsi_capabilities); + ODStringCToPascal(pRA2ExitInfoRecord->emsi_requests,40,od_control.user_emsi_requests); + ODStringCToPascal(pRA2ExitInfoRecord->emsi_software,40,od_control.user_emsi_software); + memcpy(&pRA2ExitInfoRecord->hold_attr1,&od_control.user_hold_attr1,3); + ODStringCToPascal(pRA2ExitInfoRecord->page_reason,77,od_control.user_reasonforchat); + if(bRAStatus) + { + pRA2ExitInfoRecord->status_line = btCurrentStatusLine + 1; + } + + ODStringCToPascal(pRA2ExitInfoRecord->last_cost_menu,9,od_control.user_last_cost_menu); + pRA2ExitInfoRecord->menu_cost_per_min=od_control.user_menu_cost; + pRA2ExitInfoRecord->has_rip=od_control.user_rip; + pRA2ExitInfoRecord->btRIPVersion=od_control.user_rip_ver; + + fwrite(pRA2ExitInfoRecord,1,sizeof(tRA2ExitInfoRecord),pfDropFile); + free(pRA2ExitInfoRecord); + break; + + case EXITINFO: + ODStringCToPascal(pExitInfoRecord->bbs.ra.timeofcreation,5,od_control.user_timeofcreation); + ODStringCToPascal(pExitInfoRecord->bbs.ra.logonpassword,15,od_control.user_logonpassword); + pExitInfoRecord->bbs.ra.wantchat=od_control.user_wantchat; + + ODWriteExitInfoPrimitive(pfDropFile,476); + break; + + + case RA1EXITINFO: + pExtendedExitInfo->deducted_time=od_control.user_deducted_time; + + for(btCount=0;btCount<50;++btCount) + { + ODStringCToPascal(pExtendedExitInfo->menustack[btCount],8,od_control.user_menustack[btCount]); + } + + pExtendedExitInfo->menustackpointer=od_control.user_menustackpointer; + ODStringCToPascal(pExtendedExitInfo->userhandle,35,od_control.user_handle); + ODStringCToPascal(pExtendedExitInfo->comment,80,od_control.user_comment); + ODStringCToPascal(pExtendedExitInfo->firstcall,8,od_control.user_firstcall); + memcpy(pExtendedExitInfo->combinedrecord,od_control.user_combinedrecord,25); + ODStringCToPascal(pExtendedExitInfo->birthday,8,od_control.user_birthday); + ODStringCToPascal(pExtendedExitInfo->subdate,8,od_control.user_subdate); + pExtendedExitInfo->screenwidth=od_control.user_screenwidth; + pExtendedExitInfo->msgarea = (BYTE)od_control.user_msg_area; + pExtendedExitInfo->filearea = (BYTE)od_control.user_file_area; + pExtendedExitInfo->language=od_control.user_language; + pExtendedExitInfo->dateformat=od_control.user_date_format; + ODStringCToPascal(pExtendedExitInfo->forwardto,35,od_control.user_forward_to); + memcpy(&pExtendedExitInfo->error_free,&od_control.user_error_free,3); + ODStringCToPascal(pExtendedExitInfo->emsi_crtdef,40,od_control.user_emsi_crtdef); + ODStringCToPascal(pExtendedExitInfo->emsi_protocols,40,od_control.user_emsi_protocols); + ODStringCToPascal(pExtendedExitInfo->emsi_capabilities,40,od_control.user_emsi_capabilities); + ODStringCToPascal(pExtendedExitInfo->emsi_requests,40,od_control.user_emsi_requests); + ODStringCToPascal(pExtendedExitInfo->emsi_software,40,od_control.user_emsi_software); + memcpy(&pExtendedExitInfo->hold_attr1,&od_control.user_hold_attr1,3); + + ODStringCToPascal(pExitInfoRecord->bbs.ra.timeofcreation,5,od_control.user_timeofcreation); + ODStringCToPascal(pExitInfoRecord->bbs.ra.logonpassword,15,od_control.user_logonpassword); + pExitInfoRecord->bbs.ra.wantchat=od_control.user_wantchat; + + ODWriteExitInfoPrimitive(pfDropFile,476); + fwrite(pExtendedExitInfo,1,1017,pfDropFile); + free(pExtendedExitInfo); + break; + + + case QBBS275EXITINFO: + pExitInfoRecord->elapsed=nInitialElapsed; + pExitInfoRecord->bbs.qbbs.qwantchat=od_control.user_wantchat; + pExitInfoRecord->bbs.qbbs.gosublevel=od_control.user_menustackpointer; + for(btCount=0;btCountbbs.qbbs.gosublevel;++btCount) + { + ODStringCToPascal(pExitInfoRecord->bbs.qbbs.menustack[btCount],8,od_control.user_menustack[btCount]); + } + ODStringCToPascal(pExitInfoRecord->bbs.qbbs.menu,8,od_control.user_menustack[od_control.user_menustackpointer]); + pExitInfoRecord->bbs.qbbs.externlogoff = bTermCall ? 1 : 0; + pExitInfoRecord->bbs.qbbs.ripactive = od_control.user_rip ? 1 : 0; + + ODWriteExitInfoPrimitive(pfDropFile,644); + } + + fclose(pfDropFile); + } + } + + + switch(od_control.od_info_type) + { + case DOORSYS_GAP: + case DOORSYS_WILDCAT: + pfDropFile=fopen(szDropFilePath,"w"); + if(od_control.baud==0L) + { + fprintf(pfDropFile,"COM0:\n"); + } + else + { + fprintf(pfDropFile,"COM%d:\n",od_control.port+1); + } + fprintf(pfDropFile,"%s",apszDropFileInfo[0]); + fprintf(pfDropFile,"%s",apszDropFileInfo[1]); + fprintf(pfDropFile,"%u\n",od_control.od_node); + switch(btDoorSYSLock) + { + case 0: + fprintf(pfDropFile,"%lu\n",od_control.baud); + break; + case 1: + fprintf(pfDropFile,"N\n"); + break; + case 2: + fprintf(pfDropFile,"Y\n"); + } + fprintf(pfDropFile,"%s",apszDropFileInfo[3]); + fprintf(pfDropFile,"%s",apszDropFileInfo[4]); + fprintf(pfDropFile,"%s",apszDropFileInfo[5]); + fprintf(pfDropFile,"%s",apszDropFileInfo[22]); + strupr(od_control.user_name); + fprintf(pfDropFile,"%s\n",od_control.user_name); + fprintf(pfDropFile,"%s\n",od_control.user_location); + fprintf(pfDropFile,"%s\n",od_control.user_homephone); + fprintf(pfDropFile,"%s\n",od_control.user_dataphone); + fprintf(pfDropFile,"%s\n",od_control.user_password); + fprintf(pfDropFile,"%u\n",od_control.user_security); + fprintf(pfDropFile,"%d\n",od_control.user_numcalls); + fprintf(pfDropFile,"%s\n",od_control.user_lastdate); + fprintf(pfDropFile,"%u\n",(signed int)od_control.user_timelimit*60); + fprintf(pfDropFile,"%d\n",od_control.user_timelimit); + if(od_control.user_rip) + { + fprintf(pfDropFile,"RIP\n"); + } + else if(od_control.user_ansi) + { + fprintf(pfDropFile,"GR\n"); + } + else + { + fprintf(pfDropFile,"NG\n"); + } + fprintf(pfDropFile,"%d\n",od_control.user_screen_length); + fprintf(pfDropFile,"%s",apszDropFileInfo[8]); + fprintf(pfDropFile,"%s",apszDropFileInfo[9]); + fprintf(pfDropFile,"%s",apszDropFileInfo[10]); + fprintf(pfDropFile,"%s\n",od_control.user_subdate); + fprintf(pfDropFile,"%u\n",od_control.user_num); + fprintf(pfDropFile,"%s",apszDropFileInfo[6]); + fprintf(pfDropFile,"%u\n",od_control.user_uploads); + fprintf(pfDropFile,"%u\n",od_control.user_downloads); + fprintf(pfDropFile,"%u\n",od_control.user_todayk); + fprintf(pfDropFile,"%s",apszDropFileInfo[21]); + + + if(od_control.od_info_type==DOORSYS_WILDCAT) + { + fprintf(pfDropFile,"%s\n",od_control.user_birthday); + fprintf(pfDropFile,"%s",apszDropFileInfo[11]); + fprintf(pfDropFile,"%s",apszDropFileInfo[12]); + fprintf(pfDropFile,"%s\n",od_control.sysop_name); + strupr(od_control.user_handle); + fprintf(pfDropFile,"%s\n",od_control.user_handle); + fprintf(pfDropFile,"%s\n",od_control.event_starttime); + if(od_control.user_error_free) + fprintf(pfDropFile,"Y\n"); + else + fprintf(pfDropFile,"N\n"); + fprintf(pfDropFile,"%s",apszDropFileInfo[7]); + fprintf(pfDropFile,"%s",apszDropFileInfo[13]); + fprintf(pfDropFile,"%s",apszDropFileInfo[14]); + fprintf(pfDropFile,"%s",apszDropFileInfo[15]); + fprintf(pfDropFile,"%s",apszDropFileInfo[16]); + fprintf(pfDropFile,"%s\n",od_control.user_logintime); + fprintf(pfDropFile,"%s\n",od_control.user_lasttime); + fprintf(pfDropFile,"%s",apszDropFileInfo[18]); + fprintf(pfDropFile,"%s",apszDropFileInfo[19]); + fprintf(pfDropFile,"%u\n",od_control.user_upk); + fprintf(pfDropFile,"%u\n",od_control.user_downk); + fprintf(pfDropFile,"%s\n",od_control.user_comment); + fprintf(pfDropFile,"%s",apszDropFileInfo[20]); + fprintf(pfDropFile,"%u\n",od_control.user_messages); + } + + fclose(pfDropFile); + break; + + + case DOORSYS_DRWY: + pfDropFile=fopen(szDropFilePath,"w"); + fprintf(pfDropFile,"%s\n",od_control.user_name); + + if(od_control.baud==0L) + { + fprintf(pfDropFile,"-1\n"); + } + else + { + fprintf(pfDropFile,"%d\n",od_control.port+1); + } + + fprintf(pfDropFile,"%lu\n",od_control.baud); + + fprintf(pfDropFile,"%d\n",od_control.user_timelimit); + + if(od_control.user_ansi) + { + fprintf(pfDropFile,"G\n"); + } + else + { + fprintf(pfDropFile,"M\n"); + } + + fclose(pfDropFile); + break; + + + case SFDOORSDAT: + pfDropFile=fopen(szDropFilePath,"w"); + + fprintf(pfDropFile,"%u\n",od_control.user_num); + fprintf(pfDropFile,"%s\n",od_control.user_name); + fprintf(pfDropFile,"%s\n",od_control.user_password); + fprintf(pfDropFile,"%s",apszDropFileInfo[0]); + fprintf(pfDropFile,"%lu\n",od_control.baud); + fprintf(pfDropFile,"%d\n",od_control.port+1); + fprintf(pfDropFile,"%d\n",od_control.user_timelimit); + fprintf(pfDropFile,"%s",apszDropFileInfo[13]); + fprintf(pfDropFile,"%s",apszDropFileInfo[14]); + if(od_control.user_ansi) + { + fprintf(pfDropFile,"TRUE\n"); + } + else + { + fprintf(pfDropFile,"FALSE\n"); + } + fprintf(pfDropFile,"%u\n",od_control.user_security); + fprintf(pfDropFile,"%u\n",od_control.user_uploads); + fprintf(pfDropFile,"%u\n",od_control.user_downloads); + fprintf(pfDropFile,"%s",apszDropFileInfo[1]); + fprintf(pfDropFile,"%s",apszDropFileInfo[2]); + fprintf(pfDropFile,"%s",apszDropFileInfo[3]); + if(od_control.sysop_next) + { + fprintf(pfDropFile,"TRUE\n"); + } + else + { + fprintf(pfDropFile,"FALSE\n"); + } + fprintf(pfDropFile,"%s",apszDropFileInfo[4]); + fprintf(pfDropFile,"%s",apszDropFileInfo[5]); + fprintf(pfDropFile,"%s",apszDropFileInfo[6]); + if(od_control.user_error_free) + { + fprintf(pfDropFile,"TRUE\n"); + } + else + { + fprintf(pfDropFile,"FALSE\n"); + } + + fprintf(pfDropFile,"%u\n",od_control.user_msg_area); + fprintf(pfDropFile,"%u\n",od_control.user_file_area); + fprintf(pfDropFile,"%u\n",od_control.od_node); + + fprintf(pfDropFile,"%s",apszDropFileInfo[10]); + fprintf(pfDropFile,"%s",apszDropFileInfo[11]); + fprintf(pfDropFile,"%s",apszDropFileInfo[12]); + fprintf(pfDropFile,"%u\n",od_control.user_todayk); + fprintf(pfDropFile,"%u\n",od_control.user_upk); + fprintf(pfDropFile,"%u\n",od_control.user_downk); + fprintf(pfDropFile,"%s\n",od_control.user_homephone); + fprintf(pfDropFile,"%s\n",od_control.user_location); + if(apszDropFileInfo[15][0]!='\0') + { + fprintf(pfDropFile, "%s", apszDropFileInfo[15]); + fprintf(pfDropFile, od_control.user_rip ? "TRUE\n" : "FALSE\n"); + fprintf(pfDropFile, od_control.user_wantchat ? "TRUE\n" + : "FALSE\n"); + fprintf(pfDropFile, "%s", apszDropFileInfo[17]); + fprintf(pfDropFile, "%d\n", od_control.od_com_irq); + fprintf(pfDropFile, "%d\n", od_control.od_com_address); + fprintf(pfDropFile, "%s", apszDropFileInfo[18]); + } + fclose(pfDropFile); + break; + + + case CHAINTXT: + pfDropFile=fopen(szDropFilePath,"w"); + fprintf(pfDropFile,"%d\n",od_control.user_num); + fprintf(pfDropFile,"%s\n",od_control.user_handle); + fprintf(pfDropFile,"%s\n",od_control.user_name); + fprintf(pfDropFile,"%s\n",od_control.user_callsign); + fprintf(pfDropFile,"%s",apszDropFileInfo[0]); + fprintf(pfDropFile,"%c\n",od_control.user_sex); + fprintf(pfDropFile,"%s",apszDropFileInfo[1]); + fprintf(pfDropFile,"%s\n",od_control.user_lastdate); + fprintf(pfDropFile,"%d\n",od_control.user_screenwidth); + fprintf(pfDropFile,"%d\n",od_control.user_screen_length); + fprintf(pfDropFile,"%d\n",od_control.user_security); + fprintf(pfDropFile,"%d\n",bIsSysop); + fprintf(pfDropFile,"%d\n",bIsCoSysop); + fprintf(pfDropFile,"%d\n",od_control.user_ansi); + if(od_control.baud==0L) + { + fprintf(pfDropFile,"0\n"); + } + else + { + fprintf(pfDropFile,"1\n"); + } + fprintf(pfDropFile," %d.00\n",od_control.user_timelimit*60); + fprintf(pfDropFile,"%s",apszDropFileInfo[3]); + fprintf(pfDropFile,"%s",apszDropFileInfo[4]); + fprintf(pfDropFile,"%s",apszDropFileInfo[5]); + if(od_control.baud==0L) + { + fprintf(pfDropFile,"KB\n"); + } + else + { + fprintf(pfDropFile,"%lu\n",od_control.baud); + } + fprintf(pfDropFile,"%d\n",od_control.port+1); + fprintf(pfDropFile,"%s",apszDropFileInfo[6]); + fprintf(pfDropFile,"%s\n",od_control.user_password); + fprintf(pfDropFile,"%s",apszDropFileInfo[2]); + fprintf(pfDropFile,"%s",apszDropFileInfo[7]); + fprintf(pfDropFile,"%s",apszDropFileInfo[8]); + fprintf(pfDropFile,"%s",apszDropFileInfo[9]); + fprintf(pfDropFile,"%s",apszDropFileInfo[10]); + fprintf(pfDropFile,"%s",apszDropFileInfo[11]); + fprintf(pfDropFile,"%s",apszDropFileInfo[12]); + fclose(pfDropFile); + break; + case TRIBBSSYS: + pfDropFile = fopen(szDropFilePath, "w"); + fprintf(pfDropFile, "%u\n", od_control.user_num); + fprintf(pfDropFile, "%s\n", od_control.user_name); + fprintf(pfDropFile, "%s\n", od_control.user_password); + fprintf(pfDropFile, "%u\n", od_control.user_security); + fprintf(pfDropFile, "%c\n", od_control.user_expert ? 'Y' : 'N'); + fprintf(pfDropFile, "%c\n", od_control.user_ansi ? 'Y' : 'N'); + fprintf(pfDropFile, "%d\n", od_control.user_timelimit); + fprintf(pfDropFile, "%s\n", od_control.user_homephone); + fprintf(pfDropFile, "%s\n", od_control.user_location); + od_control.user_birthday[2] = '/'; + od_control.user_birthday[5] = '/'; + fprintf(pfDropFile, "%s\n", od_control.user_birthday); + fprintf(pfDropFile, "%d\n", od_control.od_node); + fprintf(pfDropFile, "%d\n", od_control.port + 1); + fprintf(pfDropFile, "%lu\n", od_control.od_connect_speed); + fprintf(pfDropFile, "%lu\n", od_control.baud); + fprintf(pfDropFile, "%c\n", (od_control.od_com_flow_control + == COM_RTSCTS_FLOW) ? 'Y' : 'N'); + fprintf(pfDropFile, "%c\n", od_control.user_error_free ? 'Y' : 'N'); + fprintf(pfDropFile, "%s\n", od_control.system_name); + fprintf(pfDropFile, "%s\n", od_control.sysop_name); + fprintf(pfDropFile, "%s\n", od_control.user_handle); + fprintf(pfDropFile, "%c\n", od_control.user_rip ? 'Y' : 'N'); + fclose(pfDropFile); + break; + } + + /* Deallocate temorary strings. */ + for(btCount=0;btCount<25;++btCount) + { + free(apszDropFileInfo[btCount]); + } + + /* If logfile system is active. */ + if(pfLogClose != NULL) + { + /* Then close the logfile. */ + (*pfLogClose)(nErrorLevel); + } + + /* Disconnect the remote user if required. */ + if(od_control.baud && bTermCall) + { + BOOL bCarrier; + + /* Wait up to ten seconds for bufffer to drain. */ + ODWaitDrain(10000); + + /* Wait up to five seconds for no carrier */ + ODComSetDTR(hSerialPort, FALSE); + nMaxTime = time(NULL) + 5L; + + do + { + ODComCarrier(hSerialPort, &bCarrier); + } while(bCarrier && time(NULL) <= nMaxTime); + + /* Raise DTR signal again. */ + ODComSetDTR(hSerialPort, TRUE); + } + + /* In Win32 version, disable DTR before closing serial port, if */ + /* required. */ +#ifdef ODPLAT_WIN32 + /* If we are operating in remote mode, and we should not hangup on the */ + /* caller ... */ + if(!bTermCall && od_control.baud) + { + ODInExDisableDTR(); + } +#endif /* ODPLAT_WIN32 */ + + /* Remove the message that indicates we are in the process of exiting */ + /* or hanging up. */ + ODScrnRemoveMessage(pWindow); + +#ifndef ODPLAT_WIN32 + /* Reset output area boundary to the entire screen. */ + ODScrnSetBoundary(1,1,80,25); + + /* Reset text color. */ + ODScrnSetAttribute(0x07); + + /* Clear screen if neccesary. */ + if(od_control.od_clear_on_exit) + { + ODScrnClear(); + } + else + { + ODScrnSetCursorPos(1, 1); + } +#endif /* !ODPLAT_WIN32 */ + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Terminating kernel threads", "OpenDoors Diagnostics", + MB_OK); + } +#endif + /* Shutdown the OpenDoors kernel. */ + ODKrnlShutdown(); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Shutting down local screen", "OpenDoors Diagnostics", + MB_OK); + } +#endif + /* Shutdown OpenDoors local screen module. */ + ODScrnShutdown(); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Performing any final serial port deallocation", + "OpenDoors Diagnostics", MB_OK); + } +#endif + /* If not operating in local mode, then deallocate serial port resources. */ + if(od_control.baud != 0) + { + /* Close serial port. */ + ODComClose(hSerialPort); + + /* Deallocate serial port object. */ + ODComFree(hSerialPort); + } + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Deallocating common queue", "OpenDoors Diagnostics", + MB_OK); + } +#endif + /* Deallocate input buffer. */ + ODInQueueFree(hODInputQueue); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Going to inactive mode", "OpenDoors Diagnostics", + MB_OK); + } +#endif + /* OpenDoors is no longer active. */ + bODInitialized = FALSE; + + /* od_exit() is no longer active. */ + bExiting = FALSE; + + /* If the client does not want a call to od_exit() to shutdown the */ + /* application, but just to shutdown OpenDoors, then return now. */ + if(od_control.od_noexit) return; + + /* If exit() has already been called, then do not call it again. */ + if(bPreOrExit) return; + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + { + MessageBox(NULL, "Terminating process", "OpenDoors Diagnostics", MB_OK); + } +#endif + /* Exit with appropriate errorlevel. */ + ODProcessExit(nErrorLevel); +} + + +/* ---------------------------------------------------------------------------- + * ODSearchForDropFile() + * + * Searches for a door information (drop) file, given a list of possible drop + * file names. Searches for the drop file first in the directory specified + * by od_control.info_path. If a directory was specified in the configuration + * file, this is where that directory name would be stored. This function will + * then proceed to search the current directory and any directories specified + * by recognized environment variables, until either a drop file is found, or + * until all possibilities are exhaused. + * + * If a directory contains more than one supported dropfile, the choice of + * drop files is narrowed to the most recently written file, and any files + * written in the ten seconds before that file was written. Of these files, + * the file with the highest priority (based on its position in the list of + * possible drop file names) is selected. This heuristic attempts to ignore + * any "old" drop files that may still be hanging around from another + * program or another login session, while still choosing the file with the + * most information. + * + * Parameters: papszFileNames - Array of possible drop file names. + * + * nNumFilesNames - The number of names in papszFileNames. + * + * pszFound - If a drop file was found, this string + * will be changed to point to the filename + * of the file that was found. + * + * pszDirectory - If a drop file was found, this string + * will be changed to contain the name of + * the directory in which the file was found. + * + * Return: Index in the array of the file that was found, or -1 if no + * potential drop file was found. + */ +INT ODSearchForDropFile(char **papszFileNames, INT nNumFileNames, + char *pszFound, char *pszDirectory) +{ + BYTE btCount; + char *pszEnvVarSetting; + INT nResult; + + ASSERT(papszFileNames != NULL); + ASSERT(nNumFileNames > 0); + ASSERT(pszFound != NULL); + + /* First, look for the drop file(s) in the directory specified by */ + /* od_control.info_path. */ + if(strlen(od_control.info_path) != 0) + { + if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound, + od_control.info_path)) != -1) + { + if(pszDirectory != NULL) strcpy(pszDirectory, od_control.info_path); + return(nResult); + } + } + + /* Next, look for the drop file(s) in the current directory. */ + if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound, + "."DIRSEP_STR)) != -1) + { + if(pszDirectory != NULL) strcpy(pszDirectory, "."DIRSEP_STR); + return(nResult); + } + + /* Look through array of environment variables, checking whether any of */ + /* them specify the name of a directory in which a drop file can be */ + /* found. */ + ASSERT(DIM(apszEnvVarNames) == NUM_DIR_ENV_VARS); + for(btCount = 0; btCount < NUM_DIR_ENV_VARS; ++btCount) + { + if((pszEnvVarSetting = (char *)getenv(apszEnvVarNames[btCount])) != NULL) + { + if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound, + pszEnvVarSetting)) != -1) + { + if(pszDirectory != NULL) strcpy(pszDirectory,pszEnvVarSetting); + return(nResult); + } + } + } + + return(-1); +} + + +/* ---------------------------------------------------------------------------- + * ODSearchInDir() *** PRIVATE FUNCTION *** + * + * Private helper function used by ODSearchForDropFile(). Searches for a drop + * file in a single specified directory. The heuristic for selecting a drop + * file, if more than one exists, is described in the header for the + * ODSearchForDropFile() function. + * + * Parameters: papszFileNames - Array of possible drop file names. + * + * nNumFilesNames - The number of names in papszFileNames. + * + * pszFound - If a drop file was found, this string + * will be changed to point to the filename + * of the file that was found. + * + * pszDirectory - Name of the directory to search in. + * + * Return: Index in the array of the file that was found, or -1 if no + * potential drop file was found. + */ +static INT ODSearchInDir(char **papszFileNames, INT nNumFileNames, + char *pszFound, char *pszDirectory) +{ + BYTE btCount; + char szFullName[80]; + INT nFound = -1; + tODDirHandle hDir; + tODDirEntry DirEntry; + time_t LatestTime = 0; + + ASSERT(papszFileNames != NULL); + ASSERT(nNumFileNames > 0); + ASSERT(pszFound != NULL); + ASSERT(pszDirectory != NULL); + + for(btCount=0; btCount < nNumFileNames; ++btCount) + { + /* Do not consider DORINFO1.DEF if a DORINFOx.DEF for this node has */ + /* been found. */ + if(btCount == 2 && nFound == 1) + { + continue; + } + + ASSERT(papszFileNames[btCount] != NULL); + + ODMakeFilename(szFullName, pszDirectory, (char *)papszFileNames[btCount], + sizeof(szFullName)); + + /* Attempt to open directory. */ + if(ODDirOpen(szFullName, DIR_ATTRIB_NORMAL | DIR_ATTRIB_ARCH, &hDir) + == kODRCSuccess) + { + /* Read the first matching entry in the directory. */ + ODDirRead(hDir, &DirEntry); + + if(nFound == -1 + || DirEntry.LastWriteTime > LatestTime + DROPFILE_TIME_LEEWAY) + { + if(!ODFileAccessMode(szFullName, 4)) + { + nFound=btCount; + LatestTime = DirEntry.LastWriteTime; + } + } + + /* Close the open directory. */ + ODDirClose(hDir); + } + } + + if(nFound != -1) + { + ODMakeFilename(pszFound, pszDirectory, (char *)papszFileNames[nFound], + 160); + } + + return(nFound); +} + + +/* ---------------------------------------------------------------------------- + * ODReadExitInfoPrimitive() + * + * Reads the core a of pre-RA2 style EXITINFO.BBS file. + * + * Parameters: pfDropFile - Pointer to already open EXITINFO.BBS file. + * + * nCount - Specifies the number of bytes to read. + * + * Return: TRUE on success, or FALSE on failure. + */ +BOOL ODReadExitInfoPrimitive(FILE *pfDropFile, INT nCount) +{ + if((pExitInfoRecord=malloc(sizeof(tExitInfoRecord)))==NULL) return(FALSE); + + if(fread(pExitInfoRecord,1,nCount,pfDropFile)!=(size_t)nCount) + { + return(FALSE); + } + + /* now we read all the data from the */ + /* EXITINFO structure to the OpenDoors */ + /* control structure. This may look */ + /* a bit messy, but it gets the job */ + /* done, and allows the programmer */ + /* to access all the strings in C */ + /* format instead of Pascal */ + od_control.baud=pExitInfoRecord->baud; + od_control.system_calls=pExitInfoRecord->num_calls; + ODStringPascalToC(od_control.system_last_caller,pExitInfoRecord->last_caller,35); + ODStringPascalToC(od_control.timelog_start_date,pExitInfoRecord->start_date,8); + memcpy(&od_control.timelog_busyperhour,&pExitInfoRecord->busyperhour,62); + ODStringPascalToC(od_control.user_name,pExitInfoRecord->uname,35); + ODStringPascalToC(od_control.user_location,pExitInfoRecord->uloc,25); + ODStringPascalToC(od_control.user_password,pExitInfoRecord->password,15); + ODStringPascalToC(od_control.user_dataphone,pExitInfoRecord->dataphone,12); + ODStringPascalToC(od_control.user_homephone,pExitInfoRecord->homephone,12); + ODStringPascalToC(od_control.user_lasttime,pExitInfoRecord->lasttime,5); + ODStringPascalToC(od_control.user_lastdate,pExitInfoRecord->lastdate,8); + memcpy(&od_control.user_attribute,&pExitInfoRecord->attrib,5); + od_control.user_net_credit=pExitInfoRecord->credit; + od_control.user_pending=pExitInfoRecord->pending; + od_control.user_messages=pExitInfoRecord->posted; + od_control.user_lastread=pExitInfoRecord->lastread; + od_control.user_security=pExitInfoRecord->sec; + od_control.user_numcalls=pExitInfoRecord->nocalls; + od_control.user_uploads=pExitInfoRecord->ups; + od_control.user_downloads=pExitInfoRecord->downs; + od_control.user_upk=pExitInfoRecord->upk; + od_control.user_downk=pExitInfoRecord->downk; + od_control.user_todayk=pExitInfoRecord->todayk; + memcpy(&od_control.user_time_used,&pExitInfoRecord->elapsed,6); + od_control.user_group=pExitInfoRecord->group; + od_control.user_xi_record=pExitInfoRecord->xirecord; + od_control.event_status=pExitInfoRecord->status; + ODStringPascalToC(od_control.event_starttime,pExitInfoRecord->starttime,5); + memcpy(&od_control.event_errorlevel,&pExitInfoRecord->errorlevel,3); + ODStringPascalToC(od_control.event_last_run,pExitInfoRecord->lasttimerun,8); + memcpy(&od_control.user_netmailentered,&pExitInfoRecord->netmailentered,2); + ODStringPascalToC(od_control.user_logintime,pExitInfoRecord->logintime,5); + ODStringPascalToC(od_control.user_logindate,pExitInfoRecord->logindate,8); + + /* Note that the timelimit field is skipped here. This value has already */ + /* been read from the DORINFOx.DEF file, and is not consistently written */ + /* to the EXITINFO.BBS file by various BBS packages. */ + + memcpy(&od_control.user_loginsec,&pExitInfoRecord->loginsec,16); + od_control.user_ansi=od_control.user_attribute&8; + od_control.user_avatar=od_control.user_attrib2&2; + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODWriteExitInfoPrimitive() + * + * Writes the core a of pre-RA2 style EXITINFO.BBS file. + * + * Parameters: pfDropFile - Pointer to already open EXITINFO.BBS file. + * + * nCount - Number of bytes to be written. + * + * Return: Number of bytes actually written. + */ +INT ODWriteExitInfoPrimitive(FILE *pfDropFile, INT nCount) +{ + INT nToReturn; + DWORD dwActiveMinutes; + INT nUserTimeLost; + INT nTimeSubtractedBySysop; + time_t nCurrentUnixTime; + + pExitInfoRecord->num_calls=od_control.system_calls; + ODStringCToPascal(pExitInfoRecord->last_caller,35,od_control.system_last_caller); + ODStringCToPascal(pExitInfoRecord->start_date,8,od_control.timelog_start_date); + memcpy(&pExitInfoRecord->busyperhour,&od_control.timelog_busyperhour,31); + ODStringCToPascal(pExitInfoRecord->uname,35,od_control.user_name); + ODStringCToPascal(pExitInfoRecord->uloc,25,od_control.user_location); + ODStringCToPascal(pExitInfoRecord->password,15,od_control.user_password); + ODStringCToPascal(pExitInfoRecord->dataphone,12,od_control.user_dataphone); + ODStringCToPascal(pExitInfoRecord->homephone,12,od_control.user_homephone); + ODStringCToPascal(pExitInfoRecord->lasttime,5,od_control.user_lasttime); + ODStringCToPascal(pExitInfoRecord->lastdate,8,od_control.user_lastdate); + memcpy(&pExitInfoRecord->attrib,&od_control.user_attribute,5); + pExitInfoRecord->credit=(WORD)od_control.user_net_credit; + pExitInfoRecord->pending=(WORD)od_control.user_pending; + pExitInfoRecord->posted=(WORD)od_control.user_messages; + pExitInfoRecord->lastread=(WORD)od_control.user_lastread; + pExitInfoRecord->sec=(WORD)od_control.user_security; + pExitInfoRecord->nocalls=(WORD)od_control.user_numcalls; + pExitInfoRecord->ups=(WORD)od_control.user_uploads; + pExitInfoRecord->downs=(WORD)od_control.user_downloads; + pExitInfoRecord->upk=(WORD)od_control.user_upk; + pExitInfoRecord->downk=(WORD)od_control.user_downk; + pExitInfoRecord->todayk=(WORD)od_control.user_todayk; + memcpy(&pExitInfoRecord->elapsed,&od_control.user_time_used,6); + pExitInfoRecord->group = (BYTE)od_control.user_group; + pExitInfoRecord->xirecord=(WORD)od_control.user_xi_record; + pExitInfoRecord->status=od_control.event_status; + pExitInfoRecord->status=od_control.event_status; + ODStringCToPascal(pExitInfoRecord->starttime,5,od_control.event_starttime); + memcpy(&pExitInfoRecord->errorlevel,&od_control.event_errorlevel,3); + ODStringCToPascal(pExitInfoRecord->lasttimerun,8,od_control.event_last_run); + memcpy(&pExitInfoRecord->netmailentered,&od_control.user_netmailentered,2); + ODStringCToPascal(pExitInfoRecord->logintime,5,od_control.user_logintime); + ODStringCToPascal(pExitInfoRecord->logindate,8,od_control.user_logindate); + + /* Calculate new time limit based on how time was adjusted during door's */ + /* execution. */ + time(&nCurrentUnixTime); + ODDWordDivide(&dwActiveMinutes, NULL, nCurrentUnixTime-nStartupUnixTime, 60L); + nUserTimeLost = (nInitialRemaining - od_control.user_timelimit); + nTimeSubtractedBySysop = nUserTimeLost - (int)dwActiveMinutes; + pExitInfoRecord->timelimit -= nTimeSubtractedBySysop; + + memcpy(&pExitInfoRecord->loginsec,&od_control.user_loginsec,16); + + nToReturn=(fwrite(pExitInfoRecord,1,nCount,pfDropFile) == (size_t)nCount); + free(pExitInfoRecord); + return(nToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODAtExitCallback() + * + * OpenDoors sets up the C library to call back this function when the program + * is about to exit. OpenDoors uses this function to attempt to trap the + * condition where the programmer exits the program without explicitly calling + * od_exit(). If the program is about to exit, and OpenDoors is still active, + * then od_exit() is called. + * + * It is not recommended that the programmer using OpenDoors rely on this + * mechanism, because: + * + * 1. It doesn't seem to be supported by all compilers. + * + * 2. It doesn't permit OpenDoors to determine the actual error level + * that the program is exiting with in order to report this information + * in the log file (if enabled). + * + * Parameters: none + * + * Return: void + */ +#ifndef ODPLAT_WIN32 +void ODAtExitCallback(void) +{ + if(bODInitialized) + { + bPreOrExit = TRUE; + if(od_control.od_errorlevel[0]) + { + od_exit(od_control.od_errorlevel[7],FALSE); + } + else + { + od_exit(6,FALSE); + } + } +} +#endif /* !ODPLAT_WIN32 */ + + +/* Currently, these functions are only used in the Win32 version. */ +#ifdef ODPLAT_WIN32 + + +/* ---------------------------------------------------------------------------- + * ODSendModemCommand() *** PRIVATE FUNCTION *** + * + * Sends a sequence of commands to the modem, waiting for the specified + * response between each command. The command sequence is retried the specified + * number of times. + * + * Parameters: pszCommand - Command string to send to the modem, along with + * response strings. Each of these are separated by + * a space character. A pipe character ('|') denotes a + * CR, and a tilde character ('~') denotes a one + * second pause. + * + * nRetries - Number of times to retry command sequence. + * + * Return: TRUE on success, or FALSE if some expected response string was + * not received from the modem after modem response timeout period. + */ +static BOOL ODSendModemCommand(char *pszCommand, int nRetries) +{ + ASSERT(pszCommand != NULL); + ASSERT(nRetries >= 1); + + while(nRetries--) + { + if(ODSendModemCommandOnce(pszCommand)) + { + return(TRUE); + } + } + + return(FALSE); +} + + +/* ---------------------------------------------------------------------------- + * ODSendModemCommandOnce() *** PRIVATE FUNCTION *** + * + * Sends a series of commands to the modem, waiting for the specified response + * between each command. + * + * Parameters: pszCommand - Command string to send to the modem, along with + * response strings. Each of these are separated by + * a space character. A pipe character ('|') denotes a + * CR, and a tilde character ('~') denotes a one + * second pause. + * + * Return: TRUE on success, or FALSE if some expected response string was + * not received from the modem after modem response timeout period. + */ +static BOOL ODSendModemCommandOnce(char *pszCommand) +{ + char *pchCurrent; + char szResponse[MAX_RESPONSE_LEN + 1]; + int nResponsePos; + BOOL bSendingCommand = TRUE; + + ASSERT(pszCommand != NULL); + + /* We must be operating in remote mode. */ + ASSERT(od_control.baud != 0); + + /* Loop through each character in the string. */ + for(pchCurrent = pszCommand; *pchCurrent != '\0'; ++pchCurrent) + { + /* What we do with this character depends upon whether we are */ + /* currently sending a command, or waiting for a response. */ + if(bSendingCommand) + { + switch(*pchCurrent) + { + case ' ': + /* A space character denotes that we should toggle between */ + /* sending a command and receiving a response. */ + bSendingCommand = FALSE; + + /* Start at the beginning of the empty response string. */ + nResponsePos = 0; + szResponse[0] = '\0'; + break; + + case '|': + /* A pipe character denotes that a carriage return should be */ + /* send to the modem. */ + ODComSendByte(hSerialPort, '\r'); +#ifdef OD_DIAGNOSTICS + strcat(szDebugWorkString, "\n"); +#endif /* OD_DIAGNOSTICS */ + break; + + case '~': + /* A tilde character denotes a 1 second pause. */ + od_sleep(1000); + break; + + default: + /* Otherwise, send this character as is. */ + ODComSendByte(hSerialPort, *pchCurrent); +#ifdef OD_DIAGNOSTICS + { + char szAppend[2]; + szAppend[0] = *pchCurrent; + szAppend[1] = 0; + strcat(szDebugWorkString, szAppend); + } +#endif /* OD_DIAGNOSTICS */ + } + + od_sleep(200); + } + else + { + /* We are currently building a string that we should wait for. */ + switch(*pchCurrent) + { + case ' ': + /* A space character denotes that we should toggle between */ + /* sending a command and receiving a response. */ + + /* Wait until the response string we have built is received. */ + if(!ODWaitForString(szResponse, RESPONSE_TIMEOUT)) + { + /* If string was not received, then return now. */ + return(FALSE); + } + + /* Switch to sending command mode. */ + bSendingCommand = TRUE; + break; + + case '~': + /* Pauses are ignored in response strings. */ + break; + + default: + /* Otherwise, add this character to the response string. */ + if(nResponsePos < MAX_RESPONSE_LEN) + { + szResponse[nResponsePos] = *pchCurrent; + ++nResponsePos; + szResponse[nResponsePos] = '\0'; + } + } + } + } + + /* Return with success. */ + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODWaitForString() *** PRIVATE FUNCTION *** + * + * Waits for the specified string to be received from the modem, for up to + * the specified length of time. + * + * Parameters: pszResponse - Pointer to the string to wait for. + * + * ResponseTimeout - The maximum time, in milliseconds, to wait. + * + * Return: TRUE on success, or FALSE if some expected response string was + * not received from the modem after modem response timeout period. + */ +static BOOL ODWaitForString(char *pszResponse, tODMilliSec ResponseTimeout) +{ + tODTimer Timer; + char szReceived[MAX_RESPONSE_LEN + 1] = "\0"; + tODInputEvent InputEvent; + + ASSERT(pszResponse != NULL); + ASSERT(ResponseTimeout > 0); + + /* We must be operating in remote mode. */ + ASSERT(od_control.baud != 0); + + /* If response string is empty, then we don't wait for anything. */ + if(strlen(pszResponse) == 0) return(TRUE); + +#ifdef OD_DIAGNOSTICS + strcat(szDebugWorkString, "["); +#endif /* OD_DIAGNOSTICS */ + + ODTimerStart(&Timer, ResponseTimeout); + while(!ODTimerElapsed(&Timer)) + { + if(ODInQueueGetNextEvent(hODInputQueue, &InputEvent, + ODTimerLeft(&Timer)) == kODRCSuccess) + { + if(InputEvent.bFromRemote && InputEvent.EventType == EVENT_CHARACTER) + { +#ifdef OD_DIAGNOSTICS + { + char szAppend[2]; + szAppend[0] = InputEvent.chKeyPress; + szAppend[1] = 0; + strcat(szDebugWorkString, szAppend); + } +#endif /* OD_DIAGNOSTICS */ + + /* Add the received character to the received string. */ + if(strlen(szReceived) == MAX_RESPONSE_LEN) + { + memmove(szReceived, szReceived + 1, MAX_RESPONSE_LEN); + } + szReceived[strlen(szReceived) + 1] = '\0'; + szReceived[strlen(szReceived)] = InputEvent.chKeyPress; + + /* If the sequence has been received, then return with success. */ + if(strstr(szReceived, pszResponse) != NULL) + { +#ifdef OD_DIAGNOSTICS + strcat(szDebugWorkString, "]"); +#endif /* OD_DIAGNOSTICS */ + return(TRUE); + } + } + } + else + { + /* When no characters are waiting, allow other processes to run. */ + od_sleep(0); + } + } + +#ifdef OD_DIAGNOSTICS + strcat(szDebugWorkString, "]"); +#endif OD_DIAGNOSTICS + + /* Indicate that string was not received in the time alotted. */ + return(FALSE); +} + + +/* ---------------------------------------------------------------------------- + * ODInExDisableDTR() + * + * Disables DTR response by the modem, if required. + * + * Parameters: None + * + * Return: void + */ +void ODInExDisableDTR(void) +{ + BOOL bCarrier; + + /* If we are using the Door32 interface, then do not disable DTR. */ + if(od_control.od_com_method == COM_DOOR32 || od_control.od_com_method == COM_SOCKET) + { + return; + } + + /* Check that carrier detect signal is still present. */ + ODComCarrier(hSerialPort, &bCarrier); + if(bCarrier) + { + /* Only disable DTR response if OpenDoors opened the serial port, */ + /* and DTR disabling has not been explicitly turned off. */ + if(od_control.od_open_handle == 0 + && !(od_control.od_disable & DIS_DTR_DISABLE)) + { + if(!ODSendModemCommand(od_control.od_disable_dtr, 2)) + { +#ifdef OD_DIAGNOSTICS + if(od_control.od_internal_debug) + { + MessageBox(NULL, szDebugWorkString, "DTR Disable FAILED!", + MB_OK); + szDebugWorkString[0] = '\0'; + } +#endif /* OD_DIAGNOSTICS */ + } + else + { +#ifdef OD_DIAGNOSTICS + if(od_control.od_internal_debug) + { + MessageBox(NULL, szDebugWorkString, "DTR Disable Succeeded!", + MB_OK); + szDebugWorkString[0] = '\0'; + } +#endif /* OD_DIAGNOSTICS */ + } + } + } +} + +#endif /* ODPLAT_WIN32 */ diff --git a/utils/magiedit/odoors/ODInQue.c b/utils/magiedit/odoors/ODInQue.c new file mode 100644 index 0000000..90349a2 --- /dev/null +++ b/utils/magiedit/odoors/ODInQue.c @@ -0,0 +1,443 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODInQue.h + * + * Description: OpenDoors input queue management. This input queue is where + * all input events (e.g. keystrokes) from both local and remote + * systems are combined into a single stream. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 16, 1995 6.00 BP Created. + * Nov 17, 1995 6.00 BP Added multithreading support. + * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent. + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 30, 1996 6.00 BP Add semaphore timeout. + * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include + +#include "OpenDoor.h" +#include "ODGen.h" +#include "ODInQue.h" +#include "ODPlat.h" +#include "ODKrnl.h" + + +/* Input queue handle structure. */ +typedef struct +{ + tODInputEvent *paEvents; + INT nQueueEntries; + INT nInIndex; + INT nOutIndex; + time_t nLastActivityTime; +#ifdef OD_MULTITHREADED + tODSemaphoreHandle hItemCountSemaphore; + tODSemaphoreHandle hAddEventSemaphore; +#endif /* OD_MULTITHREADED */ +} tInputQueueInfo; + + +/* ---------------------------------------------------------------------------- + * ODInQueueAlloc() + * + * Allocates a new input queue. + * + * Parameters: phInQueue - Pointer to location where a handle to the + * newly allocated input queue should be + * stored. + * + * nInitialQueueSize - The minimum number of events that the + * input queue should be able to hold. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODInQueueAlloc(tODInQueueHandle *phInQueue, INT nInitialQueueSize) +{ + tInputQueueInfo *pInputQueueInfo = NULL; + tODInputEvent *pInputQueue = NULL; + tODResult Result = kODRCNoMemory; + + ASSERT(phInQueue != NULL); + + if(phInQueue == NULL) return(kODRCInvalidCall); + + /* Attempt to allocate a serial port information structure. */ + pInputQueueInfo = malloc(sizeof(tInputQueueInfo)); + + /* If memory allocation failed, return with failure. */ + if(pInputQueueInfo == NULL) goto CleanUp; + + /* Initialize semaphore handles to NULL. */ +#ifdef OD_MULTITHREADED + pInputQueueInfo->hItemCountSemaphore = NULL; + pInputQueueInfo->hAddEventSemaphore = NULL; +#endif /* OD_MULTITHREADED */ + + /* Attempt to allocate space for the queue itself. */ + pInputQueue = calloc(nInitialQueueSize, sizeof(tODInputEvent)); + if(pInputQueue == NULL) goto CleanUp; + + /* Create semaphores if this is a multithreaded platform. */ +#ifdef OD_MULTITHREADED + if(ODSemaphoreAlloc(&pInputQueueInfo->hItemCountSemaphore, 0, + nInitialQueueSize) != kODRCSuccess) + { + goto CleanUp; + } + + if(ODSemaphoreAlloc(&pInputQueueInfo->hAddEventSemaphore, 1, 1) + != kODRCSuccess) + { + goto CleanUp; + } +#endif /* OD_MULTITHREADED */ + + /* Initialize input queue information structure. */ + pInputQueueInfo->paEvents = pInputQueue; + pInputQueueInfo->nQueueEntries = nInitialQueueSize; + pInputQueueInfo->nInIndex = 0; + pInputQueueInfo->nOutIndex = 0; + + /* Convert intut queue information structure pointer to a handle. */ + *phInQueue = ODPTR2HANDLE(pInputQueueInfo, tInputQueueInfo); + + /* Reset the time of the last activity. */ + ODInQueueResetLastActivity(*phInQueue); + + Result = kODRCSuccess; + +CleanUp: + if(Result != kODRCSuccess) + { +#ifdef OD_MULTITHREADED + if(pInputQueueInfo != NULL + && pInputQueueInfo->hItemCountSemaphore != NULL) + { + ODSemaphoreFree(pInputQueueInfo->hItemCountSemaphore); + } + + if(pInputQueueInfo != NULL + && pInputQueueInfo->hAddEventSemaphore != NULL) + { + ODSemaphoreFree(pInputQueueInfo->hAddEventSemaphore); + } +#endif /* OD_MULTITHREADED */ + + if(pInputQueue != NULL) free(pInputQueue); + if(pInputQueueInfo != NULL) free(pInputQueueInfo); + *phInQueue = ODPTR2HANDLE(NULL, tInputQueueInfo); + } + + /* Return with the appropriate result code. */ + return(Result); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueFree() + * + * Destroys an input queue that was previously created by ODInQueueAlloc(). + * + * Parameters: hInQueue - Handle to the input queue to destroy. + * + * Return: void + */ +void ODInQueueFree(tODInQueueHandle hInQueue) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + + ASSERT(pInputQueueInfo != NULL); + + /* Deallocate semaphores, if appropriate. */ +#ifdef OD_MULTITHREADED + ASSERT(pInputQueueInfo->hItemCountSemaphore != NULL); + ODSemaphoreFree(pInputQueueInfo->hItemCountSemaphore); +#endif /* OD_MULTITHREADED */ + + /* Deallocate the input queue itself. */ + ASSERT(pInputQueueInfo->paEvents != NULL); + free(pInputQueueInfo->paEvents); + + /* Deallocate port information structure. */ + free(pInputQueueInfo); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueWaiting() + * + * Determines whether or not an event is currently waiting in the input queue. + * + * Parameters: hInQueue - Handle to the input queue to check. + * + * Return: TRUE if there is one or more waiting events, or FALSE if the + * queue is empty. + */ +BOOL ODInQueueWaiting(tODInQueueHandle hInQueue) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + BOOL bEventWaiting; + + ASSERT(pInputQueueInfo != NULL); + + /* There is data waiting in the queue if the in index is not equal to */ + /* the out index. */ + bEventWaiting = (pInputQueueInfo->nInIndex != pInputQueueInfo->nOutIndex); + + return(bEventWaiting); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueAddEvent() + * + * Adds a new event to the input queue. + * + * Parameters: hInQueue - Handle to the input queue to add an event to. + * + * pEvent - Pointer to the event structure to obtain the + * event information from. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODInQueueAddEvent(tODInQueueHandle hInQueue, + tODInputEvent *pEvent) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + INT nNextInPos; + + ASSERT(pInputQueueInfo != NULL); + ASSERT(pEvent != NULL); + if(pInputQueueInfo == NULL || pEvent == NULL) return(kODRCInvalidCall); + + /* Serialize access to add event function. */ +#ifdef OD_MULTITHREADED + ODSemaphoreDown(pInputQueueInfo->hAddEventSemaphore, OD_NO_TIMEOUT); +#endif /* OD_MULTITHREADED */ + + /* Reset the time of the last activity. */ + ODInQueueResetLastActivity(hInQueue); + + /* Determine what the next in index would be after this addition to the */ + /* queue. */ + nNextInPos = (pInputQueueInfo->nInIndex + 1) + % pInputQueueInfo->nQueueEntries; + + /* If the queue is full, then return an out of space error. */ + if(nNextInPos == pInputQueueInfo->nOutIndex) + { + /* Allow further access to input queue. */ +#ifdef OD_MULTITHREADED + ODSemaphoreUp(pInputQueueInfo->hAddEventSemaphore, 1); +#endif /* OD_MULTITHREADED */ + + return(kODRCNoMemory); + } + + /* Otherwise, add the new event to the input queue. */ + memcpy(&pInputQueueInfo->paEvents[pInputQueueInfo->nInIndex], pEvent, + sizeof(tODInputEvent)); + + /* Update queue in index. */ + pInputQueueInfo->nInIndex = nNextInPos; + + /* Increment queue items count semaphore. */ +#ifdef OD_MULTITHREADED + ODSemaphoreUp(pInputQueueInfo->hItemCountSemaphore, 1); +#endif /* OD_MULTITHREADED */ + + /* Allow further access to add event function. */ +#ifdef OD_MULTITHREADED + ODSemaphoreUp(pInputQueueInfo->hAddEventSemaphore, 1); +#endif /* OD_MULTITHREADED */ + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueGetNextEvent() + * + * Obtains the next event from the input queue. If no events are currently + * waiting in the input queue, this function blocks until an item is added + * to the queue, or the maximum wait time is reached. + * + * Parameters: hInQueue - Handle to the input queue to obtain the next event + * from. + * + * pEvent - Pointer to structure to store input event information + * in. + * + * Timeout - Maximum time, in milliseconds, to wait for next input + * event. A value of OD_NO_TIMEOUT causes this function + * to only return when an input event is obtained. + * + * Return: kODRCSuccess on succes, or kODRCTimeout if the maximum wait time + * is exceeded. + */ +tODResult ODInQueueGetNextEvent(tODInQueueHandle hInQueue, + tODInputEvent *pEvent, tODMilliSec Timeout) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + + ASSERT(pInputQueueInfo != NULL); + ASSERT(pEvent != NULL); + +#ifdef OD_MULTITHREADED + + /* In multithreaded implementations, we wait for there to be an item in */ + /* the queue by decrementing the queue size semaphore. This will cause */ + /* this thread to be blocked until an event is added to the queue, if it */ + /* is currently empty. */ + + if(ODSemaphoreDown(pInputQueueInfo->hItemCountSemaphore, Timeout)==kODRCTimeout) + return(kODRCTimeout); + +#else /* !OD_MULTITHREADED */ + + /* In non-multithreaded implementations, we check queue in and out */ + /* indicies to determine whether there are any events waiting in the */ + /* queue. If the queue is empty we loop, calling od_kernel() to check */ + /* for new events and od_yeild() to give more time to other processors */ + /* if there is nothing for us to do, until an event is added to the */ + /* queue. */ + if(pInputQueueInfo->nInIndex == pInputQueueInfo->nOutIndex) + { + tODTimer Timer; + + /* If a timeout has been specified, then start timer to keep track */ + /* of how long we have been waiting. */ + if(Timeout != 0 && Timeout != OD_NO_TIMEOUT) + { + ODTimerStart(&Timer, Timeout); + } + + /* As soon as we see that there is nothing in the queue, we do an */ + /* od_kernel() call to check for new input. */ + CALL_KERNEL_IF_NEEDED(); + + /* As long as we don't have new input, we loop, yielding to other */ + /* processes, and then giving od_kernel() a chance to run. */ + while(pInputQueueInfo->nInIndex == pInputQueueInfo->nOutIndex) + { + /* If a timeout has been specified, then ensure that the maximum */ + /* wait time has not elapsed. */ + if(Timeout != 0 && Timeout != OD_NO_TIMEOUT + && ODTimerElapsed(&Timer)) + { + return(kODRCTimeout); + } + + /* Yield the processor to other tasks. */ + od_sleep(0); + + /* Call od_kernel(). */ + CALL_KERNEL_IF_NEEDED(); + } + } + +#endif /* !OD_MULTITHREADED */ + + /* Copy next input event from the queue into the caller's structure. */ + memcpy(pEvent, &pInputQueueInfo->paEvents[pInputQueueInfo->nOutIndex], + sizeof(tODInputEvent)); + + /* Move out pointer to the next queue item, wrapping back to the start */ + /* of the queue if needed. */ + pInputQueueInfo->nOutIndex + = (pInputQueueInfo->nOutIndex + 1) % pInputQueueInfo->nQueueEntries; + + /* Now, return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueEmpty() + * + * Removes all events from the input queue. + * + * Parameters: hInQueue - Handle to the input queue to be emptied. + * + * Return: void + */ +void ODInQueueEmpty(tODInQueueHandle hInQueue) +{ + tODInputEvent InputEvent; + + ASSERT(hInQueue != NULL); + + /* Remove all items from the queue. */ + while(ODInQueueWaiting(hInQueue)) + { + ODInQueueGetNextEvent(hInQueue, &InputEvent, OD_NO_TIMEOUT); + } +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueGetLastActivity() + * + * Returns the time of the last input activity. This is the latest of the time + * that the queue was created, the time of the last call to + * ODInQueueAddEvent() on this input queue, and the time of the last call to + * ODInQueueResetLastActivity() on this input queue. + * + * Parameters: hInQueue - Handle to the input queue. + * + * Return: void + */ +time_t ODInQueueGetLastActivity(tODInQueueHandle hInQueue) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + + ASSERT(pInputQueueInfo != NULL); + + /* Returns the last activity time. */ + return(pInputQueueInfo->nLastActivityTime); +} + + +/* ---------------------------------------------------------------------------- + * ODInQueueResetLastActivity() + * + * Resets the time of the last input activity to the current time. + * + * Parameters: hInQueue - Handle to the input queue. + * + * Return: void + */ +void ODInQueueResetLastActivity(tODInQueueHandle hInQueue) +{ + tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo); + + ASSERT(pInputQueueInfo != NULL); + + /* Resets the last activity time to the current time. */ + pInputQueueInfo->nLastActivityTime = time(NULL); +} diff --git a/utils/magiedit/odoors/ODInQue.h b/utils/magiedit/odoors/ODInQue.h new file mode 100644 index 0000000..3be1e4d --- /dev/null +++ b/utils/magiedit/odoors/ODInQue.h @@ -0,0 +1,57 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODInQue.h + * + * Description: OpenDoors input queue management. This input queue is where + * all input events (e.g. keystrokes) from both local and remote + * systems are combined into a single stream. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 16, 1995 6.00 BP Created. + * Jan 04, 1996 6.00 BP Moved event type defs to OpenDoor.h. + * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent. + * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODINQUE +#define _INC_ODINQUE + +#include + +#include "ODTypes.h" + +/* OpenDoors input queue handle. */ +typedef tODHandle tODInQueueHandle; + +/* Input queue functions. */ +tODResult ODInQueueAlloc(tODInQueueHandle *phInQueue, INT nInitialQueueSize); +void ODInQueueFree(tODInQueueHandle hInQueue); +BOOL ODInQueueWaiting(tODInQueueHandle hInQueue); +tODResult ODInQueueAddEvent(tODInQueueHandle hInQueue, + tODInputEvent *pEvent); +tODResult ODInQueueGetNextEvent(tODInQueueHandle hInQueue, + tODInputEvent *pEvent, tODMilliSec Timeout); +void ODInQueueEmpty(tODInQueueHandle hInQueue); +time_t ODInQueueGetLastActivity(tODInQueueHandle hInQueue); +void ODInQueueResetLastActivity(tODInQueueHandle hInQueue); + +#endif /* _INC_ODINQUE */ diff --git a/utils/magiedit/odoors/ODInfo.ico b/utils/magiedit/odoors/ODInfo.ico new file mode 100644 index 0000000..842108f Binary files /dev/null and b/utils/magiedit/odoors/ODInfo.ico differ diff --git a/utils/magiedit/odoors/ODKrnl.c b/utils/magiedit/odoors/ODKrnl.c new file mode 100644 index 0000000..4810a0a --- /dev/null +++ b/utils/magiedit/odoors/ODKrnl.c @@ -0,0 +1,1675 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODKrnl.c + * + * Description: Contains the OpenDoors kernel, which is responsible for many + * of the core functions which continue regardless of what the + * client program is doing. The implementation of this file is + * central to the OpenDoors architecture. The functionality + * implemented by the OpenDoors kernel includes (but is not + * limited to): + * + * - Obtaining and input from the user, through the modem + * and possibly the local keyboard. + * - Monitoring maximum time and inactivity time limits. + * - Responding to loss of carrier. + * - Forcing the status line to be updated regularily, + * on platforms that it exists. + * - Implementing the system operator <-> remote user chat + * mode. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Jan 01, 1995 6.00 BP Split off from odcore.c + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 15, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Nov 21, 1995 6.00 BP Ported to Win32. + * 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 24, 1995 6.00 BP od_chat_active = TRUE on chat start. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent. + * Jan 12, 1996 6.00 BP Added bOnlyShiftArrow. + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 30, 1996 6.00 BP Add semaphore timeout. + * Feb 06, 1996 6.00 BP Added od_silent_mode. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 23, 1996 6.00 BP Only create active semapore once. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Prevent TC generated N_SCOPY@ call. + * Mar 13, 1996 6.10 BP bOnlyShiftArrow -> nArrowUseCount. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Oct 22, 2001 6.21 RS Lowered thread priorities to normal. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#ifdef ODPLAT_NIX +#include +#include +#include +#include +#include +#endif +#include "ODCore.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODCom.h" +#include "ODKrnl.h" +#include "ODScrn.h" +#include "ODInQue.h" +#include "ODInEx.h" +#ifdef ODPLAT_WIN32 +#include "ODFrame.h" +#endif /* ODPLAT_WIN32 */ + + +/* Multithreading performance tuning. */ +#define REMOTE_INPUT_THREAD_PRIORITY OD_PRIORITY_NORMAL /* was ABOVE_NORMAL */ +#define NO_CARRIER_THREAD_PRIORITY OD_PRIORITY_NORMAL /* was ABOVE_NORMAL */ +#define NO_CARRIER_THREAD_SLEEP_TIME 6000 +#define TIME_UPDATE_THREAD_PRIORITY OD_PRIORITY_NORMAL +#define TIME_UPDATE_THREAD_SLEEP_TIME 3000 + +/* Misc performance tuning. */ +#define STATUS_UPDATE_PERIOD 3L +#define CHAT_YIELD_PERIOD 25L + +/* Pending command identifiers. */ +#define KERNEL_FUNC_CHATTOGGLE 0x0001 + +/* Private function prototypes. */ +static void ODKrnlHandleReceivedChar(char chReceived, BOOL bFromRemote); +static void ODKrnlTimeUpdate(void); +static void ODKrnlChatCleanup(void); +static void ODKrnlChatMode(void); +#ifdef ODPLAT_NIX +#ifdef USE_KERNEL_SIGNAL +static void sig_run_kernel(int sig); +static void sig_get_char(int sig); +static void sig_no_carrier(int sig); +#endif +#endif + +/* Functions specific to the multithreaded implementation of the kernel. */ +#ifdef OD_MULTITHREADED +/* Thread proceedures. */ +DWORD OD_THREAD_FUNC ODKrnlRemoteInputThread(void *pParam); +DWORD OD_THREAD_FUNC ODKrnlNoCarrierThread(void *pParam); +DWORD OD_THREAD_FUNC ODKrnlTimeUpdateThread(void *pParam); +DWORD OD_THREAD_FUNC ODKrnlChatThread(void *pParam); + +/* Helper functions. */ +static void ODKrnlWaitForExclusiveControl(void); +static void ODKrnlGiveUpExclusiveControl(void); +#endif /* OD_MULTITHREADED */ + +/* Local working variables. */ +#ifdef OD_MULTITHREADED +static tODThreadHandle hRemoteInputThread = NULL; +static tODThreadHandle hNoCarrierThread = NULL; +static tODThreadHandle hTimeUpdateThread = NULL; +static tODThreadHandle hClientThread = NULL; +static tODThreadHandle hChatThread = NULL; +static BOOL bHaveExclusiveControl; +static BOOL bChatActivatedInternally; +#endif /* OD_MULTITHREADED */ +static BOOL bKernelActive = FALSE; +static BOOL bWarnedAboutInactivity = FALSE; +static INT16 nLastInactivitySetting = 0; +static time_t nNextStatusUpdateTime; +static INT nKrnlFuncPending; +static BOOL bLastStatusSetting; +static INT16 nChatOriginalAttrib; + +/* Global kernel-related variables. */ +tODTimer RunKernelTimer; +time_t nNextTimeDeductTime; +char chLastControlKey = '\0'; +INT nArrowUseCount = 0; +BOOL bForceStatusUpdate = FALSE; +BOOL bIsShell; +#ifdef OD_MULTITHREADED +tODSemaphoreHandle hODActiveSemaphore = NULL; +#endif /* OD_MULTITHREADED */ + + + +/* ========================================================================= */ +/* Core of the OpenDoors Kernel. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODKrnlInitialize() + * + * Initializes kernel activities. In multithreaded versions of OpenDoors, this + * is the function that starts the various kernel threads. + * + * Parameters: kODRCSuccess on success, or an error code on failure. + * + * Return: void + */ +tODResult ODKrnlInitialize(void) +{ +#ifdef ODPLAT_NIX + sigset_t block; +#ifdef USE_KERNEL_SIGNAL + struct sigaction act; + struct itimerval itv; +#endif +#endif + + tODResult Result = kODRCSuccess; + +#ifdef ODPLAT_NIX +#ifdef USE_KERNEL_SIGNAL + /* HUP Detection */ + act.sa_handler=sig_no_carrier; + /* If two HUP signals are recieved, die on the second */ + act.sa_flags=SA_RESETHAND|SA_RESTART; + sigemptyset(&(act.sa_mask)); + sigaction(SIGHUP,&act,NULL); + + /* Run kernel on SIGALRM (Every .01 seconds) */ + act.sa_handler=sig_run_kernel; + act.sa_flags=SA_RESTART; + sigemptyset(&(act.sa_mask)); + sigaction(SIGALRM,&act,NULL); + itv.it_interval.tv_sec=0; + itv.it_interval.tv_usec=10000; + itv.it_value.tv_sec=0; + itv.it_value.tv_usec=10000; + setitimer(ITIMER_REAL,&itv,NULL); + + /* Make stdin signal driven. */ +// act.sa_handler=sig_get_char; +// act.sa_flags=0; +// sigemptyset(&(act.sa_mask)); +// sigaction(SIGIO,&act,NULL); +// +// /* Have SIGIO signals delivered to this process */ +// fcntl(0,F_SETOWN,getpid()); +// +// /* Enable SIGIO when read possible on stdin */ +// fcntl(0,F_SETFL,fcntl(0,F_GETFL)|O_ASYNC); + + /* Make sure SIGHUP, SIGALRM, and SIGIO are unblocked */ + sigemptyset(&block); + sigaddset(&block,SIGHUP); + sigaddset(&block,SIGALRM); +#if 0 + sigaddset(&block,SIGIO); +#endif + sigprocmask(SIG_UNBLOCK,&block,NULL); +#else /* Using ODComCarrier... don't catch HUP signal */ + sigemptyset(&block); + sigaddset(&block,SIGHUP); + sigprocmask(SIG_BLOCK,&block,NULL); +#endif +#endif + + /* Initialize time of next status update and next time deduction. */ + nNextStatusUpdateTime = time(NULL) + STATUS_UPDATE_PERIOD; + nNextTimeDeductTime = time(NULL) + 60L; + bLastStatusSetting = od_control.od_status_on = TRUE; + + /* Initially, no kernel functions are pending. */ + nKrnlFuncPending = 0; + + /* Initially, the kernel is not active. */ + bKernelActive = FALSE; + +#ifdef OD_MULTITHREADED + /* Initially, we do not have exclusive control of the application. */ + bHaveExclusiveControl = FALSE; + + /* Obtain a handle to the client thread. */ + hClientThread = ODThreadGetCurrent(); + + /* Create OpenDoors activation semaphore. */ + if(hODActiveSemaphore == NULL) + { + Result = ODSemaphoreAlloc(&hODActiveSemaphore, 0, INT_MAX); + if(Result != kODRCSuccess) return(Result); + } + + /* Start the remote input thread if we are not operating in local mode. */ + if(od_control.baud != 0) + { + Result = ODThreadCreate(&hRemoteInputThread, ODKrnlRemoteInputThread, + NULL); + if(Result != kODRCSuccess) return(Result); + ODThreadSetPriority(hRemoteInputThread, REMOTE_INPUT_THREAD_PRIORITY); + } + + /* Start the carrier detection thread if we are not operating in local */ + /* mode. */ + if(od_control.baud != 0) + { + Result = ODThreadCreate(&hNoCarrierThread, ODKrnlNoCarrierThread, NULL); + if(Result != kODRCSuccess) return(Result); + ODThreadSetPriority(hNoCarrierThread, NO_CARRIER_THREAD_PRIORITY); + } + + /* Start the time update thread. */ + Result = ODThreadCreate(&hTimeUpdateThread, ODKrnlTimeUpdateThread, 0); + if(Result != kODRCSuccess) return(Result); + ODThreadSetPriority(hTimeUpdateThread, TIME_UPDATE_THREAD_PRIORITY); +#endif /* OD_MULTITHREADED */ + + /* Return with success. */ + return(Result); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlShutdown() + * + * Shuts down kernel activities. + * + * Parameters: none + * + * Return: void + */ +void ODKrnlShutdown(void) +{ + if(bKernelActive) return; + +#ifdef OD_MULTITHREADED +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + MessageBox(NULL, "Terminating remote input thread", "OpenDoors Diagnostics", MB_OK); +#endif + /* Shutdown the remote input thread, if it exists. */ + if(hRemoteInputThread != NULL) ODThreadTerminate(hRemoteInputThread); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + MessageBox(NULL, "Terminating carrier detection", "OpenDoors Diagnostics", MB_OK); +#endif + /* Shutdown the carrier detection thread, if it exists. */ + if(hNoCarrierThread != NULL) ODThreadTerminate(hNoCarrierThread); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + MessageBox(NULL, "Terminating time update thread", "OpenDoors Diagnostics", MB_OK); +#endif + /* Shutdown the time update thread, if it exists. */ + if(hTimeUpdateThread != NULL) ODThreadTerminate(hTimeUpdateThread); + +#if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32) + if(od_control.od_internal_debug) + MessageBox(NULL, "Releasing activation semaphore", "OpenDoors Diagnostics", MB_OK); +#endif +#endif /* OD_MULTITHREADED */ +} + + +/* ---------------------------------------------------------------------------- + * od_kernel() + * + * Carries out any kernel tasks that must be performed through regular, + * explicit calls to this function, + * + * Parameters: none + * + * Return: void + */ +ODAPIDEF void ODCALL od_kernel(void) +{ +#ifndef OD_MULTITHREADED + char ch; +#ifdef ODPLAT_DOS + WORD wKey; + BYTE btShiftStatus; + char *pszShellName; +#endif + BOOL bCarrier; +#endif /* OD_MULTITHREADED */ + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_kernel()"); + + /* Initialize OpenDoors if not already done. */ + if(!bODInitialized) od_init(); + + /* If this is an attempt at a re-entrant call to od_kernel() from another */ + /* function called by a currently active od_kernel(), then return without */ + /* doing anything. */ + if(bKernelActive) return; + + OD_API_ENTRY(); + + /* Note that kernel is active to prevent recursive calls to the kernel. */ + bKernelActive = TRUE; + + /* Call od_ker_exec function if required. */ + if(od_control.od_ker_exec != NULL) + { + (*od_control.od_ker_exec)(); + } + + /* The remainder of od_kernel() only applies to non-multithreaded */ + /* versions of OpenDoors. */ +#ifndef OD_MULTITHREADED + /* If not operating in local mode, then perform remote-mode specific */ + /* activies. */ + if(od_control.baud != 0) + { +#ifndef USE_KERNEL_SIGNAL + /* If carrier detection is enabled, then shutdown OpenDoors if */ + /* the carrier detect signal is no longer high. */ + if(!(od_control.od_disable&DIS_CARRIERDETECT)) + { + ODComCarrier(hSerialPort, &bCarrier); + if(!bCarrier) + { + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_NOCARRIER); + } + } +#endif + + /* Loop, obtaining any new characters from the serial port and */ + /* adding them to the common local/remote input queue. */ + while(ODComGetByte(hSerialPort, &ch, FALSE) == kODRCSuccess) + { + ODKrnlHandleReceivedChar(ch, TRUE); + } + } + +#ifdef ODPLAT_DOS +check_keyboard_again: + if(nKrnlFuncPending && !bShellChatActive) + { + if(nKrnlFuncPending & KERNEL_FUNC_CHATTOGGLE) + { + nKrnlFuncPending &=~ KERNEL_FUNC_CHATTOGGLE; + goto chat_pressed; + } + } + + /* Don't check local keyboard if sysop DIS_SYSOP_KEYS is set, or if we */ + /* are operatingin silent mode. */ + if(od_control.od_disable & DIS_SYSOP_KEYS + || od_control.od_silent_mode) + { + goto after_key_check; + } + + ASM mov ah, 1 + ASM push si + ASM push di + ASM int 0x16 + ASM jnz key_waiting + ASM pop di + ASM pop si + ASM jmp after_key_check +key_waiting: + ASM mov ah, 0 + ASM int 0x16 + ASM mov wKey, ax + ASM mov ah, 2 + ASM int 0x16 + ASM mov btShiftStatus, al + ASM pop di + ASM pop si + + if(nArrowUseCount > 0 && (wKey == 0x4800 || wKey == 0x5000) + && !(btShiftStatus & 2)) + { + /* Pass key on to od_local_input, if it is defined. */ + if(od_control.od_local_input != NULL) + { + (*od_control.od_local_input)(wKey); + } + + /* Add this key to the local/remote input queue. */ + ODKrnlHandleLocalKey(wKey); + } + + /* If hangup key is pressed. */ + else if(wKey == od_control.key_hangup) + { + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP); + } + + /* If drop to BBS key is pressed. */ + else if(wKey == od_control.key_drop2bbs) + { + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_DROPTOBBS); + } + + else if(wKey == od_control.key_dosshell) + { + if(!bShellChatActive) + { + if(pfLogWrite != NULL) + (*pfLogWrite)(6); + + /* If function hook is defined. */ + if(od_control.od_cbefore_shell != NULL) + { + /* Then call it. */ + bShellChatActive = TRUE; + (*od_control.od_cbefore_shell)(); + bShellChatActive = FALSE; + } + + if(od_control.od_before_shell != NULL) + od_disp_str(od_control.od_before_shell); + + if((pszShellName = (char *)getenv("COMSPEC")) == NULL) + { + pszShellName = (char *)"COMMAND.COM"; + } + bIsShell = TRUE; + od_spawnvpe(P_WAIT, pszShellName, NULL, NULL); + bIsShell = FALSE; + + if(od_control.od_after_shell != NULL) + od_disp_str(od_control.od_after_shell); + + /* If a function hook is defined. */ + if(od_control.od_cafter_shell != NULL) + { + /* Then call it. */ + bShellChatActive = TRUE; + (*od_control.od_cafter_shell)(); + bShellChatActive = FALSE; + } + + if(pfLogWrite != NULL) + (*pfLogWrite)(7); + } + } + + /* If toggle chat mode key is pressed. */ + else if(wKey == od_control.key_chat) + { +chat_pressed: + if(!bShellChatActive || od_control.od_chat_active) + { + /* If chat mode is active. */ + if(od_control.od_chat_active) + { + /* Signal exit of chat mode. */ + ODKrnlEndChatMode(); + } + + /* If chat mode is off. */ + else + { + /* Enable second call to kernel. */ + bKernelActive = FALSE; + + /* Enter chat mode. */ + ODKrnlChatMode(); + + /* Disable second call to kernel. */ + bKernelActive = TRUE; + } + } + else + { + if(nKrnlFuncPending & KERNEL_FUNC_CHATTOGGLE) + { + nKrnlFuncPending &= ~KERNEL_FUNC_CHATTOGGLE; + } + else + { + nKrnlFuncPending |= KERNEL_FUNC_CHATTOGGLE; + } + } + } + + /* If sysop next key is pressed. */ + else if(wKey == od_control.key_sysopnext) + { + /* Toggle sysop next setting. */ + od_control.sysop_next = !od_control.sysop_next; + + /* Update status line. */ + goto statup; + } + + /* If ESCape key is pressed and we are in chat mode. */ + else if((wKey&0xff) == 27 && od_control.od_chat_active) + { + /* Signal exit from chat mode. */ + od_control.od_chat_active = FALSE; + } + + /* If lockout user key is pressed. */ + else if(wKey == od_control.key_lockout) + { + /* Set the user's access security level to 0. */ + od_control.user_security = 0; + + /* Shutdown OpenDoors. */ + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_HANGUP); + } + + + /* If toggle keyboard off key is pressed. */ + else if(wKey == od_control.key_keyboardoff) + { + /* Toggle user keyboard settings. */ + od_control.od_user_keyboard_on =! od_control.od_user_keyboard_on; + + /* Update status line. */ + goto statup; + } + + /* If increase time key is pressed. */ + else if(wKey == od_control.key_moretime) + { + /* If time limit is less than maximum possible time limit. */ + if(od_control.user_timelimit < 1440) + { + /* Increase time left online. */ + ++od_control.user_timelimit; + } + + /* Update status line. */ + goto statup; + } + + /* If decrease time key is pressed. */ + else if(wKey == od_control.key_lesstime) + { + /* Never let user's time limit be set to a negative value. */ + if(od_control.user_timelimit > 0) + { + /* Decrease user's timelimit. */ + --od_control.user_timelimit; + } + + /* Update the status line. */ + goto statup; + } + + else + { + for(ch = 0; ch < 9; ++ch) + { + if(wKey == od_control.key_status[ch]) + { + if(btCurrentStatusLine != ch && od_control.od_status_on) + { + od_set_statusline(ch); + } + goto check_keyboard_again; + } + } + + /* Look for user-defined hotkeys. */ + for(ch=0; ch= od_control.od_num_keys) + { + /* Pass key on to od_local_input, if it is defined. */ + if(od_control.od_local_input != NULL) + { + (*od_control.od_local_input)(wKey); + } + + /* Add this key to the local/remote input queue. */ + ODKrnlHandleLocalKey(wKey); + } + } + goto check_keyboard_again; + +after_key_check: + + /* If status line has been turned on since last call to kernel. */ + if(bLastStatusSetting != od_control.od_status_on) + { + /* Generate the status line. */ + od_set_statusline(0); + } + + bLastStatusSetting = od_control.od_status_on; + + if(od_control.od_update_status_now) + { + od_set_statusline(btCurrentStatusLine); + od_control.od_update_status_now = FALSE; + } + + /* Update status line when needed. */ + if(nNextStatusUpdateTime < time(NULL) || bForceStatusUpdate) + { +statup: + nNextStatusUpdateTime = time(NULL) + STATUS_UPDATE_PERIOD; + + /* Turn off status line update force flag */ + bForceStatusUpdate = FALSE; + + if(od_control.od_status_on && btCurrentStatusLine != 8) + { + /* Store console settings. */ + ODStoreTextInfo(); + + /* Enable writes to whole screen. */ + ODScrnSetBoundary(1, 1, 80, 25); + ODScrnEnableCaret(FALSE); + (*pfCurrentPersonality)((BYTE)(10 + btCurrentStatusLine)); + ODRestoreTextInfo(); + ODScrnEnableCaret(TRUE); + } + } +#endif + + ODKrnlTimeUpdate(); + + ODTimerStart(&RunKernelTimer, 250); + + OD_API_EXIT(); + + bKernelActive = FALSE; +#endif /* !OD_MULTITHREADED */ +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlHandleLocalKey() + * + * Called when a key is pressed on the local keyboard that should be placed + * in the common local/remote input queue. This function is not called for + * sysop function keys. + * + * Parameters: wKeyCode + * + * Return: void + */ +void ODKrnlHandleLocalKey(WORD wKeyCode) +{ + /* If local keyboard input by sysop has not been disabled. */ + if(!(od_control.od_disable & DIS_LOCAL_INPUT)) + { + if((wKeyCode & 0xff) == 0) + { + ODKrnlHandleReceivedChar('\0', FALSE); + ODKrnlHandleReceivedChar((char)(wKeyCode >> 8), FALSE); + } + else + { + ODKrnlHandleReceivedChar((char)wKeyCode, FALSE); + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlHandleReceivedChar() *** PRIVATE FUNCTION *** + * + * Called when a character is received from the local or remote system. + * + * Parameters: chReceived - Character that should be handled. + * + * bFromRemote - TRUE if this character was received from the + * remote system, FALSE if it originated from the + * local console. + * + * Return: void + */ +static void ODKrnlHandleReceivedChar(char chReceived, BOOL bFromRemote) +{ + tODInputEvent InputEvent; + + /* If we are operating in remote mode, and remote user keyboard has been */ + /* disabled by the sysop, then return, ignoring this character. */ + if(bFromRemote && !od_control.od_user_keyboard_on) + { + return; + } + + /* Add this input event to the local/remote common input queue. */ + InputEvent.EventType = EVENT_CHARACTER; + InputEvent.bFromRemote = bFromRemote; + InputEvent.chKeyPress = chReceived; + ODInQueueAddEvent(hODInputQueue, &InputEvent); + + /* Update last control key information. */ + switch(chReceived) + { + case 's': + case 'S': + case 3: + case 11: + case 0x18: + chLastControlKey = 's'; + break; + case 'p': + case 'P': + chLastControlKey = 'p'; + } +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlTimeUpdate() *** PRIVATE FUNCTION *** + * + * Performs regular updating of time remaining online, inactivity time, and + * forces OpenDoors to exit if a time limit has been exceeded. + * + * Parameters: None + * + * Return: void + */ +static void ODKrnlTimeUpdate(void) +{ + time_t CurrentTime; + static char szTemp[80]; + + /* Obtain the current time. */ + CurrentTime = time(NULL); + + /* If inactivity setting has changed. */ + if(nLastInactivitySetting != od_control.od_inactivity) + { + /* If it was previously disabled. */ + if(nLastInactivitySetting == 0) + { + /* Prevent immediate timeout. */ + ODInQueueResetLastActivity(hODInputQueue); + } + + /* Store current value. */ + nLastInactivitySetting = od_control.od_inactivity; + } + + /* Check user keyboard inactivity. */ + if((ODInQueueGetLastActivity(hODInputQueue) + od_control.od_inactivity) + < CurrentTime) + { + /* If timeout, display message. */ + if(od_control.od_inactivity != 0 && !od_control.od_disable_inactivity) + { + if(od_control.od_time_msg_func == NULL) + { + od_disp_str(od_control.od_inactivity_timeout); + } + else + { + (*od_control.od_time_msg_func)(od_control.od_inactivity_timeout); + } + + /* End connection. */ + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_INACTIVITY); + } + } + + /* If less than 5s left of inactivity. */ + else if(ODInQueueGetLastActivity(hODInputQueue) + od_control.od_inactivity + < CurrentTime + od_control.od_inactive_warning) + { + if(!bWarnedAboutInactivity && od_control.od_inactivity != 0 + && !od_control.od_disable_inactivity) + { + /* Warn the user. */ + if(od_control.od_time_msg_func == NULL) + { + od_disp_str(od_control.od_inactivity_warning); + } + else + { + (*od_control.od_time_msg_func)(od_control.od_inactivity_warning); + } + /* Don't warn the user a second time. */ + bWarnedAboutInactivity = TRUE; + } + } + else + { + /* Re-enable inactivity warning. */ + bWarnedAboutInactivity = FALSE; + } + + /* If chat mode is active. */ + if(od_control.od_chat_active) + { + /* Prevent the user's time from being drained. */ + nNextTimeDeductTime = time(NULL) + 60; + } + + /* If 1 minute has passed since last time update. */ + if(CurrentTime >= nNextTimeDeductTime) + { + /* Next time update should occur 60 seconds after this one was */ + /* scheduled. */ + nNextTimeDeductTime += 60; + + /* Force status line to be updated immediately. */ + bForceStatusUpdate = TRUE; + + /* Decrement time left. */ + --od_control.user_timelimit; + + /* If the user's time limit is close to expiring, then notify */ + /* the user. */ + if(od_control.user_timelimit <= 3 && + od_control.user_timelimit > 0 && + !(od_control.od_disable & DIS_TIMEOUT)) + { + /* If less than 3 mins left, tell user. */ + sprintf(szTemp, od_control.od_time_warning, + od_control.user_timelimit); + if(od_control.od_time_msg_func == NULL) + { + od_disp_str(szTemp); + } + else + { + (*od_control.od_time_msg_func)(szTemp); + } + } + +#ifdef ODPLAT_WIN32 + ODFrameUpdateTimeDisplay(); +#endif /* ODPLAT_WIN32 */ + } + + /* If user has no time left. */ + if(od_control.user_timelimit <= 0 + && !(od_control.od_disable & DIS_TIMEOUT)) + { + /* Notify the user. */ + if(od_control.od_time_msg_func == NULL) + { + od_disp_str(od_control.od_no_time); + } + else + { + (*od_control.od_time_msg_func)(od_control.od_no_time); + } + + /* Force OpenDoors to shutdown. */ + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_TIMEOUT); + } +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlForceOpenDoorsShutdown() + * + * Called to force the application to exit due to some event in OpenDoors, + * such as loss of carrier, user inactivity timeout, the hangup command + * being chosen by the system operator, etc. The only time when OpenDoors + * is shutdown without going through this function should be as a result of + * an explicit call to od_exit() by the client application. + * + * Parameters: btReasonForShutdown - An OpenDoors exit reason code. + * + * Return: Never returns. + */ +void ODKrnlForceOpenDoorsShutdown(BYTE btReasonForShutdown) +{ + BOOL bHangup; + +#ifdef OD_MULTITHREADED + /* First, wait until an OpenDoors API is active. This way, we won't */ + /* interrupt any client application operations that may leave the */ + /* system in an unstable state (for instance, interrupting some file */ + /* I/O operations). */ + ODKrnlWaitForExclusiveControl(); +#endif /* OD_MULTITHREADED */ + + bKernelActive = TRUE; + + /* Determine whether we should hangup on the user before exiting. */ + if(btReasonForShutdown == ERRORLEVEL_HANGUP + || btReasonForShutdown == ERRORLEVEL_INACTIVITY) + { + bHangup = TRUE; + } + else + { + bHangup = FALSE; + } + + /* Record exit reason in global variable. */ + btExitReason = btReasonForShutdown - 1; + + /* Use the client-defined errorlevel, if any. */ + if(od_control.od_errorlevel[0]) + { + od_exit(od_control.od_errorlevel[btReasonForShutdown], bHangup); + } + + /* Otherwise, use the default OpenDoors errorlevel. */ + else + { + od_exit(btReasonForShutdown - 1, bHangup); + } +} + + +/* ========================================================================= */ +/* OpenDoors Kernel multithreaded implementation. */ +/* ========================================================================= */ + +#ifdef OD_MULTITHREADED + +/* ---------------------------------------------------------------------------- + * ODKrnlRemoteInputThread() *** PRIVATE FUNCTION *** + * + * Code for the remote input thread. This thread executes an infinite loop, + * blocking until a character is received from the remote system, and then + * adding this character to the common local/remote input queue. This thread + * should be given higher than normal priority. + * + * In non-multithreaded versions of OpenDoors, the task of checking for new + * characters from the remote system and adding them to the common input + * queue is performed on each call to od_kernel(). + * + * Parameters: As dictated for any thread function. + * + * Return: As dictated for any thread function. + */ +DWORD OD_THREAD_FUNC ODKrnlRemoteInputThread(void *pParam) +{ + char chReceived; + + /* We keep looping until someone else terminates this thread. */ + for(;;) + { + /* Get next character from the modem, blocking if no character */ + /* is waiting. */ + ODComGetByte(hSerialPort, &chReceived, TRUE); + + /* Handle this received character, adding it to the local/remote */ + /* common input queue, if appropriate. */ + ODKrnlHandleReceivedChar(chReceived, TRUE); + } + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlNoCarrierThread() *** PRIVATE FUNCTION *** + * + * Thread which performs carrier detection. Normally, this thread doesn't + * execute at all, but instead blocks waiting for a no carrier serial port + * event. Only when the carrier detect signal goes low does this thread + * execute, performing its one purpose in live - to trigger an OpenDoors + * shutdown. This thread should be given higher than normal priority. + * + * This thread should only be created when OpenDoors is operating in remote + * mode. + * + * In non-multithreaded versions of OpenDoors, this task is performed by + * od_kernel(). + * + * Parameters: As dictated for any thread function. + * + * Return: As dictated for any thread function. + */ +DWORD OD_THREAD_FUNC ODKrnlNoCarrierThread(void *pParam) +{ + /* Block until the carrier detect signal goes low with carrier */ + /* detection enabled. */ + for(;;) + { + /* Wait for carrier detect signal to go low. */ + ODComWaitEvent(hSerialPort, kNoCarrier); + + /* If carrier detection has not been disabled, then we have found */ + /* a condition where OpenDoors should exit. */ + if(!(od_control.od_disable&DIS_CARRIERDETECT)) break; + + /* If we have no carrier but carrier detection is currently */ + /* disabled, then we sleep for a while before checking again. */ + /* This isn't a very elegant implementation, and perhaps a */ + /* better approach will be used for future versions. */ + od_sleep(NO_CARRIER_THREAD_SLEEP_TIME); + } + + /* Force OpenDoors to exit. */ + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_NOCARRIER); + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlTimeUpdateThread() *** PRIVATE FUNCTION *** + * + * Thread which performs time limit updating and checking. This thread executes + * an infinite loop, sleeping for several seconds, waking up to perform time + * limit updating, and then going back to sleep. This thead should typically + * operate at normal priority. + * + * In non-multithreaded versions of OpenDoors, this task is performed by + * od_kernel(). + * + * Parameters: As dictated for any thread function. + * + * Return: As dictated for any thread function. + */ +DWORD OD_THREAD_FUNC ODKrnlTimeUpdateThread(void *pParam) +{ + /* We keep looping until someone else terminates this thread. */ + for(;;) + { + /* Sleep until it is time to do the next update. */ + od_sleep(TIME_UPDATE_THREAD_SLEEP_TIME); + + /* Now, perform time update. */ + ODKrnlTimeUpdate(); + } + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlWaitForExclusiveControl() *** PRIVATE FUNCTION *** + * + * Claims exclusive control of the application by the OpenDoors kernel. This is + * required to ensure that the client application is not busy when the + * OpenDoors kernel interrupts other operations for one reason or another + * (for example, to start chat mode or to force the program to exit). + * + * Parameters: None + * + * Return: void + */ +static void ODKrnlWaitForExclusiveControl(void) +{ + /* If we already have exclusive control, then don't do anything. */ + if(bHaveExclusiveControl) return; + + /* Wait until an OpenDoors API is active. */ + ODSemaphoreDown(hODActiveSemaphore, OD_NO_TIMEOUT); + + /* Now, suspend the client thread. */ + ASSERT(hClientThread != NULL); + ODThreadSuspend(hClientThread); + + /* Record that we now have exclusive control. */ + bHaveExclusiveControl = TRUE; +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlGiveUpExclusiveControl() *** PRIVATE FUNCTION *** + * + * Relinguishes exclusive control of the application by the OpenDoors kernel. + * A call to this function should only take place after a previous call to + * ODKrnlWaitForExclusiveControl(). + * + * Parameters: None + * + * Return: void + */ +static void ODKrnlGiveUpExclusiveControl(void) +{ + /* If we don't have exclusive control, then this call doesn't do */ + /* anything. */ + if(!bHaveExclusiveControl) return; + + /* First, restart the client thread. */ + ASSERT(hClientThread != NULL); + ODThreadResume(hClientThread); + + /* Now, allow currently active OpenDoors API to return control */ + /* to the client application. */ + ODSemaphoreUp(hODActiveSemaphore, 1); + + /* Note that we no longer have exclusive control. */ + bHaveExclusiveControl = FALSE; +} + +#endif /* OD_MULTITHREADED */ + + + +/* ========================================================================= */ +/* OpenDoors chat mode. */ +/* ========================================================================= */ + +BOOL bChatted; +BOOL bSysopColor; + +#ifdef OD_MULTITHREADED + +/* ---------------------------------------------------------------------------- + * ODKrnlChatThread() *** PRIVATE FUNCTION *** + * + * Thread which implements sysop <-> remote user chat mode. + * + * Parameters: As dictated for any thread function. + * + * Return: As dictated for any thread function. + */ +DWORD OD_THREAD_FUNC ODKrnlChatThread(void *pParam) +{ + BOOL bTriggeredInsideOpenDoors = bChatActivatedInternally; + + /* The chat thread doesn't start up chat mode until the kernel has */ + /* exclusive control of the client application. */ + if(bTriggeredInsideOpenDoors) + { + ODKrnlWaitForExclusiveControl(); + } + + /* Now, execute the chat mode loop. */ + ODKrnlChatMode(); + + /* If we get here, then we are responsible for relinguishing exclusive */ + /* control of the application. */ + if(bTriggeredInsideOpenDoors) + { + ODKrnlGiveUpExclusiveControl(); + } + + /* Exit the chat thread. */ + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlStartChatThread() + * + * Starts the chat mode thread. + * + * Parameters: bTriggeredInternally - TRUE if chat mode has been triggered + * inside OpenDoors, or FALSE if it has + * been triggered by a call to od_chat(). + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODKrnlStartChatThread(BOOL bTriggeredInternally) +{ + tODResult Result; + + bChatActivatedInternally = bTriggeredInternally; + + Result = ODThreadCreate(&hChatThread, ODKrnlChatThread, NULL); + if(Result != kODRCSuccess) + { + return(Result); + } + + /* If chat mode command has been chosen, then toggle chat */ + /* mode on or off. */ + od_control.od_chat_active = TRUE; + +#ifdef ODPLAT_WIN32 + /* Update the enabled and checked state of commands. */ + ODFrameUpdateCmdUI(); +#endif /* ODPLAT_WIN32 */ + + return(kODRCSuccess); +} + + +#endif /* OD_MULTITHREADED */ + + +/* ---------------------------------------------------------------------------- + * ODKrnlEndChatMode() + * + * Forces chat mode to exit. + * + * Parameters: None + * + * Return: void + */ +void ODKrnlEndChatMode(void) +{ +#ifdef OD_MULTITHREADED + + /* Shutdown the chat thread. */ + ODThreadTerminate(hChatThread); + + /* Perform post-chat cleanup operations. */ + ODKrnlChatCleanup(); + +#else /* !OD_MULTITHREADED */ + + /* Turn off chat mode. */ + od_control.od_chat_active = FALSE; + +#endif /* !OD_MULTITHREADED */ +} + + +/* ---------------------------------------------------------------------------- + * od_chat() + * + * Allows the client application to activate the line-by-line default chat + * mode provided by OpenDoors, allowing the local sysop and remote user to + * communicate with one another in real time. + * + * Parameters: none + * + * Return: void + */ +ODAPIDEF void ODCALL od_chat(void) +{ + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_chat()"); + + /* Set the main chat active flag in od_control. */ + od_control.od_chat_active = TRUE; + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + +#ifdef OD_MULTITHREADED + + /* In multithreaded versions of OpenDoors, od_chat() causes the chat */ + /* mode thread to be started, which in turn implements chat mode. */ + /* od_chat() only returns when this thread exits. */ + if(ODKrnlStartChatThread(FALSE) != kODRCSuccess) + { + od_control.od_error = ERR_GENERALFAILURE; + OD_API_EXIT(); + } + + /* Now, wait for the chat thread to exit. */ + ODThreadWaitForExit(hChatThread); + + /* Now, note that the chat thread no longer exists. */ + hChatThread = NULL; + +#else /* !OD_MULTITHREADED */ + + /* In non-multithreaded versions, a call to od_chat() maps directly to a */ + /* call to ODKrnlChatMode(), which implements chat mode. */ + ODKrnlChatMode(); + +#endif /* !OD_MULTITHREADED */ + + OD_API_EXIT(); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlChatMode() *** PRIVATE FUNCTION *** + * + * Implements the OpenDoors chat mode. + * + * Parameters: None + * + * Return: void + */ +static void ODKrnlChatMode(void) +{ + BYTE chKeyPressed; + char szCurrentWord[79]; + BYTE btWordLength = 0; + BYTE btCurrentColumn = 0; + char *pchCurrent; + BYTE btCount; +#ifndef OD_MULTITHREADED + tODTimer Timer; +#endif /* !OD_MULTITHREADED */ + + /* Empty current word string. */ + szCurrentWord[0] = '\0'; + + /* Save current display color attribute. */ + nChatOriginalAttrib = od_control.od_cur_attrib; + + /* Record that sysop has entered chat mode. */ + bChatted = TRUE; + + /* Turn off "user wants to chat" indicator, and force the status line. */ + /* to be updated. */ + od_control.user_wantchat = FALSE; +#ifdef ODPLAT_WIN32 + ODFrameUpdateWantChat(); +#endif /* ODPLAT_WIN32 */ + + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + + /* Note that chat mode is now active. */ + od_control.od_chat_active = TRUE; + + /* If a pre-chat function hook has been defined, then call it. */ + if(od_control.od_cbefore_chat!=NULL) + { + bShellChatActive = TRUE; + (*od_control.od_cbefore_chat)(); + bShellChatActive = FALSE; + + /* If chat has been deactivated, then return right away */ + if(!od_control.od_chat_active) goto cleanup; + } + + /* Display a message indicating that the sysop has entered chat mode. */ + od_set_attrib(od_control.od_chat_color1); + if(od_control.od_before_chat != NULL) + od_disp_str(od_control.od_before_chat); + + /* Currently set to sysop color. */ + bSysopColor = TRUE; + + /* If the logfile system is hooked up, then write a log entry */ + /* indicating that the sysop has entered chat mode. */ + if(pfLogWrite != NULL) + { + (*pfLogWrite)(9); + } + +#ifndef OD_MULTITHREADED + /* Start a timer that will elapse after 25 milliseconds. */ + ODTimerStart(&Timer, CHAT_YIELD_PERIOD); +#endif /* !OD_MULTITHREADED */ + + /* Loop while sysop chat mode is stilil on. */ + while(od_control.od_chat_active) + { + /* Obtain the next key from the user. */ +#ifdef OD_MULTITHREADED + chKeyPressed = od_get_key(TRUE); +#else /* !OD_MULTITHREADED */ + chKeyPressed = od_get_key(FALSE); +#endif /* !OD_MULTITHREADED */ + + /* If color not set correctly. */ + if((od_control.od_last_input && !bSysopColor) + || (!od_control.od_last_input && bSysopColor)) + { + /* If sysop was last person to type. */ + if(od_control.od_last_input) + { + /* Switch to sysop text color. */ + od_set_attrib(od_control.od_chat_color1); + } + else + { + /* Otherwise, switch to the user text color. */ + od_set_attrib(od_control.od_chat_color2); + } + + /* Record current color setting. */ + bSysopColor = od_control.od_last_input; + } + + /* If this is a displayable character. */ + if(chKeyPressed >= 32) + { + /* Display the character that was typed. */ + od_putch(chKeyPressed); + + /* If the user pressed spacebar, then this is the end of the */ + /* previous word. */ + if(chKeyPressed == 32) + { + btWordLength = 0; + szCurrentWord[0] = 0; + } + + /* Add this character to the current word, if we haven't exceeded */ + /* the maximum word length. */ + else if(btWordLength < 70) + { + szCurrentWord[btWordLength++] = chKeyPressed; + szCurrentWord[btWordLength] = '\0'; + } + + /* If we are not yet at the end of the line, then increment the */ + /* current column number. */ + if(btCurrentColumn < 75) + { + ++btCurrentColumn; + } + + /* If we are at the end of the line. */ + else + { + /* If the current word should be wrapped to the next line. */ + if(btWordLength < 70 && btWordLength > 0) + { + /* Generate a string to erase the word from the current line. */ + pchCurrent = (char *)szODWorkString; + for(btCount = 0; btCount < btWordLength; ++btCount) + { + *(pchCurrent++) = 8; + } + + for(btCount = 0; btCount < btWordLength; ++btCount) + { + *(pchCurrent++) = ' '; + } + + *pchCurrent = '\0'; + + /* Display the string to erase the old word. */ + od_disp_str(szODWorkString); + + /* Move to the next line. */ + od_disp_str("\n\r"); + + /* Redisplay the word on the next line. */ + od_disp_str(szCurrentWord); + + /* Update current column number. */ + btCurrentColumn = btWordLength; + } + + /* If we have reached the end of the line, but word wrap should */ + /* not be performed. */ + else + { + /* Move to the next line. */ + od_disp_str("\n\r"); + + /* Update the current column number. */ + btCurrentColumn = 0; + } + + /* Reset the current word information. */ + btWordLength = 0; + szCurrentWord[0] = 0; + } + } + + /* If the backspace key was pressed. */ + else if(chKeyPressed == 8) + { + /* Send backspace sequence. */ + od_disp_str(szBackspaceWithDelete); + + /* If we are in the middle of a word, then we must remove the */ + /* last character of the word. */ + if(btWordLength > 0) + { + szCurrentWord[--btWordLength] = '\0'; + } + + /* Update the current column number. */ + if(btCurrentColumn > 0) --btCurrentColumn; + } + + /* If the enter key was pressed. */ + else if(chKeyPressed == 13) + { + /* Send carriage return / line feed sequence. */ + od_disp_str("\n\r"); + + /* Reset the current word contents. */ + btWordLength = 0; + szCurrentWord[0] = 0; + + /* Update the current column number. */ + btCurrentColumn = 0; + } + + /* If the sysop pressed the escape key. */ + else if(chKeyPressed == 27 && od_control.od_last_input) + { + /* Exit chat mode. */ + goto cleanup; + } + +#ifndef OD_MULTITHREADED + /* Give up processor after 25 milliseconds elapsed. */ + else if(ODTimerElapsed(&Timer)) + { + od_sleep(0); + + /* Restart the timer, so that it will elapse after another */ + /* 25 milliseconds. */ + ODTimerStart(&Timer, CHAT_YIELD_PERIOD); + } +#endif /* !OD_MULTITHREADED */ + } + +cleanup: + ODKrnlChatCleanup(); +} + + +/* ---------------------------------------------------------------------------- + * ODKrnlChatCleanup() *** PRIVATE FUNCTION *** + * + * Performs post-chat operations, such as resetting the original display + * color, etc. + * + * Parameters: None + * + * Return: void + */ +static void ODKrnlChatCleanup(void) +{ + od_set_attrib(od_control.od_chat_color1); + + /* Indicate that chat mode is exiting. */ + if(od_control.od_after_chat != NULL) + { + od_disp_str(od_control.od_after_chat); + } + + /* If an after chat function has been provided, then call it. */ + if(od_control.od_cafter_chat != NULL) + { + bShellChatActive = TRUE; + (*od_control.od_cafter_chat)(); + bShellChatActive = FALSE; + } + + /* If the logfile system is hooked up, then write a line to the log */ + /* indicating that chat mode has been exited. */ + if(pfLogWrite != NULL) + { + (*pfLogWrite)(10); + } + + /* Restore original display color attribute. */ + od_set_attrib(nChatOriginalAttrib); + + /* Record that chat mode is no longer active. */ + od_control.od_chat_active = FALSE; + +#ifdef ODPLAT_WIN32 + /* Update the enabled and checked state of commands. */ + ODFrameUpdateCmdUI(); +#endif /* ODPLAT_WIN32 */ + +#ifdef OD_MULTITHREADED + if(bChatActivatedInternally) + { + ODKrnlGiveUpExclusiveControl(); + } +#endif +} + +#ifdef ODPLAT_NIX +#ifdef USE_KERNEL_SIGNAL +/* ---------------------------------------------------------------------------- + * sig_run_kernel(sig) *** PRIVATE FUNCTION *** + * + * Runs od_kernel() on a SIGALRM + * + */ +static void sig_run_kernel(int sig) +{ + od_kernel(); +} + +/* ---------------------------------------------------------------------------- + * sig_run_kernel(sig) *** PRIVATE FUNCTION *** + * + * Runs od_kernel() on a SIGALRM + * + */ +static void sig_get_char(int sig) +{ + static char ch; + /* Loop, obtaining any new characters from the serial port and */ + /* adding them to the common local/remote input queue. */ + while(ODComGetByte(hSerialPort, &ch, FALSE) == kODRCSuccess) + { + ODKrnlHandleReceivedChar(ch, TRUE); + } +} + +static void sig_no_carrier(int sig) +{ + if(od_control.baud != 0 && ) + { + if(!(od_control.od_disable&DIS_CARRIERDETECT)) + ODKrnlForceOpenDoorsShutdown(ERRORLEVEL_NOCARRIER); + } +} +#endif +#endif diff --git a/utils/magiedit/odoors/ODKrnl.h b/utils/magiedit/odoors/ODKrnl.h new file mode 100644 index 0000000..c94fded --- /dev/null +++ b/utils/magiedit/odoors/ODKrnl.h @@ -0,0 +1,88 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODKrnl.h + * + * Description: Contains the public definitions related to odkrnl.c + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Jan 01, 1995 6.00 BP Split off from odcore.c and oddoor.h + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Jan 12, 1996 6.00 BP Added bOnlyShiftArrow. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 13, 1996 6.10 BP bOnlyShiftArrow -> nArrowUseCount. + */ + +#ifndef _INC_ODKRNL +#define _INC_ODKRNL + +#include "ODPlat.h" + +/* Global kernel-related variables. */ +extern tODTimer RunKernelTimer; +extern time_t nNextTimeDeductTime; +extern char chLastControlKey; +extern INT nArrowUseCount; +extern BOOL bForceStatusUpdate; +extern BOOL bSysopColor; +#ifdef OD_MULTITHREADED +extern tODSemaphoreHandle hODActiveSemaphore; +#endif /* OD_MULTITHREADED */ + +/* Chat mode global variables. */ +extern BOOL bIsShell; +extern BOOL bChatted; + +/* Kernel function prototypes. */ +tODResult ODKrnlInitialize(void); +void ODKrnlShutdown(void); +void ODKrnlHandleLocalKey(WORD wKeyCode); +void ODKrnlEndChatMode(void); +void ODKrnlForceOpenDoorsShutdown(BYTE btReasonForShutdown); +#ifdef OD_MULTITHREADED +tODResult ODKrnlStartChatThread(BOOL bTriggeredInternally); +#endif /* OD_MULTITHREADED */ + +/* Macro used to generate the appropriate code (if any) to call */ +/* the OpenDoors kernel from within OpenDoors code. */ +#ifdef OD_MULTITHREADED +#define CALL_KERNEL_IF_NEEDED() +#else /* !OD_MULTITHREADED */ +#ifdef ODPLAT_NIX +#ifdef USE_KERNEL_SIGNAL +#define CALL_KERNEL_IF_NEEDED() +#else +#define CALL_KERNEL_IF_NEEDED() od_kernel() +#endif +#else +#define CALL_KERNEL_IF_NEEDED() od_kernel() +#endif /* !ODPLAT_NIX */ +#endif /* !OD_MULTITHREADED */ + +/* Macro used to increment or decrement OpenDoors active semaphore. */ +#ifdef OD_MULTITHREADED +#define OD_API_ENTRY() ODSemaphoreUp(hODActiveSemaphore, 1); +#define OD_API_EXIT() ODSemaphoreDown(hODActiveSemaphore, 1); +#else /* !OD_MULTITHREADED */ +#define OD_API_ENTRY() +#define OD_API_EXIT() +#endif /* !OD_MULTITHREADED */ + +#endif /* _INC_ODKRNL */ diff --git a/utils/magiedit/odoors/ODList.c b/utils/magiedit/odoors/ODList.c new file mode 100644 index 0000000..9ef8af0 --- /dev/null +++ b/utils/magiedit/odoors/ODList.c @@ -0,0 +1,565 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODList.c + * + * Description: Implements the od_list_files() function for displaying + * a FILES.BBS file. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Dec 09, 1994 6.00 BP Use new directory access functions. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 11, 1995 6.00 BP Moved functions from odcore.c + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODCom.h" +#include "ODPlat.h" +#include "ODKrnl.h" +#include "ODUtil.h" + + +/* Filename component identifies. */ +#define WILDCARDS 0x01 +#define EXTENSION 0x02 +#define FILENAME 0x04 +#define DIRECTORY 0x08 +#define DRIVE 0x10 + + +/* Local private helper function prototypes. */ +static void ODListFilenameMerge(char *pszEntirePath, const char *pszDrive, + const char *pszDir, const char *pszName, const char *pszExtension); +static char *ODListGetFirstWord(char *pszInStr, char *pszOutStr); +static char *ODListGetRemainingWords(char *pszInStr); +static INT ODListFilenameSplit(const char *pszEntirePath, char *pszDrive, + char *pszDir, char *pszName, char *pszExtension); + + +/* ---------------------------------------------------------------------------- + * od_list_files() + * + * Displays a list of files available for download, using an extended version + * of the standard FILES.BBS format index file. + * + * Parameters: pszFileSpec - Directory name where the FILES.BBS file can be + * found, or full path and filename of a FILES.BBS + * format index file. + * + * Return: TRUE on success or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_list_files(char *pszFileSpec) +{ + BYTE btLineCount = 2; + BOOL bPausing; + static char szLine[513]; + static char szFilename[80]; + static char szDrive[3]; + static char szDir[70]; + static char szTemp1[9]; + static char szTemp2[5]; + static char szBaseName[9]; + static char szExtension[5]; + static char szDirectory[100]; + INT nFilenameInfo; + FILE *pfFilesBBS; + static char *pszCurrent; + BOOL bIsDir; + BOOL bUseNextLine = TRUE; + tODDirHandle hDir; + tODDirEntry DirEntry; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_list_files()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Check user's page pausing setting. */ + bPausing = od_control.od_page_pausing; + + if(od_control.od_extended_info) bPausing = od_control.user_attribute & 0x04; + + /* Parse directory parameter. */ + if(pszFileSpec == NULL) + { + strcpy(szODWorkString, "."); + strcpy(szDirectory, "."DIRSEP_STR); + } + else if(*pszFileSpec == '\0') + { + strcpy(szODWorkString, "."); + strcpy(szDirectory, "."DIRSEP_STR); + } + else + { + strcpy(szODWorkString, pszFileSpec); + strcpy(szDirectory, pszFileSpec); + if(szODWorkString[strlen(szODWorkString) - 1] == DIRSEP) + { + szODWorkString[strlen(szODWorkString) - 1] = '\0'; + } + } + + /* Get directory information on path. */ + if(ODDirOpen(szODWorkString, DIR_ATTRIB_ARCH | DIR_ATTRIB_RDONLY + | DIR_ATTRIB_DIREC, &hDir) != kODRCSuccess) + { + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + if(ODDirRead(hDir, &DirEntry) != kODRCSuccess) + { + ODDirClose(hDir); + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + + ODDirClose(hDir); + + /* If it is a directory. */ + if(DirEntry.wAttributes & DIR_ATTRIB_DIREC) + { + /* Append FILES.BBS to directory name & open. */ + bIsDir = TRUE; + ODMakeFilename(szODWorkString, szODWorkString, "FILES.BBS", + sizeof(szODWorkString)); + if((pfFilesBBS = fopen(szODWorkString, "r")) == NULL) + { + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + } + + /* If it is not a directory. */ + else + { + bIsDir = FALSE; + if((pfFilesBBS = fopen(szODWorkString,"r")) == NULL) + { + od_control.od_error = ERR_FILEOPEN; + OD_API_EXIT(); + return(FALSE); + } + } + + + /* Ignore previously pressed control keys. */ + chLastControlKey = 0; + + + /* Loop until the end of the FILES.BBS file has been reached. */ + for(;;) + { + if(fgets(szLine, 512, pfFilesBBS) == NULL) break; + + if(!bUseNextLine) + { + if(szLine[strlen(szLine) - 1] == '\n') + { + bUseNextLine = TRUE; + } + continue; + } + + if(szLine[strlen(szLine) - 1] == '\n') + { + szLine[strlen(szLine) - 1] = '\0'; + } + else + { + bUseNextLine = FALSE; + } + if(szLine[strlen(szLine) - 1] == '\r') + { + szLine[strlen(szLine) - 1] = '\0'; + } + + if(chLastControlKey != 0) + { + switch(chLastControlKey) + { + case 's': + if(od_control.od_list_stop) + { + if(od_control.baud) + { + ODComClearOutbound(hSerialPort); + } + od_clear_keybuffer(); + fclose(pfFilesBBS); + OD_API_EXIT(); + return(TRUE); + } + break; + + case 'p': + if(od_control.od_list_pause) + { + od_clear_keybuffer(); + od_get_key(TRUE); + } + } + chLastControlKey = 0; + } + + /* Determine whether or not this is a comment line. */ + if(szLine[0] == ' ' || strlen(szLine) == 0) + + { + /* If so, display the line in comment color. */ + od_set_attrib(od_control.od_list_title_col); + od_disp_str(szLine); + od_disp_str("\n\r"); + ++btLineCount; + } + + /* If the line is not a comment. */ + else + { + /* Extract the first word of the line, */ + ODListGetFirstWord(szLine, szFilename); + + /* And extract the filename. */ + nFilenameInfo = ODListFilenameSplit(szFilename, szDrive, szDir, + szBaseName, szExtension); + if(!((nFilenameInfo & DRIVE) || (nFilenameInfo & DIRECTORY))) + { + if(bIsDir) + { + ODMakeFilename(szDirectory, szDirectory, szFilename, + sizeof(szDirectory)); + strcpy(szFilename, szDirectory); + } + else + { + ODListFilenameSplit(szDirectory, szDrive, szDir, szTemp1, + szTemp2); + ODListFilenameMerge(szFilename, szDrive, szDir, szBaseName, + szExtension); + } + } + + /* Search for the filespec in directory. */ + if(ODDirOpen(szFilename, DIR_ATTRIB_ARCH | DIR_ATTRIB_RDONLY, &hDir) + == kODRCSuccess) + { + /* Display information on every file that matches. */ + while(ODDirRead(hDir, &DirEntry) == kODRCSuccess) + { + od_set_attrib(od_control.od_list_name_col); + od_printf("%-12.12s ", DirEntry.szFileName); + od_set_attrib(od_control.od_list_size_col); + od_printf("%-6ld ", DirEntry.dwFileSize); + od_set_attrib(od_control.od_list_comment_col); + pszCurrent = ODListGetRemainingWords(szLine); + if(strlen(pszCurrent) <= 56) + { + od_disp_str(pszCurrent); + od_disp_str("\n\r"); + } + else + { + od_printf("%-56.56s\n\r", pszCurrent); + } + ++btLineCount; + } + + ODDirClose(hDir); + } + + /* Otherwise, indicate that the file is "Offline". */ + else + { + ODListFilenameMerge(szFilename, "", "", szBaseName, szExtension); + od_set_attrib(od_control.od_list_name_col); + od_printf("%-12.12s ", szFilename); + od_set_attrib(od_control.od_list_offline_col); + od_disp_str(od_control.od_offline); + od_set_attrib(od_control.od_list_comment_col); + + od_printf("%-56.56s\n\r", ODListGetRemainingWords(szLine)); + ++btLineCount; + } + } + + /* Check for end of screen & page pausing. */ + if(btLineCount >= od_control.user_screen_length && bPausing) + { + /* Provide page pausing at end of each screen. */ + if(ODPagePrompt(&bPausing)) + { + fclose(pfFilesBBS); + OD_API_EXIT(); + return(TRUE); + } + + /* Reset the line number counter. */ + btLineCount = 2; + } + } + + /* When finished, close the file. */ + fclose(pfFilesBBS); + + /* Return with success. */ + OD_API_EXIT(); + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODListFilenameMerge() *** PRIVATE FUNCTION *** + * + * Builds a fully-qualified path name from the provided path component + * strings. + * + * Parameters: pszEntirePath - Pointer to the destination string where the + * generated path should be stored. + * + * pszDrive - Pointer to the drive string. + * + * pszDir - Pointer to the directory string. + * + * pszName - Pointer to the base filename string. + * + * pszExtension - Pointer to the extension name string. + * + * Return: void + */ +static void ODListFilenameMerge(char *pszEntirePath, const char *pszDrive, + const char *pszDir, const char *pszName, const char *pszExtension) +{ + if(pszEntirePath == NULL) return; + + pszEntirePath[0] = '\0'; + + if(pszDrive != NULL) + { + strcpy(pszEntirePath, pszDrive); + } + if(pszDir != NULL) + { + strcat(pszEntirePath, pszDir); + } + if(pszName != NULL) + { + strcat(pszEntirePath,pszName); + } + if(pszExtension != NULL) + { + strcat(pszEntirePath,pszExtension); + } +} + + +/* ---------------------------------------------------------------------------- + * ODListFilenameSplit() *** PRIVATE FUNCTION *** + * + * Splits the provided path string into drive, directory name, file base name + * and file extension components. + * + * Parameters: pszEntirePath - A string containing the path to split. + * + * pszDrive - A string where the drive letter should be stored. + * + * pszDir - A string where the directory name should be + * stored. + * + * pszName - A string where the base filename should be + * stored. + * + * pszExtension - A string where the filename extension should be + * stored. + * + * Return: One or more flags indicating which components where found in the + * provided path name. + */ +static INT ODListFilenameSplit(const char *pszEntirePath, char *pszDrive, + char *pszDir, char *pszName, char *pszExtension) +{ + char *pchCurrentPos; + char *pchStart; + BYTE btSize; + INT nToReturn; + + ASSERT(pszEntirePath != NULL); + ASSERT(pszDrive != NULL); + ASSERT(pszDir != NULL); + ASSERT(pszName != NULL); + ASSERT(pszExtension != NULL); + + pchStart = (char *)pszEntirePath; + nToReturn = 0; + + if((pchCurrentPos = strrchr(pchStart,':')) == NULL) + { + pszDrive[0] = '\0'; + } + else + { + btSize = (int)(pchCurrentPos - pchStart) + 1; + if(btSize > 2) btSize = 2; + strncpy(pszDrive, pchStart, btSize); + pszDrive[btSize] = '\0'; + pchStart = pchCurrentPos + 1; + nToReturn |= DRIVE; + } + + if((pchCurrentPos = strrchr(pchStart, DIRSEP))==NULL) + { + pszDir[0] = '\0'; + } + else + { + btSize = (int)(pchCurrentPos - pchStart) + 1; + strncpy(pszDir,pchStart,btSize); + pszDir[btSize] = '\0'; + pchStart = pchCurrentPos + 1; + nToReturn |= DIRECTORY; + } + + if(strchr(pchStart,'*') != NULL || strchr(pchStart, '?') != NULL) + { + nToReturn |= WILDCARDS; + } + + if((pchCurrentPos = strrchr(pchStart, '.')) == NULL) + { + if(pchStart =='\0') + { + pszExtension[0] = '\0'; + pszName[0] = '\0'; + } + else + { + pszExtension[0] = '\0'; + btSize = strlen(pchStart); + if (btSize > 8) btSize = 0; + strncpy(pszName, pchStart, btSize); + pszName[btSize] = '\0'; + nToReturn |= FILENAME; + } + } + else + { + nToReturn |= FILENAME; + nToReturn |= EXTENSION; + + btSize = (int)(pchCurrentPos - pchStart); + + if(btSize > 8) btSize = 8; + + strncpy(pszName, pchStart, btSize); + pszName[btSize] = '\0'; + + btSize = strlen(pchCurrentPos); + if(btSize > 4) btSize = 4; + strncpy(pszExtension, pchCurrentPos, btSize); + pszExtension[btSize]='\0'; + } + + return(nToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODListGetFirstWord() *** PRIVATE FUNCTION *** + * + * Returns the first word in a string containing a series of words separated by + * one or more spaced. + * + * Parameters: pszInStr - String to look in. + * + * pszOutStr - Buffer to store result in. This buffer should be at + * least as long as the pszInStr string. + * + * Return: Pointer to the pszOutStr that was passed in. + */ +static char *ODListGetFirstWord(char *pszInStr, char *pszOutStr) +{ + char *pchOut = (char *)pszOutStr; + + ASSERT(pszInStr != NULL); + ASSERT(pszOutStr != NULL); + + while(*pszInStr && *pszInStr != ' ') + { + *pchOut++ = *pszInStr++; + } + *pchOut = '\0'; + + return(pszOutStr); +} + + +/* ---------------------------------------------------------------------------- + * ODListGetRemainingWords() *** PRIVATE FUNCTION *** + * + * Obtains the remaining words in a string, after the first word. This function + * is a companion to ODListGetFirstWord(), which obtains just the first word + * in a string of many words. + * + * Parameters: pszInStr - String to look at. + * + * Return: A pointer to the position in a string of the second word. + */ +static char *ODListGetRemainingWords(char *pszInStr) +{ + char *pchStartOfRemaining = (char *)pszInStr; + + /* Skip over the first word in the string. */ + while(*pchStartOfRemaining && *pchStartOfRemaining != ' ') + { + ++pchStartOfRemaining; + } + + /* Skip over any spaces after the first word. */ + while(*pchStartOfRemaining && *pchStartOfRemaining == ' ') + { + ++pchStartOfRemaining; + } + + /* Return pointer to the rest of the string. */ + return((char *)pchStartOfRemaining); + } diff --git a/utils/magiedit/odoors/ODLog.c b/utils/magiedit/odoors/ODLog.c new file mode 100644 index 0000000..4da1f7d --- /dev/null +++ b/utils/magiedit/odoors/ODLog.c @@ -0,0 +1,258 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODLog.c + * + * Description: Implements the logfile subsystem. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODInEx.h" +#include "ODKrnl.h" + + +/* Private logfile file handle */ +static FILE *logfile_pointer; + + +/* Private helper functions. */ +static BOOL ODLogWriteStandardMsg(INT nLogfileMessage); +static void ODLogClose(INT nReason); + + +/* ---------------------------------------------------------------------------- + * ODLogEnable() + * + * This function is called from od_init() when the user explicitly includes the + * OpenDoors logfile option using the od_control.od_logfile setting. + * + * Parameters: None. + * + * Return: void + */ +ODAPIDEF void ODCALL ODLogEnable(void) +{ + /* At this time, this function simply maps to a call to od_log_open(). */ + od_log_open(); +} + + +/* ---------------------------------------------------------------------------- + * od_log_open() + * + * Called to begin logfile operations. This is when the first message is + * written to the logfile, indicating that the user is entering OpenDoors. + * + * Parameters: None. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_log_open() +{ + time_t nUnixTime; + struct tm *ptmTimeRecord; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_log_open()"); + + /* Initialize OpenDoors if not already done. */ + if(!bODInitialized) od_init(); + + /* Don't open logfile if it has been disabled in config file, etc. */ + if(od_control.od_logfile_disable) return(TRUE); + + /* Open actual logfile. */ + if((logfile_pointer=fopen(od_control.od_logfile_name, "a")) == NULL) + { + return(FALSE); + } + + /* Get the current time. */ + nUnixTime = time(NULL); + ptmTimeRecord = localtime(&nUnixTime); + + /* Print logfile tear line. */ + fprintf(logfile_pointer, "\n---------- %s %02d %s %02d, %s\n", + od_control.od_day[ptmTimeRecord->tm_wday], + ptmTimeRecord->tm_mday, + od_control.od_month[ptmTimeRecord->tm_mon], + ptmTimeRecord->tm_year, + od_program_name); + + /* Print message of door start up. */ + sprintf(szODWorkString, (char *)od_control.od_logfile_messages[11], + od_control.user_name); + od_log_write(szODWorkString); + + /* Set internal function hooks to enable calling of logfile features */ + /* from elsewhere in OpenDoors. */ + pfLogWrite = ODLogWriteStandardMsg; + pfLogClose = ODLogClose; + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODLogWriteStandardMsg() *** PRIVATE FUNCTION *** + * + * Function called to write a standard message to the logfile. + * + * Parameters: nLogfileMessage - Index of the standard message to write to + * the logfile. + * + * Return: TRUE on success, or FALSE on failure. + */ +static BOOL ODLogWriteStandardMsg(INT nLogfileMessage) +{ + if(nLogfileMessage < 0 || nLogfileMessage > 11) + { + return(FALSE); + } + + od_log_write((char *)od_control.od_logfile_messages[nLogfileMessage]); + + if(nLogfileMessage == 8) + { + sprintf(szODWorkString, od_control.od_logfile_messages[12], + od_control.user_reasonforchat); + szODWorkString[67] = '\0'; + od_log_write(szODWorkString); + } + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * od_log_write() + * + * Called to write a message to the logfile. + * + * Parameters: pszMessage - Pointer to a string containing the message text. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_log_write(char *pszMessage) +{ + char *pszFormat; + time_t nUnixTime; + struct tm *ptmTimeRecord; + + /* Verify that OpenDoors has been initialized. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Stop if logfile has been disabled in config file, etc. */ + if(od_control.od_logfile_disable) + { + OD_API_EXIT(); + return(TRUE); + } + + /* If logfile has not yet been opened, then open it. */ + if(logfile_pointer==NULL) + { + if(!od_log_open()) + { + OD_API_EXIT(); + return(FALSE); + } + } + + /* Get the current system time. */ + nUnixTime=time(NULL); + ptmTimeRecord=localtime(&nUnixTime); + + /* Determine which logfile format string to use. */ + if(ptmTimeRecord->tm_hour<10) + { + pszFormat=(char *)"> %1.1d:%02d:%02d %s\n"; + } + else + { + pszFormat=(char *)"> %2.2d:%02d:%02d %s\n"; + } + + /* Write a line to the logfile. */ + fprintf(logfile_pointer, pszFormat, ptmTimeRecord->tm_hour, + ptmTimeRecord->tm_min, ptmTimeRecord->tm_sec, pszMessage); + + OD_API_EXIT(); + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODLogClose() *** PRIVATE FUNCTION *** + * + * Writes final entry to the logfile when OpenDoors is exiting. + * + * Parameters: nReason - Specifies the reason why OpenDoors is exiting. + * + * Return: void + */ +static void ODLogClose(INT nReason) +{ + /* Stop if logfile has been disabled in the config file, etc. */ + if(od_control.od_logfile_disable) return; + + /* If logfile has not been opened, then abort. */ + if(logfile_pointer==NULL) return; + + if(bPreOrExit) + { + od_log_write((char *)od_control.od_logfile_messages[13]); + } + else if(btExitReason<=5 && btExitReason>=1) + { + od_log_write((char *)od_control.od_logfile_messages[btExitReason-1]); + } + else + { + sprintf(szODWorkString,(char *)od_control.od_logfile_messages[5],nReason); + od_log_write(szODWorkString); + } + + /* Close the logfile. */ + fclose(logfile_pointer); + + /* Prevent further use of logfile without first re-opening it. */ + pfLogWrite = NULL; + pfLogClose = NULL; + logfile_pointer = NULL; +} diff --git a/utils/magiedit/odoors/ODMulti.c b/utils/magiedit/odoors/ODMulti.c new file mode 100644 index 0000000..1420959 --- /dev/null +++ b/utils/magiedit/odoors/ODMulti.c @@ -0,0 +1,255 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODMulti.c + * + * Description: Code for multiple personality system, which allows + * a status line / function key personality to be dynamically + * selected at run-time. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Aug 19, 1995 6.00 BP 32-bit portability. + * 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 Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 23, 1996 6.00 BP Disable MPS under Win32 version. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Sep 01, 1996 6.10 BP Update output area on od_set_per...(). + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODInEx.h" +#include "ODKrnl.h" + + +/* Maximum number of personalities that may be installed at once. */ +#define MAX_PERSONALITIES 12 + + +/* Information on installed personalities. */ +typedef struct +{ + char szName[33]; + INT nStatusTopLine; + INT nStatusBottomLine; + OD_PERSONALITY_PROC *pfPersonalityFunction; +} tPersonalityInfo; + +static tPersonalityInfo aPersonalityInfo[MAX_PERSONALITIES]= +{ + {"STANDARD", 1, 23, pdef_opendoors}, + {"REMOTEACCESS", 1, 23, pdef_ra}, + {"WILDCAT", 1, 23, pdef_wildcat}, + {"PCBOARD", 1, 23, pdef_pcboard} +}; + + +/* Private variables. */ +static INT nPersonalities = 5; +static INT nCurrentPersonality = 255; + + +/* ---------------------------------------------------------------------------- + * ODMPSEnable() + * + * This function is called from within od_init() when the user enables the + * multiple personality system. + * + * Parameters: None. + * + * Return: void + */ +ODAPIDEF void ODCALL ODMPSEnable(void) +{ + pfSetPersonality = od_set_personality; +} + + +/* ---------------------------------------------------------------------------- + * od_set_personality() + * + * Sets the current personality to the one that is specified in pszName. + * + * Parameters: pszName - The name of the personality to switch to. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_set_personality(const char *pszName) +{ +#ifdef OD_TEXTMODE + BYTE btNewPersonality; + char szNameToMatch[33]; + tPersonalityInfo *pNewPersonalityInfo; +#endif /* OD_TEXTMODE */ + + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_set_personality()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + +#ifdef OD_TEXTMODE + /* Check for valid parameters. */ + if(strlen(pszName) == 0) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(FALSE); + } + + /* Build personality name to match. */ + strncpy(szNameToMatch, pszName, 32); + szNameToMatch[32] = '\0'; + strupr(szNameToMatch); + + /* Loop through installed personalities, checking for a match. */ + for(btNewPersonality = 0; btNewPersonality < nPersonalities; + ++btNewPersonality) + { + /* If the name of this personality matches the one we are looking for. */ + if(strcmp(szNameToMatch, aPersonalityInfo[btNewPersonality].szName) == 0) + { + if(btNewPersonality != nCurrentPersonality) + { + /* Remove current status line from the screen .*/ + od_set_statusline(8); + + /* Initialize the new personality. */ + if(nCurrentPersonality != 255) + (*(OD_PERSONALITY_CALLBACK *)pfCurrentPersonality)(22); + od_control.od_page_statusline = -1; + pNewPersonalityInfo = + &aPersonalityInfo[nCurrentPersonality=btNewPersonality]; + bRAStatus = TRUE; + (*(OD_PERSONALITY_CALLBACK *)pNewPersonalityInfo + ->pfPersonalityFunction)(20); + ODScrnSetBoundary(1, (BYTE)pNewPersonalityInfo->nStatusTopLine, 80, + (BYTE)pNewPersonalityInfo->nStatusBottomLine); + pfCurrentPersonality + = pNewPersonalityInfo->pfPersonalityFunction; + btCurrentStatusLine = 255; + + /* Update output area. */ + btOutputTop = (BYTE)pNewPersonalityInfo->nStatusTopLine; + btOutputBottom = (BYTE)pNewPersonalityInfo->nStatusBottomLine; + + /* Draw the new statusline. */ + od_set_statusline(0); + } + + OD_API_EXIT(); + return(TRUE); + } + } + + OD_API_EXIT(); + od_control.od_error = ERR_LIMIT; + return(FALSE); + +#else /* !OD_TEXTMODE */ + + /* The multiple personality system is not supported under this platform. */ + od_control.od_error = ERR_UNSUPPORTED; + + /* Return with failure. */ + OD_API_EXIT(); + return(FALSE); + +#endif /* !OD_TEXTMODE */ +} + + + +/* ---------------------------------------------------------------------------- + * od_add_personality() + * + * Installs a new personality into the set of available personalities. + * + * Parameters: pszName - Pointer to string containing the name of + * the new personality. + * + * btOutputTop - Index of the top line of the status bar. + * + * btOutputBottom - Index of the bottom line of the status bar. + * + * pfPerFunc - Pointer to the callback function which + * implements this personality. + * + * Return: TRUE on success or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_add_personality(const char *pszName, BYTE btOutputTop, + BYTE btOutputBottom, OD_PERSONALITY_PROC *pfPerFunc) +{ + /* Log function entry if running in trace mode */ + TRACE(TRACE_API, "od_add_personality()"); + +#ifdef OD_TEXTMODE + + /* Check that we haven't exceeded the limit on the total number of */ + /* installed personalities. */ + if(nPersonalities == MAX_PERSONALITIES) + { + od_control.od_error = ERR_LIMIT; + return(FALSE); + } + + /* Store information on this new personality. */ + strncpy(aPersonalityInfo[nPersonalities].szName, pszName, 32); + aPersonalityInfo[nPersonalities].szName[32] = '\0'; + strupr(aPersonalityInfo[nPersonalities].szName); + aPersonalityInfo[nPersonalities].nStatusTopLine = btOutputTop; + aPersonalityInfo[nPersonalities].nStatusBottomLine = btOutputBottom; + aPersonalityInfo[nPersonalities].pfPersonalityFunction = pfPerFunc; + + /* Increment total number of personalities. */ + ++nPersonalities; + + /* Return with success. */ + return(TRUE); + +#else /* !OD_TEXTMODE */ + + /* The multiple personality system is not supported under this platform. */ + od_control.od_error = ERR_UNSUPPORTED; + + /* Return with failure. */ + return(FALSE); + +#endif /* !OD_TEXTMODE */ +} diff --git a/utils/magiedit/odoors/ODOORS62.TXT b/utils/magiedit/odoors/ODOORS62.TXT new file mode 100644 index 0000000..0a2426d --- /dev/null +++ b/utils/magiedit/odoors/ODOORS62.TXT @@ -0,0 +1,104 @@ +*************************************************************************** +* OpenDoors v6.24 C/C++ Door Development Kit for DOS/Win32/*nix Platforms * +*************************************************************************** + +$Id: ODOORS62.TXT,v 1.5 2006/12/07 02:06:14 rswindell Exp $ + +August 10, 2003 + +*nix (using StdIO only) update to Brian Pirie's OpenDoors Library + +August 22, 2002 + +Door32.sys and Socket update to Brian Pirie's OpenDoors Library +(http://www.pirieworld.ca/opendoors.html) + +by Rob Swindell (http://www.synchro.net/) + +The current source code is always available via CVS at cvs.synchro.net. + +The latest and greatest Win32 ODoors62.dll can always be downloaded here: +http://cvs.synchro.net/cgi-bin/cvsweb.cgi/~checkout~/src/odoors/ODoors62.dll + +============================================================================== + +This archive includes the source code to the OpenDoors library with +modifications made by me (Rob Swindell, aka Digital Man) to add support for +the Door32.sys drop file format and Win32 TCP/IP socket (Telnet) +communications. + +I made my modifications to the 6.1.1 release by Brian Pirie (ods611.zip) and +used Microsoft Visual C++ v6.0. I also eliminated any warnings or errors +detected by this compiler. The linker still warns of duplicate symbol +definition (od_control and od_printf), but I left those duplicate defintions +in the .def file since they may have been necessary for another platform or +compiler that I'm not using. + +This version also includes the ODEmu.c:od_send_file_section() modification +by Michael Dillon (gsvalore@arn.net | http://members.darktech.org/gsvalore/). + + +DOOR32.SYS +---------- +The Door32.sys drop file format was created in June of 2000 to support the +new wave of 32-bit Windows and *nix doors. The main feature of this +drop file format is that it includes the currently open Win32 comm handle or +socket descriptor (whichever is appropriate for the current connection). + +I didn't add support for the Win32 comm handle in the door32.sys file +(I run a telnet-only BBS and would have no way to test it). I can't +imagine it would be very difficult to add; I'm just not sure how much demand +there would be for such a feature today. + +I did however add support for the socket descriptor in the drop file (used for +TCP/IP - Telnet connections) and this is currently the only "standard" drop +file format that is expected to include a socket descriptor (Synchronet's +XTRN.DAT drop file also includes a socket descriptor, but I don't really +consider that format to be a "standard"). + +The Door32.sys drop file is currently supported by the following known BBS +packages: + + Software Home Page Version + -----------+-------------------------------------+-------- + Mystic BBS www.mysticbbs.com 1.07 + EleBBS www.elebbs.com 0.08? + Synchronet www.synchro.net 3.x + + +TCP SOCKET I/O +-------------- +When using a Door32.sys drop file, the communications type (Local, Serial, or +Telnet) is automatically determined and I added support for (and tested) the +Telnet/socket communication method using Synchronet BBS Software v3.10 for +Win32 and HyperTerminal Private Edition v6.1. + +Since the Telnet protocol specifies that an end-of-line sequence (ENTER or +Carriage Return) is a CRLF (ASCII 13, 10), I had to modify od_get_key() to +ignore any line feed (ASCII 10, Ctrl-J) characters. Without this modification, +hitting enter in most Telnet clients would cause a "double return" to be sent +to the door. There may be a more desirable solution to the problem, but this +one seems to work for now. + +v6.21 fixes a bug in the socket disconnection ("carrier-loss") detection in +v6.20. I also lowered the input and carrier-detect thread priorities down to +"normal" which makes the doors appear to run faster and also make debugging +continuous loop problems (like the one in v6.20) much easier. + +v6.22 changes: +Another bug fixed in socket disconnection ("carrier-loss") detection. +Added support for non-blocking sockets (e.g. EleBBS) - thanks to GSValore. +Added support for the "-SOCKET" command-line option to specify the socket +descriptor on the command-line. + +v6.23 changes: +*nix support using stdio + +v6.24 chagnes: +Fixed timeing bugs on *nix +Fixed output truncated bug on *nix +Fixed od_get_input() hang on ESC on Win32 +Fixed various other bugs. +Added od_key_pending() function. + +/* End of ODOORS62.TXT */ diff --git a/utils/magiedit/odoors/ODPCB.c b/utils/magiedit/odoors/ODPCB.c new file mode 100644 index 0000000..f5b5095 --- /dev/null +++ b/utils/magiedit/odoors/ODPCB.c @@ -0,0 +1,207 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODPCB.c + * + * Description: Implements the PC-Board personality. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 03, 1996 6.00 BP Display connect speed with %lu. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODKrnl.h" +#include "ODUtil.h" +#include "ODStat.h" + + +/* ---------------------------------------------------------------------------- + * pdef_pcboard() + * + * Personality function for the PC-Board like status line / function key + * personality. + * + * Parameters: btOperation - Indicates personality operation to be performed. + * + * Return: void + */ +ODAPIDEF void ODCALL pdef_pcboard(BYTE btOperation) +{ + static char szTemp[81]; + BYTE btInfoType = od_control.od_info_type; + + + switch(btOperation) + { + case PEROP_DISPLAY1: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" ALT-H=Help "); + ODScrnSetCursorPos(3, 24); + if(od_control.baud != 0) + { + ODScrnPrintf("(%lu) ", od_control.od_connect_speed); + } + else + { + ODScrnDisplayString("(Local) "); + } + sprintf(szTemp, "%s - %s", od_control.user_name, + od_control.user_location); + szTemp[42] = '\0'; + strupr(szTemp); + ODScrnDisplayString(szTemp); + ODScrnSetCursorPos(1,25); + if(od_control.user_ansi || od_control.user_avatar + || od_control.user_rip) + { + ODScrnDisplayChar('G'); + } + else + { + ODScrnDisplayChar('A'); + } + if(btInfoType == RA1EXITINFO || btInfoType == RA2EXITINFO + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnPrintf(" (%s)",od_control.user_firstcall); + } + ODScrnSetCursorPos(15, 25); + ODScrnPrintf("Sec(0)=%u ",od_control.user_security); + if(od_control.od_extended_info || btInfoType == DOORSYS_GAP + || btInfoType == CHAINTXT || btInfoType == DOORSYS_WILDCAT) + { + ODScrnPrintf("Times On=%u ", od_control.user_numcalls); + } + if(od_control.od_extended_info || btInfoType == SFDOORSDAT + || btInfoType == DOORSYS_GAP || btInfoType == DOORSYS_WILDCAT) + { + ODScrnPrintf("Up:Dn=%lu:%lu", od_control.user_uploads, + od_control.user_downloads); + } + ODScrnSetCursorPos(70, 25); + ODScrnPrintf("%4d", od_control.user_timelimit); + + od_control.key_status[0] = 0x0000; + od_control.key_status[1] = 0x2300; + break; + + case PEROP_DISPLAY2: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" Alt-> N=Next X=DOS F1/F2=Time 2=LkOut 5=SHELL 8=HngUp 10=Chat "); + + od_control.key_status[0] = 0x2300; + od_control.key_status[1] = 0x0000; + break; + + case PEROP_UPDATE1: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(70, 25); + ODScrnPrintf("%4d", od_control.user_timelimit); + break; + + case PEROP_INITIALIZE: + od_control.key_hangup = 0x4200; + od_control.key_drop2bbs = 0x2d00; + od_control.key_dosshell = 0x3f00; + od_control.key_chat = 0x4400; + od_control.key_sysopnext = 0x3100; + od_control.key_lockout = 0x3c00; + od_control.key_status[0] = 0x0000; + od_control.key_status[1] = 0x2300; + od_control.key_status[2] = 0x0000; + od_control.key_status[3] = 0x0000; + od_control.key_status[4] = 0x0000; + od_control.key_status[5] = 0x0000; + od_control.key_status[6] = 0x0000; + od_control.key_status[7] = 0x0000; + od_control.key_status[8] = 0x0000; + od_control.key_keyboardoff = 0x2500; + od_control.key_moretime = 0x0000; + od_control.key_lesstime = 0x0000; + ODStatAddKey(0x6900); + ODStatAddKey(0x6800); + od_control.od_page_statusline = 0; + break; + + case PEROP_CUSTOMKEY: + switch(od_control.od_last_hot) + { + /* Key to add five minutes. */ + case 0x6900: + if(od_control.user_timelimit <= 1435 && + od_control.user_timelimit >= 5) + { + od_control.user_timelimit += 5; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + } + else if(od_control.user_timelimit < 5) + { + od_control.user_timelimit++; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + } + break; + + /* Subtract five minutes from the user's remaining time. */ + case 0x6800: + if(od_control.user_timelimit > 5) + { + od_control.user_timelimit -= 5; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + } + else if(od_control.user_timelimit > 1) + { + --od_control.user_timelimit; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + } + break; + + default: + return; + } + od_control.od_last_hot = 0; + break; + } +} diff --git a/utils/magiedit/odoors/ODPlat.c b/utils/magiedit/odoors/ODPlat.c new file mode 100644 index 0000000..292d289 --- /dev/null +++ b/utils/magiedit/odoors/ODPlat.c @@ -0,0 +1,1530 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODPlat.c + * + * Description: Contains platform-specific utility functions. Non-platform + * specific utility functions are implemented in odutil.c + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 14, 1994 6.00 BP Created, with od_yield(). + * Nov 01, 1994 6.00 BP Added new directory access functions. + * Dec 09, 1994 6.00 BP Eliminate access to old dir functions. + * Dec 31, 1994 6.00 BP Added timing, file delete functions. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Dec 31, 1994 6.00 BP Added ODMultitasker and ODPlatInit() + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Added multithreading functions. + * Nov 21, 1995 6.00 BP Ported to Win32. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 13, 1995 6.00 BP Added ODThreadWaitForExit(). + * Dec 13, 1995 6.00 BP Added ODThreadGetCurrent(). + * Dec 19, 1995 6.00 BP Fixed ODThreadGetCurrent() (Win32). + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 23, 1996 6.00 BP Added ODProcessExit(). + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 30, 1996 6.00 BP Add semaphore timeout. + * Jan 31, 1996 6.00 BP Add ODTimerLeft(), rm ODTimerSleep(). + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Prevent TC calls N_LXMUL@ & N_LXDIV@. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#ifdef ODPLAT_NIX +#include +#include +#include +#include +#include +#endif +#include "ODGen.h" +#include "ODCore.h" +#include "ODPlat.h" +#include "ODUtil.h" +#include "ODSwap.h" +#include "ODKrnl.h" + +#ifdef ODPLAT_WIN32 +#include "windows.h" +#endif /* ODPLAT_WIN32 */ + + +/* Multitasker type, only availvable under DOS. */ +#ifdef ODPLAT_DOS +tODMultitasker ODMultitasker = kMultitaskerNone; +static void ODPlatYield(void); +#endif /* ODPLAT_DOS */ + +/* ---------------------------------------------------------------------------- + * ODPlatInit() + * + * Performs any initialization required to use the utility functions supplied + * by this module. + * + * Parameters: none + * + * Return: void + */ +void ODPlatInit(void) +{ +#ifdef ODPLAT_DOS + /* If this is the DOS version of OpenDoors, then ODPlatInit() must */ + /* determine what multitasker we are running under. */ + + /* Check whether running under OS/2. */ + ASM mov ah, 0x30 + ASM int 0x21 + ASM cmp al, 0x0a + ASM jl NoOS2 + + /* If we get to this point, then OS/2 has been detected. */ + ODMultitasker = kMultitaskerOS2; + return; + +NoOS2: + /* Check whether we are running under DesqView. */ + ASM mov cx, 0x4445 + ASM mov dx, 0x5351 + ASM mov ax, 0x2b01 + ASM int 0x21 + ASM cmp al, 0xff + ASM je NoDesqView + + /* If we get to this point, then DesqView has been detected. */ + ODMultitasker = kMultitaskerDV; + +NoDesqView: + /* Check whether we are running under Windows. */ + ASM push di + ASM push si + ASM mov ax, 0x1600 + ASM int 0x2f + ASM pop si + ASM pop di + ASM cmp al, 0x00 + ASM je NoWindows + ASM cmp al, 0x80 + ASM je NoWindows + + /* If we get to this point, then Windows has been detected. */ + ODMultitasker = kMultitaskerWin; + +NoWindows: + ODMultitasker = kMultitaskerNone; +#endif /* ODPLAT_DOS */ +} + + +/* ---------------------------------------------------------------------------- + * ODPlatYield() *** PRIVATE FUNCTION *** + * + * Yields control to other tasks when running as a DOS application under a + * multitasking system. + * + * Parameters: none + * + * Return: void + */ +#ifdef ODPLAT_DOS +static void ODPlatYield(void) +{ + switch(ODMultitasker) + { + case kMultitaskerDV: + ASM mov ax, 0x1000 + ASM int 0x15 + break; + + case kMultitaskerWin: + ASM mov ax, 0x1680 + ASM int 0x2f + break; + + case kMultitaskerOS2: + default: + ASM int 0x28 + } +} +#endif /* ODPLAT_DOS */ + + +/* ========================================================================= */ +/* Multithreading and synchronization support. */ +/* ========================================================================= */ + +#ifdef OD_MULTITHREADED + +/* ---------------------------------------------------------------------------- + * ODThreadCreate() + * + * Starts a new thread of concurrent execution. + * + * Parameters: phThread - Pointer to the location where the handle to the + * new thread should be stored. + * + * pfThreadProc - Function to call to begin execution of the + * thread. + * + * pThreadParam - Parameter to pass to the thread function when + * it is called. + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODThreadCreate(tODThreadHandle *phThread, + ptODThreadProc *pfThreadProc, void *pThreadParam) +{ +#ifdef ODPLAT_WIN32 + DWORD dwThreadID; + HANDLE hNewThread; + + ASSERT(phThread != NULL); + ASSERT(pfThreadProc != NULL); + + /* Attempt to create the new thread. */ + hNewThread = CreateThread(NULL, 0, pfThreadProc, pThreadParam, + 0, &dwThreadID); + + /* Check for thread creation failure. */ + if(hNewThread == NULL) + { + return(kODRCGeneralFailure); + } + + /* Pass newly created thread's handle back to the caller. */ + *phThread = hNewThread; + + /* Return with success. */ + return(kODRCSuccess); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadExit() + * + * Causes the calling thread to be terminated. + * + * Parameters: none + * + * Return: Never returns! + */ +void ODThreadExit() +{ +#ifdef ODPLAT_WIN32 + ExitThread(0); +#endif /* ODPLAT_WIN32 */ + + /* We should never get here. */ + ASSERT(FALSE); +} + + +/* ---------------------------------------------------------------------------- + * ODThreadTerminate() + * + * Terminates the specified thread. + * + * Parameters: hThread - Handle to the thread to be terminated. + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODThreadTerminate(tODThreadHandle hThread) +{ + ASSERT(hThread != NULL); + +#ifdef ODPLAT_WIN32 + return(TerminateThread(hThread, 0) ? kODRCSuccess : kODRCGeneralFailure); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadSuspend() + * + * Pauses execution of the specified thread, until the ODThreadResume() + * function is called. + * + * Parameters: hThread - Handle to the thread to be suspended. + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODThreadSuspend(tODThreadHandle hThread) +{ + ASSERT(hThread != NULL); + +#ifdef ODPLAT_WIN32 + return(SuspendThread(hThread) == 0xFFFFFFFF ? kODRCGeneralFailure + : kODRCSuccess); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadResume() + * + * Continues execution of a thread previously paused by a call to + * ODThreadSuspend(). + * + * Parameters: hThread - Handle to the thread to be resumed. + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODThreadResume(tODThreadHandle hThread) +{ + ASSERT(hThread != NULL); + +#ifdef ODPLAT_WIN32 + return(ResumeThread(hThread) == 0xFFFFFFFF ? kODRCGeneralFailure + : kODRCSuccess); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadSetPriority() + * + * Changes the execution priority of a thread. Since the exact semantics of + * thread priorities are different for each platform, this function should + * be used carefully. The caller should assume that no thread will run if there + * exists a non-blocked thread with a higher priority. + * + * Parameters: hThread - Handle to the thread to change the priority of. + * + * ThreadPriority - New priority to assign to the thread. + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODThreadSetPriority(tODThreadHandle hThread, + tODThreadPriority ThreadPriority) +{ +#ifdef ODPLAT_WIN32 + int nWindowsThreadPriority; + + ASSERT(hThread != NULL); + + /* Determine the Windows thread priority to assign to the thread. */ + switch(ThreadPriority) + { + case OD_PRIORITY_LOWEST: + nWindowsThreadPriority = THREAD_PRIORITY_LOWEST; + break; + case OD_PRIORITY_BELOW_NORMAL: + nWindowsThreadPriority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case OD_PRIORITY_NORMAL: + nWindowsThreadPriority = THREAD_PRIORITY_NORMAL; + break; + case OD_PRIORITY_ABOVE_NORMAL: + nWindowsThreadPriority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case OD_PRIORITY_HIGHEST: + nWindowsThreadPriority = THREAD_PRIORITY_HIGHEST; + break; + default: + ASSERT(FALSE); + } + + /* Update the thread's priority. */ + return(SetThreadPriority(hThread, nWindowsThreadPriority) + ? kODRCSuccess : kODRCGeneralFailure); + +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadWaitForExit() + * + * Blocks until the specified thread is terminated. + * + * Parameters: hThread - Handle to the thread to wait for. + * + * Return: void + */ +void ODThreadWaitForExit(tODThreadHandle hThread) +{ +#ifdef ODPLAT_WIN32 + WaitForSingleObject(hThread, INFINITE); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODThreadGetCurrent() + * + * Obtains a handle to the thread that called this function. + * + * Parameters: None. + * + * Return: Handle to the current thread. + */ +tODThreadHandle ODThreadGetCurrent(void) +{ +#ifdef ODPLAT_WIN32 + HANDLE hDuplicate; + if(!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hDuplicate, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + return(NULL); + } + return(hDuplicate); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODSemaphoreAlloc() + * + * Allocates a semaphore synchronization object. + * + * Parameters: phSemaphore - Pointer to location where the handle to the + * newly created semaphore should be stored. + * + * nInitialCount - Initial value to assign to the semaphore. + * + * nMaximumCount - Maximum value that the semaphore may have + * (if supported by the current platform). + * + * Return: kOCRCSuccess on success, or an error code on failure. + */ +tODResult ODSemaphoreAlloc(tODSemaphoreHandle *phSemaphore, INT nInitialCount, + INT nMaximumCount) +{ + ASSERT(phSemaphore != NULL); + ASSERT(nInitialCount >= 0); + ASSERT(nMaximumCount >= nInitialCount); + +#ifdef ODPLAT_WIN32 + *phSemaphore = CreateSemaphore(NULL, (LONG)nInitialCount, + (LONG)nMaximumCount, NULL); + + return(*phSemaphore == NULL ? kODRCGeneralFailure : kODRCSuccess); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODSemaphoreFree() + * + * Deallocates a semaphore that we previously created by ODSemaphoreAlloc(). + * + * Parameters: hSemaphore - Handle to semaphore to deallocate. + * + * Return: void + */ +void ODSemaphoreFree(tODSemaphoreHandle hSemaphore) +{ + ASSERT(hSemaphore != NULL); + +#ifdef ODPLAT_WIN32 + DeleteObject(hSemaphore); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODSemaphoreUp() + * + * Increments the count of the specified semaphore. + * + * Parameters: hSemaphore - Semaphore to increment. + * + * nIncrementBy - Amount to add to the semaphore's current value. + * + * Return: void + */ +void ODSemaphoreUp(tODSemaphoreHandle hSemaphore, INT nIncrementBy) +{ + ASSERT(hSemaphore != NULL); + ASSERT(nIncrementBy > 0); + +#ifdef ODPLAT_WIN32 + ReleaseSemaphore(hSemaphore, nIncrementBy, NULL); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODSemaphoreDown() + * + * Decrements the count of the specified semaphore. A semaphore may never have + * a value less than 0. Hence, an attempt to decrement the value of a + * semaphore below zero will cause the calling thread to be blocked until some + * other thread increments the semaphore. + * + * Parameters: hSemaphore - Handle to the semaphore to decrement. + * + * Timeout - Maximum time to wait for the semaphore to be + * incremented, or OD_NO_TIMEOUT to prevent this + * function from returning before the semaphore is + * incremented. + * + * Return: kODRCSuccess, or kODRCTimeout if the semaphore was not + * decremented before Timeout milliseconds elapsed. + */ +tODResult ODSemaphoreDown(tODSemaphoreHandle hSemaphore, tODMilliSec Timeout) +{ + ASSERT(hSemaphore != NULL); + +#ifdef ODPLAT_WIN32 + if(WaitForSingleObject(hSemaphore, Timeout) != WAIT_OBJECT_0) + { + return(kODRCTimeout); + } +#endif /* ODPLAT_WIN32 */ + + /* Return with success. */ + return(kODRCSuccess); +} + +#endif /* OD_MULTITHREADED */ + + +/* ---------------------------------------------------------------------------- + * ODProcessExit() + * + * Ends the current process. + * + * Parameters: nExitCode - Exit code to return to the calling process. + * + * Return: Never returns. + */ +void ODProcessExit(INT nExitCode) +{ +#ifdef ODPLAT_WIN32 + ExitProcess(nExitCode); +#else /* !ODPLAT_WIN32 */ + exit(nExitCode); +#endif /* !ODPLAT_WIN32 */ +} + + +/* ========================================================================= */ +/* Millisecond timer functions. */ +/* ========================================================================= */ + +#ifdef ODPLAT_DOS +/* For the DOS platform, we need to know the number of milliseconds per */ +/* clock tick. */ +#define MILLISEC_PER_TICK 55 /* (approx. == 1000 / CLOCKS_PER_SEC) */ +#endif /* ODPLAT_DOS */ + +/* ---------------------------------------------------------------------------- + * ODTimerStart() + * + * Starts a timer for a specified number of milliseconds. Future calls to + * ODTimerElapsed() can be used to determine whether or not specified time + * has elapsed. Note that while this function accepts its parameter in + * milliseconds, it does not gurantee millisecond resolution. In fact, under + * DOS, this timer mechanism has just under a 55 millisecond resolution, with + * an average error of about 27 milliseconds. + * + * Parameters: pTimer - Pointer to a tODTimer structure that will be later + * passed to ODTimerElapsed(). + * + * Duration - Number of milliseconds after which timer should + * elapse. + * + * Return: void + */ +void ODTimerStart(tODTimer *pTimer, tODMilliSec Duration) +{ +#ifdef ODPLAT_NIX + struct timeval tv; +#endif + ASSERT(pTimer != NULL); + ASSERT(Duration >= 0); + +#ifdef ODPLAT_DOS + /* Store timer start time right away. */ + pTimer->Start = clock(); + + /* Calculate duration of timer. */ + ODDWordDivide((DWORD *)&pTimer->Duration, NULL, Duration, + MILLISEC_PER_TICK); +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + /* Store timer start time now. */ + pTimer->Start = GetTickCount(); + pTimer->Duration = Duration; +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + gettimeofday(&tv,NULL); + pTimer->Start=tv.tv_sec*1000+tv.tv_usec/1000; + pTimer->Duration = Duration; +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODTimerElapsed() + * + * Determines whether or not a timer set by ODTimerStart() has elapsed. + * + * Parameters: pTimer - Pointer to a tODTimer structure that was populated + * by ODTimerStart(). + * + * Return: TRUE if timer has elapsed, FALSE if it has not. + */ +BOOL ODTimerElapsed(tODTimer *pTimer) +{ + ASSERT(pTimer != NULL); + +#ifdef ODPLAT_DOS + return(clock() > pTimer->Start + pTimer->Duration + || clock() < pTimer->Start); +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + return(ODTimerLeft(pTimer)==0); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + return(ODTimerLeft(pTimer)==0); +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODTimerWaitForElapse() + * + * Sleeps until the specified timer elapses. + * + * Parameters: pTimer - Pointer to a tODTimer structure that was populated + * by ODTimerStart(). + * + * Return: void + */ +void ODTimerWaitForElapse(tODTimer *pTimer) +{ + ASSERT(pTimer != NULL); + +#ifdef ODPLAT_DOS + + /* Under DOS, our timer resolution is low enough (only 18.2 ticks per */ + /* second), that we cannot accurately calculate the time to sleep for. */ + /* For this reason, we simply loop until the timer has elapsed, yielding */ + /* control to other tasks if when the timer has not elapsed. */ + + /* While timer has not elapsed. */ + while(!ODTimerElapsed(pTimer)) + { + /* Let other tasks run. */ + od_sleep(0); + } + +#else /* !ODPLAT_DOS */ + /* Under other platforms, timer resolution is high enough that we can */ + /* ask the OS to block this thread for the amount of time required */ + /* for the timer to elapse. */ + + od_sleep(ODTimerLeft(pTimer)); +#endif /* !ODPLAT_DOS */ +} + + +/* ---------------------------------------------------------------------------- + * ODTimerLeft() + * + * Determines the number of milliseconds left before the timer elapses. + * + * Parameters: pTimer - Pointer to a tODTimer structure that was populated + * by ODTimerStart(). + * + * Return: Number of milliseconds before timer elapses, or 0 if the timer + * has already elapsed. + */ +tODMilliSec ODTimerLeft(tODTimer *pTimer) +{ +#ifdef ODPLAT_NIX + struct timeval tv; + time_t nowtick; +#endif + ASSERT(pTimer != NULL); + +#ifdef ODPLAT_DOS + { + clock_t Now = clock(); + clock_t Left; + + /* If timer has elapsed, return 0. */ + if(Now > pTimer->Start + pTimer->Duration + || Now < pTimer->Start) + { + return(0); + } + + Left = pTimer->Start + pTimer->Duration - Now; + + return(ODDWordMultiply(Left, MILLISEC_PER_TICK)); + } +#elif defined(ODPLAT_NIX) + gettimeofday(&tv,NULL); + nowtick=tv.tv_sec*1000+(tv.tv_usec/1000); + if(pTimer->Start+pTimer->Duration <= nowtick) + return(0); + return((tODMilliSec)(pTimer->Start + pTimer->Duration - nowtick)); +#else /* !ODPLAT_DOS */ + { + tODMilliSec Now; + +#ifdef ODPLAT_WIN32 + Now = GetTickCount(); +#endif /* ODPLAT_WIN32 */ + + /* If timer has elapsed, return 0. */ + if(Now > pTimer->Start + pTimer->Duration + || Now < pTimer->Start) + { + return(0); + } + + return(pTimer->Start + pTimer->Duration - Now); + } +#endif /* !ODPLAT_DOS */ +} + + +/* ---------------------------------------------------------------------------- + * od_sleep() + * + * Sleeps for the specified number of milliseconds, being as friendly to other + * running tasks as possible. Under DOS, this function uses the ODTimerStart()/ + * ODTimerElapsed() mechanism, and so its accuracy is limited by the accuracy + * of that mechanism. + * + * Parameters: Milliseconds - Number of milliseconds to sleep. A value of 0 + * allows any other waiting processes to run for + * the rest of the current timeslice. + * + * Return: void + */ +ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds) +{ +#ifdef ODPLAT_NIX + struct timeval tv; + struct timeval start; + time_t started; + time_t left +#endif + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_sleep()"); + + /* Ensure that OpenDoors is initialized before proceeding. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + +#ifdef ODPLAT_DOS + if(Milliseconds == 0) + { + ODPlatYield(); + } + else + { + tODTimer SleepTimer; + ODTimerStart(&SleepTimer, Milliseconds); + while(!ODTimerElapsed(&SleepTimer)) + { + /* Let other tasks run. */ + ODPlatYield(); + } + } +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + Sleep(Milliseconds); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + if(Milliseconds==0) { + /* Prevent 100% CPU *only* no delay is actually required here */ + tv.tv_sec=0; + tv.tv_usec=1000; + select(0,NULL,NULL,NULL,&tv); + } + else { + gettimeofday(&start,NULL); + started=start.tv_sec*1000+(start.tv_usec/1000); + + while(1) { + /* This is timing sensitive and *MUST* wait for at least Milliseconds regardless of 100% CPU or signals */ + gettimeofday(&tv,NULL); + left=tv.tv_sec*1000+(tv.tv_usec/1000); + left-=started; + left=Milliseconds-left; + tv.tv_sec = left/1000; + tv.tv_usec = (left*1000)%1000000; + if(tv.tv_sec<0 || tv.tv_usec<0) + break; + if(!select(0,NULL,NULL,NULL,&tv)) + break; + } + } +#endif + + OD_API_EXIT(); +} + + +/* ========================================================================= */ +/* Directory access. */ +/* ========================================================================= */ + +/* Structure for directories entries returned by DOS. */ +#ifdef ODPLAT_DOS +typedef struct +{ + BYTE abtReserved[21]; + BYTE btAttrib; + WORD wFileTime; + WORD wFileDate; + DWORD dwFileSize; + char szFileName[13]; +} tDOSDirEntry; +#endif /* ODPLAT_DOS */ + + +/* Dir handle structure. */ +typedef struct +{ + BOOL bEOF; +#ifdef ODPLAT_DOS + tDOSDirEntry FindBlock; +#endif /* ODPLAT_DOS */ +#ifdef ODPLAT_WIN32 + HANDLE hWindowsDir; + WIN32_FIND_DATA WindowsDirEntry; + int wAttributes; +#endif /* ODPLAT_WIN32 */ +#ifdef ODPLAT_NIX + glob_t g; + int pos; + int wAttributes; +#endif +} tODDirInfo; + + +/* Directory access private function prototypes. */ +#if defined(ODPLAT_DOS) || defined(ODPLAT_WIN32) +static time_t DOSToCTime(WORD wDate, WORD wTime); +#endif +#ifdef ODPLAT_DOS +static INT ODDirDOSFindFirst(CONST char *pszPath, tDOSDirEntry *pBlock, + WORD wAttributes); +static INT ODDirDOSFindNext(tDOSDirEntry *pBlock); +#endif /* ODPLAT_DOS */ +#ifdef ODPLAT_WIN32 +static BOOL ODDirWinMatchesAttributes(tODDirInfo *pDirInfo); +#endif /* ODPLAT_WIN32 */ + + +/* ---------------------------------------------------------------------------- + * ODDirOpen() + * + * Opens a directory for future access using ODDirRead(). On Success, + * ODDirOpen() provides a directory handle that represents a list of directory + * entries that match the specified path and attributes. When finished with + * the directory handle, the caller should release it using ODDirClose(). + * + * Parameters: pszPath - Directory with filename (wildcards are supported), + * for which matching files should be found. If there + * are no matching files, ODDirOpen() returns with + * kODRCNoMatch. + * + * nAttributes - One or more of the DIR_ATTRIB_... constants, + * connected by the bitmap-OR (|) operator. + * + * phDir - Pointer to a tODDirHandle, into which ODDirOpen() + * will place a valid directory handle if and only + * if it returns kODRCSuccess. + * + * Return: A tODResult indicating success or reason for failure. + */ +tODResult ODDirOpen(CONST char *pszPath, WORD wAttributes, tODDirHandle *phDir) +{ + tODDirInfo *pDirInfo; + + ASSERT(pszPath != NULL); + ASSERT(phDir != NULL); + + /* Attempt to allocate a directory information structure. */ + if((pDirInfo = malloc(sizeof(tODDirInfo))) == NULL) + { + /* If unable to allocate enough memory, return this state to the */ + /* caller. */ + return(kODRCNoMemory); + } + + /* Initialize directory information structure. */ + pDirInfo->bEOF = FALSE; + +#ifdef ODPLAT_DOS + /* Read the first matching directory entry structure. */ + if(ODDirDOSFindFirst(pszPath, &pDirInfo->FindBlock, wAttributes)) + { + /* If unable to read directory entry, release directory information */ + /* structure, and return indicating that there are no matching files. */ + free(pDirInfo); + return(kODRCNoMatch); + } +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + /* Store a copy of the attributes passed to open function. */ + pDirInfo->wAttributes = wAttributes; + + /* Attempt to read first directory entry. */ + pDirInfo->hWindowsDir = FindFirstFile(pszPath, &pDirInfo->WindowsDirEntry); + + if(pDirInfo->hWindowsDir == INVALID_HANDLE_VALUE) + { + /* If unable to read directory entry, release directory information */ + /* structure, and return indicating that there are no matching files. */ + free(pDirInfo); + return(kODRCNoMatch); + } + + /* If first file doesn't match specified attributes, then find one that */ + /* does. */ + /* Find next matching entry, if any. */ + while(!ODDirWinMatchesAttributes(pDirInfo)) + { + if(!FindNextFile(pDirInfo->hWindowsDir, &pDirInfo->WindowsDirEntry)) + { + /* If unable to find matching directory entry, then release */ + /* structure, return indicating that there are no matching files. */ + free(pDirInfo); + return(kODRCNoMatch); + } + } +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + if(glob(pszPath,GLOB_NOSORT,NULL,&(pDirInfo->g))) + return(kODRCNoMatch); + if(pDirInfo->g.gl_pathc==0) { + globfree(&(pDirInfo->g)); + return(kODRCNoMatch); + } + pDirInfo->pos=0; + pDirInfo->wAttributes = wAttributes; +#endif + + /* Now that open operation is complete, give the caller a directory */ + /* handle. */ + *phDir = ODPTR2HANDLE(pDirInfo, tODDirInfo); + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODDirRead() + * + * Reads the next directory entry from an open directory, placing the directory + * information into the tODDirEntry structure pointed to by pDirEntry. + * + * Parameters: hDir - Handle to an open directory, as provided by + * ODDirOpen(). + * + * pDirEntry - Pointer to structure into which directory entry + * information should be placed. + * + * Return: A tODResult indicating success or reason for failure. After the + * last directory entry has been read, all subsequent calls to + * ODDirRead() will return kODRCEndOfFile. + */ +tODResult ODDirRead(tODDirHandle hDir, tODDirEntry *pDirEntry) +{ + tODDirInfo *pDirInfo = ODHANDLE2PTR(hDir, tODDirInfo); +#ifdef ODPLAT_WIN32 + WORD wDOSDate; + WORD wDOSTime; +#endif /* ODPLAT_WIN32 */ +#ifdef ODPLAT_NIX + struct stat st; +#endif + + ASSERT(pDirEntry != NULL); + ASSERT(pDirInfo != NULL); + + /* Check whether the last directory entry has been returned yet. */ + if(pDirInfo->bEOF) + { + /* Return this state information to the caller. */ + return(kODRCEndOfFile); + } + +#ifdef ODPLAT_DOS + /* Provide the caller with the information from the previously read */ + /* directory entry. */ + + /* Copy the filename to the caller's structure. */ + ODStringCopy(pDirEntry->szFileName, pDirInfo->FindBlock.szFileName, + DIR_FILENAME_SIZE); + + /* Copy the attributes to the caller's structure. */ + pDirEntry->wAttributes = pDirInfo->FindBlock.btAttrib; + + /* Copy the file size to the caller's structure. */ + pDirEntry->dwFileSize = pDirInfo->FindBlock.dwFileSize; + + /* Determine the last file write time, in C library time format. */ + pDirEntry->LastWriteTime = DOSToCTime(pDirInfo->FindBlock.wFileDate, + pDirInfo->FindBlock.wFileTime); + + /* Read next directory entry, if any. */ + pDirInfo->bEOF = ODDirDOSFindNext(&pDirInfo->FindBlock); + +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + /* Provide the caller with the information from the previously read */ + /* directory entry. */ + + /* Copy filename from Win32 8.3 filename. */ + if(strlen(pDirInfo->WindowsDirEntry.cAlternateFileName) == 0) + { + ODStringCopy(pDirEntry->szFileName, + pDirInfo->WindowsDirEntry.cFileName, DIR_FILENAME_SIZE); + } + else + { + ODStringCopy(pDirEntry->szFileName, + pDirInfo->WindowsDirEntry.cAlternateFileName, DIR_FILENAME_SIZE); + } + + /* Copy attribute bits. */ + pDirEntry->wAttributes = DIR_ATTRIB_NORMAL; + if(pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) + { + pDirEntry->wAttributes |= DIR_ATTRIB_ARCH; + } + if(pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + pDirEntry->wAttributes |= DIR_ATTRIB_DIREC; + } + if(pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + { + pDirEntry->wAttributes |= DIR_ATTRIB_HIDDEN; + } + if(pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + { + pDirEntry->wAttributes |= DIR_ATTRIB_RDONLY; + } + if(pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + { + pDirEntry->wAttributes |= DIR_ATTRIB_SYSTEM; + } + + /* Copy the file size to the caller's structure. */ + pDirEntry->dwFileSize = (long)pDirInfo->WindowsDirEntry.nFileSizeLow; + + /* Determine the last file write time, in C library time format. */ + FileTimeToDosDateTime(&pDirInfo->WindowsDirEntry.ftLastWriteTime, &wDOSDate, + &wDOSTime); + pDirEntry->LastWriteTime = DOSToCTime(wDOSDate, wDOSTime); + + /* Find next matching entry, if any. */ + do + { + if(!FindNextFile(pDirInfo->hWindowsDir, &pDirInfo->WindowsDirEntry)) + { + pDirInfo->bEOF = TRUE; + } + } while(!ODDirWinMatchesAttributes(pDirInfo)); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + while(!pDirInfo->bEOF) { + if(strrchr(pDirInfo->g.gl_pathv[pDirInfo->pos],DIRSEP)==NULL) + strcpy(pDirEntry->szFileName,pDirInfo->g.gl_pathv[pDirInfo->pos]); + else + strcpy(pDirEntry->szFileName,strrchr(pDirInfo->g.gl_pathv[pDirInfo->pos],DIRSEP)); + stat(pDirInfo->g.gl_pathv[pDirInfo->pos],&st); + pDirEntry->wAttributes=DIR_ATTRIB_NORMAL; + if(st.st_mode & S_IFDIR) + pDirEntry->wAttributes |= DIR_ATTRIB_DIREC; + if(!st.st_mode & S_IWUSR) + pDirEntry->wAttributes |= DIR_ATTRIB_RDONLY; + if(!st.st_mode & S_IRUSR) + pDirEntry->wAttributes |= DIR_ATTRIB_SYSTEM; + pDirEntry->LastWriteTime=st.st_mtime; + pDirEntry->dwFileSize=st.st_size; + pDirInfo->pos++; + if(pDirInfo->pos==pDirInfo->g.gl_pathc) + pDirInfo->bEOF=TRUE; + if(pDirEntry->wAttributes==pDirInfo->wAttributes) + return(kODRCSuccess); + if(pDirInfo->bEOF==TRUE) + return(kODRCEndOfFile); + } +#endif + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODDirClose() + * + * Closes and open directory handle. + * + * Parameters: hDir - Handle to an open directory handle, as provided by the + * ODDirOpen() function. + * + * Return: void + */ +void ODDirClose(tODDirHandle hDir) +{ + tODDirInfo *pDirInfo = ODHANDLE2PTR(hDir, tODDirInfo); + + ASSERT(pDirInfo != NULL); + +#ifdef ODPLAT_WIN32 + /* Under Win32, close directory handle. */ + FindClose(pDirInfo->hWindowsDir); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + globfree(&(pDirInfo->g)); +#endif + + /* Free the directory information structure. */ + free(pDirInfo); +} + + +#if defined(ODPLAT_DOS) || defined(ODPLAT_WIN32) +/* ---------------------------------------------------------------------------- + * DOSToCTime() *** PRIVATE FUNCTION *** + * + * Converts DOS directory entry time format to the C library time format. + * + * Parameters: uDate - Date portion of the time to be converted. + * + * uTime - Time of day portion of the time to be converted. + * + * Return: The specified time, represented as a time_t. + */ +static time_t DOSToCTime(WORD wDate, WORD wTime) +{ + struct tm TimeStruct; + + TimeStruct.tm_sec = (wTime & 0x001f) * 2; + TimeStruct.tm_min = (wTime & 0x07e0) >> 5; + TimeStruct.tm_hour = (wTime & 0xf800) >> 11; + TimeStruct.tm_mday = wDate & 0x001f; + TimeStruct.tm_mon = ((wDate & 0x01e0) >> 5) - 1; + TimeStruct.tm_year = 80 + ((wDate & 0xfe00) >> 9); + + return(mktime(&TimeStruct)); +} +#endif + + +/* MS-DOS specific functions for directory access. */ +#ifdef ODPLAT_DOS + +/* ---------------------------------------------------------------------------- + * ODDirDOSFindFirst() *** PRIVATE FUNCTION *** + * + * MS-DOS specific "Find First" function for reading directory entries. This + * is essentially just a C-language interface to the interrupt function call + * that is provided by DOS. + * + * Parameters: pszPath - Pointer to string containing directory and + * filespec to search for. + * + * pBlock - Pointer to directory block. + * + * nAttributes - Attributes to match, if any. + * + * Return: 0 on success, -1 on failure. + */ +static int ODDirDOSFindFirst(CONST char *pszPath, tDOSDirEntry *pBlock, + WORD wAttributes) +{ + int nToReturn; + + ASSERT(pszPath != NULL); + ASSERT(pBlock != NULL); + + ASM push ds + ASM mov ah, 0x2f /* Int 0x21, ah=0x2f: Get current DOS DTA */ + ASM int 0x21 /* Get current DTA */ + ASM push bx /* Store offset of current DTA on stack */ + ASM push es /* Store segment of current DTA on stack */ + ASM mov ah, 0x1a /* Int 0x21, ah=0x1a: Set new DOS DTA */ +#ifdef LARGEDATA /* If using far pointers */ + ASM lds dx, pBlock /* Load DS:DX with far address of pBlock */ +#else /* If using near pointers */ + ASM mov dx, pBlock /* Load DX with near address of pBlock */ +#endif + ASM int 0x21 /* Set DOS DTA */ + ASM mov ah, 0x4e /* Int 0x21, ah=0x4e: DOS findfirst function */ + ASM mov cx, wAttributes /* Load attributes into CX */ +#ifdef LARGEDATA /* If using far pointers */ + ASM lds dx, pszPath /* Load DS:DX with far address in pszPath */ +#else /* If using near pointers */ + ASM mov dx, pszPath /* Load DX with near address in pszPath */ +#endif + ASM int 0x21 /* Call findfirst function */ + ASM jc error /* If carry flag is set, then an error has ocurred */ + ASM mov word ptr nToReturn, 0 /* If no error, return 0 */ + ASM jmp after_result +error: + ASM mov word ptr nToReturn, -1 /* If error, return -1 */ +after_result: + ASM mov ah, 0x1a /* Int 0x21, ah=0x1a: Set new DOS DTA */ + ASM pop ds /* Pop original DTA segment off of stack */ + ASM pop dx /* Pop original DTA offest from stack */ + ASM int 0x21 /* Reset DOS DTA to original */ + ASM pop ds /* Restore DS stored at function startup */ + return(nToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODDirDOSFindNext() *** PRIVATE FUNCTION *** + * + * MS-DOS specific "Find Next" function for reading directory entries. This + * is essentially just a C-language interface to the interrupt function call + * that is provided by DOS. + * + * Parameters: pBlock - Pointer to block in which to store next directory + * entry. + * + * Return: 0 on success, -1 on failure. + */ +static int ODDirDOSFindNext(tDOSDirEntry *pBlock) +{ + int nToReturn; + + ASSERT(pBlock != NULL); + + ASM push ds /* Save DS */ + ASM mov ah, 0x2f /* Int 0x21, ah=0x2f: Get current DOS DTA */ + ASM int 0x21 /* Get current DTA */ + ASM push bx /* Store offset of current DTA on stack */ + ASM push es /* Store segment of current DTA on stack */ + ASM mov ah, 0x1a /* Int 0x21, ah=0x1a: Set new DOS DTA */ +#ifdef LARGEDATA /* If using far pointers */ + ASM lds dx, pBlock /* Load DS:DX with far address of pBlock */ +#else /* If using near pointers */ + ASM mov dx, pBlock /* Load DX with near address of pBlock */ +#endif + ASM int 0x21 /* Set DOS DTA */ + ASM mov ah, 0x4f /* Int 0x21, ah=0x4f: DOS findnext function */ + ASM int 0x21 /* Call findfirst function */ + ASM jc error /* If carry flag is set, then an error has ocurred */ + ASM mov word ptr nToReturn, 0 /* If no error, return 0 */ + ASM jmp after_result +error: + ASM mov word ptr nToReturn, -1 /* If error, return -1 */ +after_result: + ASM mov ah, 0x1a /* Int 0x21, ah=0x1a: Set new DOS DTA */ + ASM pop ds /* Pop original DTA segment off of stack */ + ASM pop dx /* Pop original DTA offest from stack */ + ASM int 0x21 /* Reset DOS DTA to original */ + ASM pop ds /* Restore DS stored at function startup */ + return(nToReturn); +} + +#endif /* ODPLAT_DOS */ + + +/* Win32 specific private functions for directory access. */ +#ifdef ODPLAT_WIN32 +/* ---------------------------------------------------------------------------- + * ODDirWinMatchesAttributes() *** PRIVATE FUNCTION *** + * + * Determines whether or not the directory entry pDirInfo->WindowsDirEntry + * meets the attribute requirements specified in pDirInfo->nAttributes + * + * Parameters: pDirInfo - Pointer to a directory information structure with + * attribute and directory entry values. + * + * Return: TRUE if the file matches the attributes, FALSE if it does not. + */ +static BOOL ODDirWinMatchesAttributes(tODDirInfo *pDirInfo) +{ + if((pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + && !(pDirInfo->wAttributes & DIR_ATTRIB_DIREC)) + { + return(FALSE); + } + + if((pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) + && !(pDirInfo->wAttributes & DIR_ATTRIB_ARCH)) + { + return(FALSE); + } + + if((pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + && !(pDirInfo->wAttributes & DIR_ATTRIB_HIDDEN)) + { + return(FALSE); + } + + if((pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + && !(pDirInfo->wAttributes & DIR_ATTRIB_RDONLY)) + { + return(FALSE); + } + + if((pDirInfo->WindowsDirEntry.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + && !(pDirInfo->wAttributes & DIR_ATTRIB_SYSTEM)) + { + return(FALSE); + } + + return(TRUE); +} +#endif /* ODPLAT_WIN32 */ + + +/* ---------------------------------------------------------------------------- + * ODDirChangeCurrent() + * + * Changes current directory to the one specified. + * + * Parameters: pszPath - String containing path to change to. + * + * Return: void + */ +void ODDirChangeCurrent(char *pszPath) +{ +#ifdef ODPLAT_DOS + int nDrive = 0; + + if(pszPath[1] == ':') + { + nDrive = (toupper(pszPath[0]) - 'A'); + } + + _setdrvcd(nDrive, (char *)pszPath); +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + SetCurrentDirectory(pszPath); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + chdir(pszPath); +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODDirGetCurrent() + * + * Obtains the name of the current directory, including the current drive + * designator. + * + * Parameters: pszPath - String containing path to change to. + * + * nMaxPathChars - Maximum characters in the buffer pointer to by + * pszPath. + * + * Return: void + */ +void ODDirGetCurrent(char *pszPath, INT nMaxPathChars) +{ + ASSERT(pszPath != NULL); + ASSERT(nMaxPathChars > 0); + +#ifdef ODPLAT_DOS + UNUSED(nMaxPathChars); + + strcpy(pszPath, "X:\\"); + pszPath[0] = 'A' + _getdrv(); + _getcd(0, (char *)pszPath + 3); +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + GetCurrentDirectory(nMaxPathChars, pszPath); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + getcwd(pszPath,nMaxPathChars); +#endif + + ASSERT((INT)strlen(pszPath) + 1 <= nMaxPathChars); +} + + +/* ========================================================================= */ +/* Misc. Functions */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODFileDelete() + * + * Deletes the file with the specified filename. + * + * Parameters: pszPath - Filename, possibly with path, to delete. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODFileDelete(CONST char *pszPath) +{ +#ifdef ODPLAT_DOS + { + tODResult Result; + + ASM push ds +#ifdef LARGEDATA + ASM lds dx, pszPath +#else /* !LARGEDATA */ + ASM mov ax, ss + ASM mov ds, ax + ASM mov dx, pszPath +#endif /* !LARGEDATA */ + ASM mov ah, 0x41 + ASM int 0x21 + ASM jc Failure + ASM mov word ptr Result, kODRCSuccess + ASM jmp Done +Failure: + ASM mov word ptr Result, kODRCGeneralFailure +Done: + ASM pop ds + + return(Result); + } +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + return(DeleteFile(pszPath) ? kODRCSuccess : kODRCGeneralFailure); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + return(unlink(pszPath)); +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODFileAccessMode() + * + * Determines the access permissions of a file. + * + * Parameters: pszFilename - Name of file to test. + * + * nAccessMode - Indicates which file access mode to test for. + * A value of 0 indicates existance, 2 indicates + * write permission, 4 indicates read permission, + * and 6 indicates read/write permission. + * + * Return: FALSE if file can be accessed or TRUE if file cannot be + * accessed. + */ +BOOL ODFileAccessMode(char *pszFilename, int nAccessMode) +{ + FILE *pfFileToTest; + char *pszModeString; + tODDirHandle hDir; + +#ifdef ODPLAT_DOS + BYTE nLength; + /* If we are looking for the root directory. */ + nLength = strlen(pszFilename); + if((nLength == 3 && pszFilename[1] == ':' && pszFilename[2] == DIRSEP) || + (nLength == 1 && pszFilename[0] == DIRSEP)) + { + if(nAccessMode == 0) + { + int to_return = FALSE; + +#ifdef LARGEDATA + ASM push ds + ASM lds dx, pszFilename +#else + ASM mov dx, pszFilename +#endif + ASM mov ax, 0x4300 + ASM int 0x21 + ASM jnc done + ASM mov word ptr to_return, TRUE +done: +#ifdef LARGEDATA + ASM pop ds +#endif + return(to_return); + } + else + { + return(TRUE); + } + } +#endif /* ODPLAT_DOS */ + + /* If the file doesn't exit, we fail in any mode. */ + if(ODDirOpen(pszFilename, + DIR_ATTRIB_ARCH | DIR_ATTRIB_RDONLY | DIR_ATTRIB_DIREC, + &hDir) != kODRCSuccess) + { + return(TRUE); + } + + /* If directory open succeeded, then close it again. */ + ODDirClose(hDir); + + /* If the file does exist, then amode 0 is satisfied. */ + if(nAccessMode == 0) return(FALSE); + + /* If testing for an access permission, determine corresponding fopen() */ + /* mode. */ + switch(nAccessMode) + { + case 2: + pszModeString = "a"; + break; + case 4: + pszModeString = "r"; + break; + default: + pszModeString = "r+"; + } + + /* Attempt to open the file, if unable to do so return failure. */ + if((pfFileToTest=fopen(pszFilename,pszModeString)) == NULL) return(TRUE); + + /* If file open was successful, close it again, and return success. */ + fclose(pfFileToTest); + return(FALSE); +} diff --git a/utils/magiedit/odoors/ODPlat.h b/utils/magiedit/odoors/ODPlat.h new file mode 100644 index 0000000..310dc72 --- /dev/null +++ b/utils/magiedit/odoors/ODPlat.h @@ -0,0 +1,203 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODPlat.h + * + * Description: Contains platform-related definitions and prototypes for + * those function's whose implementation is platform-specific + * (functions implemented in odplat.c). Non-platform specific + * utility functions are defined in odutil.h and implemented in + * odutil.c. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 14, 1994 6.00 BP Created. + * Nov 01, 1994 6.00 BP Added ODDir...() functions. + * Dec 31, 1994 6.00 BP Added timing, file delete functions. + * Dec 31, 1994, 6.00 BP Added ODMultitasker and ODPlatInit() + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 17, 1995 6.00 BP Added multithreading functions. + * Dec 13, 1995 6.00 BP Added ODThreadWaitForExit(). + * Dec 13, 1995 6.00 BP Added ODThreadGetCurrent(). + * Jan 23, 1996 6.00 BP Added ODProcessExit(). + * Jan 30, 1996 6.00 BP Add semaphore timeout. + * Jan 31, 1996 6.00 BP Add ODTimerLeft(), rm ODTimerSleep(). + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODPLAT +#define _INC_ODPLAT + +#include + +#include "ODTypes.h" +#include "ODGen.h" + +#ifdef ODPLAT_NIX +#include +#endif + +#ifdef ODPLAT_WIN32 +#include "windows.h" +#endif /* ODPLAT_WIN32 */ + +/* odplat.c initialization function prototype */ +void ODPlatInit(void); + + +/* ========================================================================= */ +/* Millisecond timer functions. */ +/* ========================================================================= */ + +/* Timer data type. */ +typedef struct +{ +#ifdef ODPLAT_DOS + clock_t Start; + clock_t Duration; +#elif defined(ODPLAT_NIX) + time_t Start; + tODMilliSec Duration; +#else /* !ODPLAT_DOS */ + tODMilliSec Start; + tODMilliSec Duration; +#endif /* !ODPLAT_DOS */ +} tODTimer; + +/* Timer function prototypes. */ +void ODTimerStart(tODTimer *pTimer, tODMilliSec Duration); +BOOL ODTimerElapsed(tODTimer *pTimer); +void ODTimerWaitForElapse(tODTimer *pTimer); +tODMilliSec ODTimerLeft(tODTimer *pTimer); + + +/* ========================================================================= */ +/* Multithreading and synchronization support. */ +/* ========================================================================= */ + +#ifdef OD_MULTITHREADED + +/* Thread handle data type. */ +#ifdef ODPLAT_WIN32 +typedef HANDLE tODThreadHandle; +#endif /* ODPLAT_WIN32 */ + +/* Thread priority enumeration. */ +typedef enum +{ + OD_PRIORITY_LOWEST, + OD_PRIORITY_BELOW_NORMAL, + OD_PRIORITY_NORMAL, + OD_PRIORITY_ABOVE_NORMAL, + OD_PRIORITY_HIGHEST +} tODThreadPriority; + +/* Thread start proceedure type. */ +#define OD_THREAD_FUNC WINAPI +#ifdef ODPLAT_WIN32 +typedef DWORD (OD_THREAD_FUNC ptODThreadProc)(void *); +#endif /* ODPLAT_WIN32 */ + +/* Thread creation, temination and suspension. */ +tODResult ODThreadCreate(tODThreadHandle *phThread, + ptODThreadProc *pfThreadProc, void *pThreadParam); +void ODThreadExit(); +tODResult ODThreadTerminate(tODThreadHandle hThread); +tODResult ODThreadSuspend(tODThreadHandle hThread); +tODResult ODThreadResume(tODThreadHandle hThread); +tODResult ODThreadSetPriority(tODThreadHandle hThread, + tODThreadPriority ThreadPriority); +void ODThreadWaitForExit(tODThreadHandle hThread); +tODThreadHandle ODThreadGetCurrent(void); + + +/* Semaphore handle data type. */ +#ifdef ODPLAT_WIN32 +typedef HANDLE tODSemaphoreHandle; +#endif /* ODPLAT_WIN32 */ + +/* Semaphore manipulation functions. */ +tODResult ODSemaphoreAlloc(tODSemaphoreHandle *phSemaphore, INT nInitialCount, + INT nMaximumCount); +void ODSemaphoreFree(tODSemaphoreHandle hSemaphore); +void ODSemaphoreUp(tODSemaphoreHandle hSemaphore, INT nIncrementBy); +tODResult ODSemaphoreDown(tODSemaphoreHandle hSemaphore, tODMilliSec Timeout); + +#endif /* OD_MULTITHREADED */ + +void ODProcessExit(INT nExitCode); + + +/* ========================================================================= */ +/* DOS multitasker information. */ +/* ========================================================================= */ +#ifdef ODPLAT_DOS +typedef enum +{ + kMultitaskerNone, + kMultitaskerDV, + kMultitaskerWin, + kMultitaskerOS2 +} tODMultitasker; + +extern tODMultitasker ODMultitasker; +#endif /* ODPLAT_DOS */ + + +/* ========================================================================= */ +/* Directory Access. */ +/* ========================================================================= */ + +/* Open directory handle type. */ +typedef tODHandle tODDirHandle; + +/* Directory entry structure. */ +#define DIR_FILENAME_SIZE 1024 + +#define DIR_ATTRIB_NORMAL 0x00 +#define DIR_ATTRIB_RDONLY 0x01 +#define DIR_ATTRIB_HIDDEN 0x02 +#define DIR_ATTRIB_SYSTEM 0x04 +#define DIR_ATTRIB_LABEL 0x08 +#define DIR_ATTRIB_DIREC 0x10 +#define DIR_ATTRIB_ARCH 0x20 + +typedef struct +{ + char szFileName[DIR_FILENAME_SIZE]; + WORD wAttributes; + time_t LastWriteTime; + DWORD dwFileSize; +} tODDirEntry; + +/* Directory function prototypes. */ +tODResult ODDirOpen(CONST char *pszPath, WORD wAttributes, tODDirHandle *phDir); +tODResult ODDirRead(tODDirHandle hDir, tODDirEntry *pDirEntry); +void ODDirClose(tODDirHandle hDir); +void ODDirChangeCurrent(char *pszPath); +void ODDirGetCurrent(char *pszPath, INT nMaxPathChars); + + +/* ========================================================================= */ +/* Miscellaneous Functions. */ +/* ========================================================================= */ +tODResult ODFileDelete(CONST char *pszPath); +BOOL ODFileAccessMode(char *pszFilename, int nAccessMode); + +#endif /* !_INC_ODPLAT */ diff --git a/utils/magiedit/odoors/ODPopup.c b/utils/magiedit/odoors/ODPopup.c new file mode 100644 index 0000000..29d495c --- /dev/null +++ b/utils/magiedit/odoors/ODPopup.c @@ -0,0 +1,716 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODPopUp.c + * + * Description: Implements od_popup_menu(), for displaying a menu in + * a window, allowing the user to make a selection using + * "hot keys" or by using arrow keys. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Jan 15, 1995 6.00 BP Free menu structure on menu destroy. + * Feb 02, 1995 6.00 BP Added od_yield() call in for(;;) loop. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Change valid range of nLevel to 0-10. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 23, 1995 6.00 BP Restore original color on exit. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 04, 1996 6.00 BP Use od_get_input(). + * Jan 12, 1996 6.00 BP Claim exclusive use of arrow keys. + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 31, 1996 6.00 BP Added timeout for od_get_input(). + * Jan 31, 1996 6.00 BP Add ODPopupCheckForKey() wait param. + * Jan 31, 1996 6.00 BP Ignore left & right if !MENU_PULLDOWN. + * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODKrnl.h" +#include "ODStat.h" + + +/* Configurable od_popup_menu() parameters. */ + +/* Maximum menu level. */ +#define MENU_LEVELS 11 + +/* Maximum number of items in a menu. */ +#define MAX_MENU_ITEMS 21 + +/* Maximum width of any menu item. */ +#define MAX_ITEM_WIDTH 76 + + +/* Other manifest constants. */ +#define NO_COMMAND -10 + + +/* Local data types. */ + +/* Information on an individual menu item. */ +typedef struct +{ + char szItemText[MAX_ITEM_WIDTH + 1]; + BYTE btKeyIndex; +} tMenuItem; + +/* Information on a popup menu level. */ +typedef struct +{ + tMenuItem *paMenuItems; + BYTE btNumMenuItems; + BYTE btWidth; + BYTE btRight; + BYTE btBottom; + BYTE btCursor; + BYTE btLeft; + BYTE btTop; + WORD wFlags; + void *pWindow; +} tMenuLevelInfo; + + +/* Private variables. */ + +/* Array of information on each menu level. */ +tMenuLevelInfo MenuLevelInfo[MENU_LEVELS]; + +/* Current menu settings. */ +static BYTE btCorrectItem; +static INT nCommand; +static WORD wCurrentFlags; +static BYTE btCurrentNumMenuItems; +static INT nCurrentLevel; + + +/* Private helper functions used by od_popup_menu(). */ +static void ODPopupCheckForKey(BOOL bWaitForInput); +static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop, + tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth, + BOOL bPositionCursor); + + +/* ---------------------------------------------------------------------------- + * od_popup_menu() + * + * Displays a popup menu on the local and remote screens. + * + * Parameters: pszTitle - Text to show as the window title of the popup menu. + * If no title is desired, this parameter should be set + * to either "" or NULL. + * + * pszText - String which contains the menu definition. In the + * menu definition string, individual menu items are + * separated by a pipe ('|') character, and hotkeys are + * proceeded by a carat ('^') character. + * + * nLeft - The 1-based column number of the upper right corner + * of the menu. + * + * nTop - The 1-based row number of the upper right corner of + * the menu. + * + * nLevel - Menu level, which must be a value between 0 and + * MENU_LEVELS. + * + * uFlags - One or more flags, combined by the bitwise or (|) + * operator. + * + * Return: POPUP_ERROR on error, POPUP_ESCAPE if user pressed the Escape + * key, POPUP_LEFT if the user choose to move to the next menu to + * the left, POPUP_RIGHT if the user choose to move to the next + * menu to the right, or a postive value if the user choose an item + * from the menu. In this case, the return value is the 1-based + * index of the selected menu item. + */ +ODAPIDEF INT ODCALL od_popup_menu(char *pszTitle, char *pszText, INT nLeft, + INT nTop, INT nLevel, WORD uFlags) +{ + tMenuItem *paMenuItems = NULL; + BYTE btCount; + BYTE btWidth; + BYTE btRight; + BYTE btBottom; + BYTE btCursor; + BYTE btLeft; + BYTE btTop; + void *pWindow; + BYTE btBetweenSize; + BYTE btTitleSize; + BYTE btRemaining; + BYTE btLineCount; + INT16 nOriginalAttrib; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_popup_menu()"); + + /* Initialize OpenDoors, if not already done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Setup od_box_chars appropriately. */ + if(od_control.od_box_chars[BOX_BOTTOM] == 0) + { + od_control.od_box_chars[BOX_BOTTOM] = od_control.od_box_chars[BOX_TOP]; + } + if(od_control.od_box_chars[BOX_RIGHT] == 0) + { + od_control.od_box_chars[BOX_RIGHT] = od_control.od_box_chars[BOX_LEFT]; + } + + /* Store initial display color. */ + nOriginalAttrib = od_control.od_cur_attrib; + + + /* check level bounds */ + if(nLevel < 0 || nLevel > MENU_LEVELS) + { + od_control.od_error = ERR_LIMIT; + OD_API_EXIT(); + return(POPUP_ERROR); + } + /* normalize level */ + nCurrentLevel = nLevel; + + if(MenuLevelInfo[nLevel].pWindow == NULL) + { + btLeft = nLeft; + btTop = nTop; + wCurrentFlags = uFlags; + + if(pszText == NULL) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(POPUP_ERROR); + } + + if(paMenuItems == NULL) + { + if((paMenuItems = malloc(sizeof(tMenuItem) * MAX_MENU_ITEMS)) == NULL) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(POPUP_ERROR); + } + } + MenuLevelInfo[nLevel].paMenuItems = paMenuItems; + + btCurrentNumMenuItems = 0; + btWidth = 0; + btCount = 0; + nCommand = NO_COMMAND; + paMenuItems[0].btKeyIndex = 0; + while(*pszText && btCurrentNumMenuItems < MAX_MENU_ITEMS) + { + switch(*pszText) + { + case '|': + paMenuItems[btCurrentNumMenuItems++].szItemText[btCount] + = '\0'; + if(btCount > btWidth) btWidth = btCount; + btCount = 0; + paMenuItems[btCurrentNumMenuItems].btKeyIndex = 0; + break; + + case '^': + if(btCount < MAX_ITEM_WIDTH) + { + paMenuItems[btCurrentNumMenuItems].btKeyIndex = btCount; + } + break; + + default: + if(btCount < MAX_ITEM_WIDTH) + { + paMenuItems[btCurrentNumMenuItems].szItemText[btCount++] = + *pszText; + } + } + ++pszText; + } + + /* If we were in the middle of a menu item when we encountered the end */ + /* of the string, then it should form an additional menu entry. This */ + /* handles the case of a menu string to no terminating | for the last */ + /* entry. */ + if(btCount != 0) + { + /* null-terminate current menu entry string */ + paMenuItems[btCurrentNumMenuItems++].szItemText[btCount] = '\0'; + + /* If this is the widest entry, update he menu width appropriately */ + if(btCount > btWidth) btWidth = btCount; + } + + /* If the menu description string does not contain any menu items */ + if(btCurrentNumMenuItems == 0) + { + /* Return with parameter error */ + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(POPUP_ERROR); + } + + /* Adjust menu width to allow title to fit, if possible */ + /* If a title string was passed, and that string is wider than widest */ + /* menu entry ... */ + if(pszTitle != NULL && strlen(pszTitle) + 2 > btWidth) + { + /* Then width of menu window should be large enough to allow up to */ + /* the first 76 characters of the title to fit. */ + btWidth = strlen(pszTitle) + 2 > MAX_ITEM_WIDTH + ? MAX_ITEM_WIDTH : strlen(pszTitle) + 2; + } + + /* Based on number and size of menu items, and width of title, */ + /* determine the bottom, right and inside width of the menu. */ + btBottom = btTop + btCurrentNumMenuItems + 1; + btRight = btLeft + btWidth + 3; + btBetweenSize = (btRight - btLeft) - 1; + + /* If neither ANSI nor AVATAR mode is available, return with an error */ + if(!(od_control.user_ansi || od_control.user_avatar)) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(POPUP_ERROR); + } + + /* If menu would "fall off" edge of screen, return with an error */ + if(btLeft < 1 || btTop < 1 || btRight > OD_SCREEN_WIDTH + || btBottom > OD_SCREEN_HEIGHT || btRight - btLeft < 2 + || btBottom - btTop < 2) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(POPUP_ERROR); + } + + /* Allocate space to store window information. If unable to allocate */ + /* enough space, return with an error. */ + if((pWindow = malloc((btRight - btLeft + 1) * 2 + + (btBottom - btTop + 1) * 160)) == NULL) + { + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return(POPUP_ERROR); + } + + /* Store contents of screen where memu will be drawn in the temporary */ + /* buffer. */ + if(!od_gettext(btLeft, btTop, btRight, btBottom, pWindow)) + { + free(pWindow); + pWindow = NULL; + + /* Note that od_error code has been set in od_gettext(). */ + OD_API_EXIT(); + return(POPUP_ERROR); + } + + /* Determine number of characters of title to be displayed */ + if(pszTitle == NULL) + { + btTitleSize = 0; + } + else + { + if((btTitleSize = strlen(pszTitle)) > (btBetweenSize - 4)) + { + btTitleSize = btBetweenSize - 4; + } + } + + od_set_cursor(btTop,btLeft); + od_set_attrib(od_control.od_menu_border_col); + od_putch(od_control.od_box_chars[BOX_UPPERLEFT]); + if(btTitleSize == 0) + { + od_repeat(od_control.od_box_chars[BOX_TOP], btBetweenSize); + } + else + { + od_repeat(od_control.od_box_chars[BOX_TOP], + btRemaining = ((btBetweenSize - btTitleSize - 2) / 2)); + od_set_attrib(od_control.od_menu_title_col); + od_putch(' '); + od_disp(pszTitle,btTitleSize, TRUE); + od_putch(' '); + od_set_attrib(od_control.od_menu_border_col); + od_repeat(od_control.od_box_chars[BOX_TOP], + (BYTE)(btBetweenSize - btRemaining - btTitleSize - 2)); + } + od_putch(od_control.od_box_chars[BOX_UPPERRIGHT]); + + btLineCount = btTop + 1; + btCorrectItem = 0; + ODPopupCheckForKey(FALSE); + btCursor = btCorrectItem; + for(btCount = 0; btCount < btCurrentNumMenuItems + && btLineCount < btBottom; ++btCount) + { + ODPopupCheckForKey(FALSE); + if(nCommand != NO_COMMAND && !(wCurrentFlags & MENU_KEEP)) + { + goto exit_now; + } + + od_set_cursor(btLineCount,btLeft); + od_putch(od_control.od_box_chars[BOX_LEFT]); + od_set_attrib(od_control.od_menu_text_col); + + if(btCount == btCursor) + { + ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount, + TRUE, btWidth, FALSE); + } + else + { + ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount, + FALSE, btWidth, FALSE); + } + + od_set_attrib(od_control.od_menu_border_col); + od_putch(od_control.od_box_chars[BOX_RIGHT]); + ++btLineCount; + } + + od_set_cursor(btBottom, btLeft); + od_putch(od_control.od_box_chars[BOX_LOWERLEFT]); + od_repeat(od_control.od_box_chars[BOX_BOTTOM], btBetweenSize); + od_putch(od_control.od_box_chars[BOX_LOWERRIGHT]); + od_set_cursor(btTop + 1, btLeft + 1); + } + else + { + paMenuItems = MenuLevelInfo[nLevel].paMenuItems; + btCurrentNumMenuItems = MenuLevelInfo[nLevel].btNumMenuItems; + btWidth = MenuLevelInfo[nLevel].btWidth; + btRight = MenuLevelInfo[nLevel].btRight; + btBottom = MenuLevelInfo[nLevel].btBottom; + btLeft = MenuLevelInfo[nLevel].btLeft; + btTop = MenuLevelInfo[nLevel].btTop; + wCurrentFlags = MenuLevelInfo[nLevel].wFlags; + pWindow = MenuLevelInfo[nLevel].pWindow; + btCorrectItem = btCursor = MenuLevelInfo[nLevel].btCursor; + nCommand = NO_COMMAND; + + if(uFlags & MENU_DESTROY) + { + nCommand = POPUP_ESCAPE; + goto destroy; + } + + /* Otherwise, position flashing hardware cursor appropriately */ + od_set_cursor(btTop + btCursor + 1, btLeft + 1); + } + + /* Claim exclusive use of arrow keys. */ + ODStatStartArrowUse(); + + for(;;) + { + ODPopupCheckForKey(TRUE); + if(btCorrectItem != btCursor) + { + ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor, + FALSE, btWidth, TRUE); + btCursor = btCorrectItem; + ODWaitDrain(25); + ODPopupCheckForKey(FALSE); + ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor, + TRUE, btWidth, TRUE); + } + + if(nCommand != NO_COMMAND) + { + goto exit_now; + } + } + +exit_now: + if((!(wCurrentFlags & MENU_KEEP)) || nCommand <= 0) + { +destroy: + od_puttext(btLeft, btTop, btRight, btBottom, pWindow); + free(pWindow); + MenuLevelInfo[nLevel].pWindow = NULL; + if(paMenuItems != NULL) + { + free(paMenuItems); + MenuLevelInfo[nLevel].paMenuItems = NULL; + } + } + else if(wCurrentFlags & MENU_KEEP) + { + MenuLevelInfo[nLevel].paMenuItems = paMenuItems; + MenuLevelInfo[nLevel].btNumMenuItems = btCurrentNumMenuItems; + MenuLevelInfo[nLevel].btWidth = btWidth; + MenuLevelInfo[nLevel].btRight = btRight; + MenuLevelInfo[nLevel].btBottom = btBottom; + MenuLevelInfo[nLevel].btCursor = btCursor; + MenuLevelInfo[nLevel].btLeft = btLeft; + MenuLevelInfo[nLevel].btTop = btTop; + MenuLevelInfo[nLevel].wFlags = wCurrentFlags; + MenuLevelInfo[nLevel].pWindow = pWindow; + } + + /* Restore original display color. */ + od_set_attrib(nOriginalAttrib); + + /* Release exclusive use of arrow keys. */ + ODStatEndArrowUse(); + + OD_API_EXIT(); + return(nCommand); +} + + +/* ---------------------------------------------------------------------------- + * ODPopupCheckForKey() *** PRIVATE FUNCTION *** + * + * Checks whether or not the user has pressed any key. If one or more keys + * have been pressed, then these keystrokes are processed. This function + * returns when no more keys are waiting in the inbound buffer, or when a key + * has been pressed that requires immediate action (such as the [ENTER] key). + * + * Parameters: bWaitForInput - Indicates whether this function should return + * immediately if no input is waiting (FALSE), or + * wait for the next input even before returning + * (TRUE). + * + * Return: void + */ +static void ODPopupCheckForKey(BOOL bWaitForInput) +{ + BYTE btCount; + tODInputEvent InputEvent; + BOOL bDoneAnythingYet = FALSE; + + /* Loop, processing keys. If a command has been selected, stop looping */ + /* immediately. If there are no more keys waiting, stop looping */ + while(nCommand == NO_COMMAND) + { + CALL_KERNEL_IF_NEEDED(); + + if(!od_get_input(&InputEvent, bWaitForInput && !bDoneAnythingYet + ? OD_NO_TIMEOUT : 0, GETIN_NORMAL)) + { + /* Return right away if no input event is waiting. */ + return; + } + + bDoneAnythingYet = TRUE; + + if(InputEvent.EventType == EVENT_EXTENDED_KEY) + { + switch(InputEvent.chKeyPress) + { + case OD_KEY_UP: +up_arrow: + if(btCorrectItem == 0) + { + btCorrectItem = btCurrentNumMenuItems - 1; + } + else + { + --btCorrectItem; + } + break; + + case OD_KEY_DOWN: +down_arrow: + if(++btCorrectItem >= btCurrentNumMenuItems) + { + btCorrectItem = 0; + } + break; + + case OD_KEY_LEFT: +left_arrow: + if(wCurrentFlags & MENU_PULLDOWN) + { + nCommand = POPUP_LEFT; + return; + } + break; + + case OD_KEY_RIGHT: +right_arrow: + if(wCurrentFlags & MENU_PULLDOWN) + { + nCommand = POPUP_RIGHT; + return; + } + break; + } + } + + else if(InputEvent.EventType == EVENT_CHARACTER) + { + if(InputEvent.chKeyPress == '\n' || InputEvent.chKeyPress == '\r') + { + nCommand = btCorrectItem + 1; + return; + } + + else if(InputEvent.chKeyPress == 27) + { + if(wCurrentFlags & MENU_ALLOW_CANCEL) + { + nCommand = POPUP_ESCAPE; + return; + } + } + + else + { + /* Check whether key is a menu "hot key" */ + for(btCount = 0; btCount < btCurrentNumMenuItems; ++btCount) + { + if(toupper(MenuLevelInfo[nCurrentLevel].paMenuItems[btCount] + .szItemText[MenuLevelInfo[nCurrentLevel].paMenuItems[btCount] + .btKeyIndex]) == toupper(InputEvent.chKeyPress)) + { + btCorrectItem = btCount; + nCommand = btCorrectItem + 1; + return; + } + } + + /* At this point, we know that key was not one of the "hot keys" */ + /* Check for 4, 6, 8 and 2 keys as arrow keys. */ + if(InputEvent.chKeyPress == '4') + { + goto left_arrow; + } + else if(InputEvent.chKeyPress == '6') + { + goto right_arrow; + } + else if(InputEvent.chKeyPress == '8') + { + goto up_arrow; + } + else if(InputEvent.chKeyPress == '2') + { + goto down_arrow; + } + } + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODPopupDisplayMenuItem() *** PRIVATE FUNCTION *** + * + * Displays an individual menu item. + * + * Parameters: btLeft - Column number where the menu item will be + * displayed. + * + * btTop - Row number where the menu item will be + * displayed. + * + * paMenuItems - Pointer to array of available menu items. + * + * btItemIndex - Index into paMenuItems of the menu item that + * is to be displayed. + * + * bHighlighted - TRUE if the items is to be displayed as + * highlighted, FALSE if it is to be displayed as + * non-highlighted. + * + * btWidth - Width of the menu item, in characters. + * + * bPositionCursor - TRUE if the cursor needs to be positioned + * prior to drawing the menu item, FALSE if the + * cursor is already in the required position. + * + * Return: void + */ +static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop, + tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth, + BOOL bPositionCursor) +{ + BYTE btCount; + char *pchItemText; + BYTE btKeyPosition; + BYTE btTextColor; + BYTE btKeyColor; + + /* Check that parameters are reasonable when operating in debug mode. */ + ASSERT(paMenuItems != NULL); + ASSERT(btItemIndex < MAX_MENU_ITEMS); + ASSERT(btWidth < OD_SCREEN_WIDTH); + + ++btLeft; + ++btTop; + + btTextColor = bHighlighted ? od_control.od_menu_highlight_col + : od_control.od_menu_text_col; + btKeyColor = bHighlighted ? od_control.od_menu_highkey_col + : od_control.od_menu_key_col; + + pchItemText = (char *)(paMenuItems[btItemIndex].szItemText); + btKeyPosition = paMenuItems[btItemIndex].btKeyIndex; + + if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft); + + od_set_attrib(btTextColor); + od_putch(' '); + + for(btCount = 0; btCount < btWidth && *pchItemText; ++btCount) + { + if(btCount == btKeyPosition) + { + od_set_attrib(btKeyColor); + od_putch(*pchItemText++); + od_set_attrib(btTextColor); + } + else + { + od_putch(*pchItemText++); + } + } + + od_repeat(' ', (BYTE)((btWidth - btCount) + 1)); + + if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft); +} diff --git a/utils/magiedit/odoors/ODPrntf.c b/utils/magiedit/odoors/ODPrntf.c new file mode 100644 index 0000000..c2ca57d --- /dev/null +++ b/utils/magiedit/odoors/ODPrntf.c @@ -0,0 +1,197 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODPrntf.c + * + * Description: Implements the od_printf() function. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 03, 1996 6.00 BP Use ODVCALL instead of ODCALL. + * Jan 04, 1996 6.00 BP Add missing OD_API_EXIT() at end. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODKrnl.h" + + +/* Size of od_printf() working buffer. Adjust this upwards if you are */ +/* encountering difficulties when calling od_printf() with long strings. */ +#define WORK_BUFFER_SIZE 512 + + +/* ---------------------------------------------------------------------------- + * od_printf() + * + * The OpenDoors equivalent of the C printf() function, this function performs + * formatted string output to both the local and remote screens. + * + * Parameters: pszFormat - Format string, in the same format as the printf() + * format string. + * + * The semantics of any further parameters are dicated by the + * contents of the format string. + * + * Return: void + */ +ODAPIDEF void ODVCALL od_printf(const char *pszFormat,...) +{ + va_list pArgumentList; + static char *pszWorkBuffer = NULL; + char *pchCurrent; + char *pchStart; + BOOL bNotFound; + INT nCharCount; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_printf()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + /* Allocate work buffer if none has been allocated yet. */ + if(pszWorkBuffer == NULL && + (pszWorkBuffer = malloc(WORK_BUFFER_SIZE)) == NULL) + { + /* If we are unable to allocate a buffer, return with a memory error. */ + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return; + } + + /* Copy the arguments after the format string. */ + va_start(pArgumentList, pszFormat); + + /* Perform a string printf to the working buffer. */ + vsprintf(pszWorkBuffer, pszFormat, pArgumentList); + + va_end(pArgumentList); + + /* If no color characters are defined, then just display the entire */ + /* buffer in one shot. */ + if(!od_control.od_color_char && !od_control.od_color_delimiter) + goto quick_print; + + chColorCheck = od_control.od_color_delimiter; + + bNotFound = TRUE; + pchCurrent = (char *)pszWorkBuffer; + pchStart = (char *)pszWorkBuffer; + nCharCount = 0; + while(*pchCurrent) + { + if(*pchCurrent == od_control.od_color_delimiter) + { + bNotFound = FALSE; + + if(nCharCount != 0) + { + od_disp(pchStart, nCharCount, TRUE); + } + + if(!*(++pchCurrent)) + { + chColorCheck = 0; + OD_API_EXIT(); + return; + } + od_set_attrib(od_color_config(pchCurrent)); + if(!*(pchCurrent = (char *)pchColorEndPos)) + { + chColorCheck = 0; + OD_API_EXIT(); + return; + } + + if(!*(++pchCurrent)) + { + OD_API_EXIT(); + return; + } + pchStart = (char *)pchCurrent; + nCharCount = 0; + } + + else if(*pchCurrent == od_control.od_color_char) + { + bNotFound = FALSE; + + if(nCharCount != 0) + { + od_disp(pchStart, nCharCount, TRUE); + } + + if(!*(++pchCurrent)) + { + OD_API_EXIT(); + return; + } + od_set_attrib(*pchCurrent); + + if(!*(++pchCurrent)) + { + OD_API_EXIT(); + return; + } + pchStart = (char *)pchCurrent; + nCharCount = 0; + } + else + { + ++nCharCount; + ++pchCurrent; + } + } + + chColorCheck = 0; + + if(bNotFound) + { +quick_print: + /* Display the entire string in one shot. */ + od_disp_str(pszWorkBuffer); + } + else if(nCharCount != 0) + { + /* If there are remaining characters in the string, then display them. */ + od_disp(pchStart, nCharCount, TRUE); + } + + OD_API_EXIT(); +} diff --git a/utils/magiedit/odoors/ODRA.c b/utils/magiedit/odoors/ODRA.c new file mode 100644 index 0000000..be2f3fc --- /dev/null +++ b/utils/magiedit/odoors/ODRA.c @@ -0,0 +1,619 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODRA.c + * + * Description: Implements the RemoteAccess personality. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 19, 1994 6.00 BP Use new od_page constants. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Jul 18, 1995 6.00 BP Fix ODStatGetUserAge() bug. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Dec 24, 1995 6.00 BP Fixed black square at pos 25x80. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 03, 1996 6.00 BP Display connect speed with %lu. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODStat.h" +#include "ODInEx.h" + + +/* Private variables, local to this module. */ +static BOOL bRAPersHasBeenOn = FALSE; + + +/* Private function prototypes. */ +static void ODRADisplayPageInfo(void); +static void ODRADisplayDate(char *pszDateString); +static void ODRADisplayFlags(BYTE btFlags); +static void ODRADisplayTime(void); + + +/* ---------------------------------------------------------------------------- + * pdef_ra() + * + * Personality function for the RemoteAccess-like status line / function key + * personality. + * + * Parameters: btOperation - Indicates personality operation to be performed. + * + * Return: void + */ +ODAPIDEF void ODCALL pdef_ra(BYTE btOperation) +{ + BYTE btInfoType = od_control.od_info_type; + + switch(btOperation) + { + case PEROP_DISPLAY1: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" (Node "); + ODScrnSetCursorPos(1, 24); + ODScrnPrintf("%s of %s at %lu BPS", od_control.user_name, + od_control.user_location, od_control.od_connect_speed); + + if(!od_control.od_user_keyboard_on) + { + ODScrnSetCursorPos(49, 24); + ODScrnSetAttribute(0x99); + ODScrnDisplayString("(Keyboard)"); + ODScrnSetAttribute(0x70); + bRAPersHasBeenOn = TRUE; + } + + ODRADisplayPageInfo(); + + ODScrnSetCursorPos(76, 24); + if(od_control.od_node < 1000) + { + ODScrnPrintf("%u)", od_control.od_node); + } + else + { + ODScrnDisplayString("?)"); + } + ODScrnSetCursorPos(1, 25); + ODScrnDisplayString("Security: Time: (F9)=Help "); + + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + + ODScrnSetCursorPos(11, 25); + ODScrnPrintf("%u", od_control.user_security); + ODScrnSetCursorPos(24, 25); + ODScrnPrintf("%d mins ", od_control.user_timelimit); + if(od_control.user_ansi) + { + ODScrnSetCursorPos(42, 25); + ODScrnDisplayString("(ANSI)"); + } + + if(od_control.user_avatar) + { + ODScrnSetCursorPos(48, 25); + ODScrnDisplayString("(AVT)"); + } + + if(od_control.sysop_next) + { + ODScrnSetCursorPos(53, 25); + ODScrnDisplayString("(SN) "); + } + + if(od_control.user_wantchat) + { + ODScrnSetCursorPos(57, 25); + ODScrnSetAttribute(0x99); + ODScrnDisplayString("(Wants Chat)"); + ODScrnSetAttribute(0x70); + } + break; + + + case PEROP_DISPLAY2: + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString("Voice#: Last Call : First Call: "); + ODScrnSetCursorPos(1, 25); + ODScrnDisplayString("Data #: Times Called: Age: Birthdate: "); + if(od_control.od_extended_info || btInfoType == SFDOORSDAT + || btInfoType == DOORSYS_GAP || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(8, 24); + ODScrnPrintf("%13.13s", od_control.user_homephone); + } + if(od_control.od_extended_info || btInfoType == DOORSYS_GAP + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(8, 25); + ODScrnPrintf("%13.13s", od_control.user_dataphone); + } + if(od_control.od_extended_info || btInfoType == DOORSYS_GAP + || btInfoType == CHAINTXT || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(37, 24); + ODRADisplayDate(od_control.user_lastdate); + } + if(od_control.od_extended_info || btInfoType == DOORSYS_GAP + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(37, 25); + ODScrnPrintf("%lu", od_control.user_numcalls); + } + if(btInfoType == RA1EXITINFO || btInfoType == RA2EXITINFO + || btInfoType == DOORSYS_WILDCAT) + { + char szUserAge[7]; + ODScrnSetCursorPos(53, 25); + ODStatGetUserAge(szUserAge); + ODScrnDisplayString(szUserAge); + ODScrnSetCursorPos(71, 24); + ODRADisplayDate(od_control.user_firstcall); + ODScrnSetCursorPos(71, 25); + ODRADisplayDate(od_control.user_birthday); + } + break; + + + case PEROP_DISPLAY3: + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1, 24); + if(od_control.od_extended_info || btInfoType == SFDOORSDAT + || btInfoType == DOORSYS_GAP || btInfoType == DOORSYS_WILDCAT) + { + ODScrnDisplayString("Uploads: Downloads: Tagged: 0k (0) "); + if(btInfoType == DOORSYS_GAP) + { + ODScrnSetCursorPos(10, 24); + ODScrnPrintf("%lu", od_control.user_uploads); + ODScrnSetCursorPos(36, 24); + ODScrnPrintf("%lu", od_control.user_downloads); + } + else + { + ODScrnSetCursorPos(10, 24); + ODScrnPrintf("%luk (%lu)", od_control.user_upk, + od_control.user_uploads); + ODScrnSetCursorPos(36,24); + ODScrnPrintf("%luk (%lu)", od_control.user_downk, + od_control.user_downloads); + } + } + else + { + ODScrnDisplayString(" "); + } + ODScrnSetCursorPos(1, 25); + if(od_control.od_extended_info) + { + ODScrnDisplayString("Flags: (A):-------- (B):-------- (C):-------- (D):-------- "); + ODScrnSetCursorPos(12, 25); + ODRADisplayFlags(od_control.user_flags[0]); + ODScrnSetCursorPos(26, 25); + ODRADisplayFlags(od_control.user_flags[1]); + ODScrnSetCursorPos(40, 25); + ODRADisplayFlags(od_control.user_flags[2]); + ODScrnSetCursorPos(54, 25); + ODRADisplayFlags(od_control.user_flags[3]); + } + else + { + ODScrnDisplayString(" "); + } + break; + + + case PEROP_DISPLAY4: + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" (Time ) "); + if(od_control.od_extended_info) + { + ODScrnSetCursorPos(1, 24); + ODScrnPrintf("Last Caller: %s Total System Calls: %lu", + od_control.system_last_caller, od_control.system_calls); + } + ODRADisplayTime(); + + ODScrnSetCursorPos(1, 25); + if(od_control.od_extended_info || btInfoType == DOORSYS_WILDCAT) + { + ODScrnDisplayString("(Printer OFF) (Local Screen ON ) Next Event "); + ODScrnSetCursorPos(57, 25); + if(od_control.event_status == ES_ENABLED + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnPrintf("(%s, errorlevel %u)",od_control.event_starttime,od_control.event_errorlevel); + } + else + { + ODScrnDisplayString("none, errorlevel 0"); + } + } + else + { + ODScrnDisplayString(" "); + } + break; + + + case PEROP_DISPLAY5: + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1, 24); + if(od_control.od_extended_info || btInfoType == DOORSYS_WILDCAT) + { + ODScrnDisplayString("Msgs posted : Highread : Group 1 "); + ODScrnSetCursorPos(18,24); + ODScrnPrintf("%u",od_control.user_messages); + ODScrnSetCursorPos(39,24); + ODScrnPrintf("%u",od_control.user_lastread); + if(btInfoType == RA1EXITINFO || btInfoType == RA2EXITINFO) + { + ODScrnSetCursorPos(76, 24); + ODScrnPrintf("%u", od_control.user_group); + } + } + else + { + ODScrnDisplayString(" "); + } + + ODScrnSetCursorPos(1, 25); + if(od_control.od_extended_info || btInfoType == CHAINTXT + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnDisplayString("Credit : Handle : "); + if(btInfoType == EXITINFO || btInfoType == RA1EXITINFO + || btInfoType == RA2EXITINFO) + { + ODScrnSetCursorPos(18, 25); + ODScrnPrintf("%u.00", (unsigned int)od_control.user_net_credit); + } + if(btInfoType == CHAINTXT || btInfoType == RA1EXITINFO + || btInfoType == RA2EXITINFO || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(39, 25); + ODScrnDisplayString(od_control.user_handle); + } + } + else + { + ODScrnDisplayString(" "); + } + break; + + + case PEROP_DISPLAY6: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" "); + ODScrnSetCursorPos(1, 25); + ODScrnDisplayString(" "); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + if(btInfoType == RA1EXITINFO || btInfoType == RA2EXITINFO + || btInfoType == DOORSYS_WILDCAT) + { + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(od_control.user_comment); + } + if(od_control.user_wantchat + && strlen(od_control.user_reasonforchat) !=0 ) + { + ODScrnSetCursorPos(1, 25); + strcpy(szStatusText, od_control.user_reasonforchat); + szStatusText[69 - strlen(od_control.user_name)] = '\0'; + ODScrnPrintf("Chat (%s): %s", od_control.user_name, szStatusText); + } + break; + + case PEROP_DISPLAY7: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(" "); + ODScrnSetCursorPos(1, 25); + ODScrnDisplayString(" "); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + break; + + case PEROP_DISPLAY8: + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString("ALT: (C)hat (H)angup (J)Shell (L)ockOut (K)eyboard (N)extOn (D)rop To BBS "); + ODScrnDisplayString(" -Inc Time -Dec Time (F1)-(F7)=Extra Stats"); + break; + + case PEROP_UPDATE1: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(24, 25); + + ODScrnPrintf("%d mins ", od_control.user_timelimit); + + ODScrnSetCursorPos(42, 25); + if(od_control.user_ansi) + { + ODScrnDisplayString("(ANSI)"); + } + else + { + ODScrnDisplayString(" "); + } + + if(od_control.user_avatar) + { + ODScrnDisplayString("(AVT)"); + } + else + { + ODScrnDisplayString(" "); + } + + if(od_control.sysop_next) + { + ODScrnDisplayString("(SN)"); + } + else + { + ODScrnDisplayString(" "); + } + + if(od_control.user_wantchat) + { + ODScrnSetAttribute(0x99); + ODScrnDisplayString("(Wants Chat)"); + ODScrnSetAttribute(0x70); + } + else + { + ODScrnDisplayString(" "); + } + + ODRADisplayPageInfo(); + + if(od_control.od_user_keyboard_on && bRAPersHasBeenOn) + { + ODScrnSetCursorPos(49, 24); + ODScrnDisplayString(" "); + } + if(!od_control.od_user_keyboard_on) + { + bRAPersHasBeenOn = TRUE; + ODScrnSetCursorPos(49, 24); + ODScrnSetAttribute(0x99); + ODScrnDisplayString("(Keyboard)"); + ODScrnSetAttribute(0x70); + } + + break; + + case PEROP_UPDATE4: + ODScrnSetAttribute(0x70); + ODRADisplayTime(); + break; + + case PEROP_INITIALIZE: + bRAStatus = TRUE; + od_control.key_hangup = 0x2300; + od_control.key_drop2bbs = 0x2000; + od_control.key_dosshell = 0x2400; + od_control.key_chat = 0x2e00; + od_control.key_sysopnext = 0x3100; + od_control.key_lockout = 0x2600; + od_control.key_status[0] = 0x3b00; + od_control.key_status[1] = 0x3c00; + od_control.key_status[2] = 0x3d00; + od_control.key_status[3] = 0x3e00; + od_control.key_status[4] = 0x3f00; + od_control.key_status[5] = 0x4000; + od_control.key_status[6] = 0x4100; + od_control.key_status[7] = 0x4300; + od_control.key_status[8] = 0x4400; + od_control.key_keyboardoff = 0x2500; + od_control.key_moretime = 0x4800; + od_control.key_lesstime = 0x5000; + od_control.od_page_statusline = 5; + } +} + + +/* ---------------------------------------------------------------------------- + * ODRADisplayPageInfo() *** PRIVATE FUNCTION *** + * + * Displays the current sysop page information on the RemoteAccess status line, + * at the appropriate position, and in the appropriate color. + * + * Parameters: none + * + * Return: void + */ +static void ODRADisplayPageInfo(void) +{ + time_t nUnixTime; + struct tm *TimeBlock; + BOOL bFailed = FALSE; + INT nMinute; + + ODScrnSetCursorPos(60, 24); + + switch(od_control.od_okaytopage) + { + case PAGE_ENABLE: + ODScrnSetAttribute(0x19); + ODScrnDisplayString("(PAGE ON) "); + ODScrnSetAttribute(0x70); + break; + + case PAGE_DISABLE: + ODScrnSetAttribute(0x19); + ODScrnDisplayString("(PAGE OFF)"); + ODScrnSetAttribute(0x70); + break; + + case PAGE_USE_HOURS: + 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(nMinute < od_control.od_pagestartmin + && nMinute >= od_control.od_pageendmin) + { + bFailed=TRUE; + } + } + + if(bFailed) + { + ODScrnDisplayString("(PAGE OFF)"); + } + else + { + ODScrnDisplayString("(PAGE ON) "); + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODRADisplayTime() *** PRIVATE FUNCTION *** + * + * Displays the current time on the RemoteAccess status line, at the + * appropriate position. The time is displayed in the current color. + * + * Parameters: none + * + * Return: void + */ +static void ODRADisplayTime(void) +{ + time_t nUnixTime; + struct tm *TimeBlock; + + nUnixTime = time(NULL); + TimeBlock = localtime(&nUnixTime); + ODScrnSetCursorPos(74, 24); + ODScrnPrintf("%02.2d:%02.2d", TimeBlock->tm_hour, TimeBlock->tm_min); +} + + +/* ---------------------------------------------------------------------------- + * ODRADisplayDate() *** PRIVATE FUNCTION *** + * + * Displays a date stored in a string on the RemoteAccess status line, if + * the string represents a valid date. The date is displayed at the current + * cursor location, in the current color. + * + * Parameters: pszDateString - Pointer to a string containing the date to + * display. + * + * Return: void + */ +static void ODRADisplayDate(char *pszDateString) +{ + INT nMonth; + INT nTemp; + + ASSERT(pszDateString != NULL); + + if(strlen(pszDateString) != 8) return; + + nMonth = atoi(pszDateString) - 1; + if(nMonth < 0 || nMonth > 11) return; + + nTemp=atoi((char *)pszDateString + 3); + if(nTemp < 1 || nTemp > 31) return; + + if(pszDateString[6] < '0' || pszDateString[6] > '9' + || pszDateString[7] < '0' || pszDateString[7] > '9') + { + return; + } + + ODScrnDisplayChar(pszDateString[3]); + ODScrnDisplayChar(pszDateString[4]); + ODScrnDisplayChar('-'); + ODScrnDisplayString(od_control.od_month[nMonth]); + ODScrnDisplayChar('-'); + ODScrnDisplayChar(pszDateString[6]); + ODScrnDisplayChar(pszDateString[7]); +} + + +/* ---------------------------------------------------------------------------- + * ODRADisplayFlags() *** PRIVATE FUNCTION *** + * + * Displays sysop-defined user flags on the status line. The flags are + * displayed at the current cursor location, in the current color. + * + * Parameters: btFlags - Byte of eight flags to display. + * + * Return: void + */ +static void ODRADisplayFlags(BYTE btFlags) +{ + BYTE btMask = 0x01; + INT nFlag; + + for(nFlag = 0; nFlag < 8; ++nFlag) + { + if(btFlags & btMask) + { + ODScrnDisplayChar('X'); + } + else + { + ODScrnDisplayChar('-'); + } + btMask <<= 1; + } +} diff --git a/utils/magiedit/odoors/ODRes.aps b/utils/magiedit/odoors/ODRes.aps new file mode 100644 index 0000000..58cd452 Binary files /dev/null and b/utils/magiedit/odoors/ODRes.aps differ diff --git a/utils/magiedit/odoors/ODRes.h b/utils/magiedit/odoors/ODRes.h new file mode 100644 index 0000000..c1f7932 --- /dev/null +++ b/utils/magiedit/odoors/ODRes.h @@ -0,0 +1,78 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODRes.h + * + * Description: OpenDoors resource-related definitions. This file is only + * applicable when building the Win32 version of OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Dec 02, 1995 6.00 BP Created. + * Jan 20, 1996 6.00 BP Added login dialog box. + * Jan 21, 1996 6.00 BP Added message dialog box. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 23, 1996 6.00 BP Remove unused IDs. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 14, 1996 6.10 BP Added configuration menu option. + */ + +/* Resource IDs. */ +#define IDR_FRAME_MENU 200 +#define IDD_ABOUT 201 +#define IDI_OPENDOORS 202 +#define IDB_TOOLBAR 203 +#define IDR_FRAME 204 +#define IDD_LOGIN 205 +#define IDI_MESSAGE_INFO 206 +#define IDD_MESSAGE 207 + + +/* Dialog box control IDs. (The same values can safely be used by other */ +/* dialog boxes.) */ +/* Help dialog box. */ +#define IDC_DOORNAME 1000 +#define IDC_COPYRIGHT 1001 +#define IDC_VERSION 1002 + +/* Login dialog box. */ +#define IDC_USER_NAME 1000 + +/* Message dialog box. */ +#define IDC_MESSAGE_ICON 1000 +#define IDC_MESSAGE_TEXT1 1001 + + +/* Command IDs. */ +#define ID_DOOR_CHATMODE 50000 +#define ID_DOOR_USERKEYBOARDOFF 50001 +#define ID_DOOR_SYSOPNEXT 50002 +#define ID_DOOR_HANGUP 50003 +#define ID_VIEW_STATUSBAR 50006 +#define ID_USER_ADDONEMINUTE 50007 +#define ID_USER_ADDFIVEMINUTES 50008 +#define ID_USER_SUBTRACTONEMINUTE 50009 +#define ID_USER_SUBTRACTFIVEMINUTES 50010 +#define ID_USER_INACTIVITYTIMER 50011 +#define ID_HELP_ABOUT 50012 +#define ID_HELP_CONTENTS 50013 +#define ID_VIEW_TOOL_BAR 50014 +#define ID_DOOR_EXIT 50015 +#define ID_DOOR_LOCKOUT 50016 +#define ID_VIEW_STAT_BAR 50017 +#define ID_DOOR_CONFIG 50018 diff --git a/utils/magiedit/odoors/ODRes.rc b/utils/magiedit/odoors/ODRes.rc new file mode 100644 index 0000000..59ed0c1 --- /dev/null +++ b/utils/magiedit/odoors/ODRes.rc @@ -0,0 +1,197 @@ +/* OpenDoors 6.10 + * (C) Copyright 1991 - 1997 by Brian Pirie. All Rights Reserved. + * + * + * File: ODRes.rc + * + * Description: OpenDoors resource script. Contains defintions for OpenDoors + * menus, dialog boxes, icons, bitmaps, accelerator table and + * string resources. This file is only applicable when building + * the Win32 version of OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Dec 02, 1995 6.00 BP Created. + * Jan 01, 1996 6.00 BP Changed copyright to 1996 in About Box + * Jan 20, 1996 6.00 BP Added login dialog box. + * Jan 21, 1996 6.00 BP Added message dialog box. + * Jan 21, 1996 6.00 BP Renamed opendoor.ico to odapp.ico. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 14, 1996 6.10 BP Added configuration menu option. + */ + +#include "windows.h" +#include "ODRes.h" + + +/* ========================================================================= */ +/* The OpenDoors frame window menu. */ +/* ========================================================================= */ + +IDR_FRAME_MENU MENU DISCARDABLE +BEGIN + POPUP "&Door" + BEGIN + MENUITEM "C&onfigure..." ID_DOOR_CONFIG + MENUITEM "&Chat Mode\tAlt+C", ID_DOOR_CHATMODE + MENUITEM SEPARATOR + MENUITEM "User &Keyboard Off\tAlt+K", ID_DOOR_USERKEYBOARDOFF + MENUITEM "Sysop &Next\tAlt+N", ID_DOOR_SYSOPNEXT + MENUITEM SEPARATOR + MENUITEM "&Hangup\tAlt+H", ID_DOOR_HANGUP + MENUITEM "&Lockout\tAlt+L", ID_DOOR_LOCKOUT + MENUITEM SEPARATOR + MENUITEM "E&xit To BBS\tAlt+X", ID_DOOR_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Toolbar", ID_VIEW_TOOL_BAR, CHECKED + MENUITEM "Status Bar", ID_VIEW_STAT_BAR, CHECKED + END + POPUP "&User" + BEGIN + MENUITEM "Add &One Minute\tShift+Up Arrow", ID_USER_ADDONEMINUTE + MENUITEM "Add &Five Minutes\tAlt+Up Arrow", ID_USER_ADDFIVEMINUTES + MENUITEM SEPARATOR + MENUITEM "&Subtract One Minute\tShift+Down Arrow", + ID_USER_SUBTRACTONEMINUTE + MENUITEM "S&ubtract Five Minutes\tAlt+Down Arrow", + ID_USER_SUBTRACTFIVEMINUTES + MENUITEM SEPARATOR + MENUITEM "&Inactivity Timer", ID_USER_INACTIVITYTIMER + , CHECKED + END + POPUP "&Help" + BEGIN + MENUITEM "&Contents\tF1" ID_HELP_CONTENTS + MENUITEM "&About...", ID_HELP_ABOUT + END +END + + +/* ========================================================================= */ +/* Dialog Boxes. */ +/* ========================================================================= */ + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 217, 89 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_OPENDOORS,-1,6,7,18,20 + LTEXT "BBS Door Program",IDC_DOORNAME,32,5,120,8 + LTEXT "",IDC_VERSION,32,14,123,7 + LTEXT "",IDC_COPYRIGHT,32,23,119,8 + LTEXT "Written using:",-1,31,48,69,8 + LTEXT "OpenDoors 6.24, Win32 Edition",-1,31,57,127,8 + LTEXT "Copyright \251 1991-1997 by Brian Pirie.",-1,31, + 66,139,8,SS_NOPREFIX + LTEXT "All Rights Reserved.",-1,31,75,90,8 + DEFPUSHBUTTON "OK",IDOK,161,6,50,14 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 194, 80 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "OpenDoors" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "This program has been started in local",-1,6,6,128,8 + LTEXT "mode, independently of a BBS system.",-1,6,14,128,8 + LTEXT "When operating in this mode, you may",-1,6,22,128,8 + LTEXT "specify what name you should be",-1,6,30,128,8 + LTEXT "known to the program by.",-1,6,38,128,8 + LTEXT "Your &name:",-1,6,52,42,8 + EDITTEXT IDC_USER_NAME,6,61,121,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,138,6,50,14 + PUSHBUTTON "Cancel",IDCANCEL,138,23,50,14 +END + +IDD_MESSAGE DIALOG DISCARDABLE 0, 0, 186, 31 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "OpenDoors" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_MESSAGE_INFO,IDC_MESSAGE_ICON,6,6,18,20 + LTEXT "",IDC_MESSAGE_TEXT1,32,10,149,8 +END + + +/* ========================================================================= */ +/* Icons. */ +/* ========================================================================= */ + +IDI_OPENDOORS ICON DISCARDABLE "odapp.ico" +IDI_MESSAGE_INFO ICON DISCARDABLE "odinfo.ico" + + +/* ========================================================================= */ +/* Bitmaps. */ +/* ========================================================================= */ + +IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp" + + +/* ========================================================================= */ +/* Accelerator Table. */ +/* ========================================================================= */ + +/* Dumb dumb dumb. +IDR_FRAME ACCELERATORS DISCARDABLE +BEGIN + "C", ID_DOOR_CHATMODE, VIRTKEY, CONTROL, NOINVERT + "H", ID_DOOR_HANGUP, VIRTKEY, CONTROL, NOINVERT + "K", ID_DOOR_USERKEYBOARDOFF, VIRTKEY, CONTROL, NOINVERT + "L", ID_DOOR_LOCKOUT, VIRTKEY, CONTROL, NOINVERT + "N", ID_DOOR_SYSOPNEXT, VIRTKEY, CONTROL, NOINVERT + "X", ID_DOOR_EXIT, VIRTKEY, CONTROL, NOINVERT + VK_DOWN, ID_USER_SUBTRACTFIVEMINUTES, VIRTKEY, CONTROL, NOINVERT + VK_DOWN, ID_USER_SUBTRACTONEMINUTE, VIRTKEY, SHIFT, NOINVERT + VK_F1, ID_HELP_CONTENTS, VIRTKEY, NOINVERT + VK_UP, ID_USER_ADDFIVEMINUTES, VIRTKEY, CONTROL, NOINVERT + VK_UP, ID_USER_ADDONEMINUTE, VIRTKEY, SHIFT, NOINVERT +END +*/ +IDR_FRAME ACCELERATORS DISCARDABLE +BEGIN + "C", ID_DOOR_CHATMODE, VIRTKEY, ALT, NOINVERT + "H", ID_DOOR_HANGUP, VIRTKEY, ALT, NOINVERT + "K", ID_DOOR_USERKEYBOARDOFF, VIRTKEY, ALT, NOINVERT + "L", ID_DOOR_LOCKOUT, VIRTKEY, ALT, NOINVERT + "N", ID_DOOR_SYSOPNEXT, VIRTKEY, ALT, NOINVERT + "X", ID_DOOR_EXIT, VIRTKEY, ALT, NOINVERT + VK_DOWN, ID_USER_SUBTRACTFIVEMINUTES, VIRTKEY, ALT, NOINVERT + VK_DOWN, ID_USER_SUBTRACTONEMINUTE, VIRTKEY, SHIFT, NOINVERT + VK_F1, ID_HELP_CONTENTS, VIRTKEY, NOINVERT + VK_UP, ID_USER_ADDFIVEMINUTES, VIRTKEY, ALT, NOINVERT + VK_UP, ID_USER_ADDONEMINUTE, VIRTKEY, SHIFT, NOINVERT +END + + +/* ========================================================================= */ +/* String Resources. */ +/* ========================================================================= */ + +STRINGTABLE DISCARDABLE +BEGIN + ID_DOOR_CHATMODE "Enters or exits chat mode, allowing you to communicate with the remote user." + ID_DOOR_USERKEYBOARDOFF "Causes any keys or commands from the remote user to be ignored." + ID_DOOR_SYSOPNEXT "Reserves the system for the sysop after this user logs off (if supported by BBS)." + ID_DOOR_HANGUP "Hangs up the modem and exits the door." + ID_USER_ADDONEMINUTE "Increases the user's time remaining by one minute." + ID_USER_ADDFIVEMINUTES "Increases the user's time remaining by five minutes." + ID_USER_SUBTRACTONEMINUTE + "Decreases the user's time remaining by one minute." + ID_USER_SUBTRACTFIVEMINUTES + "Decreases the user's time remaining by five minutes." + ID_USER_INACTIVITYTIMER "Enables the timer that will log off the user after a long period of no activity." + ID_HELP_ABOUT "Displays program information and copyright." + ID_VIEW_TOOL_BAR "Shows or hides the toolbar." +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_DOOR_EXIT "Exits the door without hanging up." + ID_DOOR_LOCKOUT "Hangs up the modem, denying any further access to the user (if supported by BBS)." + ID_VIEW_STAT_BAR "Shows or hides the status bar." +END diff --git a/utils/magiedit/odoors/ODScrn.c b/utils/magiedit/odoors/ODScrn.c new file mode 100644 index 0000000..e095741 --- /dev/null +++ b/utils/magiedit/odoors/ODScrn.c @@ -0,0 +1,2554 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODScrn.c + * + * Description: Functions used to access the local display screen buffer, which + * keeps a copy of the text that is displayed on the remote + * terminal. The local display screen buffer also displays the + * OpenDoors status lines on some platforms. In addition to + * maintaining the current screen buffer, the odscrn.c module + * also contains the code to display this buffer on the screen. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Dec 31, 1994 6.00 BP Use new multitasker variable. + * Nov 11, 1995 6.00 BP Removed register keyword. + * Nov 14, 1995 6.00 BP 32-bit portability. + * Nov 14, 1995 6.00 BP Created odscrn.h. + * Nov 14, 1995 6.00 BP Make screen size configurable. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Nov 21, 1995 6.00 BP Port to Win32. + * Jan 20, 1996 6.00 BP Prompt for user name if force_local. + * Jan 21, 1996 6.00 BP Added ODScrnShowMessage() and related. + * Jan 27, 1996 6.00 BP Expand tab ('\t') characters. + * Jan 27, 1996 6.00 BP Added ODScrollUpAndInvalidate(). + * Jan 27, 1996 6.00 BP Made text-mode window f'ns static. + * Jan 31, 1996 6.00 BP Made them non-static again. + * Jan 31, 1996 6.00 BP Added ODScrnLocalInput(). + * Feb 06, 1996 6.00 BP Added od_silent_mode. + * Feb 16, 1996 6.00 BP Make caret visible after local login. + * Feb 17, 1996 6.00 BP Recognize non-ASCII keys under Win32. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 21, 1996 6.00 BP Forward SC_KEYMENU to frame thread. + * Feb 21, 1996 6.00 BP Don't beep in "silent mode". + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 13, 1996 6.10 BP Added od_local_win_col. + * Mar 17, 1996 6.10 BP Terminate string in ODScrnLocalInput() + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODPlat.h" +#include "ODScrn.h" +#include "ODUtil.h" +#include "ODFrame.h" +#include "ODInEx.h" +#ifdef ODPLAT_WIN32 +#include "ODKrnl.h" +#include "ODRes.h" +#endif /* ODPLAT_WIN32 */ + + +/* ========================================================================= */ +/* Definitions of variables used by the local screen module. */ +/* ========================================================================= */ + +/* Manifest constants used in this module. */ +#define SCREEN_BUFFER_SIZE (OD_SCREEN_WIDTH * OD_SCREEN_HEIGHT * 2) +#define SCREEN_BUFFER_SEGMENT_SIZE (SCREEN_BUFFER_SIZE / 16) +#define BYTES_PER_CHAR 2 +#define BUFFER_LINE_BYTES (OD_SCREEN_WIDTH * BYTES_PER_CHAR) +#define LINE_BUFFER_SIZE (OD_SCREEN_WIDTH + 1) + + +/* Private variables used by the screen I/O functions. */ + +#if defined(ODPLAT_DOS) || defined(ODPLAT_NIX) +static void *pAllocatedBufferMemory; +#endif /* ODPLAT_DOS */ + +/* Far pointer to video buffer. */ +static void ODFAR *pScrnBuffer; + +/* Current cursor position. */ +static BYTE btCursorColumn; +static BYTE btCursorRow; + +/* Current output boundaries. */ +static BYTE btLeftBoundary; +static BYTE btTopBoundary; +static BYTE btRightBoundary; +static BYTE btBottomBoundary; + +/* Current display color. */ +static BYTE btCurrentAttribute; + +/* Is scrolling enabled. */ +static BOOL bScrollEnabled; + +#ifdef ODPLAT_DOS +/* Segment address of video buffer. */ +static WORD wBufferSegment; +/* Display page to use. */ +static BYTE btDisplayPage; +#endif + +/* Is cursor currently on. */ +static BYTE bCaretOn; + +/* Static temporary working buffer. */ +static char szBuffer[LINE_BUFFER_SIZE]; + + +/* Private function prototypes. */ +static void ODScrnGetCursorPos(void); +static void ODScrnUpdateCaretPos(void); +static void ODScrnScrollUpOneLine(void); +static void ODScrnScrollUpAndInvalidate(void); + + +/* ========================================================================= */ +/* Implementation of the local screen window for the Win32 platform. */ +/* ========================================================================= */ + +#ifdef ODPLAT_WIN32 + +/* Screen thread startup information. */ +typedef struct +{ + HWND hwndFrame; + HANDLE hInstance; +} tODScrnThreadInfo; + +/* Handle to the screen window. */ +static HWND hwndScreenWindow; + +/* Does the screen window currently have input focus? */ +BOOL bScreenHasFocus; + +/* Current font-related information. */ +static HFONT hCurrentFont; +static INT nFontCellWidth; +static INT nFontCellHeight; + +/* Table to translate from PC text color values used in the screen buffer */ +/* to their corresponding RGB values. */ +COLORREF acrPCTextColors[] = +{ + RGB(0x00, 0x00, 0x00), + RGB(0x00, 0x00, 0xc0), + RGB(0x00, 0xc0, 0x00), + RGB(0x00, 0xc0, 0xc0), + RGB(0xc0, 0x00, 0x00), + RGB(0xc0, 0x00, 0xc0), + RGB(0xc0, 0xc0, 0x00), + RGB(0xc0, 0xc0, 0xc0), + RGB(0x7f, 0x7f, 0x7f), + RGB(0x00, 0x00, 0xff), + RGB(0x00, 0xff, 0x00), + RGB(0x00, 0xff, 0xff), + RGB(0xff, 0x00, 0x00), + RGB(0xff, 0x00, 0xff), + RGB(0xff, 0xff, 0x00), + RGB(0xff, 0xff, 0xff), +}; + +/* Table to translate from Windows key codes to OpenDoors key codes. */ +typedef struct +{ + int nVirtKey; + BYTE btODKey; +} tWinKeyToODKey; + +tWinKeyToODKey aWinKeyToODKey[] = +{ + {VK_UP, OD_KEY_UP}, + {VK_DOWN, OD_KEY_DOWN}, + {VK_LEFT, OD_KEY_LEFT}, + {VK_RIGHT, OD_KEY_RIGHT}, + {VK_INSERT, OD_KEY_INSERT}, + {VK_DELETE, OD_KEY_DELETE}, + {VK_END, OD_KEY_END}, + {VK_HOME, OD_KEY_HOME}, + {VK_PRIOR, OD_KEY_PGUP}, + {VK_NEXT, OD_KEY_PGDN}, + {VK_F1, OD_KEY_F1}, + {VK_F2, OD_KEY_F2}, + {VK_F3, OD_KEY_F3}, + {VK_F4, OD_KEY_F4}, + {VK_F5, OD_KEY_F5}, + {VK_F6, OD_KEY_F6}, + {VK_F7, OD_KEY_F7}, + {VK_F8, OD_KEY_F8}, + {VK_F9, OD_KEY_F9}, + {VK_F10, OD_KEY_F10}, +}; + +/* Utility macros. */ +#define COLUMN_AS_XPIXEL(nColumn) (((INT)(nColumn)) * nFontCellWidth) +#define ROW_AS_YPIXEL(nRow) (((INT)(nRow)) * nFontCellHeight) +#define XPIXEL_AS_COLUMN(nX) (((INT)(nX)) / nFontCellWidth) +#define YPIXEL_AS_ROW(nY) (((INT)(nY)) / nFontCellHeight) + +/* User defined messages. */ +#define WM_MOVE_YOUR_CARET (WM_USER + 1) +#define WM_KEYDOWN_RELAY (WM_USER + 2) + +/* Height of the flashing caret, in pixels. */ +#define CARET_HEIGHT 3 + +/* Local function prototypes. */ +LRESULT CALLBACK ODScrnWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +static HWND ODScrnCreateWin(HWND hwndFrame, HANDLE hInstance); +static void ODScrnMessageLoop(HANDLE hInstance, HWND hwndScreen); +DWORD OD_THREAD_FUNC ODScrnThreadProc(void *pParam); +static void ODScrnPaint(HDC hdc, INT nLeft, INT nTop, INT nRight, INT nBottom); +static void ODScrnInvalidate(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom); +static void ODScrnSetCurrentFont(HWND hwndScreen, HFONT hNewFont); +static void ODScrnSetWinCaretPos(void); + + +/* ---------------------------------------------------------------------------- + * ODScrnCreateWin() *** PRIVATE FUNCTION *** + * + * Creates the local screen window, which covers the client area of the + * OpenDoors frame window. + * + * Parameters: hwndFrame - Handle to the frame window. + * + * hInstance - Handle to application instance. + * + * Return: A handle to the newly created window, or NULL on failure. + */ +static HWND ODScrnCreateWin(HWND hwndFrame, HANDLE hInstance) +{ + HWND hwndScreen = NULL; + WNDCLASS wcScreenWindow; + + ASSERT(hwndFrame != NULL); + ASSERT(hInstance != NULL); + + /* Register the screen window's window class. */ + memset(&wcScreenWindow, 0, sizeof(wcScreenWindow)); + wcScreenWindow.style = CS_HREDRAW | CS_VREDRAW; + wcScreenWindow.lpfnWndProc = ODScrnWindowProc; + wcScreenWindow.cbClsExtra = 0; + wcScreenWindow.cbWndExtra = 0; + wcScreenWindow.hInstance = hInstance; + wcScreenWindow.hIcon = NULL; + wcScreenWindow.hCursor = LoadCursor(NULL, IDC_ARROW); + wcScreenWindow.hbrBackground = NULL; + wcScreenWindow.lpszMenuName = NULL; + wcScreenWindow.lpszClassName = "ODScreen"; + + RegisterClass(&wcScreenWindow); + + /* Create the screen window. */ + if((hwndScreen = CreateWindowEx( + WS_EX_CLIENTEDGE, + wcScreenWindow.lpszClassName, + "", + WS_CHILD | WS_BORDER, + 0, + 0, + 500, + 300, + hwndFrame, + NULL, + hInstance, + (LPVOID)hInstance)) == NULL) + { + /* On window creation failure, return NULL. */ + return(NULL); + } + + /* Store handle to screen window for access from screen. */ + hwndScreenWindow = hwndScreen; + + return(hwndScreen); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnWindowProc() *** PRIVATE FUNCTION *** + * + * The local screen window proceedure. + * + * Parameters: hwnd - Handle to the local screen window. + * + * uMsg - Specifies the message. + * + * wParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * lParam - Specifies additional message information. The content + * of this parameter depends on the value of the uMsg + * parameter. + * + * Return: The return value is the result of the message processing and + * depends on the message. + */ +LRESULT CALLBACK ODScrnWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + HINSTANCE hInstance; + + ASSERT(hwnd != NULL); + + hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_USERDATA); + + switch(uMsg) + { + case WM_SYSCOMMAND: + /* We move any SC_KEYMENU WM_SYSCOMMAND messages to the frame */ + /* window's message queue so that the screen window thread */ + /* can continue to process messages when the menu is */ + /* activated from the keyboard when the screen window has */ + /* the keyboard focus. If this isn't done, the menu will not */ + /* behave correctly when activated this way. */ + if(wParam == SC_KEYMENU) + { + PostMessage(GetParent(hwnd), uMsg, wParam, lParam); + } + else + { + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + break; + + case WM_CREATE: + { + CREATESTRUCT *pCreateStruct = (CREATESTRUCT *)lParam; + hInstance = (HINSTANCE)pCreateStruct->lpCreateParams; + SetWindowLong(hwnd, GWL_USERDATA, (LONG)hInstance); + break; + } + + case WM_PAINT: + { + PAINTSTRUCT PaintStruct; + HDC hdc; + + /* Obtain device context and paint information. */ + hdc = BeginPaint(hwnd, &PaintStruct); + + if(hdc != NULL) + { + /* Redraw the portion of the window that has been invalidated. */ + ODScrnPaint(hdc, + XPIXEL_AS_COLUMN(PaintStruct.rcPaint.left), + YPIXEL_AS_ROW(PaintStruct.rcPaint.top), + XPIXEL_AS_COLUMN(PaintStruct.rcPaint.right), + YPIXEL_AS_ROW(PaintStruct.rcPaint.bottom)); + + /* Release device context. */ + EndPaint(hwnd, &PaintStruct); + } + break; + } + + case WM_MOVE_YOUR_CARET: + ODScrnSetWinCaretPos(); + break; + + case WM_LBUTTONDOWN: + SetFocus(hwnd); + break; + + case WM_SETFOCUS: + /* Turn on the caret when we receive the input focus. */ + /* First, create the caret. */ + CreateCaret(hwnd, NULL, nFontCellWidth, CARET_HEIGHT); + + /* Remember that we now have the input focus. */ + bScreenHasFocus = TRUE; + + /* Update the position of the caret. */ + ODScrnSetWinCaretPos(); + + /* Now, make the caret visible. */ + ShowCaret(hwnd); + break; + + case WM_KILLFOCUS: + /* Remember that we no longer have the input focus. */ + bScreenHasFocus = FALSE; + + /* Turn off the caret when we loose the input focus. */ + DestroyCaret(); + break; + + case WM_KEYDOWN_RELAY: + { + int nVirtKeyPressed = (int)wParam; + WORD wRepeatCount = LOWORD(lParam); + int nKeyTableIndex; + WORD wKey = 0; + + /* Look for a matching key in the OpenDoors key table. */ + for(nKeyTableIndex = 0; nKeyTableIndex < DIM(aWinKeyToODKey); + ++nKeyTableIndex) + { + if(aWinKeyToODKey[nKeyTableIndex].nVirtKey == nVirtKeyPressed) + { + wKey = MAKEWORD(0, aWinKeyToODKey[nKeyTableIndex].btODKey); + break; + } + } + + /* If a matching key was found, then add it to the queue. */ + if(wKey != 0) + { + while(wRepeatCount--) + { + ODKrnlHandleLocalKey(wKey); + } + } + + break; + } + + case WM_CHAR: + { + WORD wRepeatCount = LOWORD(lParam); + BYTE btScanCode = LOBYTE(HIWORD(lParam)); + TCHAR chCharCode = (TCHAR)wParam; + WORD wKey; + + wKey = MAKEWORD(chCharCode, btScanCode); + + /* Loop for each repitition of this key. */ + while(wRepeatCount--) + { + ODKrnlHandleLocalKey(wKey); + } + break; + } + + default: + /* Pass messages that we don't explicitly handle on to the */ + /* default window proc. */ + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnPaint() *** PRIVATE FUNCTION *** + * + * Draws the specified portion of the screen on the provided device context. + * + * Parameters: hdc - Handle to the device context to draw on. + * + * nLeft - Left column to draw. + * + * nTop - Top row to draw. + * + * nRight - Right column to draw. + * + * nBottom - Bottom row to draw. + * + * Return: void. + */ +static void ODScrnPaint(HDC hdc, INT nLeft, INT nTop, INT nRight, INT nBottom) +{ + INT nIDSavedState; + INT nCurrentLine; + INT nStartColumn; + INT nEndColumn; + BYTE *pbtBufferContents; + char achStringToOutput[OD_SCREEN_WIDTH]; + char *pchNextChar; + BYTE btCurrentAttribute; + + ASSERT(hdc != NULL); + ASSERT(nLeft >= 0); + ASSERT(nTop >= 0); + ASSERT(nRight >= nLeft); + ASSERT(nBottom >= nTop); + + /* Ensure that parameters are within valid range. */ + if(nRight >= OD_SCREEN_WIDTH) nRight = OD_SCREEN_WIDTH - 1; + if(nBottom >= OD_SCREEN_HEIGHT) nBottom = OD_SCREEN_HEIGHT - 1; + + /* Save the current state of the device context so that we can restore */ + /* it before returning. */ + nIDSavedState = SaveDC(hdc); + + /* Setup device context for displaying text from the screen buffer. */ + SetBkMode(hdc, OPAQUE); + SelectObject(hdc, hCurrentFont); + + /* Loop through each line that is to be painted. */ + for(nCurrentLine = nTop; nCurrentLine <= nBottom; ++nCurrentLine) + { + /* Obtain a pointer to the first byte representing this line in */ + /* the screen buffer. */ + pbtBufferContents = (BYTE *)(pScrnBuffer) + + ((nCurrentLine * OD_SCREEN_WIDTH) + nLeft) * 2; + + /* Loop for each portion of this line that can be drawn in a single */ + /* TextOut() call. */ + for(nStartColumn = nLeft; nStartColumn <= nRight; + nStartColumn = nEndColumn) + { + /* Begin constructing a string containing the text to output */ + /* in this call to TextOut(). */ + pchNextChar = achStringToOutput; + + /* Determine the color of this portion. */ + btCurrentAttribute = pbtBufferContents[1]; + + /* Loop, finding the first column that has an incompatible color. */ + for(nEndColumn = nStartColumn; nEndColumn <= nRight; ++nEndColumn) + { + /* Stop looping if we come to a non-equivalent color */ + /* attribute. */ + if(btCurrentAttribute != pbtBufferContents[1]) + { + break; + } + + /* Otherwise, add this character to the string to output. */ + *pchNextChar++ = *pbtBufferContents; + + /* Move to the next position in the buffer. */ + pbtBufferContents += 2; + } + + /* Change current display colors to match the current color */ + /* attribute. */ + SetTextColor(hdc, acrPCTextColors[btCurrentAttribute & 0x0f]); + SetBkColor(hdc, acrPCTextColors[(btCurrentAttribute & 0xf0) >> 4]); + + /* Output the string. */ + TextOut(hdc, + COLUMN_AS_XPIXEL(nStartColumn), + ROW_AS_YPIXEL(nCurrentLine), + achStringToOutput, + (nEndColumn - nStartColumn)); + } + } + + /* Restore the device context to its original state before this function */ + /* was called. */ + RestoreDC(hdc, nIDSavedState); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnInvalidate() *** PRIVATE FUNCTION *** + * + * Marks the specified area of the screen window as invalid, forcing the + * screen thread to redraw it. + * + * Parameters: btLeft - The left most column to invalidate. + * + * btTop - The top most row to invalidate. + * + * btRight - The right most column to invalidate. + * + * btBottom - The bottom most row to invalidate. + * + * Return: void. + */ +static void ODScrnInvalidate(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom) +{ + RECT rcToInvalidate; + + /* If the screen window has not been created yet, then return without */ + /* doing anything. */ + if(hwndScreenWindow == NULL) return; + + /* Obtain rectangle in client window coordinates, to be invalidated. */ + rcToInvalidate.left = COLUMN_AS_XPIXEL(btLeft); + rcToInvalidate.top = ROW_AS_YPIXEL(btTop); + rcToInvalidate.right = COLUMN_AS_XPIXEL(btRight + 1); + rcToInvalidate.bottom = ROW_AS_YPIXEL(btBottom + 1); + + /* Mark this rectangle as invalid. */ + InvalidateRect(hwndScreenWindow, &rcToInvalidate, FALSE); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetCurrentFont() *** PRIVATE FUNCTION *** + * + * Changes the current font to be used for drawing, updating anything that + * needs updating. + * + * Parameters: hwndScreen - Handle to the screen window. + * + * nNewFont - Handle to the font to switch to. + * + * Return: void. + */ +static void ODScrnSetCurrentFont(HWND hwndScreen, HFONT hNewFont) +{ + HDC hdc; + INT nIDSavedState; + TEXTMETRIC TextMetrics; + + /* Obtain a handle to the a device context for the screen window. */ + hdc = GetDC(hwndScreen); + + /* If we are unable to obtian a device context, then return without */ + /* doing anything. */ + if(hdc == NULL) + { + return; + } + + /* Change the current font. */ + hCurrentFont = hNewFont; + + /* Obtain text metrics from the device context, and then release the */ + /* device context. */ + nIDSavedState = SaveDC(hdc); + SelectObject(hdc, hCurrentFont); + GetTextMetrics(hdc, &TextMetrics); + RestoreDC(hdc, nIDSavedState); + ReleaseDC(hwndScreen, hdc); + + /* Determine the new size of a character cell. */ + nFontCellWidth = TextMetrics.tmMaxCharWidth; + nFontCellHeight = TextMetrics.tmHeight; + + /* Force window sizes to be adjusted for the new font size. */ + ODScrnAdjustWindows(); + ODScrnAdjustWindows(); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnAdjustWindows() + * + * Resizes and repositions the screen window to the appropriate size based + * on the current font, portions of the frame window's client area that are + * in use, etc. Other windows whose size depends on the size of the screen + * window are also updated. + * + * Parameters: None. + * + * Return: void. + */ +void ODScrnAdjustWindows(void) +{ + INT nNewClientWidth; + INT nNewClientHeight; + RECT rcClient; + RECT rcWindow; + INT nNonClientWidth; + INT nNonClientHeight; + INT nScreenWindowWidth; + INT nScreenWindowHeight; + HWND hwndFrame; + INT nTopFrameUsed; + INT nBottomFrameUsed; + HWND hwndScreen; + + hwndScreen = hwndScreenWindow; + ASSERT(hwndScreen != NULL); + + hwndFrame = GetParent(hwndScreen); + ASSERT(hwndFrame != NULL); + + /* Determine areas of the frame window's client area that are already */ + /* in use. */ + nTopFrameUsed = ODFrameGetUsedClientAtTop(hwndFrame); + nBottomFrameUsed = ODFrameGetUsedClientAtBottom(hwndFrame); + + /* Determine the new required size of the window's client area. */ + nNewClientWidth = nFontCellWidth * OD_SCREEN_WIDTH; + nNewClientHeight = nFontCellHeight * OD_SCREEN_HEIGHT; + + /* Determine the size of the window's non-client area. */ + GetClientRect(hwndScreen, &rcClient); + GetWindowRect(hwndScreen, &rcWindow); + nNonClientWidth = (rcWindow.right - rcWindow.left) + - (rcClient.right - rcClient.left); + nNonClientHeight = (rcWindow.bottom - rcWindow.top) + - (rcClient.bottom - rcClient.top); + + /* Determine the overall size required for the screen window. */ + nScreenWindowWidth = nNewClientWidth + nNonClientWidth; + nScreenWindowHeight = nNewClientHeight + nNonClientHeight; + + /* Resize the screen window accordingly. */ + SetWindowPos(hwndScreen, NULL, 0, nTopFrameUsed, nScreenWindowWidth, + nScreenWindowHeight, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER); + + /* Resize the OpenDoors frame window (which is the screen window's */ + /* parent) so that the screen window just fill's the frame window's */ + /* remaining client area. */ + GetClientRect(hwndFrame, &rcClient); + GetWindowRect(hwndFrame, &rcWindow); + nNonClientWidth = (rcWindow.right - rcWindow.left) + - (rcClient.right - rcClient.left); + nNonClientHeight = (rcWindow.bottom - rcWindow.top) + - (rcClient.bottom - rcClient.top); + + SetWindowPos(hwndFrame, NULL, 0, 0, nScreenWindowWidth + nNonClientWidth, + nScreenWindowHeight + nNonClientHeight + nTopFrameUsed + + nBottomFrameUsed, + SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnMessageLoop() *** PRIVATE FUNCTION *** + * + * Message loop for OpenDoors screen window thread. + * + * Parameters: hInstance - Handle to current instance. + * + * hwndScreen - Handle to the screen window. + * + * Return: void. + */ +static void ODScrnMessageLoop(HANDLE hInstance, HWND hwndScreen) +{ + MSG msg; + HWND hwndFrame; + + ASSERT(hInstance != NULL); + ASSERT(hwndScreen != NULL); + + /* Obtain a handle to the OpenDoors main frame window. */ + hwndFrame = GetParent(hwndScreen); + + /* Loop, fetching, translating and dispatching messages for any windows */ + /* created by this thread. (GetMessage() blocks when no messages are */ + /* available.) */ + while(GetMessage(&msg, NULL, 0, 0)) + { + if(!ODFrameTranslateAccelerator(hwndFrame, &msg)) + { + TranslateMessage(&msg); + if(msg.message == WM_KEYDOWN) + { + PostMessage(hwndScreen, WM_KEYDOWN_RELAY, msg.wParam, msg.lParam); + } + DispatchMessage(&msg); + } + } +} + + +/* ---------------------------------------------------------------------------- + * ODScrnThreadProc() *** PRIVATE FUNCTION *** + * + * Function that execute the OpenDoors screen window thread. This thread's + * primary task is to draw the screen window contents, when needed. + * + * Parameters: pParam - The thread parameter, which is a pointer to a + * tODScrnThreadInfo structure. + * + * Return: TRUE on success, or FALSE on failure. + */ +DWORD OD_THREAD_FUNC ODScrnThreadProc(void *pParam) +{ + tODScrnThreadInfo *pScrnThreadInfo = (tODScrnThreadInfo *)pParam; + HWND hwndScreen; + HANDLE hInstance = pScrnThreadInfo->hInstance; + HWND hwndFrame = pScrnThreadInfo->hwndFrame; + + /* We are now done with the thread startup information structure, */ + /* so deallocate it. */ + free(pScrnThreadInfo); + + /* Create the screen window. */ + hwndScreen = ODScrnCreateWin(hwndFrame, hInstance); + + if(hwndScreen == NULL) + { + return(FALSE); + } + + /* Set the current font for the window. This, in turn will force the */ + /* window to be adjusted to the appropriate size, and will adjust the */ + /* size of the OpenDoors frame window accordingly. */ + ODScrnSetCurrentFont(hwndScreen, GetStockObject(OEM_FIXED_FONT)); + + /* Prompt for the user's name before showing the windows, if required. */ +#ifdef ODPLAT_WIN32 + if(bPromptForUserName) + { + if(DialogBox(hInstance, MAKEINTRESOURCE(IDD_LOGIN), hwndFrame, + ODInitLoginDlgProc) == IDCANCEL) + { + exit(od_control.od_errorlevel[1]); + } + + PostMessage(hwndScreen, WM_SETFOCUS, 0, 0L); + } +#endif /* ODPLAT_WIN32 */ + + /* Now, we can make the frame window visible. */ + if(od_control.od_cmd_show == SW_MINIMIZE || + od_control.od_cmd_show == SW_SHOWMINIMIZED || + od_control.od_cmd_show == SW_SHOWMINNOACTIVE) + { + ShowWindow(hwndFrame, SW_SHOWMINNOACTIVE); + } + else + { + ShowWindow(hwndFrame, SW_RESTORE); + } + + /* Now, show the screen window. */ + ShowWindow(hwndScreen, SW_SHOW); + + /* Loop, processing messages for the screen window. */ + ODScrnMessageLoop(hInstance, hwndScreen); + + /* Destroy the screen window. */ + DestroyWindow(hwndScreen); + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnStartWindow() + * + * Function that starts up the screen window thread, which in turn creates + * and manages the screen window. + * + * Parameters: hInstance - Handle to the current application instance. + * + * phScreenThread - Pointer to location where screen thread handle + * should be stored. + * + * hwndFrame - Handle to already created frame window. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODScrnStartWindow(HANDLE hInstance, tODThreadHandle *phScreenThread, + HWND hwndFrame) +{ + tODScrnThreadInfo *pScrnThreadInfo; + + ASSERT(hInstance != NULL); + ASSERT(phScreenThread != NULL); + ASSERT(hwndFrame != NULL); + + /* Setup thread information to pass into the screen thread at startup. */ + if((pScrnThreadInfo = malloc(sizeof(tODScrnThreadInfo))) == NULL) + { + return(kODRCNoMemory); + } + + pScrnThreadInfo->hInstance = hInstance; + pScrnThreadInfo->hwndFrame = hwndFrame; + + /* Create the screen thread. */ + return(ODThreadCreate(phScreenThread, ODScrnThreadProc, + pScrnThreadInfo)); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetFocusToWindow() + * + * Sets the current input focus to the screen window. + * + * Parameters: none + * + * Return: void + */ +void ODScrnSetFocusToWindow(void) +{ + if(hwndScreenWindow != NULL) + { + SetFocus(hwndScreenWindow); + } +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetWinCaretPos() + * + * Repositions the Windows caret to the position of our cursor, if + * appropriate. + * + * Parameters: none + * + * Return: void + */ +static void ODScrnSetWinCaretPos(void) +{ + /* Only move the caret if we have focus, and thus we are the one who */ + /* owns the caret. */ + if(bScreenHasFocus) + { + SetCaretPos(COLUMN_AS_XPIXEL(btCursorColumn + btLeftBoundary), + ROW_AS_YPIXEL(btCursorRow + btTopBoundary + 1) - CARET_HEIGHT); + } +} + + +#endif /* ODPLAT_WIN32 */ + + + +/* ========================================================================= */ +/* Functions used throughout OpenDoors to manipulate local screen buffer. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODScrnInitialize() + * + * Initializes the local screen module. + * + * Parameters: none + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODScrnInitialize(void) +{ + BOOL bClear = TRUE; + +#if defined(ODPLAT_DOS) || defined(ODPLAT_NIX) + /* In silent mode, we perform all output in a block of memory that is */ + /* never displayed. */ + /* *nix is always in "silent mode" */ +#ifndef ODPLAT_NIX + if(od_control.od_silent_mode) + { +#endif + /* Allocate memory for screen buffer, using standard pointer type */ + /* for current memory model. */ + pAllocatedBufferMemory = malloc(SCREEN_BUFFER_SIZE); + + if(pAllocatedBufferMemory == NULL) + { + return(kODRCNoMemory); + } + + /* Set the screen buffer far pointer to point to the allocated */ + /* buffer. */ + pScrnBuffer = pAllocatedBufferMemory; +#ifndef ODPLAT_NIX + } + else + { + BYTE btDisplayMode; + + /* Get current video mode. */ + ASM push si + ASM push di + ASM mov ah, 0x0f + ASM int 0x10 + ASM mov btDisplayMode, al + ASM pop di + ASM pop si + + switch(btDisplayMode & 0x7f) + { + /* No need to change mode, already colour 80x25. */ + case 0x02: + case 0x03: + wBufferSegment = 0xb800; + pScrnBuffer = (void ODFAR *)0xb8000000L; + bClear = TRUE; + break; + + /* No need to change mode, already monochrome 80x25. */ + case 0x07: + wBufferSegment = 0xb000; + pScrnBuffer = (void ODFAR *)0xb0000000L; + bClear = TRUE; + break; + + /* Must change mode to monochrome 80x25. */ + case 0x21: + wBufferSegment = 0xb000; + pScrnBuffer = (void ODFAR *)0xb0000000L; + bClear = FALSE; + + /* set mode to 0x07 */ + ASM push si + ASM push di + ASM mov ax, 0x0007 + ASM int 0x10 + ASM pop di + ASM pop si + break; + + /* Must change mode to colour 80x25. */ + default: + wBufferSegment = 0xb800; + pScrnBuffer = (void ODFAR *)0xb8000000L; + bClear = FALSE; + + /* set mode to 0x03. */ + ASM push si + ASM push di + ASM mov ax, 0x0003 + ASM int 0x10 + ASM pop di + ASM pop si + } + + + + /* Adjust address for display page which is being used. */ + ASM push si + ASM push di + ASM mov ah, 0x0f + ASM int 0x10 + ASM mov btDisplayPage, bh + ASM pop di + ASM pop si + + if(btDisplayPage!=0) + { + wBufferSegment += (SCREEN_BUFFER_SEGMENT_SIZE * btDisplayPage); + ((char ODFAR *)pScrnBuffer) += (SCREEN_BUFFER_SIZE * btDisplayPage); + } + + if(ODMultitasker == kMultitaskerDV) + { + /* Determine address of DV screen buffer. */ + /* This doesn't check rows, bh = rows, bl = columns. */ + ASM mov ax, 0x2b02 + ASM mov cx, 0x4445 + ASM mov dx, 0x5351 + ASM int 0x21 + ASM cmp bx, 0x1950 + ASM jne no_change + ASM mov wBufferSegment, dx + + (long)pScrnBuffer = ODDWordShiftLeft((long)wBufferSegment, 16); + no_change: ; + } + } +#endif /* ODPLAT_DOS */ +#endif /* ODPLAT_DOS/NIX */ + +#ifdef ODPLAT_WIN32 + /* Allocate memory for screen buffer. */ + pScrnBuffer = malloc(SCREEN_BUFFER_SIZE); + + if(pScrnBuffer == NULL) + { + return(kODRCNoMemory); + } +#endif /* ODPLAT_WIN32 */ + + /* Initialize display system variables. */ + btLeftBoundary = 0; + btRightBoundary = 79; + btTopBoundary = 0; + btBottomBoundary = 24; + btCurrentAttribute = 0x07; + bScrollEnabled = 1; + + /* Clear local screen. */ + if(bClear) + { + ODScrnClear(); + } + + /* Enable flashing cursor. */ + bCaretOn = FALSE; + ODScrnEnableCaret(TRUE); + + /* Return with success. */ + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnShutdown() + * + * De-initializes the screen module. + * + * Parameters: none + * + * Return: void + */ +void ODScrnShutdown(void) +{ +#ifdef ODPLAT_WIN32 + /* Deallocate screen buffer memory. */ + if(pScrnBuffer != NULL) + { + free(pScrnBuffer); + pScrnBuffer = NULL; + } +#else /* !ODPLAT_WIN32 */ + /* In silent mode, we must deallocate screen buffer memory. */ + /* *nix is always in silent mode */ +#ifndef ODPLAT_NIX + if(od_control.od_silent_mode && pAllocatedBufferMemory != NULL) + { +#endif + free(pAllocatedBufferMemory); + pAllocatedBufferMemory = NULL; + pScrnBuffer = NULL; +#ifndef ODPLAT_NIX + } +#endif +#endif +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetBoundary() + * + * Sets the current boundary area on the screen. All output is constrained + * within this boundary area. + * + * Parameters: btLeft - 1-based column number of the left edge of the area. + * + * btTop - 1-based row number of the top edge of the area. + * + * btRight - 1-based column number of the right edge of the area. + * + * btBottom - 1-based row number of the bottom edge of the area. + * + * Return: void + */ +void ODScrnSetBoundary(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom) +{ + /* Set internal window location variables. */ + btLeftBoundary = btLeft - 1; + btRightBoundary = btRight - 1; + btTopBoundary = btTop - 1; + btBottomBoundary = btBottom - 1; + + /* Ensure that the cursor is located within the new window boundaries. */ + if(btCursorColumn > btRightBoundary - btLeftBoundary) + { + btCursorColumn = btRightBoundary - btLeftBoundary; + } + else if(btCursorColumn < btLeftBoundary) + { + btCursorColumn = btLeftBoundary; + } + + if(btCursorRow > btBottomBoundary - btTopBoundary) + { + btCursorRow = btBottomBoundary - btTopBoundary; + } + else if(btCursorRow < btTopBoundary) + { + btCursorRow = btTopBoundary; + } + + /* Execute the position flashing cursor primitive. */ + ODScrnUpdateCaretPos(); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetCursorPos() + * + * Sets the current cursor position. The cursor position is where the caret + * (flashing cursor) appears (if it is currently turned on), and is the + * location where ODScrnDisplayChar(), ODScrnDisplayString() and ODScrnPrintf() + * will perform their output. Each of these functions, update the cursor + * position to the next character cell after the end of their output. Other + * ODScrn...() functions may also change the current cursor position. + * + * Parameters: btColumn - The 1-based column number where the cursor will + * be placed. + * + * Return: void + */ +void ODScrnSetCursorPos(BYTE btColumn, BYTE btRow) +{ + /* Set internal cursor position values. */ + btCursorColumn = btColumn - 1; + btCursorRow = btRow - 1; + + /* Ensure that cursor falls within the current output window. */ + if(btCursorColumn > btRightBoundary - btLeftBoundary) + btCursorColumn = btRightBoundary - btLeftBoundary; + + if(btCursorRow > btBottomBoundary - btTopBoundary) + btCursorRow = btBottomBoundary - btTopBoundary; + + /* Execute the position flashing cursor primitive. */ + ODScrnUpdateCaretPos(); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnSetAttribute() + * + * Sets the current display attribute, to be used by ODScrnDisplayChar(), + * ODScrnDisplayString(), ODScrnPrintf() and ODScrnClear(). The display + * attribute byte is always in the IBM color attribute format, with the + * lower 4 bits indicating the foreground color, and the next 3 bits + * indicating the background color. The upper bit specifies whether the text + * is flashing, although this code may not actually show flashing text on + * all platforms. + * + * Parameters: btAttribute - The new color attribute to use. + * + * Return: void + */ +void ODScrnSetAttribute(BYTE btAttribute) +{ + /* Set internal display colour attribute. */ + btCurrentAttribute = btAttribute; +} + + +/* ---------------------------------------------------------------------------- + * ODScrnEnableScrolling() + * + * Enables or disables scrolling of text within the currently defined boundary + * area when a carriage return is sent with the cursor located on the bottom + * line of bounary area. + * + * Parameters: bEnable - TRUE to enable scrolling, FALSE to disable scrolling. + * + * Return: void + */ +void ODScrnEnableScrolling(BOOL bEnable) +{ + /* Stores the current scrolling setting. */ + bScrollEnabled = bEnable; +} + + +/* ---------------------------------------------------------------------------- + * ODScrnEnableCaret() + * + * Turns the caret (flashing indicator of the current cursor location) on or + * off. Under the Win32 platform, the caret is always active when the + * window has input focus, and inactive at any other time. Hene, under + * Win32, this function has no effect. + * + * Parameters: bEnable - TRUE to turn on the flashing caret, FALSE to turn it + * off. + * + * Return: void + */ +void ODScrnEnableCaret(BOOL bEnable) +{ +#ifdef ODPLAT_DOS + if(bCaretOn == bEnable) return; + + bCaretOn = bEnable; + + /* Execute the cursor on / off primitive. */ + ASM push si + ASM push di + ASM mov ah, 0x03 + ASM mov bh, btDisplayPage + ASM int 0x10 + + /* ch = start line, cl = end line. */ + ASM push cx + ASM mov ah, 0x0f + ASM int 0x10 + ASM pop cx + + /* al = video mode. */ + ASM push ax + ASM and ch, 0x1f + ASM mov al, bCaretOn + ASM and al, al + ASM jnz set_cursor + /* ch bits 5-6 = blink attr */ + /* 00 = normal */ + /* 01 = invisible */ + ASM or ch, 0x20 +set_cursor: + ASM pop ax + ASM mov bh, btDisplayPage + ASM mov ah, 0x01 + ASM int 0x10 + ASM pop di + ASM pop si + + + if(bCaretOn) + { + /* Turn on the local caret, updating its position. */ + ODScrnUpdateCaretPos(); + } + else + { + /* Turn off the local caret. */ + ASM mov ah, 0x02 + ASM mov bh, btDisplayPage + ASM mov dh, OD_SCREEN_HEIGHT + ASM mov dl, OD_SCREEN_WIDTH + ASM push si + ASM push di + ASM int 0x10 + ASM pop di + ASM pop si + } +#endif /* ODPLAT_DOS */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnGetTextInfo() + * + * Fills a structure with information about the current display settings, + * including the position of the current boundary area (output window), + * color attribute and cursor location. + * + * Parameters: pTextInfo - Pointer to the structure to store the current text + * settings information in. + * + * Return: void + */ +void ODScrnGetTextInfo(tODScrnTextInfo *pTextInfo) +{ + pTextInfo->wintop = btTopBoundary + 1; + pTextInfo->winleft = btLeftBoundary + 1; + pTextInfo->winright = btRightBoundary + 1; + pTextInfo->winbottom = btBottomBoundary + 1; + pTextInfo->attribute = btCurrentAttribute; + pTextInfo->curx = btCursorColumn + 1; + pTextInfo->cury = btCursorRow + 1; +} + + +/* ---------------------------------------------------------------------------- + * ODScrnPrintf() + * + * Performs formatted output within the current boundary area. + * + * Parameters: pszFormat - Format string, which is in the same format as is + * used by the standard C printf() function. + * + * The semantics of additional parameters is specified by the + * contents of the pszFormat string. + * + * Return: The standard printf() return value. + */ +INT ODScrnPrintf(char *pszFormat, ...) +{ + va_list pArgumentList; + INT nToReturn; + + /* Generate string to display. */ + va_start(pArgumentList, pszFormat); + nToReturn = vsprintf(szBuffer, pszFormat, pArgumentList); + va_end(pArgumentList); + + /* Ensure that we didn't overrun the buffer. */ + ASSERT(strlen(szBuffer) <= sizeof(szBuffer) - 1); + + /* Display generated string. */ + ODScrnDisplayString(szBuffer); + + /* Return appropriate value. */ + return (nToReturn); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnDisplayChar() + * + * Writes a single character within the current boundary area, advancing the + * cursor. + * + * Parameters: chToOutput - The character to display. + * + * Return: void + */ +void ODScrnDisplayChar(unsigned char chToOutput) +{ + BYTE ODFAR *pbtDest; + + ODScrnGetCursorPos(); + + if(btCursorColumn > btRightBoundary - btLeftBoundary) + { + btCursorColumn = btRightBoundary - btLeftBoundary; + } + + if(btCursorRow > btBottomBoundary - btTopBoundary) + { + btCursorRow = btBottomBoundary - btTopBoundary; + } + + switch(chToOutput) + { + /* If character is a carriage return. */ + case '\r': + btCursorColumn = 0; + break; + + /* If character is a line feed. */ + case '\n': + /* If cursor is at bottom of output window. */ + if(btCursorRow == btBottomBoundary - btTopBoundary) + { + /* Scroll the screen up by one line. */ + ODScrnScrollUpAndInvalidate(); + } + /* If cursor is not at bottom of output window. */ + else + { + /* Move the cursor down one line. */ + ++btCursorRow; + } + break; + + case '\b': + /* If backspace. */ + if(btCursorColumn != 0) --btCursorColumn; + break; + + case '\t': + /* If tab character. */ + btCursorColumn = ((btCursorColumn / 8) + 1) * 8; + if(btCursorColumn > btRightBoundary - btLeftBoundary) + { + btCursorColumn = 0; + + /* If moving cursor down one line advances past end of window. */ + if(++btCursorRow > btBottomBoundary - btTopBoundary) + { + /* Move cursor back to bottom line of window. */ + btCursorRow = btBottomBoundary - btTopBoundary; + + /* Scroll the screen up by one line. */ + ODScrnScrollUpAndInvalidate(); + } + } + break; + + case '\a': + /* If bell. */ + if(!od_control.od_silent_mode) + { +#ifdef ODPLAT_DOS + ASM mov ah, 0x02 + ASM mov dl, 7 + ASM int 0x21 +#endif /* ODPLAT_DOS */ +#ifdef ODPLAT_WIN32 + MessageBeep(0xffffffff); +#endif /* ODPLAT_WIN32 */ + } + break; + + /* If character is not a control character. */ + default: + /* Output character to display buffer. */ + pbtDest = (BYTE ODFAR *)pScrnBuffer + + ((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES + + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR); + *pbtDest++ = chToOutput; + *pbtDest = btCurrentAttribute; + + ASSERT(pbtDest >= (BYTE ODFAR *)pScrnBuffer); + ASSERT(pbtDest < (BYTE ODFAR *)pScrnBuffer + SCREEN_BUFFER_SIZE); + +#ifdef ODPLAT_WIN32 + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate((BYTE)(btCursorColumn + btLeftBoundary), + (BYTE)(btCursorRow + btTopBoundary), + (BYTE)(btCursorColumn + btLeftBoundary), + (BYTE)(btCursorRow + btTopBoundary)); +#endif /* ODPLAT_WIN32 */ + + /* Advance cursor. If at end of line ... */ + if(++btCursorColumn > btRightBoundary - btLeftBoundary) + { + /* Wrap cursor if necessary. */ + btCursorColumn = 0; + + /* If moving cursor down one line advances past end of window. */ + if(++btCursorRow > btBottomBoundary - btTopBoundary) + { + /* Move cursor back to bottom line of window. */ + btCursorRow = btBottomBoundary - btTopBoundary; + + /* Scroll the screen up by one line. */ + ODScrnScrollUpAndInvalidate(); + } + } + } + + /* Execute the update flashing cursor primitive. */ + ODScrnUpdateCaretPos(); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnGetCursorPos() *** PRIVATE FUNCTION *** + * + * Updates the current cursor position (output position) from the location of + * the caret (flashing cursor). This function doesn't do anything on the + * Win32 platform, since we nobody else can reposition the cursor. + * + * Parameters: none + * + * Return: void + */ +static void ODScrnGetCursorPos(void) +{ +#ifdef ODPLAT_DOS + if(!bCaretOn) return; + + ASM mov ah, 0x03 + ASM mov bh, btDisplayPage + ASM push si + ASM push di + ASM int 0x10 + ASM pop di + ASM pop si + ASM sub dh, btTopBoundary + ASM mov btCursorRow, dh + ASM sub dl, btLeftBoundary + ASM mov btCursorColumn, dl +#endif /* ODPLAT_DOS */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnUpdateCaretPos() *** PRIVATE FUNCTION *** + * + * Updates the position of the caret (flashing cursor) from the current cursor + * location (output position). + * + * Parameters: none + * + * Return: void + */ +static void ODScrnUpdateCaretPos(void) +{ +#ifdef ODPLAT_DOS + if(!bCaretOn) return; + + /* Update position of flashing cursor on screen */ + ASM mov ah, 0x02 + ASM mov bh, btDisplayPage + ASM mov dh, btCursorRow + ASM add dh, btTopBoundary + ASM mov dl, btCursorColumn + ASM add dl, btLeftBoundary + ASM push si + ASM push di + ASM int 0x10 + ASM pop di + ASM pop si +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + if(hwndScreenWindow != NULL) + { + PostMessage(hwndScreenWindow, WM_MOVE_YOUR_CARET, 0, 0); + } +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnClear() + * + * Clears the text within the currently defined boundary area, setting the + * display attribute of the entire boundary area to the current display + * color. + * + * Parameters: none + * + * Return: void + */ +void ODScrnClear(void) +{ + WORD ODFAR *pDest = (WORD ODFAR *)pScrnBuffer + + ((btTopBoundary * OD_SCREEN_WIDTH) + btLeftBoundary); + WORD wBlank = (((WORD)btCurrentAttribute) << 8) | 32; + BYTE btCurColumn; + BYTE btCurLine = (btBottomBoundary - btTopBoundary) + 1; + BYTE btColumnStart = (btRightBoundary - btLeftBoundary) + 1; + BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart; + + /* Clear contents of current window. */ + do + { + btCurColumn = btColumnStart; + do + { + ASSERT(pDest >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pDest <= (WORD ODFAR *)pScrnBuffer + 2000); + *(pDest++) = wBlank; + } while ((--btCurColumn) != 0); + pDest += btSkip; + } while((--btCurLine) != 0); + + /* Move cursor to top left-hand corner of current window. */ + btCursorColumn = btCursorRow = 0; + + /* Execute the update flashing cursor primitive. */ + ODScrnUpdateCaretPos(); + +#ifdef ODPLAT_WIN32 + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate(btLeftBoundary, btTopBoundary, btRightBoundary, + btBottomBoundary); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnScrollUpAndInvalidate() *** PRIVATE FUNCTION *** + * + * Scrolls the entire screen up by one line, only if scrolling is enabled. + * If scrolling is performed, invalidates area that was scrolled. Scrolling + * is accomplished using ODScrnScrollUpOneLine(). + * + * Parameters: none + * + * Return: void + */ +static void ODScrnScrollUpAndInvalidate(void) +{ + /* If scrolling is enabled. */ + if(bScrollEnabled) + { + /* Execute the scroll primitive. */ + ODScrnScrollUpOneLine(); + +#ifdef ODPLAT_WIN32 + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate(btLeftBoundary, btTopBoundary, btRightBoundary, + btBottomBoundary); +#endif /* ODPLAT_WIN32 */ + } +} + + +/* ---------------------------------------------------------------------------- + * ODScrnScrollUpOneLine() *** PRIVATE FUNCTION *** + * + * Scrolls the area within the current output boundary up one line, leaving the + * newly created line at the bottom of the area blank, with the current display + * attribute. + * + * Parameters: none + * + * Return: void + */ +static void ODScrnScrollUpOneLine(void) +{ + WORD ODFAR *pwDest = (WORD ODFAR *)pScrnBuffer + + (btTopBoundary * OD_SCREEN_WIDTH + btLeftBoundary); + WORD ODFAR *pwSource; + BYTE btCurColumn; + BYTE btCurLine = btBottomBoundary - btTopBoundary; + BYTE btColumnStart = btRightBoundary - btLeftBoundary + 1; + BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart; + WORD wBlank = (((WORD)btCurrentAttribute) << 8) | 32; + + pwSource = pwDest + OD_SCREEN_WIDTH; + + ASSERT(btSkip >= 0 && btSkip <= OD_SCREEN_WIDTH); + + /* Move text in area of window up one line. */ + do + { + btCurColumn = btColumnStart; + do + { + ASSERT(pwDest >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pwDest <= (WORD ODFAR *)pScrnBuffer + 2000); + ASSERT(pwSource >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pwSource <= (WORD ODFAR *)pScrnBuffer+2000); + *(pwDest++) = *(pwSource++); + } while((--btCurColumn) != 0); + pwDest += btSkip; + pwSource += btSkip; + } while ((--btCurLine) != 0); + + /* Clear newly created line at bottom of window. */ + btCurColumn = btColumnStart; + do + { + ASSERT(pwDest >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pwDest <= (WORD ODFAR *)pScrnBuffer + 2000); + *(pwDest++) = wBlank; + } while((--btCurColumn) != 0); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnGetText() + * + * Copies a portion of the currently displayed text and corresponding color + * attributes to a buffer provided by the caller. + * + * Parameters: btLeft - Column number of the left edge of the area to copy + * from. + * + * btTop - Row number of the top edge of the area to copy from. + * + * btRight - Column number of the right edge of the area to copy + * from. + * + * btBottom - Row number of the bottom edge of the area to copy + * from. + * + * pbtBuffer - A pointer to the buffer to copy to. It is the + * caller's responsibility to ensure that this buffer + * is large enough. This buffer must be at least + * 2 x (Width of area) x (Height of area) bytes in size. + * + * Return: TRUE on success, or FALSE on failure. + */ +BOOL ODScrnGetText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + void *pbtBuffer) +{ + WORD *pwBuffer = (WORD *)pbtBuffer; + WORD ODFAR *pSource = (WORD ODFAR *)pScrnBuffer + + ((((--btTop) + btTopBoundary) + * OD_SCREEN_WIDTH) + btLeftBoundary + (--btLeft)); + BYTE btCurColumn; + BYTE btCurLine = (--btBottom) - btTop + 1; + BYTE btColumnStart = (--btRight) - btLeft + 1; + BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart; + + ASSERT(btLeft >= 0); + ASSERT(btTop >= 0); + ASSERT(btRight <= btRightBoundary - btLeftBoundary); + ASSERT(btBottom <= btBottomBoundary - btTopBoundary); + ASSERT(pbtBuffer); + + /* Copy contents of screen block to buffer */ + do + { + btCurColumn = btColumnStart; + do + { + ASSERT(pSource >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pSource <= (WORD ODFAR *)pScrnBuffer + 2000); + ASSERT(pwBuffer >= (WORD *)pbtBuffer); + ASSERT(pwBuffer <= (WORD *)pbtBuffer + 2000); + *(pwBuffer++) = *(pSource++); + } while ((--btCurColumn) != 0); + pSource += btSkip; + } while((--btCurLine) != 0); + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnPutText() + * + * Changes the currently displayed text and corresponding color attributes in + * the specified area, to the values taken from the buffer. This buffer is in + * the same format as is produce by the ODScrnGetText() function. + * + * Parameters: btLeft - Column number of the left edge of the area to copy + * to. + * + * btTop - Row number of the top edge of the area to copy to. + * + * btRight - Column number of the right edge of the area to copy + * to. + * + * btBottom - Row number of the bottom edge of the area to copy + * to. + * + * pbtBuffer - A pointer to the buffer to copy from. + * + * Return: TRUE on success, or FALSE on failure. + */ +BOOL ODScrnPutText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + void *pbtBuffer) +{ + WORD *pwBuffer = (WORD *)pbtBuffer; + WORD ODFAR *pDest = (WORD ODFAR *)pScrnBuffer + + ((((--btTop) + btTopBoundary) + * OD_SCREEN_WIDTH) + btLeftBoundary + (--btLeft)); + BYTE btCurColumn; + BYTE btCurLine = (--btBottom) - btTop + 1; + BYTE btColumnStart = (--btRight) - btLeft + 1; + BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart; + + ASSERT(btLeft >= 0 && btTop >= 0); + ASSERT(btLeft <= btRightBoundary - btLeftBoundary); + ASSERT(btTop <= btBottomBoundary - btTopBoundary); + ASSERT(btRight >= 0 && btBottom >= 0); + ASSERT(btRight <= btRightBoundary - btLeftBoundary); + ASSERT(btBottom <= btBottomBoundary - btTopBoundary); + ASSERT(pbtBuffer != NULL); + + /* Copy contents of screen block to buffer. */ + do + { + btCurColumn = btColumnStart; + do + { + ASSERT(pDest >= (WORD ODFAR *)pScrnBuffer); + ASSERT(pDest <= (WORD ODFAR *)pScrnBuffer + 2000); + ASSERT(pwBuffer >= (WORD *)pbtBuffer); + ASSERT(pwBuffer <= (WORD *)pbtBuffer + 2000); + *(pDest++) = *(pwBuffer++); + } while ((--btCurColumn) != 0); + pDest += btSkip; + } while((--btCurLine) != 0); + +#ifdef ODPLAT_WIN32 + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate((BYTE)(btLeftBoundary + btLeft), + (BYTE)(btTopBoundary + btTop), + (BYTE)(btRightBoundary + btRight), + (BYTE)(btBottomBoundary + btBottom)); +#endif /* ODPLAT_WIN32 */ + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnDisplayString() + * + * Copies the contents of a string to the display, using the currently set + * color attributes. The cursor location is updated to the end of the string + * on the screen. + * + * Parameters: pszString - Pointer to the string to display. + * + * Return: void. + */ +void ODScrnDisplayString(const char *pszString) +{ + ODScrnDisplayBuffer(pszString, strlen(pszString)); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnDisplayBuffer() + * + * Copies the contents of a buffer to the display, using the currently set + * color attributes. The cursor location is updated to the end of the text + * displayed to the screen. + * + * Parameters: pBuffer - Pointer to a buffer containing the + * character(s) to display. + * + * nCharsToDisplay - Count of number of characters to display from + * the buffer. + * + * Return: void. + */ +void ODScrnDisplayBuffer(const char *pBuffer, INT nCharsToDisplay) +{ + const char *pchCurrentChar = pBuffer; + INT nCharsLeft = nCharsToDisplay; + BYTE ODFAR *pDest; + BYTE btLeftColumn; + BYTE btAttribute = btCurrentAttribute; + BYTE btCurrentColumn; + BYTE btBottom = btBottomBoundary - btTopBoundary; +#ifdef ODPLAT_WIN32 + BOOL bAnythingInvalid = FALSE; + BYTE btLeftMost; + BYTE btRightMost; + BYTE btTopMost; + BYTE btBottomMost; +#endif /* ODPLAT_WIN32 */ + + ASSERT(pBuffer != NULL); + ASSERT(nCharsToDisplay >= 0); + + ODScrnGetCursorPos(); + + if(btCursorColumn > btRightBoundary - btLeftBoundary) + { + btCursorColumn = btRightBoundary - btLeftBoundary; + } + + if(btCursorRow > btBottomBoundary - btTopBoundary) + { + btCursorRow = btBottomBoundary - btTopBoundary; + } + + btCurrentColumn = btCursorColumn; + + btLeftColumn = btRightBoundary - (btCurrentColumn + btLeftBoundary); + pDest = (BYTE ODFAR *) pScrnBuffer + (((btTopBoundary + btCursorRow) + * BUFFER_LINE_BYTES) + + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR); + + while(nCharsLeft--) + { + ASSERT(pDest >= (BYTE ODFAR *)pScrnBuffer); + ASSERT(pDest <= (BYTE ODFAR *)pScrnBuffer + SCREEN_BUFFER_SIZE); + switch(*pchCurrentChar) + { + case '\r': + btCurrentColumn = 0; + btLeftColumn = btRightBoundary - btLeftBoundary; + pDest = (BYTE ODFAR *)pScrnBuffer + ((btTopBoundary + btCursorRow) + * BUFFER_LINE_BYTES + btLeftBoundary * BYTES_PER_CHAR); + pchCurrentChar++; + break; + case '\n': + if (btCursorRow < btBottom) + { + ++btCursorRow; + pDest += BUFFER_LINE_BYTES; + } + else if(bScrollEnabled) + { + ODScrnScrollUpOneLine(); +#ifdef ODPLAT_WIN32 + /* Entire boundary area is now invalid. */ + bAnythingInvalid = TRUE; + btLeftMost = btLeftBoundary; + btRightMost = btRightBoundary; + btTopMost = btTopBoundary; + btBottomMost = btBottomBoundary; +#endif /* ODPLAT_WIN32 */ + } + pchCurrentChar++; + break; + + case '\a': + /* If bell */ + if(!od_control.od_silent_mode) + { +#ifdef ODPLAT_DOS + ASM mov ah, 0x02 + ASM mov dl, 7 + ASM int 0x21 +#endif /* ODPLAT_DOS */ +#ifdef ODPLAT_WIN32 + MessageBeep(0xffffffff); +#endif /* ODPLAT_WIN32 */ + pchCurrentChar++; + } + break; + + case '\t': + /* If tab character. */ + btCurrentColumn = ((btCurrentColumn / 8) + 1) * 8; + if(btCurrentColumn > btRightBoundary - btLeftBoundary) + { + btCurrentColumn = 0; + + /* If moving cursor down one line advances past end of window. */ + if(++btCursorRow > btBottomBoundary - btTopBoundary) + { + /* Move cursor back to bottom line of window. */ + btCursorRow = btBottomBoundary - btTopBoundary; + + /* If scrolling is enabled. */ + if(bScrollEnabled) + { + /* Execute the scroll primitive .*/ + ODScrnScrollUpOneLine(); +#ifdef ODPLAT_WIN32 + /* Entire boundary area is now invalid. */ + bAnythingInvalid = TRUE; + btLeftMost = btLeftBoundary; + btRightMost = btRightBoundary; + btTopMost = btTopBoundary; + btBottomMost = btBottomBoundary; +#endif /* ODPLAT_WIN32 */ + } + } + } + + /* Determine new buffer destination address. */ + pDest = (BYTE ODFAR *) pScrnBuffer + + (((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES) + + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR); + break; + + case '\b': + if(btCurrentColumn > 0) + { + --btCurrentColumn; + pDest-=2; + btLeftColumn++; + } + pchCurrentChar++; + break; + + default: + *(pDest++) = *(pchCurrentChar++); + *(pDest++) = btAttribute; + +#ifdef ODPLAT_WIN32 + /* Expand area to invalidate, if needed. */ + if(!bAnythingInvalid) + { + bAnythingInvalid = TRUE; + btLeftMost = btLeftBoundary + btCurrentColumn; + btRightMost = btLeftBoundary + btCurrentColumn; + btTopMost = btTopBoundary + btCursorRow; + btBottomMost = btTopBoundary + btCursorRow; + } + else + { + BYTE btColumn = btLeftBoundary + btCurrentColumn; + BYTE btRow = btTopBoundary + btCursorRow; + + if(btColumn < btLeftMost) btLeftMost = btColumn; + if(btColumn > btRightMost) btRightMost = btColumn; + if(btRow < btTopMost) btTopMost = btRow; + if(btRow > btBottomMost) btBottomMost = btRow; + } +#endif /* ODPLAT_WIN32 */ + + if(btLeftColumn--) + { + ++btCurrentColumn; + } + else + { + btCurrentColumn = 0; + btLeftColumn = btRightBoundary - btLeftBoundary; + + if(btCursorRow < btBottom) + { + ++btCursorRow; + } + else if(bScrollEnabled) + { + ODScrnScrollUpOneLine(); +#ifdef ODPLAT_WIN32 + /* Entire boundary area is now invalid. */ + bAnythingInvalid = TRUE; + btLeftMost = btLeftBoundary; + btRightMost = btRightBoundary; + btTopMost = btTopBoundary; + btBottomMost = btBottomBoundary; +#endif /* ODPLAT_WIN32 */ + } + + pDest = (BYTE ODFAR *)pScrnBuffer + + ((btTopBoundary + btCursorRow) + * BUFFER_LINE_BYTES + btLeftBoundary * BYTES_PER_CHAR); + } + } + } + + btCursorColumn = btCurrentColumn; + ODScrnUpdateCaretPos(); + +#ifdef ODPLAT_WIN32 + if(bAnythingInvalid) + { + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate(btLeftMost, btTopMost, btRightMost, + btBottomMost); + } +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnCopyText() + * + * Copies the contents of the specified area on the screen to another location + * on the screen. The destination location must be such that the entire area + * specified as the source can be displayed without falling off the edge of the + * screen. + * + * Parameters: btLeft - Column number of the left edge of the area to + * copy from. + * + * btTop - Row number of the top edge of the area to copy + * from. + * + * btRight - Column number of the right edge of the area to + * copy from. + * + * btBottom - Row number of the bottom edge of the area to + * copy from. + * + * btDestColumn - Column number where the upper right corner of + * the area should be copied to. + * + * btDestRow - Row number where the upper right cornder of the + * area should be copied to. + * + * Return: TRUE on success, or FALSE on failure. May fail due to + * insufficient available memory. + */ +BOOL ODScrnCopyText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + BYTE btDestColumn, BYTE btDestRow) +{ + void *pScrnBuffer; + + ASSERT(btLeft >= 0 && btTop >= 0); + ASSERT(btLeft <= btRightBoundary - btLeftBoundary); + ASSERT(btTop <= btBottomBoundary - btTopBoundary); + ASSERT(btRight >= 0 && btBottom >= 0); + ASSERT(btRight <= btRightBoundary - btLeftBoundary); + ASSERT(btBottom <= btBottomBoundary - btTopBoundary); + ASSERT(btDestColumn >= 0 && btDestRow >= 0); + ASSERT(btDestColumn <= btRightBoundary - btLeftBoundary); + ASSERT(btDestRow <= btBottomBoundary - btTopBoundary); + + if( !(btLeft <= btRightBoundary - btLeftBoundary + && btTop <= btBottomBoundary - btTopBoundary) + || !(btRight <= btRightBoundary - btLeftBoundary + && btBottom <= btBottomBoundary - btTopBoundary) + || !(btDestColumn <= btRightBoundary - btLeftBoundary + && btDestRow <= btBottomBoundary - btTopBoundary)) + { + return(FALSE); + } + + + if((pScrnBuffer = malloc((btRight - btLeft + 1) * (btBottom - btTop + 1) + * BYTES_PER_CHAR)) == NULL) + { + /* Insufficient memory, return with failure. */ + return (FALSE); + } + + ODScrnGetText(btLeft, btTop, btRight, btBottom, pScrnBuffer); + ODScrnPutText(btDestColumn, btDestRow, + (BYTE)(btRight + (btDestColumn - btLeft)), + (BYTE)(btBottom + (btDestRow - btTop)), pScrnBuffer); + free(pScrnBuffer); + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODScrnClearToEndOfLine() + * + * Clears the contents of the current line, from the current cursor location + * to the end of the line. + * + * Parameters: none + * + * Return: void + */ +void ODScrnClearToEndOfLine(void) +{ + unsigned char btCharsToDelete = btRightBoundary + - (btLeftBoundary + btCursorColumn); + BYTE ODFAR *pDest = (BYTE ODFAR *) pScrnBuffer + + (((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES) + + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR); + BYTE btAttribute = btCurrentAttribute; + + while(btCharsToDelete--) + { + *(pDest++) = ' '; + *(pDest++) = btAttribute; + } + +#ifdef ODPLAT_WIN32 + /* Force the updated area of the screen window to be redrawn. */ + ODScrnInvalidate((BYTE)(btLeftBoundary + btCursorColumn), + (BYTE)(btTopBoundary + btCursorRow), btRightBoundary, + (BYTE)(btTopBoundary + btCursorRow)); +#endif /* ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnCreateWindow() + * + * Creates a text-based window on the local terminal. + * + * Parameters: btLeft - Column numebr of the left of the window. + * + * btTop - Row number of the top of the window. + * + * btRight - Column number of the right of the window. + * + * btBottom - Row number of the bottom of the window. + * + * btAttribute - Display attribute for the window boarder and + * the area inside the window. + * + * pszTitle - Pointer to a string containing the title to + * display, or "" for none. + * + * btTitleAttribute - Display attribute for the title text. + * + * Return: void + */ +#ifdef OD_TEXTMODE +void *ODScrnCreateWindow(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom, BYTE btAttribute, char *pszTitle, BYTE btTitleAttribute) +{ + void *pUnder; + INT nBetween; + INT nCount; + INT nFirst; + char *pszString; + int nTitleWidth; + + ASSERT(pszTitle != NULL); + + /* Alocate space to store screen contents "under" window. */ + if((pUnder = malloc((btRight - btLeft + 1) * (btBottom - btTop + 1) + * BYTES_PER_CHAR + 4 * sizeof(BYTE))) == NULL) + { + return(NULL); + } + + /* Store the window's position in the buffer. */ + ((BYTE *)pUnder)[0] = btLeft; + ((BYTE *)pUnder)[1] = btTop; + ((BYTE *)pUnder)[2] = btRight; + ((BYTE *)pUnder)[3] = btBottom; + + /* Retrieve screen contents in window area. */ + ODScrnGetText(btLeft, btTop, btRight, btBottom, ((BYTE *)pUnder) + 4); + + /* Determine area between left & right of window, distance of line before */ + /* title, and distance of line after title. */ + if(strlen(pszTitle) == 0) + { + nTitleWidth = 0; + } + else + { + nTitleWidth = strlen(pszTitle) + 2; + } + nCount = (nBetween = btRight - btLeft - 1) - nTitleWidth; + nCount -= (nFirst = nCount / 2); + + /* Prepare to begin drawing window at upper left corner */ + ODScrnSetCursorPos(btLeft, btTop); + ODScrnSetAttribute(btAttribute); + + /* Draw first line of window */ + ODScrnDisplayChar((unsigned char)214); + while(nFirst--) ODScrnDisplayChar((unsigned char)196); + if(strlen(pszTitle) != 0) + { + ODScrnSetAttribute(btTitleAttribute); + ODScrnDisplayChar(' '); + ODScrnDisplayString(pszTitle); + ODScrnDisplayChar(' '); + ODScrnSetAttribute(btAttribute); + } + while(nCount--) ODScrnDisplayChar((unsigned char)196); + ODScrnDisplayChar((unsigned char)183); + + /* Build string for working lines */ + pszString = szBuffer; + *pszString++ = (unsigned char)186; + nCount = nBetween; + while(nCount--) *pszString++ = ' '; + *pszString++ = (unsigned char)186; + *pszString++ = '\0'; + + /* Draw working lines of window */ + for(nCount = btTop + 1; nCount < btBottom; ++nCount) + { + ODScrnSetCursorPos(btLeft, (BYTE)nCount); + ODScrnDisplayString(szBuffer); + } + + /* Draw last line of window */ + ODScrnSetCursorPos(btLeft, btBottom); + ODScrnDisplayChar((unsigned char)211); + while(nBetween--) ODScrnDisplayChar((unsigned char)196); + ODScrnDisplayChar((unsigned char)189); + + /* return pointer to buffer */ + return(pUnder); +} +#endif /* OD_TEXTMODE */ + + +/* ---------------------------------------------------------------------------- + * ODScrnDestroyWindow() + * + * Removes a text-based window that was created by ODScrnCreateWindow(). + * + * Parameters: pWindow - Pointer to the buffer returned by the corresponding + * call to ODScrnCreateWindow(). + * + * Return: void + */ +#ifdef OD_TEXTMODE +void ODScrnDestroyWindow(void *pWindow) +{ + BYTE btLeft; + BYTE btTop; + BYTE btRight; + BYTE btBottom; + BYTE *pabtWindow = (BYTE *)pWindow; + + ASSERT(pWindow != NULL); + + /* Determine the location of the window. */ + btLeft = pabtWindow[0]; + btTop = pabtWindow[1]; + btRight = pabtWindow[2]; + btBottom = pabtWindow[3]; + + /* Restore original screen contents under the window. */ + ODScrnPutText(btLeft, btTop, btRight, btBottom, ((BYTE *)pWindow) + 4); + + /* Deallocate window buffer. */ + free(pWindow); +} +#endif /* OD_TEXTMODE */ + + +/* ---------------------------------------------------------------------------- + * ODScrnLocalInput() + * + * Inputs a string, only displaying input on local screen. + * + * Parameters: btLeft - Column number of the left end of the input + * field. + * + * btRow - Row number where the input field appears. + * + * pszString - Location where user's input should be stored. Must + * be initialized. + * + * nMaxChars - The maximum number of characters that may be + * accepted for input into the string. + * + * Return: void + */ +#ifdef OD_TEXTMODE +void ODScrnLocalInput(BYTE btLeft, BYTE btRow, char *pszString, + BYTE btMaxChars) +{ + BYTE btCount; + BYTE btCurrentPos; + BOOL bAnyKeysPressed = FALSE; + tODInputEvent InputEvent; + + /* Draw initial input field. */ + ODScrnSetCursorPos(btLeft, btRow); + ODScrnDisplayString(pszString); + for(btCount = strlen(pszString); btCount <= btMaxChars; ++btCount) + { + ODScrnDisplayChar(177); + } + + /* Start with the cursor at the end of the input field. */ + btCurrentPos = strlen(pszString); + + /* Loop until the user presses enter. */ + for(;;) + { + /* Position the cursor at the appropriate location. */ + ODScrnSetCursorPos((BYTE)(btLeft + btCurrentPos), btRow); + + /* Obtain the next input event. */ + ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT); + + switch(InputEvent.chKeyPress) + { + case '\b': + /* If user presses [Backspace], then move back if we are not at */ + /* the left of the input field. */ + if(btCurrentPos > 0) + { + /* Backspace, removing last character from string. */ + btCurrentPos--; + ODScrnSetCursorPos((BYTE)(btLeft + btCurrentPos), btRow); + ODScrnDisplayChar(177); + pszString[btCurrentPos] = '\0'; + } + break; + + case '\n': + case '\r': + /* If user presses [Enter], then exit from the function. */ + return; + + case '\0': + /* In the case of a multi-character sequence, skip the next */ + /* character from the input queue. */ + ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT); + break; + + default: + /* If this is a valid string character for the string. */ + if(InputEvent.chKeyPress >= ' ') + { + /* If no keys have been pressed yet, then erase the entire */ + /* string first. */ + if(!bAnyKeysPressed) + { + btCurrentPos = 0; + ODScrnSetCursorPos(btLeft, btRow); + for(btCount = 0; btCount <= btMaxChars; ++btCount) + { + ODScrnDisplayChar(177); + } + ODScrnSetCursorPos(btLeft, btRow); + } + + /* If we are not at the end of the string, then add the */ + /* character to the string. */ + if(btCurrentPos < btMaxChars) + { + /* Display the new character. */ + ODScrnDisplayChar(InputEvent.chKeyPress); + + /* Add the character to the string. */ + pszString[btCurrentPos] = InputEvent.chKeyPress; + + /* Update the current cursor position. */ + ++btCurrentPos; + + /* Terminate the string. */ + pszString[btCurrentPos] = '\0'; + } + } + } + + /* Note that a key has now been pressed. */ + bAnyKeysPressed = TRUE; + } +} +#endif /* OD_TEXTMODE */ + + +/* ---------------------------------------------------------------------------- + * ODScrnShowMessage() + * + * Displays a message window with the specified message text. Unlike the + * Windows MessageBox() function, this message box is removed by the caller + * of the function rather than the user. + * + * Parameters: pszText - Pointer to message text to be displayed. This string + * must continue to exist until after the + * ODScrnRemoveMessage() function is called. + * + * nFlags - Currently unused, must be 0. + * + * Return: A pointer which must be passed to ODScrnRemoveMessage() in + * order to remove this message from the screen. A return value + * of NULL does not necessarily indicate window creation failure, + * and should still be passed to a corresponding call to + * ODScrnRemoveMessage(). + */ +void *ODScrnShowMessage(char *pszText, int nFlags) +{ + ASSERT(pszText != NULL); + ASSERT(nFlags == 0); + + /* In silent mode, this function does nothing. */ + if(od_control.od_silent_mode) return(NULL); + +#ifdef ODPLAT_WIN32 + + /* Place a message in the frame window's message queue, asking it to */ + /* create the message window. */ + PostMessage(GetParent(hwndScreenWindow), WM_SHOW_MESSAGE, (WPARAM)nFlags, + (LPARAM)pszText); + + return(NULL); + +#else /* !ODPLAT_WIN32 */ + { + int nWindowWidth; + int nLeftColumn; + char szMessage[74]; + void *pWindow; + + UNUSED(nFlags); + + ODStringCopy(szMessage, pszText, sizeof(szMessage)); + + ODStoreTextInfo(); + + nWindowWidth = strlen(szMessage) + 4; + nLeftColumn = 40 - (nWindowWidth / 2); + if((pWindow = ODScrnCreateWindow((BYTE)nLeftColumn, 10, + (BYTE)(nLeftColumn + (nWindowWidth - 1)), 14, + od_control.od_local_win_col, "", od_control.od_local_win_col)) + == NULL) + { + return(NULL); + } + + ODScrnSetCursorPos((BYTE)(42 - (nWindowWidth / 2)), 12); + ODScrnDisplayString(szMessage); + ODRestoreTextInfo(); + + ODScrnEnableCaret(FALSE); + + return(pWindow); + } +#endif /* !ODPLAT_WIN32 */ +} + + +/* ---------------------------------------------------------------------------- + * ODScrnRemoveMessage() + * + * Removes a message that was shown by a previous call to ODScrnShowMessage(). + * + * Parameters: pMessageInfo - Pointer to the buffer returned by the + * corresponding call to ODScrnShowMessage(). + * + * Return: void + */ +void ODScrnRemoveMessage(void *pMessageInfo) +{ + /* In silent mode, this function does nothing. */ + if(od_control.od_silent_mode) return; + +#ifdef ODPLAT_WIN32 + /* Place a message in the frame window's message queue, asking it to */ + /* remove the message window. */ + SendMessage(GetParent(hwndScreenWindow), WM_REMOVE_MESSAGE, 0, 0L); +#else /* !ODPLAT_WIN32 */ + /* If pMessageInfo is NULL, then we do nothing. */ + if(pMessageInfo == NULL) return; + + ODStoreTextInfo(); + ODScrnDestroyWindow(pMessageInfo); + ODRestoreTextInfo(); + ODScrnEnableCaret(TRUE); +#endif /* !ODPLAT_WIN32 */ +} + diff --git a/utils/magiedit/odoors/ODScrn.h b/utils/magiedit/odoors/ODScrn.h new file mode 100644 index 0000000..2d087ab --- /dev/null +++ b/utils/magiedit/odoors/ODScrn.h @@ -0,0 +1,110 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODScrn.h + * + * Description: Functions used to access the local display screen buffer, which + * keeps a copy of the text that is displayed on the remote + * terminal. The local display screen buffer also displays the + * OpenDoors status lines on some platforms. In addition to + * maintaining the current screen buffer, the odscrn.c module + * also contains the code to display this buffer on the screen. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 14, 1995 6.00 BP Created. + * Jan 21, 1996 6.00 BP Added ODScrnShowMessage() and related. + * Jan 27, 1996 6.00 BP Made text-mode window f'ns static. + * Jan 31, 1996 6.00 BP Made them non-static again. + * Jan 31, 1996 6.00 BP Added ODScrnLocalInput(). + * 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. + */ + +#ifndef _INC_ODSCRN +#define _INC_ODSCRN + +#include "ODTypes.h" +#include "ODPlat.h" + +/* Text information structure. */ +typedef struct +{ + unsigned char winleft; + unsigned char wintop; + unsigned char winright; + unsigned char winbottom; + unsigned char attribute; + unsigned char curx; + unsigned char cury; +} tODScrnTextInfo; + + +/* Screen buffer initialization and shutdown functions. */ +tODResult ODScrnInitialize(void); +void ODScrnShutdown(void); + +/* Basic text output functions. */ +void ODScrnDisplayChar(unsigned char chToOutput); +void ODScrnDisplayBuffer(const char *pBuffer, INT nCharsToDisplay); +void ODScrnDisplayString(const char *pszString); +INT ODScrnPrintf(char *pszFormat, ...); + +/* Functions for manipulating rectangular areas of the screen buffer. */ +BOOL ODScrnGetText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + void *pbtBuffer); +BOOL ODScrnPutText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + void *pbtBuffer); +BOOL ODScrnCopyText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom, + BYTE btDestColumn, BYTE btDestRow); + +/* Functions for clearing portions of the screen buffer. */ +void ODScrnClear(void); +void ODScrnClearToEndOfLine(void); + +/* Functions for setting or obtaining current display settings. */ +void ODScrnSetBoundary(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom); +void ODScrnSetCursorPos(BYTE btColumn, BYTE btRow); +void ODScrnSetAttribute(BYTE btAttribute); +void ODScrnEnableScrolling(BOOL bEnable); +void ODScrnEnableCaret(BOOL bEnable); +void ODScrnGetTextInfo(tODScrnTextInfo *pTextInfo); + +/* Functions for displaying OpenDoors message window. */ +void *ODScrnShowMessage(char *pszText, int nFlags); +void ODScrnRemoveMessage(void *pMessageInfo); + +/* Additional local output functions for text mode based versions. */ +#ifdef OD_TEXTMODE +void *ODScrnCreateWindow(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom, BYTE btAttribute, char *pszTitle, BYTE btTitleAttribute); +void ODScrnDestroyWindow(void *pWindow); +void ODScrnLocalInput(BYTE btLeft, BYTE btRow, char *pszString, + BYTE btMaxChars); +#endif /* OD_TEXTMODE */ + +/* Functions for local screen window under Win32 version. */ +#ifdef ODPLAT_WIN32 +tODResult ODScrnStartWindow(HANDLE hInstance, tODThreadHandle *phScreenThread, + HWND hwndFrame); +void ODScrnSetFocusToWindow(void); +void ODScrnAdjustWindows(void); +#endif /* ODPLAT_WIN32 */ + +#endif /* _INC_ODSCRN */ diff --git a/utils/magiedit/odoors/ODSpawn.c b/utils/magiedit/odoors/ODSpawn.c new file mode 100644 index 0000000..81f6bc3 --- /dev/null +++ b/utils/magiedit/odoors/ODSpawn.c @@ -0,0 +1,1102 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODSpawn.c + * + * Description: Implements the od_spawn...() functions for suspending this + * program and executing a sub-program. Can be called by the + * user explicitly, or invoked for sysop OS shell. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Oct 21, 1994 6.00 BP Further isolated com routines. + * Dec 09, 1994 6.00 BP Use new directory access functions. + * Dec 13, 1994 6.00 BP Standardized coding style. + * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code. + * Jan 01, 1995 6.00 BP _waitdrain -> ODWaitDrain() + * Aug 19, 1995 6.00 BP 32-bit portability. + * 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 Removed oddoor.h, added odcore.h. + * Nov 17, 1995 6.00 BP Use new input queue mechanism. + * Nov 21, 1995 6.00 BP Ported to Win32. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 23, 1996 6.00 BP Finished port to Win32. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 23, 1996 6.00 BP Enable and test under Win32. + * Feb 27, 1996 6.00 BP Store screen info in our own struct. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Aug 10, 2003 6.23 SH *nix support - some functions not supported (Yet) + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#ifdef ODPLAT_NIX +#include +#include +#include +#include +#endif +#include "ODCore.h" +#include "ODGen.h" +#include "ODCom.h" +#include "ODPlat.h" +#include "ODScrn.h" +#include "ODInQue.h" +#include "ODInEx.h" +#include "ODUtil.h" +#include "ODKrnl.h" +#include "ODSwap.h" + +#ifdef ODPLAT_WIN32 +#include "ODFrame.h" +#endif /* ODPLAT_WIN32 */ + +#if defined(ODPLAT_WIN32) && defined(_MSC_VER) +#undef P_WAIT +#undef P_NOWAIT +#include +#endif /* ODPLAT_WIN32 && _MSC_VER */ + +#ifdef ODPLAT_DOS + +/* Local and global variables for memory swapping spawn routines. */ + +int _swap = 0; /* if 0, do swap */ +char *_swappath = NULL; /* swap path */ +int _useems = 0; /* if 0, use EMS */ +int _required = 0; /* child memory requirement in K */ +static long swapsize; /* swap size requirement in bytes */ +static int ems = 2; /* if 0, EMS is available */ +static int mapsize; /* size of page map information */ +static unsigned int tempno = 1; /* tempfile number */ +static char errtab[] = /* error table */ +{ + 0, + EINVAL, + ENOENT, + ENOENT, + EMFILE, + EACCES, + EBADF, + ENOMEM, + ENOMEM, + ENOMEM, + E2BIG, + ENOEXEC, + EINVAL, + EINVAL, + -1, + EXDEV, + EACCES, + EXDEV, + ENOENT, + -1 +}; + +static VECTOR vectab1[]= +{ + 0, 1, 0, 0, + 1, 1, 0, 0, + 2, 1, 0, 0, + 3, 1, 0, 0, + 0x1B, 1, 0, 0, + 0x23, 1, 0, 0, + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 2, 0, 0, /* free record */ + 0, 3, 0, 0 /* end record */ +}; + +static VECTOR vectab2[(sizeof vectab1)/(sizeof vectab1[0])]; + +/* Location function prototypes. */ +int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[], + char *papszEnviron[]); +int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[], + char * papszEnviron[]); +static void savevect(void); + + +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_NIX +/* Location function prototypes. */ +int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[], + char *papszEnviron[]); +#endif /* ODPLAT_NIX */ + +/* ---------------------------------------------------------------------------- + * od_spawn() + * + * Executes the specified command line, suspending OpenDoors operations while + * the spawned-to program is running. + * + * Parameters: pszCommandLine - Command to execute along with any parameters. + * + * Return: TRUE on success, or FALSE on failure. + */ +ODAPIDEF BOOL ODCALL od_spawn(const char *pszCommandLine) +{ +#ifdef ODPLAT_DOS + char *apszArgs[4]; + INT16 nReturnCode; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_spawn()"); + + *apszArgs=getenv("COMSPEC"); + + apszArgs[1] = "/c"; + apszArgs[2] = pszCommandLine; + apszArgs[3] = NULL; + + if(*apszArgs != NULL) + { + if((nReturnCode = od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL)) != -1 + || errno != ENOENT) + { + return(nReturnCode != -1); + } + } + + *apszArgs = "command.com"; + + return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1); +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_WIN32 + char *pch; + char *apszArgs[3]; + char szProgName[80]; + + /* Build command and arguments list. */ + /* Build program name. */ + ODStringCopy(szProgName, pszCommandLine, sizeof(szProgName)); + pch = strchr(szProgName, ' '); + if(pch != NULL) *pch = '\0'; + apszArgs[0] = szProgName; + + /* Build arguments. */ + pch = strchr(pszCommandLine, ' '); + if(pch == NULL) + { + apszArgs[1] = NULL; + } + else + { + apszArgs[1] = pch + 1; + apszArgs[2] = NULL; + } + + /* Now, call od_spawnvpe(). */ + return(od_spawnvpe(P_WAIT, *apszArgs, apszArgs, NULL) != -1); +#endif /* ODPLAT_WIN32 */ + +#ifdef ODPLAT_NIX + sigset_t block; + int retval; + + /* Suspend kernel */ + sigemptyset(&block); + sigaddset(&block,SIGALRM); + sigprocmask(SIG_BLOCK,&block,NULL); + retval=system(pszCommandLine); + + /* Restore kernel */ + sigemptyset(&block); + sigaddset(&block,SIGALRM); + sigprocmask(SIG_UNBLOCK,&block,NULL); + + return(retval!=-1 && retval != 127); +#endif +} + + +/* ---------------------------------------------------------------------------- + * od_spawnvpe() + * + * Executes the specified program, using the specified arguments and + * environment variables, optionally suspending OpenDoors operations while + * the spawned-to program is running. + * + * Parameters: nModeFlag - P_WAIT to for OpenDoors operations to be suspended + * while the spawned-to program is running, or + * P_NOWAIT if the calling program should continue to + * run while the spawned-to program is running. In + * non-multitasking environments, the only valid value + * of this parameters is P_WAIT. + * + * pszPath - Complete path and filename of the program to + * exectute. + * + * papszArg - Array of string pointers to command line arguments. + * + * papszEnv - Array of string pointers to environment variables. + * + * Return: -1 on failure or the spawned-to program's return value on + * success. + */ +ODAPIDEF INT16 ODCALL od_spawnvpe(INT16 nModeFlag, char *pszPath, + char *papszArg[], char *papszEnv[]) +{ + INT16 nToReturn; + time_t nStartUnixTime; + DWORD dwQuotient; +#ifdef ODPLAT_WIN32 + void *pWindow; +#endif /* ODPLAT_WIN32 */ +#ifdef ODPLAT_DOS + char *pszDir; + BYTE *abtScreenBuffer; + INT nDrive; + tODScrnTextInfo TextInfo; +#endif /* ODPLAT_DOS */ + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_spawnvpe()"); + + /* Initialize OpenDoors if it hasn't already been done. */ + if(!bODInitialized) od_init(); + +#ifdef ODPLAT_DOS + /* Ensure the nModeFlag is P_WAIT, which is the only valid value for */ + /* the MS-DOS version of OpenDoors. */ + if(nModeFlag != P_WAIT) + { + od_control.od_error = ERR_PARAMETER; + return(-1); + } + + /* Store current screen contents. */ + if((abtScreenBuffer = malloc(4000)) == NULL) + { + od_control.od_error = ERR_MEMORY; + return(-1); + } + if((pszDir = malloc(256)) == NULL) + { + od_control.od_error = ERR_MEMORY; + free(abtScreenBuffer); + return(-1); + } + + /* Store current display settings. */ + ODScrnGetTextInfo(&TextInfo); + + /* Set current output area to the full screen. */ + ODScrnSetBoundary(1,1,80,25); + + /* Store contents of entire screen. */ + ODScrnGetText(1, 1, 80, 25, (char *)abtScreenBuffer); + + /* Set the current display colour to grey on black. */ + ODScrnSetAttribute(0x07); + + /* Clear the screen if required. Otherwise, move the cursor to the */ + /* upper left corner of the screen. */ + if(od_control.od_clear_on_exit) + { + ODScrnClear(); + } + else + { + ODScrnSetCursorPos(1, 1); + } + + /* Store current directory. */ + strcpy(pszDir, "X:\\"); + pszDir[0] = 'A' + (nDrive = _getdrv()); + _getcd(0, (char *)pszDir + 3); +#endif /* ODPLAT_DOS */ + + /* Remember when spawned to program was executed. */ + nStartUnixTime = time(NULL); + + if(nModeFlag == P_WAIT) + { + /* Display the spawn message box under Win32. */ +#ifdef ODPLAT_WIN32 + pWindow = ODScrnShowMessage("Running sub-program...", 0); +#endif /* ODPLAT_WIN32 */ + + /* Wait for up to ten seconds for outbound buffer to drain. */ + ODWaitDrain(10000); + +#ifdef OD_MULTITHREADED + /* Mutlithreaded versions of OpenDoors must shutdown the kernel */ + /* before closing the serial port. */ + ODKrnlShutdown(); +#endif /* OD_MULTITHREADED */ + + /* Close serial port. */ + if(od_control.baud != 0) + { +#ifdef ODPLAT_WIN32 + /* Disable DTR response by the modem before closing the serial */ + /* port, if this is required. */ + ODInExDisableDTR(); +#endif /* ODPLAT_WIN32 */ + ODComClose(hSerialPort); + } + } + + /* Execute specified program with the specified arguments. */ + nToReturn = _spawnvpe(nModeFlag, pszPath, papszArg, papszEnv); + + if(nModeFlag == P_WAIT) + { + /* Re-open serial port. */ + if(od_control.baud != 0) + { + ODComOpen(hSerialPort); + } + +#ifdef OD_MULTITHREADED + /* Mutlithreaded versions of OpenDoors must shutdown the kernel */ + /* before closing the serial port, so reinitialize the kernel now. */ + ODKrnlInitialize(); +#endif /* OD_MULTITHREADED */ + + if(!(bIsShell || od_control.od_spawn_freeze_time)) + { + ODDWordDivide(&dwQuotient, NULL, time(NULL) - nStartUnixTime, 60L); + od_control.user_timelimit -= (int)dwQuotient; + } + else + { + nNextTimeDeductTime += time(NULL) - nStartUnixTime; + } + + /* Reset the time of the last input activity to the current time. */ + /* This will prevent an immediate inactity timeout, regardless of */ + /* how long the spawned-to program was active. */ + ODInQueueResetLastActivity(hODInputQueue); + + /* Clear inbound buffer. */ + od_clear_keybuffer(); + + /* Remove the spawn message box under Win32. */ +#ifdef ODPLAT_WIN32 + ODScrnRemoveMessage(pWindow); +#endif /* ODPLAT_WIN32 */ + } + +#ifdef ODPLAT_DOS + /* Redisplay the door screen. */ + ODScrnPutText(1, 1, 80, 25, (char *)abtScreenBuffer); + + /* Restore cursor to old position. */ + ODScrnSetBoundary(TextInfo.winleft, TextInfo.wintop, + TextInfo.winright, TextInfo.winbottom); + ODScrnSetAttribute(TextInfo.attribute); + ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury); + + _setdrvcd(nDrive, pszDir); + + /* Free allocated space. */ + free(abtScreenBuffer); + free(pszDir); +#endif /* ODPLAT_DOS */ + + /* Return appropriate value. */ + return(nToReturn); +} + + +#ifdef ODPLAT_DOS + +/* ---------------------------------------------------------------------------- + * _spawnvpe() *** PRIVATE FUNCTION *** + * + * Executes a child program in the MS-DOS environment, swapping the calling + * program out of memory if enabled. + * + * Parameters: nModeFlag - Must be P_WAIT. + * + * pszPath - Name of program to execute. + * + * papszArgs - Array of command-line arguments. + * + * papszEnviron - Array of environment variables. + * + * Return: -1 on failure or the spawned-to program's return value on + * success. + */ +int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[], + char *papszEnviron[]) +{ + char *e; + char *p; + char buf[80]; + int nReturnCode; + + + _swappath = (char *)(strlen(od_control.od_swapping_path) == 0 ? NULL + : (char *)od_control.od_swapping_path); + _useems = od_control.od_swapping_noems; + _swap = od_control.od_swapping_disable; + + if((nReturnCode=_spawnve(nModeFlag, pszPath, papszArgs, papszEnviron))!=-1 + || errno!=ENOENT || *pszPath=='\\' || *pszPath=='/' + || *pszPath && *(pszPath+1)==':' || (e=getenv("PATH"))==NULL) + { + return(nReturnCode); + } + + for (;;e++) + { + if((p=strchr(e,';'))!=NULL) + { + if(p-e > 66) + { + e=p; + continue; + } + } + else if(strlen(e)>66) + { + return( -1 ); + } + + p=buf; + + while(*e && *e!=';') *p++=*e++; + + if(p>buf) + { + if(*(p-1)!='\\' && *(p-1)!='/') *p++ = '\\'; + strcpy(p,pszPath); + + if((nReturnCode=_spawnve(nModeFlag,buf,papszArgs,papszEnviron))!=-1 || errno!=ENOENT) + { + return(nReturnCode); + } + } + if(*e=='\0') return(-1); + } +} + + +/* ---------------------------------------------------------------------------- + * addvect() *** PRIVATE FUNCTION *** + * + * Adds a vector to the vector table. + * + * Parameters: number - The vector number. + * + * opcode - Vector flags. + * + * Return: -1 on failure, or 0 on success. + */ +int addvect(int number, int opcode) +{ + VECTOR *vect = vectab1; + + if ( number < 0 || number > 0xFF || + ( opcode != IRET && opcode != CURRENT )) + { + errno = EINVAL; + return( -1 ); + } + + /* see if number is already in table */ + while ( vect->flag != 3 && ( vect->flag == 2 || + vect->number != ( char )number )) + { + vect++; + } + + if ( vect->flag == 3 ) + { + /* look for a free record */ + vect = vectab1; + while ( vect->flag == CURRENT || vect->flag == IRET ) + vect++; + } + + if ( vect->flag != 3 ) + { + vect->number = ( char )number; + vect->flag = ( char )opcode; + if ( opcode == CURRENT ) + _getvect( number, &vect->vseg, &vect->voff ); + return( 0 ); + } + + errno = ENOMEM; + return( -1 ); +} + + +/* ---------------------------------------------------------------------------- + * savevect() *** PRIVATE FUNCTION *** + * + * Saves current vector in vector table. + * + * Parameters: none + * + * Return: void + */ +static void savevect(void) +{ + VECTOR *vect1 = vectab1; + VECTOR *vect2 = vectab2; + + while ( vect1->flag != 3 ) + { + if ( vect1->flag != 2 ) + { + vect2->number = vect1->number; + vect2->flag = CURRENT; + _getvect( vect1->number, &vect2->vseg, &vect2->voff ); + } + else + vect2->flag = 2; /* free */ + vect1++; + vect2++; + } + vect2->flag = 3; /* end */ +} + + +/* ---------------------------------------------------------------------------- + * testfile() *** PRIVATE FUNCTION *** + * + * Tests swap file. + * + * Parameters: p - Path. + * + * file - File name. + * + * handle - File handle. + * + * Return: 1 on failure. + */ +static int testfile(char *p, char *file, int *handle) +{ + unsigned int startno = tempno; + int nDrive = ( *file | 32 ) - 96; /* a = 1, b = 2, etc. */ + int root; + unsigned int bytes; /* bytes per cluster */ + unsigned int clusters; /* free clusters */ + int need; /* clusters needed for swap file */ + int nReturnCode; /* return code */ + unsigned long dwQuotient; + unsigned long remainder; + + if ( file + 2 == p ) + { + *p++ = '\\'; + if ( _getcd( nDrive, p )) /* get current directory */ + return( 1 ); /* invalid drive */ + p = file + strlen( file ); + } + else + { + *p = '\0'; + if ( ODFileAccessMode( file, 0 )) + return( 1 ); /* path does not exist */ + } + if ( *( p - 1 ) != '\\' && *( p - 1 ) != '/' ) + *p++ = '\\'; + if ( p - file == 3 ) + root = 1; /* is root directory */ + else + root = 0; /* is not root directory */ + strcpy( p, "swp" ); + p += 3; + + if ( _dskspace( nDrive, &bytes, &clusters ) != 0 ) + return( 1 ); /* invalid drive */ + + + + ODDWordDivide(&dwQuotient, &remainder, swapsize, bytes); + need = (int)dwQuotient; + + if ( remainder ) + need++; + if ( root == 0 ) /* if subdirectory */ + need++; /* in case the directory needs space */ + if ( clusters < ( unsigned int )need ) + return( 1 ); /* insufficient free disk space */ + + do + { +again: tempno = ( ++tempno ) ? tempno : 1; + if ( tempno == startno ) + return( 1 ); /* extremely unlikely */ + ltoa(( long )tempno, p, 10 ); + } + while ( !ODFileAccessMode( file, 0 )); + +/* + * The return code from _create will equal 80 if the user is running DOS 3.0 + * or above and the file was created by another program between the access + * call and the _create call. + */ + + if (( nReturnCode = _create( file, handle )) == 80 ) + goto again; + return( nReturnCode ); +} + + +/* ---------------------------------------------------------------------------- + * tempfile() *** PRIVATE FUNCTION *** + * + * Creates a temporary swap file. + * + * Parameters: file - Filename + * + * handle - Handle to file. + * + * Return: 0 on success, or 1 on failure. + */ +static int tempfile(char *file, int *handle) +{ + char *s = _swappath; + char *p = file; + + if ( s ) + { + for ( ;; s++ ) + { + while ( *s && *s != ';' ) + *p++ = *s++; + if ( p > file ) + { + if ( p == file + 1 || file[ 1 ] != ':' ) + { + memmove( file + 2, file, ( int )( p - file )); + *file = ( char )( _getdrv() + 'a' ); + file[ 1 ] = ':'; + p += 2; + } + if ( testfile( p, file, handle ) == 0 ) + return( 0 ); + p = file; + } + if ( *s == '\0' ) + break; + } + } + else /* try the current directory */ + { + *p++ = ( char )( _getdrv() + 'a' ); + *p++ = ':'; + if ( testfile( p, file, handle ) == 0 ) + return( 0 ); + } + + errno = EACCES; + return( 1 ); +} + + +/* ---------------------------------------------------------------------------- + * cmdenv() *** PRIVATE FUNCTION *** + * + * Constructs environment. + * + * Parameters: papszArgs - Array of arguments. + * + * papszEnviron - Array of environment variables to add. + * + * command - The command specified. + * + * env - Pointer to environment. + * + * memory - Allocated memory. + * + * Return: Environment length. + */ +static int cmdenv(char **papszArgs, char **papszEnviron, char *command, + char **env, char **memory) +{ + char **vp; + unsigned int elen = 0; /* environment length */ + char *p; + int cnt; + int len; + + /* construct environment */ + + if ( papszEnviron == NULL ) + { + char far *parent_env; + char far *env_ptr; + int nul_count; + + ASM mov ah, 0x62 + ASM int 0x21 + ASM push es + ASM mov es, bx + ASM mov ax, es:[0x2c] + ASM pop es + ASM mov word ptr parent_env, 0 + ASM mov word ptr parent_env + 2, ax + + env_ptr = parent_env; + nul_count = 0; + while(nul_count < 2) + { + if(*env_ptr) + { + nul_count = 0; + } + else + { + ++nul_count; + } + + ++env_ptr; + ++elen; + } + + if ( elen > 32766 ) /* 32K - 2 */ + { + errno = E2BIG; + return( -1 ); + } + + if (( p = malloc(elen + 15 )) == NULL ) + { + errno = ENOMEM; + return( -1 ); + } + *memory = p; + + *( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15; + *env = p; + + len = elen; + while(len--) + { + *p++ = *parent_env++; + } + } + else + { + for ( vp = papszEnviron; *vp; vp++ ) + { + elen += strlen( *vp ) + 1; + if ( elen > 32766 ) /* 32K - 2 */ + { + errno = E2BIG; + return( -1 ); + } + } + + if (( p = malloc( ++elen + 15 )) == NULL ) + { + errno = ENOMEM; + return( -1 ); + } + *memory = p; + + *( unsigned int * )&p = *( unsigned int * )&p + 15 & ~15; + *env = p; + + for ( vp = papszEnviron; *vp; vp++ ) + p = strchr( strcpy( p, *vp ), '\0' ) + 1; + + *p = '\0'; /* final element */ + } + + + /* construct command-line */ + + vp = papszArgs; + p = command + 1; + cnt = 0; + + if (vp!=NULL && *vp ) + { + while ( *++vp ) + { + *p++ = ' '; + cnt++; + len = strlen( *vp ); + if ( cnt + len > 125 ) + { + errno = E2BIG; + free( *memory ); + return( -1 ); + } + strcpy( p, *vp ); + p += len; + cnt += len; + } + } + + *p = '\r'; + *command = ( char )cnt; + + return(( int )elen ); /* return environment length */ +} + + +/* ---------------------------------------------------------------------------- + * doxspawn() *** PRIVATE FUNCTION *** + * + * Performs spawn using memory swapping. + * + * Parameters: pszPath - Path to command to exectute. + * + * papszArg - Array of arugments. + * + * papszEnviron - Pointer to the environment. + * + * Return: 0 on success, or -1 on failure. + */ +static int doxspawn(char *pszPath, char *papszArgs[], char *papszEnviron[]) +{ + int nReturnCode = 0; /* assume do xspawn */ + int doswap = 0; /* assume do swap */ + int elen; /* environment length */ + char *memory; + char *env; /* environment */ + char command[ 128 ]; /* command-line */ + long totalsize; /* parent and free memory in bytes */ + int handle; + int pages; + char file[ 79 ]; + char *mapbuf = NULL; /* buffer for map information */ + + /* construct the command-line and the environment */ + if (( elen = cmdenv( papszArgs, papszEnviron, command, &env, &memory )) == -1 ) + return( -1 ); + + if ( _swap == 0 ) + { + if ( _useems == 0 ) + { + if ( ems == 2 ) + ems = _chkems( "EMMXXXX0", &mapsize ); + if ( ems == 0 && ( mapbuf = malloc( mapsize )) == NULL ) + { + errno = ENOMEM; + free( memory ); + return( -1 ); + } + } + if (( nReturnCode = _xsize( _psp, &swapsize, &totalsize )) == 0 ) + { + if ( _required == 0 || totalsize - swapsize - 272 + < (long)ODDWordShiftLeft(( long )_required , 10 )) + { + if ( ems == 0 && _useems == 0 ) + { + pages = ( int )ODDWordShiftRight( swapsize , 14); + if ((long)ODDWordShiftLeft(( long )pages , 14 ) < swapsize ) + pages++; + if ( _savemap( mapbuf ) == 0 && + _getems( pages, &handle ) == 0 ) + *file = '\0'; /* use EMS */ + else if ( tempfile( file, &handle ) != 0 ) + nReturnCode = -1; /* don't do xspawn */ + } + else if ( tempfile( file, &handle ) != 0 ) + nReturnCode = -1; /* don't do xspawn */ + } + else + doswap = 1; /* don't do swap */ + } + else + { + errno = errtab[ nReturnCode ]; + nReturnCode = -1; /* don't do xspawn */ + } + } + else + doswap = 1; /* don't do swap */ + + if ( nReturnCode == 0 ) + { + savevect(); /* save current vectors */ + nReturnCode = _xspawn( pszPath, command, env, vectab1, doswap, elen, file, + handle ); + _setvect( vectab2 ); /* restore saved vectors */ + if ( nReturnCode == 0 ) + nReturnCode = _getrc(); /* get child return code */ + else + { + errno = errtab[ nReturnCode ]; + nReturnCode = -1; + } + /* + * If EMS was used, restore the page-mapping state of the expanded + * memory hardware. + */ + if ( doswap == 0 && *file == '\0' && _restmap( mapbuf ) != 0 ) + { + errno = EACCES; + nReturnCode = -1; + } + } + + if ( mapbuf ) + free( mapbuf ); + free( memory ); + return( nReturnCode ); +} + + +/* ---------------------------------------------------------------------------- + * _spawnve() *** PRIVATE FUNCTION *** + * + * Performs a spawn. + * + * Parameters: nModeFlag - Must be P_WAIT + * + * pszPath - Command to execute. + * + * papszArgs - Command line arguments. + * + * papszEnviron - Pointer to environment. + * + * Return: void + */ +int _spawnve(int nModeFlag, char *pszPath, char *papszArgs[], + char * papszEnviron[]) +{ + char *p; + char *s; + int nReturnCode = -1; + char buf[ 80 ]; + + if ( nModeFlag != P_WAIT ) + { + errno = EINVAL; + return( -1 ); + } + + p = strrchr( pszPath, '\\' ); + s = strrchr( pszPath, '/' ); + if ( p == NULL && s == NULL ) + p = pszPath; + else if ( p == NULL || s > p ) + p = s; + + if ( strchr( p, '.' )) + { + if ( !ODFileAccessMode( pszPath, 0 )) + nReturnCode = doxspawn( pszPath, papszArgs, papszEnviron ); + /* If file not found, access will have set errno to ENOENT. */ + } + else + { + strcpy( buf, pszPath ); + strcat( buf, ".com" ); + if ( !ODFileAccessMode( buf, 0 )) + nReturnCode = doxspawn( buf, papszArgs, papszEnviron ); + else + { + strcpy( strrchr( buf, '.' ), ".exe" ); + if ( !ODFileAccessMode( buf, 0 )) + nReturnCode = doxspawn( buf, papszArgs, papszEnviron ); + /* If file not found, access will have set errno to ENOENT. */ + } + } + + return( nReturnCode ); +} + +#endif /* ODPLAT_DOS */ + +#ifdef ODPLAT_NIX +/* ---------------------------------------------------------------------------- + * _spawnvpe() *** PRIVATE FUNCTION *** + * + * Executes a child program in the *nix environment. + * + * Parameters: nModeFlag - Must be P_WAIT or P_NOWAIT + * + * pszPath - Name of program to execute. + * + * papszArgs - Array of command-line arguments. + * + * papszEnviron - Array of environment variables. + * + * Return: -1 on failure or the spawned-to program's return value on + * success. + */ +int _spawnvpe(int nModeFlag, char *pszPath, char *papszArgs[], + char *papszEnviron[]) +{ + pid_t child; + int status; + pid_t wret; + struct sigaction act; + + + child=fork(); + + if(nModeFlag == P_WAIT) { + /* require wait for child */ + act.sa_handler=SIG_IGN; + sigemptyset(&(act.sa_mask)); + act.sa_flags=SA_NOCLDSTOP; + sigaction(SIGCHLD,&act,NULL); + } + else { + /* Ignore SIGCHLD for backgrounded spawned processes */ + act.sa_handler=SIG_IGN; + sigemptyset(&(act.sa_mask)); + act.sa_flags=SA_NOCLDSTOP|SA_NOCLDWAIT; + sigaction(SIGCHLD,&act,NULL); + } + + if(!child) { + /* Do the exec stuff here */ + execve(pszPath,papszArgs,papszEnviron); + exit(-1); /* this should never happen! */ + } + if(nModeFlag == P_WAIT) { + wret=waitpid(child,&status,0); + if(WIFEXITED(status)) { + return(WEXITSTATUS(status)); + } + return(-1); + } + return(0); +} +#endif /* ODPLAT_NIX */ diff --git a/utils/magiedit/odoors/ODStand.c b/utils/magiedit/odoors/ODStand.c new file mode 100644 index 0000000..d2282af --- /dev/null +++ b/utils/magiedit/odoors/ODStand.c @@ -0,0 +1,226 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODStand.c + * + * Description: Implements the OpenDoors standard (default) personality. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Nov 13, 1995 6.00 BP 32-bit portability. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Dec 24, 1995 6.00 BP Fixed black square at pos 25x80. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODInEx.h" + + +/* ---------------------------------------------------------------------------- + * pdef_opendoors() + * + * Personality function for the OpenDoors standard status line / function key + * personality. + * + * Parameters: btOperation - Indicates personality operation to be performed. + * + * Return: void + */ +ODAPIDEF void ODCALL pdef_opendoors(BYTE btOperation) +{ + switch(btOperation) + { + case PEROP_DISPLAY1: + /* Display standard status line. */ + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1, 24); + ODScrnDisplayString(od_control.od_status_line[0]); + ODScrnSetCursorPos(1, 24); + ODScrnPrintf(od_control.od_status_line[1], od_control.user_name, + od_control.user_location, od_control.od_connect_speed); + ODScrnSetCursorPos(77, 24); + if(od_control.od_node < 1000) + { + ODScrnPrintf("%d]", od_control.od_node); + } + else + { + ODScrnDisplayString("?]"); + } + ODScrnSetCursorPos(1,25); + ODScrnDisplayString(od_control.od_status_line[2]); + + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + + ODScrnSetCursorPos(11,25); + ODScrnPrintf("%u",od_control.user_security); + ODScrnSetCursorPos(24,25); + ODScrnPrintf(od_control.od_time_left,od_control.user_timelimit); + if(od_control.user_ansi) + { + ODScrnSetCursorPos(40,25); + ODScrnDisplayString("[ANSI]"); + } + + if(od_control.user_avatar) + { + ODScrnSetCursorPos(47,25); + ODScrnDisplayString("[AVT]"); + } + + if(od_control.sysop_next) + { + ODScrnSetCursorPos(35,25); + ODScrnDisplayString(od_control.od_sysop_next); + } + + if(od_control.user_wantchat) + { + ODScrnSetCursorPos(57,25); + ODScrnSetAttribute(0xf0); + ODScrnDisplayString(od_control.od_want_chat); + } + + if(!od_control.od_user_keyboard_on) + { + ODScrnSetCursorPos(58,24); + ODScrnSetAttribute(0xf0); + ODScrnDisplayString(od_control.od_no_keyboard); + } + break; + + case PEROP_DISPLAY8: + /* Display help status line. */ + ODScrnSetAttribute(0x70); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + ODScrnSetCursorPos(1,24); + ODScrnDisplayString(od_control.od_help_text); + ODScrnSetCursorPos(1,25); + /* Display copyright inforomation. */ + if(bUserFull)/**/ + { + ODScrnDisplayString(od_control.od_help_text2); + } + else + { + ODScrnDisplayString(OD_VER_UNREG_STAT); + } + break; + + case PEROP_UPDATE1: + /* Update primary status line. */ + ODScrnSetAttribute(0x70); + + /* Update user's time limit. */ + ODScrnSetCursorPos(24,25); + ODScrnPrintf(od_control.od_time_left,od_control.user_timelimit); + + /* Update "sysop next" setting. */ + ODScrnSetCursorPos(35,25); + if(od_control.sysop_next) + { + ODScrnDisplayString(od_control.od_sysop_next); + } + else + { + ODScrnDisplayString(" "); + } + + /* Update ANSI mode indicator. */ + if(od_control.user_ansi) + { + ODScrnDisplayString("[ANSI] "); + } + else + { + ODScrnDisplayString(" "); + } + + /* Update AVATAR mode indicator. */ + if(od_control.user_avatar) + { + ODScrnDisplayString("[AVT] "); + } + else + { + ODScrnDisplayString(" "); + } + + /* Update keyboard-off indicator. */ + ODScrnSetCursorPos(58,24); + if(od_control.od_user_keyboard_on) + { + ODScrnDisplayString(" "); + } + else + { + ODScrnSetAttribute(0xf0); + ODScrnDisplayString(od_control.od_no_keyboard); + } + + /* Update want-chat indicator. */ + ODScrnSetCursorPos(57,25); + if(od_control.user_wantchat) + { + ODScrnSetAttribute(0xf0); + ODScrnDisplayString(od_control.od_want_chat); + } + else + { + ODScrnDisplayString(" "); + } + break; + + case PEROP_INITIALIZE: + od_control.key_hangup=0x2300; + od_control.key_drop2bbs=0x2000; + od_control.key_dosshell=0x2400; + od_control.key_chat=0x2e00; + od_control.key_sysopnext=0x3100; + od_control.key_lockout=0x2600; + od_control.key_status[0]=0x3b00; + od_control.key_status[1]=0x0000; + od_control.key_status[2]=0x0000; + od_control.key_status[3]=0x0000; + od_control.key_status[4]=0x0000; + od_control.key_status[5]=0x0000; + od_control.key_status[6]=0x0000; + od_control.key_status[7]=0x4300; + od_control.key_status[8]=0x4400; + od_control.key_keyboardoff=0x2500; + od_control.key_moretime=0x4800; + od_control.key_lesstime=0x5000; + od_control.od_page_statusline=-1; + break; + } +} diff --git a/utils/magiedit/odoors/ODStat.c b/utils/magiedit/odoors/ODStat.c new file mode 100644 index 0000000..027c64c --- /dev/null +++ b/utils/magiedit/odoors/ODStat.c @@ -0,0 +1,197 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODStat.c + * + * Description: Helper functions used by various built-in personalities. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Jul 18, 1995 6.00 BP Fix ODStatGetUserAge() bug. + * Nov 13, 1995 6.00 BP 32-bit portability. + * Nov 13, 1995 6.00 BP Created odstat.h. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Jan 12, 1996 6.00 BP Added ODStatStartArrowUse(), etc. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 13, 1996 6.10 BP bOnlyShiftArrow -> nArrowUseCount. + * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODCore.h" +#include "ODGen.h" +#include "ODStat.h" +#include "ODKrnl.h" + + +/* Global working string available to all personalities for status line */ +/* generation. */ +char szStatusText[80]; + + +/* ---------------------------------------------------------------------------- + * ODStatAddKey() + * + * Adds another hot key to the array of custom local keys. + * + * Parameters: wKeyCode - IBM scan-code/ASCII-code style key identification + * code to add. + * + * Return: void + */ +void ODStatAddKey(WORD wKeyCode) +{ + if(od_control.od_num_keys < 16) + od_control.od_hot_key[od_control.od_num_keys++] = wKeyCode; +} + + +/* ---------------------------------------------------------------------------- + * ODStatRemoveKey() + * + * Removes a custom sysop hotkey that was previously added with ODStatAddKey(). + * + * Parameters: wKeyCode - The scan code / ASCII code key identification code + * to remove. + * + * Return: void + */ +void ODStatRemoveKey(WORD wKeyCode) +{ + INT nCount; + + for(nCount = 0; nCount < od_control.od_num_keys; ++nCount) + if((WORD)od_control.od_hot_key[nCount] == wKeyCode) + { + if(nCount != od_control.od_num_keys - 1) + { + od_control.od_hot_key[nCount] = + od_control.od_hot_key[od_control.od_num_keys-1]; + } + --od_control.od_num_keys; + return; + } +} + + +/* ---------------------------------------------------------------------------- + * ODStatGetUserAge() + * + * Generates a string containing the age, in years, of the current + * user, based on the current date and the user's birthday. + * + * Parameters: pszAge - Pointer to a string where user's age should be stored. + * + * Return: void + */ +void ODStatGetUserAge(char *pszAge) +{ + INT nAge; + INT n; + time_t Time; + struct tm *TimeBlock; + + if(od_control.od_info_type==RA2EXITINFO || od_control.od_info_type==DOORSYS_WILDCAT) + { + nAge = atoi(od_control.user_birthday) - 1; + + if(strlen(od_control.user_birthday) == 8 && nAge <= 11) + { + if(od_control.user_birthday[6] >= '0' + && od_control.user_birthday[6] <= '9' + && od_control.user_birthday[7] >= '0' + && od_control.user_birthday[7] <= '9') + { + if(od_control.user_birthday[3] >= '0' + && od_control.user_birthday[3] <= '3' + && od_control.user_birthday[4] >= '0' + && od_control.user_birthday[4] <= '9') + { + Time = time(NULL); + TimeBlock = localtime(&Time); + + n = (TimeBlock->tm_year % 100) + - atoi((char *)od_control.user_birthday + 6); + + if(n < 0) nAge = n + 100; else nAge = n; + + n = atoi(od_control.user_birthday) - 1; + if(TimeBlock->tm_mon < n) + --nAge; + else if(TimeBlock->tm_mon == n) + { + n=atoi((char *)od_control.user_birthday + 3); + + if(TimeBlock->tm_mday < n) --nAge; + } + + sprintf(pszAge, "%d", nAge); + return; + } + } + } + } + + strcpy(pszAge, "?"); +} + + +/* ---------------------------------------------------------------------------- + * ODStatStartArrowUse() + * + * Called by OpenDoors when it needs to use the arrow keys, and so they + * shouldn't be used by the status line. + * + * Parameters: None + * + * Return: void + */ +void ODStatStartArrowUse(void) +{ + ++nArrowUseCount; +} + + +/* ---------------------------------------------------------------------------- + * ODStatEndArrowUse() + * + * Called by OpenDoors when it no longer needs to use the arrow keys, and so + * they can again be used by the status line. + * + * Parameters: None + * + * Return: void + */ +void ODStatEndArrowUse(void) +{ + ASSERT(nArrowUseCount > 0); + --nArrowUseCount; +} diff --git a/utils/magiedit/odoors/ODStat.h b/utils/magiedit/odoors/ODStat.h new file mode 100644 index 0000000..34aee89 --- /dev/null +++ b/utils/magiedit/odoors/ODStat.h @@ -0,0 +1,49 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODStat.h + * + * Description: Public functions provided by the odstat.c module, for status + * line functions shared among personalities. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 13, 1995 6.00 BP Created. + * Jan 12, 1996 6.00 BP Added ODStatStartArrowUse(), etc. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODSTAT +#define _INC_ODSTAT + + +/* Global working string available to all personalities for status line */ +/* generation. */ +extern char szStatusText[80]; + + +/* Public status line function prototypes. */ +void ODStatAddKey(WORD wKeyCode); +void ODStatRemoveKey(WORD wKeyCode); +void ODStatGetUserAge(char *pszAge); +void ODStatStartArrowUse(void); +void ODStatEndArrowUse(void); + + +#endif /* _INC_ODSTAT */ diff --git a/utils/magiedit/odoors/ODStr.c b/utils/magiedit/odoors/ODStr.c new file mode 100644 index 0000000..4828cde --- /dev/null +++ b/utils/magiedit/odoors/ODStr.c @@ -0,0 +1,55 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODStr.c + * + * Description: Functions used to mainuplate strings + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Aug 10, 2003 6.23 SH *nix support + */ + +#include +#include "OpenDoor.h" + +#ifdef ODPLAT_NIX +#include + +char * +od_strlwr(char *str) +{ + char *p; + + for(p=str;*p;p++) + *p=tolower(*p); + + return(str); +} + +char * +od_strupr(char *str) +{ + char *p; + + for(p=str;*p;p++) + *p=toupper(*p); + + return(str); +} +#endif diff --git a/utils/magiedit/odoors/ODStr.h b/utils/magiedit/odoors/ODStr.h new file mode 100644 index 0000000..b6f9638 --- /dev/null +++ b/utils/magiedit/odoors/ODStr.h @@ -0,0 +1,42 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODStr.h + * + * Description: Functions used to maipulate strings + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Aug 10, 2003 6.23 SH Initial rev. + */ + +#include "OpenDoor.h" + +#ifndef _INC_ODSTR +#define _INC_ODSTR + +#ifdef ODPLAT_NIX +#define strnicmp strncasecmp +#define stricmp strcasecmp +#define strlwr(x) od_strlwr(x) +#define strupr(x) od_strupr(x) +char *od_strlwr(char *str); +char *od_strupr(char *str); +#endif + +#endif diff --git a/utils/magiedit/odoors/ODSwap.asm b/utils/magiedit/odoors/ODSwap.asm new file mode 100644 index 0000000..b147d42 --- /dev/null +++ b/utils/magiedit/odoors/ODSwap.asm @@ -0,0 +1,1453 @@ +; OpenDoors Online Software Programming Toolkit +; (C) Copyright 1991 - 1999 by Brian Pirie. +; +; 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: ODSwap.asm +; +; Description: Performs EMS/disk swapping and low level spawning +; activities. This file should only be included when building +; the MS-DOS version of OpenDoors. +; +; Revisions: Date Ver Who Change +; --------------------------------------------------------------- +; Oct 13, 1994 6.00 BP New file header format. +; Feb 19, 1996 6.00 BP Changed version number to 6.00. +; Mar 03, 1996 6.10 BP Begin version 6.10. + + +; If you have increased the file handle table size so that more than 20 files +; may be open in the parent process, set FHTSZ to the new size. + +FHTSZ EQU 20 + +IFDEF LCODE +ARG_1 EQU 6 +ELSE +ARG_1 EQU 4 +ENDIF + +arena struc ; arena header +sig db 0 ; 'M' or 'Z' if last block +own dw 0 ; PSP of owner or 0 if free +siz dw 0 ; size not including header +arena ends + +vector struc +number db 0 ; vector number +flag db 0 ; 0-CURRENT,1-IRET,2-free,3-end +vseg dw 0 ; vector segment +voff dw 0 ; vector offset +vector ends + +_TEXT SEGMENT word public 'CODE' + ASSUME cs:_TEXT + ASSUME ds:nothing + ASSUME es:nothing + ASSUME ss:nothing + +; The code between slidetop and slidebot constitutes the spawn kernel. The +; kernel is copied to the front of the parent process immediately following the +; parent's PSP. The environment passed to the child is copied to immediately +; following the kernel. + +slidetop: + +path db 79 dup (0) ; program to execute +command db 128 dup (0) ; command-line +file db 79 dup (0) ; swap file + +parmblk label byte ; parameter block +environ dw 0 ; environment block +cmd dw 0,0 ; command-line tail +fcb1 dw 0,0 ; first file control block +fcb2 dw 0,0 ; second file control block + +fcb5c db 10h dup (0) ; first file control block +fcb6c db 10h dup (0) ; second file control block + +cntsvl dw 0 ; count save low +cntsvh dw 0 ; count save high +tmpcode dw 0 ; temporary return code +env dw 0 ; environment segment +envlen dw 0 ; environment length +parsz dw 0 ; parent size +ttlsz dw 0 ; total size +oldsz dw 0 ; old size +newsz dw 0 ; new size +emsseg dw 0 ; EMS page frame segment +handle dw 0 ; EMS handle +useems db 0 ; if 0, use EMS +save db 4 dup (0) ; save 4 bytes at DS:[2Eh] +f1add dd 0 ; fnish1 address +last db 0 ; if 0, last block swap +IF FHTSZ - 20 +fhtsv db FHTSZ dup (0) ; file handle table save +ENDIF + +errmsg db 'spawn error',0Dh,0Ah +msglen EQU $-errmsg + + EVEN +lclstk dw 64 dup (0) ; local stack +stktop label word ; stack top + +slide1: mov ax,cs ; install local stack + cli + mov ss,ax + mov sp,offset stktop - offset slidetop + 100h + sti + +; copy environment + + mov bx,offset slidebot - offset slidetop + 15 + 100h + mov cl,4 + shr bx,cl ; convert to paragraphs + add bx,ax ; add CS (actually PSP) +index = offset environ - offset slidetop + 100h + mov cs:[index],bx ; parameter block + mov es,bx + xor di,di +index = offset env - offset slidetop + 100h + mov ds,cs:[index] + xor si,si +index = offset envlen - offset slidetop + 100h + mov cx,cs:[index] + shr cx,1 ; translate to word count + rep movsw ; CF set if one byte left over + adc cx,cx ; CX = 1 or 0, depending CF + rep movsb ; possible final byte + + dec ax ; PSP segment + mov es,ax ; program arena header + mov bx,es:[siz] +index = offset oldsz - offset slidetop + 100h + mov cs:[index],bx ; old size + mov byte ptr es:[sig],'M' ; not last +index = offset newsz - offset slidetop + 100h + mov bx,cs:[index] ; new size + mov es:[siz],bx + + inc ax ; PSP segment + add ax,bx ; add new size + mov es,ax ; new last arena header + mov byte ptr es:[sig],'Z' ; last +index = offset last - offset slidetop + 100h + cmp byte ptr cs:[index],0 + je slide2 ; jump if last block swap + mov byte ptr es:[sig],'M' ; not last + +slide2: mov word ptr es:[own],0 ; free +index = offset ttlsz - offset slidetop + 100h + mov ax,cs:[index] ; total size + sub ax,bx ; subtract new size + dec ax ; account for arena header + mov es:[siz],ax + +; save 4 bytes destroyed by DOS 2.0 at DS:2Eh + + mov ax,cs ; PSP segment + mov es,ax + mov bx,es:[2Eh] +index = offset save - offset slidetop + 100h + mov cs:[index],bx + mov bx,es:[30h] +index = offset save - offset slidetop + 102h + mov cs:[index],bx + + mov bx,offset parmblk - offset slidetop + 100h + mov ds,ax ; PSP segment + mov dx,100h ; offset path + mov ax,4B00h ; load and execute program + int 21h + jnc slide3 ; jump if no error +index = offset tmpcode - offset slidetop + 100h + mov cs:[index],ax ; temporary return code + +slide3: mov ax,cs ; install local stack + cli + mov ss,ax + mov sp,offset stktop - offset slidetop + 100h + sti + +; restore 4 bytes destroyed by DOS 2.0 at DS:2Eh + + mov es,ax ; PSP segment +index = offset save - offset slidetop + 100h + mov bx,cs:[index] + mov es:[2Eh],bx +index = offset save - offset slidetop + 102h + mov bx,cs:[index] + mov es:[30h],bx + +index = offset oldsz - offset slidetop + 100h + mov bx,cs:[index] ; old size + mov ah,4Ah ; resize memory block + int 21h + jnc slide7 + +index = offset useems - offset slidetop + 100h +slide4: cmp byte ptr cs:[index],0 + jne slide6 ; jump if don't use EMS +index = offset handle - offset slidetop + 100h + mov dx,cs:[index] ; EMS handle + +slide5: mov ah,45h ; release handle and memory + int 67h + cmp ah,82h ; memory manager busy? + je slide5 ; jump if busy + +slide6: jmp slide18 ; exit + +index = offset parsz - offset slidetop + 100h +slide7: mov bx,cs:[index] ; parent size +index = offset ttlsz - offset slidetop + 100h + mov ax,cs:[index] ; total size + sub ax,bx ; subtract parent size + or ax,ax + jz slide9 + mov dx,cs ; PSP segment + add dx,bx ; add parent size + mov es,dx ; new last arena header + mov byte ptr es:[sig],'Z' ; last +index = offset last - offset slidetop + 100h + cmp byte ptr cs:[index],0 + je slide8 ; jump if last block swap + mov byte ptr es:[sig],'M' ; not last + +slide8: mov word ptr es:[own],0 ; free + dec ax ; account for arena header + mov es:[siz],ax + +slide9: push cs ; PSP segment +index = offset useems - offset slidetop + 100h + cmp byte ptr cs:[index],0 + jne slide14 ; jump if don't use EMS + pop es ; PSP segment + mov di,offset slidebot - offset slidetop + 100h +index = offset emsseg - offset slidetop + 100h + mov ds,cs:[index] ; EMS page frame segment + mov si,offset slidebot - offset slidetop +index = offset handle - offset slidetop + 100h + mov dx,cs:[index] ; EMS handle + xor bx,bx ; logical page number + mov cx,16384 - ( offset slidebot - offset slidetop ) + jmp short slide13 + +index = offset cntsvl - offset slidetop + 100h +slide10: sub cs:[index],cx +index = offset cntsvh - offset slidetop + 100h + sbb word ptr cs:[index],0 + xor al,al ; physical page number + +slide11: mov ah,44h ; map memory + int 67h + or ah,ah + jz slide12 + cmp ah,82h ; memory manager busy? + je slide11 ; jump if busy + jmp slide4 ; exit + +slide12: shr cx,1 ; translate to word count + rep movsw ; CF set if one byte left over + adc cx,cx ; CX = 1 or 0, depending CF + rep movsb ; possible final byte + xor si,si + mov cx,16384 ; assume copy full block + inc bx ; logical page number + cmp bx,1 + je slide13 + mov ax,es + add ax,1024 ; 16384 bytes + mov es,ax + mov di,16640 ; 16384 + 100h + +index = offset cntsvh - offset slidetop + 100h +slide13: cmp word ptr cs:[index],0 + jne slide10 ; jump if more than full block +index = offset cntsvl - offset slidetop + 100h + cmp cs:[index],cx + jae slide10 ; jump if at least full block + mov cx,cs:[index] ; CX = cntsvl + cmp cx,0 + jne slide10 ; jump if more left to copy + jmp short slide17 + +slide14: pop ds ; PSP segment +IF FHTSZ - 20 + +; restore the file handle table from the kernel + + mov si,offset fhtsv - offset slidetop + 100h + mov es,ds:[36h] ; file handle table segment + mov di,ds:[34h] ; file handle table offset + mov cx,FHTSZ ; file handle table size + rep movsb +ENDIF + mov dx,offset file - offset slidetop + 100h + mov ax,3D00h ; open file read only + int 21h + jc slide18 ; exit if error + mov bx,ax ; handle + + xor cx,cx + mov dx,offset slidebot - offset slidetop + mov ax,4200h ; move file pointer + int 21h ; from beginning of file + + mov dx,offset slidebot - offset slidetop + 100h + mov cx,65520 ; assume read full block + jmp short slide16 + +index = offset cntsvl - offset slidetop + 100h +slide15: sub cs:[index],cx +index = offset cntsvh - offset slidetop + 100h + sbb word ptr cs:[index],0 + mov ah,3Fh ; read file + int 21h + jc slide18 ; exit if error + cmp ax,cx + jne slide18 ; exit if not all read + + mov ax,ds + add ax,4095 ; 65520 bytes + mov ds,ax + +index = offset cntsvh - offset slidetop + 100h +slide16: cmp word ptr cs:[index],0 + jne slide15 ; jump if more than full block +index = offset cntsvl - offset slidetop + 100h + cmp word ptr cs:[index],65520 + jae slide15 ; jump if at least full block + mov cx,cs:[index] ; CX = cntsvl + cmp cx,0 + jne slide15 ; jump if more left to read + +index = offset tmpcode - offset slidetop + 100h +slide17: mov ax,cs:[index] ; temporary return code +index = offset f1add - offset slidetop + 100h + jmp dword ptr cs:[index] + +slide18: push cs ; PSP segment + pop ds + mov dx,offset errmsg - offset slidetop + 100h + mov cx,msglen ; errmsg length + mov bx,2 ; standard error device handle + mov ah,40h ; write error message + int 21h + mov ax,4C01h ; terminate with return code + int 21h + +handler: iret ; interrupt handler + +slidebot: + +cntl dw 0 ; count low +cnth dw 0 ; count high +stks dw 0 ; original SS contents +stkp dw 0 ; original SP contents +psp dw 0 ; PSP segment +s1add dd 0 ; slide1 address +rcode dw 0 ; return code +useems2 db 0 ; if 0, use EMS +vtabseg dw 0 ; vectab1 segment +vtaboff dw 0 ; vectab1 offset + +errmsg2 db 'spawn error',0Dh,0Ah +msglen2 EQU $-errmsg2 + +; +; int _xspawn( char *, char *, char *, VECTOR *, int, int, char *, int ); +; + + PUBLIC __xspawn +IFDEF LCODE +__xspawn PROC far +ELSE +__xspawn PROC near +ENDIF + + push bp + mov bp,sp + push di ; preserve register variables + push si + push ds + +IFDEF LDATA + lds si,dword ptr [bp+ARG_1] +ELSE + mov si,word ptr [bp+ARG_1] +ENDIF + mov di,offset path + +start1: mov al,ds:[si] ; copy path string + mov cs:[di],al ; to code segment + inc si + inc di + or al,al ; null char? + jnz start1 ; no, get next char + +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+4] +ELSE + mov si,word ptr [bp+ARG_1+2] +ENDIF + mov bx,si ; preserve si + mov di,offset command + mov cx,2 ; account for count and '\r' + add cl,byte ptr ds:[bx] ; add count byte + +start2: mov al,ds:[bx] ; copy command + mov cs:[di],al ; to code segment + inc bx + inc di + loop start2 ; get next char + + inc si ; skip count byte + push cs + pop es + mov di,offset fcb5c + mov ax,2901h ; parse filename + int 21h ; skip leading separators + mov di,offset fcb6c + mov al,1 ; parse filename + int 21h ; skip leading separators + +IFDEF LDATA + mov ax,word ptr [bp+ARG_1+8] +ELSE + mov ax,word ptr [bp+ARG_1+4] +ENDIF + mov cl,4 + shr ax,cl ; convert to paragraphs +IFDEF LDATA + mov bx,word ptr [bp+ARG_1+10] +ELSE + mov bx,ds +ENDIF + add ax,bx + mov cs:[env],ax ; environment segment + +IFDEF LDATA + lds bx,dword ptr [bp+ARG_1+12] ; vectab1 +ELSE + mov bx,word ptr [bp+ARG_1+6] ; vectab1 +ENDIF + mov cs:[vtabseg],ds ; vectab1 segment + mov cs:[vtaboff],bx ; vectab1 offset + + mov cs:[stks],ss ; original SS contents + mov cs:[stkp],sp ; original SP contents + mov cs:[rcode],0 ; assume success + +IFDEF LDATA + mov ax,word ptr [bp+ARG_1+16] +ELSE + mov ax,word ptr [bp+ARG_1+8] +ENDIF + or ax,ax ; do swap? + jz start3 ; yes, jump + jmp noswap1 + +IFDEF LDATA +start3: mov ax,word ptr [bp+ARG_1+18] +ELSE +start3: mov ax,word ptr [bp+ARG_1+10] +ENDIF + mov cs:[envlen],ax ; environment length + add ax,offset slidebot - offset slidetop + 30 + 100h + mov cl,4 + shr ax,cl ; convert to paragraphs + mov cs:[newsz],ax ; new size + +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+20] +ELSE + mov si,word ptr [bp+ARG_1+12] +ENDIF + mov di,offset file + mov cs:[useems2],1 ; assume don't use EMS + cmp byte ptr ds:[si],0 + jne start4 + mov cs:[useems2],0 ; use EMS + +start4: mov al,ds:[si] ; copy file string + mov cs:[di],al ; to code segment + inc si + inc di + or al,al ; null char? + jnz start4 ; no, get next char + +; save fnish1 address + + mov word ptr cs:[f1add+2],cs + mov word ptr cs:[f1add],offset fnish1 + +; initialize parameter block + + mov ax,cs:[psp] ; PSP segment + mov cs:[cmd],offset command - offset slidetop + 100h + mov cs:[cmd+2],ax + mov cs:[fcb1],offset fcb5c - offset slidetop + 100h + mov cs:[fcb1+2],ax + mov cs:[fcb2],offset fcb6c - offset slidetop + 100h + mov cs:[fcb2+2],ax + + cld ; left to right direction + + mov ds,ax ; PSP segment +IFDEF LDATA + mov dx,word ptr [bp+ARG_1+24] +ELSE + mov dx,word ptr [bp+ARG_1+14] +ENDIF +IF FHTSZ - 20 + cmp word ptr ds:[32h],FHTSZ ; file handle table size + je start5 ; jump if OK + mov cs:[rcode],5 + jmp short start6 +ENDIF + +start5: mov ax,cs:[newsz] ; new size + cmp ax,cs:[ttlsz] ; new size < total size? + jb start8 ; yes, jump + mov cs:[rcode],7 ; extremely unlikely + +start6: cmp cs:[useems2],0 + jne start7 ; jump if don't use EMS + jmp fnish2 + +start7: mov bx,dx ; file handle + jmp fnish6 + +start8: cmp cs:[useems2],0 + jne start12 ; jump if don't use EMS + mov cs:[useems],0 ; use EMS + mov cs:[handle],dx ; EMS handle + mov es,cs:[emsseg] ; EMS page frame segment + xor bx,bx ; logical page number + jmp short start11 + +start9: sub cs:[cntl],cx + sbb cs:[cnth],0 + call mapems + or ah,ah + jz start10 ; jump if map succeeded + jmp fnish2 + +start10: mov si,100h + xor di,di + shr cx,1 ; translate to word count + rep movsw ; CF set if one byte left over + adc cx,cx ; CX = 1 or 0, depending CF + rep movsb ; possible final byte + inc bx ; logical page number + mov ax,ds + add ax,1024 ; 16384 bytes + mov ds,ax + +start11: mov cx,16384 ; assume copy full block + cmp cs:[cnth],0 + jne start9 ; jump if more than full block + cmp cs:[cntl],16384 + jae start9 ; jump if at least full block + mov cx,cs:[cntl] + cmp cx,0 + jne start9 ; jump if more left to copy + jmp short start17 + +start12: mov cs:[useems],1 ; don't use EMS + mov bx,dx ; handle + mov dx,100h ; DS:DX segment:offset buffer + mov cx,65520 ; assume write full block + jmp short start16 + +start13: sub cs:[cntl],cx + sbb cs:[cnth],0 + mov ah,40h ; write file + int 21h + jc start14 ; jump if error + cmp ax,cx + je start15 ; jump if all written + +start14: mov ah,3Eh ; close file + int 21h + mov cs:[rcode],5 + jmp fnish7 + +start15: mov ax,ds + add ax,4095 ; 65520 bytes + mov ds,ax + +start16: cmp cs:[cnth],0 + jne start13 ; jump if more than full block + cmp cs:[cntl],65520 + jae start13 ; jump if at least full block + mov cx,cs:[cntl] + cmp cx,0 + jne start13 ; jump if more left to write + + mov ah,3Eh ; close file + int 21h +IF FHTSZ - 20 + +; save the file handle table in the kernel + + mov es,cs:[psp] ; PSP segment + mov ds,es:[36h] ; file handle table segment + mov si,es:[34h] ; file handle table offset + push cs + pop es + mov di,offset fhtsv ; file handle table save + mov cx,FHTSZ ; file handle table size + rep movsb +ENDIF + +start17: mov cx,cs + mov dx,offset handler ; interrupt handler offset + call safevect ; set vectors in vectab1 + +; time to copy the kernel + + mov es,cs:[psp] ; PSP segment + mov di,100h + mov ds,cx ; DS = CS + mov si,offset slidetop + mov cx,offset slidebot - offset slidetop + shr cx,1 ; translate to word count + rep movsw ; CF set if one byte left over + adc cx,cx ; CX = 1 or 0, depending CF + rep movsb ; possible final byte + + mov word ptr cs:[s1add+2],es ; PSP segment +index = offset slide1 - offset slidetop + 100h + mov word ptr cs:[s1add],index ; slide1 offset + + mov cx,es ; PSP segment +index = offset handler - offset slidetop + 100h + mov dx,index ; interrupt handler offset + call safevect ; set vectors in vectab1 + + jmp dword ptr cs:[s1add] ; jump to the kernel + +; If all goes well, this is where we come back to from the kernel. + +fnish1: mov cs:[rcode],ax ; return code + + cli ; restore original stack + mov ss,cs:[stks] + mov sp,cs:[stkp] + sti + + push ds ; maybe EMS page frame segment + push dx ; maybe EMS handle + push bx ; maybe swap file handle + mov cx,cs + mov dx,offset handler ; interrupt handler offset + call safevect ; set vectors in vectab1 + pop bx + pop dx + pop ds + + cmp cs:[useems2],0 + jne fnish4 ; jump if don't use EMS + +; DS = EMS page frame segment +; DX = EMS handle + + mov cx,offset slidebot - offset slidetop + mov es,cs:[psp] ; PSP segment + mov di,100h + xor si,si + xor bx,bx ; logical page number + call mapems + or ah,ah + jnz fnish3 ; jump if map failed + shr cx,1 ; translate to word count + rep movsw ; CF set if one byte left over + adc cx,cx ; CX = 1 or 0, depending CF + rep movsb ; possible final byte + +fnish2: mov ah,45h ; release handle and memory + int 67h + cmp ah,82h ; memory manager busy? + je fnish2 ; jump if busy + jmp short fnish7 + +fnish3: mov ah,45h ; release handle and memory + int 67h + cmp ah,82h ; memory manager busy? + je fnish3 ; jump if busy + jmp short fnish5 ; exit + +; BX = swap file handle + +fnish4: xor cx,cx ; offset 0 + xor dx,dx ; offset 0 + mov ax,4200h ; move file pointer + int 21h ; from beginning of file + + mov cx,offset slidebot - offset slidetop + mov ds,cs:[psp] ; PSP segment + mov dx,100h + mov ah,3Fh ; read file + int 21h + jc fnish5 ; exit if error + cmp ax,cx + je fnish6 + +fnish5: push cs + pop ds + mov dx,offset errmsg2 + mov cx,msglen2 ; errmsg2 length + mov bx,2 ; standard error device handle + mov ah,40h ; write error message + int 21h + mov ax,4C01h ; terminate with return code + int 21h + +fnish6: mov ah,3Eh ; close file + int 21h + push cs + pop ds + mov dx,offset file + mov ah,41h ; delete file + int 21h + +fnish7: pop ds + pop si ; restore register variables + pop di + pop bp + + mov ax,cs:[rcode] ; return code + or ax,ax + jz fnish11 + push ax + mov ax,3000h ; get DOS version number + int 21h + cmp al,3 ; major version number + pop ax + jb fnish8 + cmp al,34 ; unknown error - 3.0 + jae fnish9 + cmp al,32 ; sharing violation + jb fnish8 + mov al,5 ; access denied + jmp short fnish10 + +fnish8: cmp al,19 ; unknown error - 2.0 + jbe fnish10 + +fnish9: mov al,19 ; unknown error - 2.0 + +fnish10: xor ah,ah + +fnish11: ret + +; If we are not swapping, we jump here. + +noswap1: mov ax,cs + +; initialize parameter block + + mov bx,cs:[env] + mov cs:[environ],bx + mov cs:[cmd],offset command + mov cs:[cmd+2],ax + mov cs:[fcb1],offset fcb5c + mov cs:[fcb1+2],ax + mov cs:[fcb2],offset fcb6c + mov cs:[fcb2+2],ax + +; save 4 bytes destroyed by DOS 2.0 at DS:2Eh + + mov si,cs:[2Eh] + mov word ptr cs:[save],si + mov si,cs:[30h] + mov word ptr cs:[save+2],si + + mov cx,cs + mov dx,offset handler ; interrupt handler offset + call safevect ; set vectors in vectab1 + + mov es,cx ; ES = CS + mov bx,offset parmblk + mov ds,cx ; DS = CS + mov dx,offset path + mov ax,4B00h ; load and execute program + int 21h + jnc noswap2 ; jump if no error + mov cs:[rcode],ax ; return code + +noswap2: cli ; restore original stack + mov ss,cs:[stks] + mov sp,cs:[stkp] + sti + +; restore 4 bytes destroyed by DOS 2.0 at DS:2Eh + + mov si,word ptr cs:[save] + mov cs:[2Eh],si + mov si,word ptr cs:[save+2] + mov cs:[30h],si + + jmp fnish7 + +__xspawn ENDP + +mapems PROC near + +; DX = handle +; BX = logical page number + + xor al,al ; physical page number + +map1: mov ah,44h ; map memory + int 67h + cmp ah,82h ; memory manager busy? + je map1 ; jump if busy + + ret + +mapems ENDP + +setvectsub PROC near + +; ES = vector table segment +; BX = vector table offset + + mov ah,25h ; set interrupt vector + +setvectsub1: mov al,es:[bx+flag] ; 0-CURRENT,1-IRET,2-free,3-end + cmp al,3 ; is it the end? + je setvectsub3 ; yes, jump + cmp al,2 ; is it free? + je setvectsub2 ; yes, jump + mov al,es:[bx+number] ; vector number + mov ds,es:[bx+vseg] ; vector segment + mov dx,es:[bx+voff] ; vector offset + int 21h ; set interrupt vector + +setvectsub2: add bx,6 ; size of vector structure + jmp setvectsub1 ; next + +setvectsub3: ret + +setvectsub ENDP + +safevect PROC near + +; CX = handler segment +; DX = handler offset + + mov es,cs:[vtabseg] ; vectab1 segment + mov bx,cs:[vtaboff] ; vectab1 offset + +safevect1: mov al,es:[bx+flag] ; 0-CURRENT,1-IRET,2-free,3-end + cmp al,3 ; is it the end? + je safevect3 ; yes, jump + cmp al,1 ; is it IRET? + jne safevect2 ; no, jump + mov es:[bx+vseg],cx ; handler segment + mov es:[bx+voff],dx ; handler offset + +safevect2: add bx,6 ; size of vector structure + jmp safevect1 ; next + +safevect3: mov bx,cs:[vtaboff] ; vectab1 offset + call setvectsub + + ret + +safevect ENDP + +; +; int _xsize( unsigned int, long *, long * ); +; + + PUBLIC __xsize +IFDEF LCODE +__xsize PROC far +ELSE +__xsize PROC near +ENDIF + + push bp + mov bp,sp + push di ; preserve register variables + push si + push ds + + mov cs:[last],0 ; assume last block swap + mov bx,word ptr [bp+ARG_1] ; PSP segment + mov cs:[psp],bx + mov dx,bx + dec bx ; program arena header + +size1: mov es,bx ; current arena header + mov ax,es:[own] + or ax,ax ; is it free? + jz size2 ; yes, count it + cmp ax,dx ; do we own it? + jne size4 ; no, jump + mov cx,bx ; last owned block + +size2: inc bx + add bx,es:[siz] ; block size + jc size3 ; carry, arena is trashed + mov al,es:[sig] ; get arena signature + cmp al,'M' ; are we at end of memory? + je size1 ; no, jump + cmp al,'Z' + je size5 + +size3: mov bx,-1 ; request maximum memory + mov ah,48h ; allocate memory block + int 21h + mov cs:[rcode],7 + jmp fnish7 + +size4: mov cs:[last],1 ; not last block swap + +size5: sub bx,dx ; subtract PSP segment + mov ax,cx ; last owned block + mov es,cx + inc ax + add ax,es:[siz] ; block size + sub ax,dx ; subtract PSP segment + mov cs:[parsz],ax ; parent size + sub ax,10h ; subtract PSP size + xor dx,dx ; convert to bytes + mov cx,4 + +size6: shl ax,1 + rcl dx,1 + loop size6 +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+2] +ELSE + mov si,word ptr [bp+ARG_1+2] +ENDIF + mov ds:[si],ax ; swap size requirement + mov ds:[si+2],dx + mov cs:[cntl],ax ; count low + mov cs:[cnth],dx ; count high + mov cx,offset slidebot - offset slidetop + sub ax,cx + sbb dx,0 + mov cs:[cntsvl],ax ; count save low + mov cs:[cntsvh],dx ; count save high + mov cs:[ttlsz],bx ; total size + xor dx,dx ; convert to bytes + mov cx,4 + +size7: shl bx,1 + rcl dx,1 + loop size7 +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+6] +ELSE + mov si,word ptr [bp+ARG_1+4] +ENDIF + mov ds:[si],bx ; parent and free memory + mov ds:[si+2],dx + + pop ds + pop si ; restore register variables + pop di + pop bp + xor ax,ax + ret + +__xsize ENDP + +; +; int _chkems( char *, int * ); +; + + PUBLIC __chkems +IFDEF LCODE +__chkems PROC far +ELSE +__chkems PROC near +ENDIF + + push bp + mov bp,sp + +; determine whether expanded memory is available + +IFDEF LDATA + push ds + lds dx,dword ptr [bp+ARG_1] ; EMM device driver name +ELSE + mov dx,word ptr [bp+ARG_1] ; EMM device driver name +ENDIF + mov ax,3D00h ; open file read only + int 21h +IFDEF LDATA + pop ds +ENDIF + jc check2 ; expanded memory unavailable + +; determine whether we opened the EMM device driver or a file + + mov bx,ax ; handle + mov ax,4400h ; IOCTL - get device info + int 21h + jc check1 ; expanded memory unavailable + test dx,80h ; test bit 7 + jz check1 ; expanded memory unavailable + + mov ax,4407h ; IOCTL - get output status + int 21h + jc check1 ; expanded memory unavailable + or al,al + jz check1 ; expanded memory unavailable + +; close EMM device driver to reclaim handle + + mov ah,3Eh ; close file + int 21h + +; determine whether the EMM is functional + + mov ah,40h ; get manager status + int 67h + or ah,ah + jnz check2 ; expanded memory unavailable + +; check EMM version + + mov ah,46h ; get EMM version + int 67h + or ah,ah + jnz check2 ; expanded memory unavailable + cmp al,32h ; version 3.2 + jb check2 ; expanded memory unavailable + +; get page frame segment + + mov ah,41h ; get page frame segment + int 67h + or ah,ah + jnz check2 ; expanded memory unavailable + mov cs:[emsseg],bx ; segment + +; get size of page map information + + mov ax,4E03h ; get size of page map info + int 67h + or ah,ah + jnz check2 ; expanded memory unavailable +IFDEF LDATA + les bx,dword ptr [bp+ARG_1+4] ; mapsize address + mov es:[bx],ax +ELSE + mov bx,word ptr [bp+ARG_1+2] ; mapsize address + mov ds:[bx],ax +ENDIF + xor ax,ax ; expanded memory available + pop bp + ret + +; close EMM device driver or file to reclaim handle + +check1: mov ah,3Eh ; close file + int 21h + +check2: mov ax,1 ; expanded memory unavailable + pop bp + ret + +__chkems ENDP + +; +; int _savemap( char * ); +; + + PUBLIC __savemap +IFDEF LCODE +__savemap PROC far +ELSE +__savemap PROC near +ENDIF + + push bp + mov bp,sp + push di ; preserve register variable + +IFDEF LDATA + les di,dword ptr [bp+ARG_1] ; buffer address +ELSE + mov di,word ptr [bp+ARG_1] ; buffer address + push ds + pop es +ENDIF + mov ax,4E00h ; save page map + int 67h + + pop di ; restore register variable + pop bp + ret + +__savemap ENDP + +; +; int _restmap( char * ); +; + + PUBLIC __restmap +IFDEF LCODE +__restmap PROC far +ELSE +__restmap PROC near +ENDIF + + push bp + mov bp,sp + push ds + push si ; preserve register variable + +IFDEF LDATA + lds si,dword ptr [bp+ARG_1] ; buffer address +ELSE + mov si,word ptr [bp+ARG_1] ; buffer address +ENDIF + mov ax,4E01h ; restore page map + int 67h + xor al,al + + pop si ; restore register variable + pop ds + pop bp + ret + +__restmap ENDP + +; +; int _getems( int, int * ); +; + + PUBLIC __getems +IFDEF LCODE +__getems PROC far +ELSE +__getems PROC near +ENDIF + + push bp + mov bp,sp + + mov bx,word ptr [bp+ARG_1] ; number of pages + mov ah,43h ; get handle and allocate + ; memory + int 67h +IFDEF LDATA + les bx,dword ptr [bp+ARG_1+2] ; handle address + mov es:[bx],dx ; handle +ELSE + mov bx,word ptr [bp+ARG_1+2] ; handle address + mov ds:[bx],dx ; handle +ENDIF + xor al,al + pop bp + ret + +__getems ENDP + +; +; int _dskspace( int, unsigned int *, unsigned int * ); +; + + PUBLIC __dskspace +IFDEF LCODE +__dskspace PROC far +ELSE +__dskspace PROC near +ENDIF + + push bp + mov bp,sp + push di ; preserve register variable + + mov ah,36h ; get free disk space + mov dl,byte ptr [bp+ARG_1] ; drive code (0=default, 1=A) + int 21h + cmp ax,0FFFFh ; was drive invalid? + je space1 ; yes, jump + mul cx ; bytes per sector * + ; sectors per cluster +IFDEF LDATA + les di,dword ptr [bp+ARG_1+2] + mov es:[di],ax ; bytes per cluster +ELSE + mov di,word ptr [bp+ARG_1+2] + mov ds:[di],ax ; bytes per cluster +ENDIF +IFDEF LDATA + les di,dword ptr [bp+ARG_1+6] + mov es:[di],bx ; number of available clusters +ELSE + mov di,word ptr [bp+ARG_1+4] + mov ds:[di],bx ; number of available clusters +ENDIF + xor ax,ax + +space1: pop di ; restore register variable + pop bp + ret + +__dskspace ENDP + +; +; int _getrc( void ); +; + + PUBLIC __getrc +IFDEF LCODE +__getrc PROC far +ELSE +__getrc PROC near +ENDIF + + mov ah,4Dh ; get child return code + int 21h + + ret + +__getrc ENDP + +; +; int _create( char *, int * ); +; + + PUBLIC __create +IFDEF LCODE +__create PROC far +ELSE +__create PROC near +ENDIF + + push bp + mov bp,sp +IFDEF LDATA + push ds +ENDIF + + mov ax,3000h ; get DOS version number + int 21h +IFDEF LDATA + lds dx,dword ptr [bp+ARG_1] ; file +ELSE + mov dx,word ptr [bp+ARG_1] ; file +ENDIF + xor cx,cx ; normal attribute + mov ah,5Bh ; create new file + cmp al,3 ; major version number + jae create1 + mov ah,3Ch ; create file + +create1: int 21h + jc create2 +IFDEF LDATA + lds bx,dword ptr [bp+ARG_1+4] ; handle address +ELSE + mov bx,word ptr [bp+ARG_1+2] ; handle address +ENDIF + mov ds:[bx],ax + xor ax,ax + +create2: +IFDEF LDATA + pop ds +ENDIF + pop bp + ret + +__create ENDP + + +; +; int _getcd( int, char * ); +; + + + PUBLIC __getcd +IFDEF LCODE +__getcd PROC far +ELSE +__getcd PROC near +ENDIF + + push bp + mov bp,sp + push si ; preserve register variable +IFDEF LDATA + push ds +ENDIF + + mov dl,byte ptr [bp+ARG_1] ; drive code (0=default, 1=A) +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+2] ; buffer +ELSE + mov si,word ptr [bp+ARG_1+2] ; buffer +ENDIF + mov ah,47h ; get current directory + int 21h + jc getcd1 + xor ax,ax + +getcd1: +IFDEF LDATA + pop ds +ENDIF + pop si ; restore register variable + pop bp + ret + +__getcd ENDP + +; +; int _getdrv( void ); +; + + PUBLIC __getdrv +IFDEF LCODE +__getdrv PROC far +ELSE +__getdrv PROC near +ENDIF + + mov ah,19h ; get default disk drive + int 21h + xor ah,ah + +; AX = drive (0 = A, 1 = B, etc.) + + ret + +__getdrv ENDP + +; +; void _getvect( int, unsigned int *, unsigned int * ); +; + + PUBLIC __getvect +IFDEF LCODE +__getvect PROC far +ELSE +__getvect PROC near +ENDIF + + push bp + mov bp,sp + push ds + push si ; preserve register variable + + mov ah,35h ; get interrupt vector + mov al,byte ptr [bp+ARG_1] ; interrupt number + int 21h +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+2] +ELSE + mov si,word ptr [bp+ARG_1+2] +ENDIF + mov ds:[si],es ; segment +IFDEF LDATA + lds si,dword ptr [bp+ARG_1+6] +ELSE + mov si,word ptr [bp+ARG_1+4] +ENDIF + mov ds:[si],bx ; offset + + pop si ; restore register variable + pop ds + pop bp + ret + +__getvect ENDP + +; +; void _setvect( VECTOR * ); +; + + PUBLIC __setvect +IFDEF LCODE +__setvect PROC far +ELSE +__setvect PROC near +ENDIF + + push bp + mov bp,sp + push ds ; modified in setvectsub + +IFDEF LDATA + les bx,dword ptr [bp+ARG_1] ; vector table +ELSE + mov bx,word ptr [bp+ARG_1] ; vector table + push ds + pop es +ENDIF + + call setvectsub + + pop ds + pop bp + ret + +__setvect ENDP + + +; +; void _setdrvcd(int drive, char * string); +; + + PUBLIC __setdrvcd +IFDEF LCODE +__setdrvcd PROC far +ELSE +__setdrvcd PROC near +ENDIF + push bp + mov bp,sp +IFDEF LDATA + push ds +ENDIF + mov dl,byte ptr [bp+ARG_1] ; drive code (0=A, 1=B) + mov ah,0eh + int 21h +IFDEF LDATA + lds dx,dword ptr [bp+ARG_1+2] ; buffer +ELSE + mov dx,word ptr [bp+ARG_1+2] ; buffer +ENDIF + mov ah,3bh ; set current directory + int 21h + +IFDEF LDATA + pop ds +ENDIF + pop bp + ret + +__setdrvcd ENDP + +_TEXT ENDS + + END + diff --git a/utils/magiedit/odoors/ODSwap.h b/utils/magiedit/odoors/ODSwap.h new file mode 100644 index 0000000..d1d0e16 --- /dev/null +++ b/utils/magiedit/odoors/ODSwap.h @@ -0,0 +1,68 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODSwap.h + * + * Description: Provides memory swapping, spawning and certain other low- + * level assembly routines needed by OpenDoors. This file is only + * applicable when building the MS-DOS version of OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 25, 1995 6.00 BP Created. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODSWAP +#define _INC_ODSWAP + +#ifdef ODPLAT_DOS + +/* Data types. */ +typedef struct _vector +{ + char number; /* vector number */ + char flag; /* 0-CURRENT, 1-IRET, 2-free, 3-end */ + unsigned int vseg; /* vector segment */ + unsigned int voff; /* vector offset */ +} VECTOR; + +/* Global variables. */ +extern char **environ; + +/* Public functions. */ +int _chkems(char *, int *); +int _create(char *, int *); +int _dskspace(int, unsigned int *, unsigned int *); +int _getcd(int, char *); +int _getdrv(void); +int _getems(int, int *); +int _getrc(void); +void _getvect(int, unsigned int *, unsigned int *); +int _restmap(char *); +int _savemap(char *); +void _setdrvcd(int, char * ); +void _setvect(VECTOR *); +int _xsize(unsigned int, long *, long *); +int _xspawn(char *, char *, char *, VECTOR *, int, int, char *, int); + +#endif /* ODPLAT_DOS */ + + +#endif /* _INC_ODSWAP */ diff --git a/utils/magiedit/odoors/ODTypes.h b/utils/magiedit/odoors/ODTypes.h new file mode 100644 index 0000000..c93a286 --- /dev/null +++ b/utils/magiedit/odoors/ODTypes.h @@ -0,0 +1,70 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODTypes.c + * + * Description: Defines special data types used by OpenDoors. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 15, 1994 6.00 BP Created. + * Jan 30, 1996 6.00 BP Added kODRCTimeout. + * Feb 08, 1996 6.00 BP Added kODRCSafeFailure. + * Feb 08, 1996 6.00 BP Added kODRCUnrecoverableFailure. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + */ + +#ifndef _INC_ODTYPES +#define _INC_ODTYPES + +/* Generic handle data type. */ +typedef void * tODHandle; +#define ODHANDLE2PTR(h, t) ((t *) h) +#define ODPTR2HANDLE(p, t) ((tODHandle) p) + +/* OpenDoors function call result codes. */ +typedef enum +{ + kODRCSuccess, + kODRCGeneralFailure, + kODRCNoMemory, + kODRCNothingWaiting, + kODRCNoMatch, + kODRCEndOfFile, + kODRCNoPortAddress, + kODRCNoUART, + kODRCInvalidCall, + kODRCFileAccessError, + kODRCFilenameTooLong, + kODRCTimeout, + kODRCSafeFailure, + kODRCUnrecoverableFailure, + kODRCUnsupported +} tODResult; + +/* Callback function types. */ +#ifdef _MSC_VER +typedef void ODCALL OD_COMPONENT_CALLBACK(void); +typedef void ODCALL OD_PERSONALITY_CALLBACK(BYTE btOperation); +#else /* !_MSC_VER */ +typedef void OD_COMPONENT_CALLBACK(void); +typedef void OD_PERSONALITY_CALLBACK(BYTE btOperation); +#endif /* !_MSC_VER */ + +#endif /* !_INC_ODTYPES */ diff --git a/utils/magiedit/odoors/ODUtil.c b/utils/magiedit/odoors/ODUtil.c new file mode 100644 index 0000000..5078f04 --- /dev/null +++ b/utils/magiedit/odoors/ODUtil.c @@ -0,0 +1,461 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODUtil.c + * + * Description: Implements the non-platform specific utility functions that + * are defined in odutil.h. Platform specific utility functions + * are implemented in odplat.c. + * + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 01, 1994 6.00 BP Created. + * Dec 31, 1994 6.00 BP Added ODMakeFilename(). + * Nov 13, 1995 6.00 BP 32-bit portability. + * Nov 23, 1995 6.00 BP Added ODDWordDivide(). + * Nov 23, 1995 6.00 BP Added ODDStringHasTail(). + * Nov 23, 1995 6.00 BP Added ODFileSize(). + * Nov 24, 1995 6.00 BP ODMakeFilename(): handle empty path. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Added ODDWordMultiply(). + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include + +#include "OpenDoor.h" +#include "ODStr.h" +#include "ODUtil.h" +#include "ODGen.h" + + +/* ========================================================================= */ +/* General string manipulation functions. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODStringCopy() + * + * Safely copies one string to another. Unlike strncpy(), ODStringCopy() + * ensures that the destination string is always '\0' terminated. + * + * Parameters: pszDest - Pointer to destination string to which to copy + * characters. + * + * pszSource - Pointer to source string from which to copy + * characters. + * + * nSizeOfDest - Maximum number of characters to place in pszDest, + * INCLUDING the '\0' string terminator. + * + * Return: void + */ +void ODStringCopy(char *pszDest, CONST char *pszSource, INT nSizeofDest) +{ + ASSERT(pszDest != NULL); + ASSERT(pszSource != NULL); + ASSERT(nSizeofDest > 0); + + /* Copy at most the specified number of bytes from source to dest, using */ + /* (presumably well optimized) strncpy(). */ + strncpy(pszDest, pszSource, nSizeofDest); + + /* Ensure that destination string is '\0' terminated. This will not */ + /* already be the case if strlen(pszSource) >= nSizeofDest. */ + pszDest[nSizeofDest - 1] = '\0'; +} + + +/* ---------------------------------------------------------------------------- + * ODStringCToPascal() + * + * Converts a string from C's zero-terminated string format to Pascal's + * length byte + string data format. + * + * Parameters: psPascalString - Pointer to the destination string. + * + * btMaxPascalLength - Size of the destination string, as declared + * in Pascal. + * + * pszCString - Pointer to the source string, in C format. + * + * Return: A pointer to psPascalString. + */ +char *ODStringCToPascal(char *psPascalString, BYTE btMaxPascalLength, + char *pszCString) +{ + BYTE btCStringLength = strlen(pszCString); + + ASSERT(psPascalString != NULL); + ASSERT(btMaxPascalLength > 0); + ASSERT(pszCString != NULL); + + memcpy((char *)psPascalString + 1, + pszCString, *psPascalString = (btCStringLength < btMaxPascalLength) + ? btCStringLength : btMaxPascalLength); + return(psPascalString); +} + + +/* ---------------------------------------------------------------------------- + * ODStringPascalToC() + * + * Converts a string from Pascal's length byte + string data format to C's + * zero-terminated string format. + * + * Parameters: pszCString - Pointer to destination string. + * + * psPascalString - Pointer to Pascal format source string. + * + * btMaxLength - Length of C string. + * + * Return: A pointer to pszCString. + */ +char *ODStringPascalToC(char *pszCString, char *psPascalString, + BYTE btMaxLength) +{ + ASSERT(pszCString != NULL); + ASSERT(psPascalString != NULL); + ASSERT(btMaxLength > 0); + + if(*(BYTE *)psPascalString <= btMaxLength) + { + memcpy(pszCString, (char *)psPascalString + 1, *psPascalString); + pszCString[(int)psPascalString[0]] = '\0'; + } + else + { + pszCString[0] = '\0'; + } + return(pszCString); +} + + +/* ---------------------------------------------------------------------------- + * ODStringHasTail() + * + * Determines whether a string ends in exactly the specified sequence of + * characters. + * + * Parameters: pszFullString - String to examine. + * + * pszTail - String to look for at the end of + * pszFullString. + * + * Return: TRUE if the pszFullString does end with pszTail, FALSE if + * it does not. + */ +BOOL ODStringHasTail(char *pszFullString, char *pszTail) +{ + INT nTailLength = strlen(pszTail); + INT nFullStringLength = strlen(pszFullString); + + ASSERT(pszFullString != NULL); + ASSERT(pszTail != NULL); + + if(nFullStringLength < nTailLength) + { + return(FALSE); + } + + return(stricmp(pszFullString + (nFullStringLength - nTailLength), pszTail) == 0); +} + + +/* ========================================================================= */ +/* File-related functions. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODMakeFilename() + * + * Generates a fully-qualified filename from a path and base filename. + * + * Parameters: pszOut - String to store generated filename in. + * + * pszPath - Directory name. May be the same as pszOut, or + * may be different. + * + * pszFilename - Base filename. + * + * nMaxOutSize - Size of pszOut. This value should be one more + * than the maximum number of characters to be + * stored in the output string. + * + * Return: kODRCSuccess on success, or an error code on failure. + */ +tODResult ODMakeFilename(char *pszOut, CONST char *pszPath, + CONST char *pszFilename, INT nMaxOutSize) +{ + /* Validate parameters in debug mode */ + ASSERT(pszPath != NULL); + ASSERT(pszFilename != NULL); + ASSERT(pszOut != NULL); + ASSERT(pszFilename != pszOut); + ASSERT(nMaxOutSize > 0); + + /* Check that there is enough room in the destination string to hold */ + /* both source strings plus possibly an additional \-seperator. */ + if((INT)(strlen(pszPath) + strlen(pszFilename) + 1) > nMaxOutSize - 1) + { + return(kODRCFilenameTooLong); + } + + /* Copy path to output filename, if the addresses are different. */ + if(pszPath != pszOut) + { + strcpy(pszOut, pszPath); + } + + /* Ensure there is a trailing backslash, if path was not empty. */ +#ifdef ODPLAT_NIX + +#else + if(pszOut[strlen(pszOut) - 1] != DIRSEP && strlen(pszOut) > 0) + { + strcat(pszOut, DIRSEP_STR); + } +#endif + + /* Append base filename. */ + strcat(pszOut, pszFilename); + + return(kODRCSuccess); +} + + +/* ---------------------------------------------------------------------------- + * ODFileSize() + * + * Determines the size of a currently open file. + * + * Parameters: pfFile - Pointer to an already open file to examine. + * + * Return: The size of the file. In the case of a file that is open in + * binary mode, this will be the file length in bytes. + */ +DWORD ODFileSize(FILE *pfFile) +{ + DWORD dwOriginal; + DWORD dwFileSize; + + ASSERT(pfFile != NULL); + + dwOriginal = ftell(pfFile); + fseek(pfFile, 0L, SEEK_END); + dwFileSize = ftell(pfFile); + fseek(pfFile, dwOriginal, SEEK_SET); + return(dwFileSize); +} + + +/* ========================================================================= */ +/* DWORD math functions. */ +/* ========================================================================= */ + +/* ---------------------------------------------------------------------------- + * ODDWordShiftLeft() + * + * Shifts a DWORD to the left by the specified number of bits. + * + * Parameters: dwValue - Value to be shifted. + * + * btDistance - Distance to shift dwValue by. + * + * Return: Result of the shift operation. + */ +DWORD ODDWordShiftLeft(DWORD dwValue, BYTE btDistance) +{ + WORD wUpper; + WORD wLower; + + wLower = (WORD)dwValue; + wUpper = *(WORD *)(((BYTE *)(&dwValue)) + 2); + + while(btDistance--) + { + wUpper <<= 1; + wUpper |= (wLower & 0x8000) >> 15; + wLower <<= 1; + } + + dwValue = wLower; + *(WORD *)(((BYTE *)(&dwValue)) + 2) = wUpper; + + return(dwValue); +} + + +/* ---------------------------------------------------------------------------- + * ODDWordShiftRight() + * + * Shifts a DWORD to the right by the specified number of bits. + * + * Parameters: dwValue - Value to be shifted. + * + * btDistance - Distance to shift dwValue by. + * + * Return: Result of the shift operation. + */ +DWORD ODDWordShiftRight(DWORD dwValue, BYTE btDistance) +{ + WORD wUpper; + WORD wLower; + + wLower = (WORD)dwValue; + wUpper = *(WORD *)(((BYTE *)(&dwValue)) + 2); + + while(btDistance--) + { + wLower >>= 1; + wLower |= (wUpper & 0x0001) << 15; + wUpper >>= 1; + } + + dwValue=wLower; + *(WORD *)(((BYTE *)(&dwValue)) + 2) = wUpper; + return(dwValue); +} + + +/* ---------------------------------------------------------------------------- + * ODDWordDivide() + * + * Divides one DWORD by another DWORD, calculating the quotient and remainder. + * + * Parameters: pdwQuotient - Location where the quotient should be stored, + * or NULL if quotient is not required. + * + * pdwRemainder - Location where remainder should be stored, + * or NULL if remainder is not required. + * + * dwDividend - Dividend to be divided by divisor. + * + * dwDivisor - Divisor to divide dividend by. + * + * Return: TRUE on success or FALSE on failure. + */ +BOOL ODDWordDivide(DWORD *pdwQuotient, DWORD *pdwRemainder, + DWORD dwDividend, DWORD dwDivisor) +{ + INT nTimes = 0; + DWORD dwQuotient; + DWORD dwRemainder; + + /* Check for divide by zero in debug versions. */ + ASSERT(dwDivisor != 0); + + /* Check that divisor is not zero. (An attempt to divide by zero will */ + /* put this algorithm into an infinite loop, rather than triggering */ + /* a divide fault.) */ + if(dwDivisor == 0L) + { + return(FALSE); + } + + /* Initialize remainder to be entire dividend */ + dwRemainder = dwDividend; + + /* Initialize quotient to 0 */ + dwQuotient = 0L; + + /* Determine largest required multiple of divisor */ + while(dwRemainder >= dwDivisor) + { + dwDivisor = ODDWordShiftLeft(dwDivisor, 1); + ++nTimes; + } + + /* Loop across for all multiples of divisor, beginning with the largest */ + do + { + dwQuotient = ODDWordShiftLeft(dwQuotient, 1); + + /* If current remainder is >= this multiple of the divisor */ + if(dwRemainder >= dwDivisor) + { + /* Subtract the multiple of the divisor from the remainder */ + dwRemainder -= dwDivisor; + + /* The next bit of the quotient should be a 1 */ + dwQuotient |= 1L; + } + + /* Divide current multiple of divisor by two */ + dwDivisor = ODDWordShiftRight(dwDivisor, 1); + + /* Repeat for all multiples of the divisor */ + } while(nTimes--); + + /* If caller asked for quotient, then return it */ + if(pdwQuotient != NULL) + { + *pdwQuotient = dwQuotient; + } + + /* If caller asked for remainder, then return it */ + if(pdwRemainder != NULL) + { + *pdwRemainder = dwRemainder; + } + + return(TRUE); +} + + +/* ---------------------------------------------------------------------------- + * ODDWordDivide() + * + * Multiplies one DWORD by another, returning the product. Multiplication + * is performed by using at most 32 additions. + * + * Parameters: dwMultiplicand - The multiplicand. + * + * dwMultiplier - The multiplier. + * + * Return: Result of the multiplication. + */ +DWORD ODDWordMultiply(DWORD dwMultiplicand, DWORD dwMultiplier) +{ + DWORD dwResult = 0; + + /* Loop while multiplier is not zero */ + while(dwMultiplier != 0) + { + /* If least significant bit of multiplier is set */ + if(dwMultiplier & 0x00000001) + { + /* Add multiplicand to product */ + dwResult += dwMultiplicand; + } + + /* Shift multiplicand left one bit */ + dwMultiplicand = ODDWordShiftLeft(dwMultiplicand, 1); + + /* Shift multiplier right one bit */ + dwMultiplier = ODDWordShiftRight(dwMultiplier, 1); + } + + /* Return the final result to the caller. */ + return(dwResult); +} diff --git a/utils/magiedit/odoors/ODUtil.h b/utils/magiedit/odoors/ODUtil.h new file mode 100644 index 0000000..da5423e --- /dev/null +++ b/utils/magiedit/odoors/ODUtil.h @@ -0,0 +1,66 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODUtil.h + * + * Description: Contains prototypes and definitions for use by non-platform + * specific utility functions. These functions are implemented in + * odutil.c. Platform-specific utility functions are defined in + * odplat.h, and implemented in odplat.c. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Nov 01, 1994 6.00 BP Created. + * Dec 31, 1994 6.00 BP Added ODMakeFilename(). + * Nov 13, 1995 6.00 BP 32-bit portability. + * Nov 23, 1995 6.00 BP Added ODDWordDivide(). + * Nov 23, 1995 6.00 BP Added ODDStringHasTail(). + * Nov 23, 1995 6.00 BP Added ODFileSize(). + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 06, 1996 6.10 BP Added ODDWordMultiply(). + */ + +#ifndef _INC_ODUTIL +#define _INC_ODUTIL + +#include "ODGen.h" +#include "ODTypes.h" +#include "OpenDoor.h" + +/* General string manipulation functions. */ +void ODStringCopy(char *pszDest, CONST char *pszSource, INT nSizeofDest); +char *ODStringCToPascal(char *psPascalString, BYTE btMaxPascalLength, + char *pszCString); +char *ODStringPascalToC(char *pszCString, char *psPascalString, + BYTE btMaxLength); +BOOL ODStringHasTail(char *pszFullString, char *pszTail); + +/* File-related functions. */ +tODResult ODMakeFilename(char *pszOut, CONST char *pszPath, + CONST char *pszFilename, INT nMaxOutSize); +DWORD ODFileSize(FILE *pfFile); + +/* DWORD math functions. */ +DWORD ODDWordShiftLeft(DWORD dwValue, BYTE btDistance); +DWORD ODDWordShiftRight(DWORD dwValue, BYTE btDistance); +BOOL ODDWordDivide(DWORD *pdwQuotient, DWORD *pdwRemainder, + DWORD dwDividend, DWORD dwDivisor); +DWORD ODDWordMultiply(DWORD dwMultiplicand, DWORD dwMultiplier); + +#endif /* !_INC_ODUTIL */ diff --git a/utils/magiedit/odoors/ODWCat.c b/utils/magiedit/odoors/ODWCat.c new file mode 100644 index 0000000..f6ea356 --- /dev/null +++ b/utils/magiedit/odoors/ODWCat.c @@ -0,0 +1,270 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODWCat.c + * + * Description: Implements the Wildcat personality. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Jul 18, 1995 6.00 BP Fix ODStatGetUserAge() bug. + * Nov 13, 1995 6.00 BP 32-bit portability. + * Nov 14, 1995 6.00 BP Added include of odscrn.h. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 24, 1995 6.00 BP Fixed black square at pos 25x80. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 03, 1996 6.00 BP Display connect speed with %lu. + * 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. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include +#include +#include +#include + +#include "OpenDoor.h" +#include "ODGen.h" +#include "ODScrn.h" +#include "ODCore.h" +#include "ODStat.h" +#include "ODKrnl.h" + + +/* ---------------------------------------------------------------------------- + * pdef_wildcat() + * + * Personality function for the Wildcat BBS-like status line / function key + * personality. + * + * Parameters: btOperation - Indicates personality operation to be performed. + * + * Return: void + */ +ODAPIDEF void ODCALL pdef_wildcat(BYTE btOperation) +{ + BYTE btInfoType = od_control.od_info_type; + + switch(btOperation) + { + case PEROP_DISPLAY1: + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(1,24); + ODScrnDisplayString(" Baud: "); + ODScrnSetCursorPos(1,25); + ODScrnDisplayString("Phone: Sec: Time Left: "); + ODScrnPutText(80, 25, 80, 25, abtGreyBlock); + + ODScrnSetAttribute(0x71); + ODScrnSetCursorPos(1,24); + sprintf(szStatusText, "(%s), ", od_control.user_name, + od_control.user_location); + ODScrnPrintf("%34.34s", szStatusText); + ODScrnSetCursorPos(43, 24); + ODScrnPrintf("%lu", od_control.od_connect_speed); + + ODScrnSetCursorPos(8,25); + if(od_control.od_extended_info || btInfoType==SFDOORSDAT || btInfoType==DOORSYS_GAP || btInfoType==DOORSYS_WILDCAT) + { + ODScrnDisplayString(od_control.user_homephone); + } + + if(btInfoType==RA1EXITINFO || btInfoType==RA2EXITINFO || btInfoType==DOORSYS_WILDCAT) + { + char szUserAge[7]; + ODScrnSetCursorPos(28,25); + ODScrnSetAttribute(0x70); + ODScrnDisplayString("Age: "); + ODScrnSetAttribute(0x71); + ODStatGetUserAge(szUserAge); + ODScrnDisplayString(szUserAge); + } + + ODScrnSetCursorPos(43,25); + ODScrnPrintf("%u",od_control.user_security); + + if(btInfoType==RA1EXITINFO || btInfoType==RA2EXITINFO || btInfoType==DOORSYS_WILDCAT) + { + if(strlen(od_control.user_firstcall)==8) + { + ODScrnSetCursorPos(49,25); + ODScrnSetAttribute(0x70); + ODScrnDisplayString("Since: "); + ODScrnSetAttribute(0x71); + ODScrnDisplayChar(od_control.user_firstcall[0]); + ODScrnDisplayChar(od_control.user_firstcall[1]); + ODScrnDisplayChar('/'); + ODScrnDisplayChar(od_control.user_firstcall[6]); + ODScrnDisplayChar(od_control.user_firstcall[7]); + } + } + + case PEROP_UPDATE1: + ODScrnSetAttribute(0x71); + ODScrnSetCursorPos(74,25); + if(od_control.user_timelimit<=9) + { + ODScrnPrintf(" %d",od_control.user_timelimit); + } + else if(od_control.user_timelimit<=99) + { + ODScrnPrintf(" %d",od_control.user_timelimit); + } + else if(od_control.user_timelimit<=999) + { + ODScrnPrintf(" %d",od_control.user_timelimit); + } + else + { + ODScrnPrintf("%d",od_control.user_timelimit); + } + + ODScrnSetAttribute(0x70); + ODScrnSetCursorPos(56,24); + + if(od_control.od_okaytopage==TRUE) + ODScrnDisplayString("Page Bell "); + else + ODScrnDisplayString(" "); + + if(od_control.od_user_keyboard_on) + ODScrnDisplayString("Kybd "); + else + ODScrnDisplayString(" "); + + if(od_control.sysop_next) + ODScrnDisplayString("Local-Next"); + else + ODScrnDisplayString(" "); + break; + + case PEROP_INITIALIZE: + od_control.key_hangup=0x0000; + od_control.key_drop2bbs=0x4400; + od_control.key_dosshell=0x2000; + od_control.key_chat=0x4100; + od_control.key_sysopnext=0x3b00; + od_control.key_lockout=0x8100; + od_control.key_status[0]=0x0000; + od_control.key_status[1]=0x0000; + od_control.key_status[2]=0x0000; + od_control.key_status[3]=0x0000; + od_control.key_status[4]=0x0000; + od_control.key_status[5]=0x0000; + od_control.key_status[6]=0x0000; + od_control.key_status[7]=0x0000; + od_control.key_status[8]=0x0000; + od_control.key_keyboardoff=0x2500; + od_control.key_moretime=0x0000; + od_control.key_lesstime=0x0000; + od_control.od_page_statusline=-1; + ODStatAddKey(0x4200); /* Key to end chat */ + ODStatAddKey(0x4800); /* Key to add five minutes */ + ODStatAddKey(0x5000); /* key to subtract five minutes */ + ODStatAddKey(0x7800); /* key to hangup */ + ODStatAddKey(0x7900); /* key to hangup */ + ODStatAddKey(0x7a00); /* key to hangup */ + ODStatAddKey(0x7b00); /* key to hangup */ + ODStatAddKey(0x7c00); /* key to hangup */ + ODStatAddKey(0x7d00); /* key to hangup */ + ODStatAddKey(0x7e00); /* key to hangup */ + ODStatAddKey(0x7f00); /* key to hangup */ + ODStatAddKey(0x8000); /* key to hangup */ + ODStatAddKey(0x3f00); /* key to toggle bell */ + ODStatAddKey(0x3e00); /* key to toggle bell */ + break; + + case PEROP_CUSTOMKEY: + switch((WORD)od_control.od_last_hot) + { + case 0x4200: + od_control.od_chat_active = FALSE; + break; + + case 0x4800: + if(od_control.user_timelimit <= 1435) + { + od_control.user_timelimit += 5; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + } + break; + + case 0x5000: + od_control.user_timelimit -= 5; + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + break; + + case 0x7800: + case 0x7900: + case 0x7a00: + case 0x7b00: + case 0x7c00: + case 0x7d00: + case 0x7e00: + case 0x7f00: + case 0x8000: + od_exit(2,TRUE); + break; + + case 0x3f00: + case 0x3e00: + if(od_control.od_okaytopage!=TRUE) + { + od_control.od_okaytopage=TRUE; + } + else + { + od_control.od_okaytopage=FALSE; + } + bForceStatusUpdate = TRUE; + CALL_KERNEL_IF_NEEDED(); + break; + + default: + return; + } + od_control.od_last_hot=0; + break; + + case PEROP_DEINITIALIZE: + ODStatRemoveKey(0x4200); + ODStatRemoveKey(0x4800); + ODStatRemoveKey(0x5000); + ODStatRemoveKey(0x7800); + ODStatRemoveKey(0x7900); + ODStatRemoveKey(0x7a00); + ODStatRemoveKey(0x7b00); + ODStatRemoveKey(0x7c00); + ODStatRemoveKey(0x7d00); + ODStatRemoveKey(0x7e00); + ODStatRemoveKey(0x7f00); + ODStatRemoveKey(0x8000); + ODStatRemoveKey(0x3e00); + ODStatRemoveKey(0x3f00); + break; + } +} diff --git a/utils/magiedit/odoors/ODWin.c b/utils/magiedit/odoors/ODWin.c new file mode 100644 index 0000000..1ebaff3 --- /dev/null +++ b/utils/magiedit/odoors/ODWin.c @@ -0,0 +1,319 @@ +/* OpenDoors Online Software Programming Toolkit + * (C) Copyright 1991 - 1999 by Brian Pirie. + * + * 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: ODWin.c + * + * Description: Implements the od_window_...() functions for creating + * and removing text-mode windows. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Oct 13, 1994 6.00 BP New file header format. + * Nov 01, 1994 6.00 BP Include stdlib.h for malloc prototype. + * Dec 09, 1994 6.00 BP Standardized coding style. + * Dec 12, 1994 6.00 BP Set od_error on window remove failure. + * Aug 19, 1995 6.00 BP 32-bit portability. + * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h. + * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Aug 10, 2003 6.23 SH *nix support + */ + +#define BUILDING_OPENDOORS + +#include +#include + +#include "OpenDoor.h" +#include "ODGen.h" +#include "ODCore.h" +#include "ODKrnl.h" + + +/* ---------------------------------------------------------------------------- + * od_window_create() + * + * Creates a window on the screen, storing information on the original screen + * contents "under" the window in order to restore the screen after the window + * is removed. A window that is created with this function must be destroyed + * by od_window_remove() in order to free up memory that is allocated by this + * function. + * + * Parameters: nLeft - 1-based column number of left edge of window. + * + * nTop - 1-based row number of top edge of window. + * + * nRight - 1-based column number of right edge of window. + * + * nBottom - 1-based row number of bottom edge of window. + * + * pszTitle - Pointer to a string containing title for window. + * If this string is empty, no title is displayed. + * + * btBoarderCol - Colour of window boarder. + * + * btTitleCol - Colour of window title. + * + * btInsideCol - Colour of rest of window. + * + * nReserved - Should always be 0 for this version. + * + * Return: Pointer to window description buffer (which must later be + * passed to od_window_remove(), or NULL on failure. + */ +ODAPIDEF void * ODCALL od_window_create(INT nLeft, INT nTop, INT nRight, + INT nBottom, char *pszTitle, BYTE btBorderCol, BYTE btTitleCol, + BYTE btInsideCol, INT nReserved) +{ + BYTE btLine; + BYTE btBetweenSize; + void *pBuffer; + BYTE btTitleSize; + BYTE btRemaining; + + /* Log function entry if running in trace mode. */ + TRACE(TRACE_API, "od_window_create()"); + + /* Ensure that OpenDoors has been initialized */ + if(!bODInitialized) od_init(); + + OD_API_ENTRY(); + + nReserved &= 0x00; + + btBetweenSize = (nRight - nLeft) - 1; + + /* Setup od_box_chars appropriately. */ + if(od_control.od_box_chars[BOX_BOTTOM]==0) + { + od_control.od_box_chars[BOX_BOTTOM] = od_control.od_box_chars[BOX_TOP]; + } + if(od_control.od_box_chars[BOX_RIGHT]==0) + { + od_control.od_box_chars[BOX_RIGHT] = od_control.od_box_chars[BOX_LEFT]; + } + + /* Ensure that the current display mode can support the capabilities */ + /* required to display and remove windows. */ + if(!(od_control.user_ansi || od_control.user_avatar)) + { + od_control.od_error = ERR_NOGRAPHICS; + OD_API_EXIT(); + return(NULL); + } + + /* Validate parameters. */ + if(nLeft < 1 || nTop < 1 || nRight > 80 || nBottom > 25 || nRight-nLeft < 2 + || nBottom-nTop < 2) + { + od_control.od_error = ERR_PARAMETER; + OD_API_EXIT(); + return(NULL); + } + + /* Allocate a buffer large enough to hold all window information. */ + if((pBuffer = malloc((nRight - nLeft + 1) * 2 + (nBottom - nTop + 1) * 160 + + 4)) == NULL) + { + od_control.od_error = ERR_MEMORY; + OD_API_EXIT(); + return(NULL); + } + + /* Store current contents of screen where window will be drawn. */ + if(!od_gettext(nLeft, nTop, nRight, nBottom, (char *)pBuffer+4)) + { + free(pBuffer); + + /* Note: od_control.od_error code has been set by od_gettext(). */ + + OD_API_EXIT(); + return(NULL); + } + + /* Store window information in buffer. */ + ((char *)pBuffer)[0]=nLeft; + ((char *)pBuffer)[1]=nTop; + ((char *)pBuffer)[2]=nRight; + ((char *)pBuffer)[3]=nBottom; + + /* Determine number of characters of title to display. */ + if(pszTitle==NULL) + { + btTitleSize = 0; + } + else + { + if((btTitleSize = strlen(pszTitle)) > (btBetweenSize - 4)) + { + btTitleSize = btBetweenSize - 4; + } + } + + /* Move to position of window's top corner, prepare to begin drawing the */ + /* window. */ + od_set_cursor(nTop,nLeft); + od_set_attrib(btBorderCol); + + /* Display corner character. */ + od_putch(od_control.od_box_chars[BOX_UPPERLEFT]); + + /* If there is no title, display top line all in one piece. */ + if(btTitleSize == 0) + { + /* Display top line. */ + od_repeat(od_control.od_box_chars[BOX_TOP],btBetweenSize); + } + else + { + /* If there is a title, display the top line with a title centered in */ + /* it. */ + od_repeat(od_control.od_box_chars[BOX_TOP],btRemaining = + ((btBetweenSize - btTitleSize - 2) / 2)); + od_set_attrib(btTitleCol); + od_putch(' '); + od_disp(pszTitle,btTitleSize,TRUE); + od_putch(' '); + od_set_attrib(btBorderCol); + od_repeat(od_control.od_box_chars[BOX_TOP], + (BYTE)(btBetweenSize - btRemaining - btTitleSize - 2)); + } + + /* Display top right corner character. */ + od_putch(od_control.od_box_chars[BOX_UPPERRIGHT]); + + /* If AVATAR mode is available. */ + if(od_control.user_avatar) + { + /* Display first left verticle line. */ + od_set_cursor(nTop + 1, nLeft); + od_putch(od_control.od_box_chars[BOX_LEFT]); + + /* Fill in center of window with AVATAR clear area control sequence. */ + od_emulate(22); + od_emulate(12); + od_emulate(btInsideCol); + od_emulate((BYTE)((nBottom - nTop) - 1)); + od_emulate(btBetweenSize); + + od_set_attrib(btBorderCol); + od_set_cursor(nTop + 1 , nRight); + + /* Display first right verticle line. */ + od_putch(od_control.od_box_chars[BOX_RIGHT]); + + /* Display remaining verticle lines. */ + for(btLine=nTop+2;btLine + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 22 + + In addition to including the OpenDoors header file in your + source code modules, you must also "link" the appropriate + OpenDoors library file with your program. The procedure for + doing this depends upon which compiler you are using. The + following sections describe how to link with the OpenDoors + libraries using various compilers. + + + +LINKING WITH OPENDOORS USING A DOS COMPILER +------------------------------------------------------------------------------- + + This section describes how to link with the provided OpenDoors + library files under a variety of DOS compilers. If you are using + a compiler other than those described here, refer to your + compiler's manual for information on how to link with third- + party libraries. + + If you are using Borland Turbo C 2.00 or earlier, you can cause + your compiler to link your program with the OpenDoors library by + creating a text file with a .PRJ extension. In this text file, + you should list the names of your program's .C modules, along + with the name of the appropriate OpenDoors library file, as + listed in the table at the end of this section. You should then + select this Project file from within the Turbo C IDE prior to + compiling your program. + + If you are using Turbo C++ or Borland C++, you can set your + compiler to link your program with the OpenDoors library by + creating a project file from within the IDE. To do this, choose + the Open Project command from the Project menu, and enter the + name for your new project file in the Load Project dialog box. + Then add the names of your program's .C/.CPP modules, along with + the name of the appropriate OpenDoors library file, by pressing + [Insert] in the project window. When you return to Turbo C++ or + Borland C++ again, you can work with the same project file by + using the Open command from the Project menu. + + If you are using any Microsoft C compiler, such as Quick C, + Microsoft C or Visual C++, you can set your compiler to link + your program with the OpenDoors library by creating a makefile. + You can create a new project file from within Quick C by using + the Set Program List option from the Make menu. You can do this + from within Visual C++ by using the New command from the Project + menu. You should add the names of your program's .C/.CPP source + files, along with the name of the appropriate OpenDoors library + file, to the newly create makefile. + + There are several different DOS library files included with + OpenDoors, each one for use with a different memory model. The + following chart lists the library file names, along with their + corresponding memory model. It is important that you use the +=============================================================================== +OpenDoors 6.00 Manual End of Page 23 + + library file which corresponds to the memory model you are + using. Whenever you change your compiler to use a different + memory model, it is important to rebuild all of your source + files (using the "Build All" or "Rebuild All" command) in + addition to changing the library that your program is being + linked with. If you are unfamiliar with the concept of memory + models, you should refer to your compiler's manuals. If you are + unsure as to what memory model your compiler is currently using, + check this setting in the compile options dialog box or command + line reference information. + + +------------------------------------------------+ + | Library | Memory | + | Filename | Model | + |-------------|----------------------------------| + | ODOORS.LIB | DOS small memory model library | + | | | + | ODOORM.LIB | DOS medium memory model library | + | | (Available separately) | + | | | + | ODOORC.LIB | DOS compact memory model library | + | | (Available separately) | + | | | + | ODOORL.LIB | DOS large memory model library | + | | | + | ODOORH.LIB | DOS huge memory model library | + +------------------------------------------------+ + + To understand how to compile a program written with OpenDoors, + it is a good idea to try compiling one of the example programs, + such as ex_hello.c, that are included in the OpenDoors package. + + + + +LINKING WITH OPENDOORS USING A WINDOWS COMPILER +------------------------------------------------------------------------------- + + The Win32 version of OpenDoors resides in a DLL, ODOORS60.DLL. + In order to use OpenDoors from a Win32 program, you will + typically link to an import library (although it is also + possible to use load-time dynamic linking through the use of + LoadLibrary() and GetProcAddress()). The OpenDoors package + includes a COFF-format import library for use Microsoft + compilers, named ODOORW.LIB. If you are using a compiler that + uses OMF-format object files, such as a Borland compiler, you + will need to create your own version of the odoorw.lib import + library, by using the implib utility provided with your + compiler. + + When compiling an OpenDoors program with a Windows compiler, be + sure that either the WIN32 or __WIN32__ constant is defined. +=============================================================================== +OpenDoors 6.00 Manual End of Page 24 + + Microsoft and Borland compilers define one of these constants by + default. However, if you are using a compiler from another + company, you may need to explicitly configure your compiler to + define one of these preprocessor constants. + + If you are using Microsoft Visual C++ 2.0 or later, you can + setup your compiler to link with the OpenDoors import library by + creating a makefile (choose File|New|Project) and adding both + your program's .C/.CPP source file(s) and the odoorw.lib import + library to the project. When prompted for the Project type, + choose "Application", not a "MFC AppWizard". If you are using + Visual C++ 2.0, then you must manually edit the .mak file using + a text editor. In this file, replace all occurrences of + "/SUBSYSTEM:windows" with "/SUBSYSTEM:windows,4.0". This + instructs the linker to create an executable file that is + targeted for Windows 95. If you do not do this, some of the + OpenDoors visual elements will not appear correctly. Later + versions of Microsoft's compiler default to using + "/SUBSYSTEM:windows,4.0", and so this step is no longer + necessary with those compilers. + + If you are using Borland C++ 4.50 or later, you must create an + OpenDoors import library for ODOORS60.DLL before you can compile + your first OpenDoors program. To do this, go to the directory + where ODOORS60.DLL is located, move the original odoorw.lib to a + backup location, and issue the command: + + IMPLIB ODOORW.LIB ODOORS60.DLL + + This will create a new import library (ODOORW.LIB) which you can + then use with your compiler. To compile an OpenDoors program + from the command line, issue the command: + + BCC32 -tW your_program.c ODOORW.LIB + + To compile an OpenDoors program from within the IDE, create a + new project file, and add both your program's source file(s) and + the OpenDoors import library to that project. If you are + compiling from within the IDE, check the TargetExpert and be + sure that you are using the multithreaded version of the the + runtime libraries. By default, the Borland IDE compiles single- + threaded, which will not work with OpenDoors. + + Additional information on the Win32 version of OpenDoors is + provided in chapter 6. + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 25 + +RUNNING A DOOR PROGRAM WRITTEN WITH OPENDOORS +------------------------------------------------------------------------------- + + This section provides information on how to run a BBS door + program that has been written with OpenDoors. If you are using + OpenDoors to write some other form of online software, the + information provided here will apply to different degrees, + depending on the nature of your program. + + OpenDoors supports both local and remote modes. In the normal + mode of operation, remote mode, your program's output will be + displayed to both the local screen and the remote user's screen. + To run your program in remote mode, you will usually set it up + to run under some BBS package. However, for testing purposes, it + is often convenient to run your program in local mode. + + There are several ways to start your program in local mode. The + first method is to place the example DORINFO1.DEF file in the + same directory as your program. If your program uses the + OpenDoors command line processing function, od_parse_cmd_line(), + then you can start your program in local mode by simply + specifying -local on your program's command line. For example, + you can try the example program include with OpenDoors by + issuing the command VOTEDOS -LOCAL (for the DOS version) or + VOTEWIN -LOCAL (for the Windows 95/NT version). OpenDoors will + also run in local mode if you set it up to run under a BBS + package, and log into the BBS in local mode. When the BBS runs + your door program, OpenDoors will automatically run in local + mode. + + To run your program in remote mode, you will probably want to + run it under a BBS system. If you don't have a BBS package for + testing purposes, you might want to obtain a popular BBS package + such as Wildcat!, Maximus (which is free) or RemoteAccess. + + + +RUNNING DOS-BASED DOOR PROGRAMS +------------------------------------------------------------------------------- + + DOS BBS packages typically run door programs using one of two + methods. Either the BBS package directly loads and executes the + program, or it exits to a DOS batch file, which in turn executes + the door program. In either case, the BBS package produces a + door information file, common called a "drop file", which + provides information to the door program such as the name of the + current user. OpenDoors automatically supports the common drop + file formats, including DORINFOx.DEF and DOOR.SYS. + + + +RUNNING WINDOWS 95/NT DOOR PROGRAMS +=============================================================================== +OpenDoors 6.00 Manual End of Page 26 + +------------------------------------------------------------------------------- + + This section provides information specific to running door + programs that are compiled with the Win32 version of OpenDoors. + Please feel free to include this information in your program's + manual. + + Since the Win32 version of OpenDoors resides in a DLL, + ODOORS60.DLL, this file must be present on any system where your + program will be run. Although Windows 95/NT will find this file + if it is located in the same directory as your program's + executable file, it is a good idea to install this DLL into the + Windows system directory. This way, all programs using the Win32 + version of OpenDoors can share the same copy of the DLL, + reducing the amount of disk space that is used. + + The required setup for a Windows 95/NT door will depend upon + what BBS system it is being run under. If you the program is + being run under a native Windows 95/NT BBS system, then ideally + that BBS system will provide the ability to pass a live serial + port handle to the door program, on the program's command line. + Otherwise, you should run the door from a batch file, following + the instructions provided below for running the program under a + DOS-based BBS system. If the BBS system is able to pass a live + Window communications handle on the door's command line, and you + are using the OpenDoors standard command-line processing + function (od_parse_cmd_line()), then you can just setup the BBS + to run the program directly, using the command line: + + YourProgramName.exe -handle xxxxxxxxxx + + where xxxxxxxxx is the serial port handle, in decimal format. + You do not need to use the start command, nor the DTRON utility, + and you do not have to change the COMAutoAssign setting in + the system.ini file. + + If you are running the Win32 door program under a DOS-based BBS + system, or a Windows-based BBS system that is unable to pass a + live serial port handle to the door program, then follow these + steps: + + 1.Add a line of the form "COMAutoAssign=" to the [386Enh] + section of your system.ini file. Here, specifies the + serial port number that the BBS's modem is connected to, and + will usually be 0. For example, if your modem is + connected to COM1, you would add a line such as + "COM1AutoAssign=0" (sans quotes). You will then have to re- + start your computer for this change to take effect. If you do + not do this, the Windows-based door program will not be able + to access the modem. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 27 + + 2.Setup the BBS software to run the Windows-based door program + just as you would any other door program. You will probably + want to do this from a batch file. The command line that runs + the Windows program should be of the form: + + start /w /m YourProgramName.exe [any command line + parameters] + + This will cause the Windows-based door program to start in + minimized mode, and cause the calling MS-DOS session to wait + until the Windows program exits before continuing. If you do + not wish the program to be started in minimized mode, remove + the /m from the command line. If you attempt to start the + door program by calling it directly, rather than using the + "start /w" command, the BBS software will immediately start + again, cause it to attempt to run simultaneously with the + door program. + + 3.After running the start command, use DTRON.EXE or a similar + utility to re-enable DTR detection by the modem. Normally, + this command line will be of the form: + + dtron /port x /bps y + + Where x is the serial port number (0 for COM1, 1 for COM2, + etc.) and y is the locked bps rate. For example, if your + serial port is locked at 38400 bps and is connected to COM2, + you would use: + + dtron /port 1 /bps 38400 + + For full information on the DTRON utility, simply type the + command line: + + dtron /help + + You may freely redistribute the DTRON utility that is + included in this package with your program. + + Additional information on the Win32 version of OpenDoors, and + further explanation of some of these steps, is provided in + chapter 6. + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 28 + +BASICS OF DOOR PROGRAMMING WITH OPENDOORS +------------------------------------------------------------------------------- + + This section provides a complete tutorial to the basics of + writing BBS door programs using OpenDoors. If you are using + OpenDoors to write other online software, much of this + information will still be relevant. + + In addition to reading this section, I would encourage you to + look at the example programs included int the OpenDoors + packages. These programs, which are described beginning on page + 38, will give you a much better idea of what an OpenDoors + program will look like. These programs can also serve as a great + starting point for writing your own programs using OpenDoors. + + Probably the best means of introduction to door programming with + OpenDoors is by doing it yourself. As such, I strongly encourage + you to try compiling and running the simple introduction program + below. For instructions on compiling programs written with + OpenDoors, see page 22. + + DOS version: + + #include "opendoor.h" + + main() + { + od_printf("Welcome to my first door program!\n\r"); + od_printf("Press a key to return to BBS!\n\r"); + od_get_key(TRUE); + od_exit(0, FALSE); + } + + Win32 version: + + #include "opendoor.h" + + int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow) + { + od_printf("Welcome to my first door program!\n\r"); + od_printf("Press a key to return to BBS!\n\r"); + od_get_key(TRUE); + od_exit(0, FALSE); + } + + Keep in mind that even this simple program will automatically + have all of the door capabilities we have already mentioned. + Notice the line that reads #include "opendoor.h". All programs + written with OpenDoors must include the OPENDOOR.H header file + in order to compile correctly. The first two lines in the + main/WinMain function simply call the OpenDoors od_printf() +=============================================================================== +OpenDoors 6.00 Manual End of Page 29 + + function. od_printf() is similar to the printf() function that C + programmers will already be familiar with. However, unlike + printf(), the od_printf() function sends the output to both the + modem and the local screen. Notice that the lines of text + displayed by the od_printf() function end with a "\n\r" + sequence, instead of the normal "\n". This is because the + terminal emulation software that is running on the remote user's + system usually requires both a carriage return and a line feed + to correctly begin a new line. The next line in our example + program is the OpenDoors single-key input function, + od_get_key(). The TRUE value causes OpenDoors to wait for a key + to be pressed (again, either from remote or local keyboard) + before returning. The last line of the main/WinMain function is + a call to od_exit(). Any program using OpenDoors should call + this function. For the time being, you can always use the (0, + FALSE) parameters. + + Once again, you are encouraged to try compiling and running this + program, as described above. Congratulations, you have written + your first door program! Feel free to make any changes to this + program, and see what effects your changes have. + + To simplify this example, separate versions of this program are + shown for the DOS and Win32 versions of OpenDoors. However, you + would typically write your program so that it could be compiled + using either the DOS or Win32 versions of OpenDoors, by + beginning the mainline function as follows: + + #ifdef ODPLAT_WIN32 + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE + hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) + #else + int main(int argc, char *argv[]) + #endif + + In case you are not entirely familiar with the operation of door + programs, we will now provide an introduction to the internals + of a door's operation. Keep in mind that OpenDoors automatically + carries out most of these tasks for you. When any door program + starts up, one of the first things it must do is to read the + door information file(s) (sometimes called a "drop file") passed + to it by the BBS. When a user is on-line, and wishes to run a + door, they will most likely select a command from a menu. At + this point, the BBS system (such as RemoteAccess, Maximus, PC- + Board or whatever), will create a file of information about the + system, who is currently on-line, and so on. Various BBS + packages produce various styles of door information files. + OpenDoors automatically recognizes and reads a wide variety of + door information file formats. As a result, your doors will be + able to run on a almost any BBS system. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 30 + + Fortunately, OpenDoors takes care of all the work involved in + detecting and reading the door information file, and then + initializing and communicating with the serial port for you. In + order to carry out these tasks, along with setting up the status + line, and so on, OpenDoors provides a function called od_init(). + If you do not explicitly call this function, the first call to + any other OpenDoors function (such as the first time your door + program outputs anything) will automatically cause the od_init() + function to be called. As a result, upon the first call to an + OpenDoors function, all of the initialization tasks for the door + will automatically be carried out. However, there may be times + when you will want your program to have access information about + the user who is on-line, or carry out other actions which + require od_init() to have been executed - prior to the point + where you call any other OpenDoors functions. In this case, you + will have to call od_init() yourself before you do any of these + things. + + OpenDoors provides you with a C/C++ structure, by the name of + od_control, which allows you to access all the available + information about the user who is on-line, the system your door + is running on, and also allows you to adjust various OpenDoors + parameters. Depending on what BBS system your door is running + under, the actual information available from the od_control + structure will vary. For more information on the od_control + structure, see the section on the control structure, beginning + on page 148. + + Once the door has initialized itself, it will then begin + communications with the user who is online. OpenDoors takes care + of all communications, through its various input and display + functions. When the door has finished, it will then write any + information that has changed back to the door information file + (if applicable), finish communicating with the modem, and return + to the BBS. In OpenDoors, these shut-down operations are + automatically performed you call the od_exit() function. This + function will terminate the door's activity, OPTIONALLY hang up + on the user (allowing you to provide either return to BBS or + logoff options for exiting), and then exit with the specified + errorlevel. + + One other important OpenDoors function that you should be aware + of is the od_kernel() function. od_kernel() is the central + OpenDoors control function, and is responsible for much of + OpenDoor's updating of the status line, monitoring the carrier + detect and user timeout status, responding to sysop function + keys, and so on. The od_kernel() function is called + automatically by OpenDoors, within the other OpenDoors + functions. As a result, since most door programs will call some + OpenDoors function on a regular basis, you will most often have + no need to call the od_kernel() function yourself. However, if + your door is going to perform some action, such as updating data +=============================================================================== +OpenDoors 6.00 Manual End of Page 31 + + files, during which it will not call any OpenDoors function for + more than a few seconds, you should then call the od_kernel() + function yourself. For more information on the od_kernel() + function, see page 97. + + For more information on the functions available from OpenDoors, + or the control structure, see the corresponding sections in this + manual. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 32 + +TOUR OF A SAMPLE DOOR PROGRAM: "EX_VOTE" +------------------------------------------------------------------------------ + + One of the best ways to see how OpenDoors works, and the + potential that it has, is to look at the example programs + included in the OpenDoors package. A brief description of each + of these programs can be found on page 38. This section takes a + closer look at one of the example programs, EX_VOTE.C. Unlike + our simple example in the previous section, EX_VOTE.C is a much + more complicated program, taking advantage of many of the + advanced features of OpenDoors. Even if you do not understand + everything that EX_VOTE.C does, you should be able to make use + of various elements demonstrated here, in your own programs. + + The OpenDoors package includes a two compiled versions of + EX_VOTE. VOTEDOS.EXE is a plain-DOS program which can run under + DOS, Windows or OS/2. VOTEWIN.EXE was compiled using the Win32 + version of OpenDoors, and so it runs only on Windows 95/NT. The + OpenDoors package also contains a sample door information file, + DORINFO1.DEF. You can use this file to test any doors in local + mode. If you wish to manually create your own DORINFO1.DEF file, + you can do so very easily. The DORINFO1.DEF door information + file is a simple text file which lists a different piece of + information on each line, in the following format: + + +----------------------------------------------------------+ + | LINE NUMBER | DESCRIPTION | EXAMPLE | + +-------------+------------------------+-------------------| + | 1 | Name of the BBS | MY OWN BBS | + | 2 | Sysop's first name | BRIAN | + | 3 | Sysop's last name | PIRIE | + | 4 | Com Port modem is on | COM0 | + | 5 | Baud rate, etc. | 0 BAUD,N,8,1 | + | 6 | Unused | 0 | + | 7 | User's first name | JOHN | + | 8 | User's last name | PUBLIC | + | 9 | Caller's location | OTTAWA, ON | + | 10 | ANSI mode (0=off, 1=on)| 1 | + | 11 | User's security level | 32000 | + | 12 | User's time left | 60 | + +----------------------------------------------------------+ + + + Feel free to make any changes you wish to EX_VOTE.C, and + recompile it. One of the most effective and enjoyable ways to + learn OpenDoors is by experimenting. If you are a registered + owner of OpenDoors, you may even distribute your own versions of + this door. Also, you may find that EX_VOTE.C serves as a good + framework for building your own door programs. + + The EX_VOTE.C door behaves similarly to most other door + programs, and will have a fair bit in common with any other door +=============================================================================== +OpenDoors 6.00 Manual End of Page 33 + + you write in OpenDoors. What you see in the output window is + identical to what a remote user will be seeing. If the user has + ANSI, AVATAR or RIP mode turned on, you will see the same colors + as they do, and if they have screen clearing turned on, your + screen will be cleared when theirs is. The status line at the + bottom of the window will list the name of the user currently + on-line (if you are using the sample DORINFO1.DEF file, the + user's name will be "The Sysop"), the user's location, and the + user's baud rate (0 if the door is operating in local mode). The + local display also shows how much time the user has left, + whether the user has paged the system operator for a chat, and + other information. + + There are a number of special commands that are only available + to the system operator on the local keyboard. These commands + allow the system operator to hang up on the user, adjust the + amount of time the user may remain online, enter chat mode with + the user, enter a DOS shell (in the DOS version), and so on. In + the DOS version, help on these commands is available on the + status line by pressing the [F9] key. In the Windows version, + these commands are listed on the menu that appears at the top of + the window. + + Now, let us take a closer look at the actual source code for the + EX_VOTE.C door. If you have not already printed out a copy of + this manual, and possibly the EX_VOTE.C file as well, it would + probably be a good idea to do so now. + + Notice that near the top of the program, along with all the + standard header files, the OPENDOOR.H file is included. This + file must be included in all programs written under OpenDoors. + If you are placing the OPENDOOR.H file in the same directory as + the door you are compiling, simply include the line: + + #include "opendoor.h" + + in your program. + + The main()/WinMain() function of the EX_VOTE.C program has a + for(;;) loop that repeatedly displays the main menu, obtains a + choice from the user and responds to the command, until the user + chooses to exit the program. Before the main menu is displayed, + the screen is cleared by calling od_clr_scr(). The od_clr_scr() + function will clear both the local and remote screens, but only + if the user has screen clearing enabled. Refer to page 57 for + information on how to force the screen to be cleared, regardless + of the user's screen clearing setting. The main menu is + displayed using the od_printf() function, one of the most common + OpenDoors functions you will use. Next, od_get_answer() is used + to obtain a menu choice from the user from the specified set of + keys. Next, a switch() statement is used to respond to the + user's command appropriately. If the user presses the P key to +=============================================================================== +OpenDoors 6.00 Manual End of Page 34 + + page the system operator, od_page() is called. If the user + chooses to return to the BBS, od_exit() is called to terminate + OpenDoor's activities and return control to the BBS. The FALSE + parameter passed to od_exit() indicates that OpenDoors should + not disconnect (hangup) before exiting. If the user chooses to + log off, EX_VOTE.C first confirms this action with the user, and + then calls od_exit() with the TRUE parameter. The numerical + parameter passed to od_exit() sets the errorlevel that OpenDoors + will exit with. + + In its ChooseQuestion() function, EX_VOTE.C uses the OpenDoors + function od_get_key(). This function is similar to the + od_get_answer() function that we have already seen. However, + unlike od_get_answer() which will wait until the user presses + some key from the list of possibilities you provide, + od_get_key() will allow the user to press any key. od_get_key() + accepts a single parameter. If this parameter is TRUE, + od_get_key() will wait for the user to press a key before + returning. If this parameter is FALSE, od_get_key() will return + immediately with a value of 0 if there are no keys waiting in + the inbound buffer, and returning the next key if there are + characters waiting. + + In a number of places, EX_VOTE.C also uses the od_input_str() + function. Unlike od_get_key() and od_get_answer() which return a + single character, od_input_str() allows the user to input and + edit a string of many characters. You will only receive the + string entered by the user after they press the enter key. + od_input_str() accepts four parameters: the string where the + user's input should be stored, the maximum number of characters + to input, the minimum character value to accept and the maximum + character value to accept. + + Another new feature of OpenDoors that is used by EX_VOTE.C is + the OpenDoors control structure, od_control. This global + structure is documented in chapter 5 of this manual. The + OpenDoors control structure allows you to access a wide variety + of information about the user who is currently online, the BBS + system your program is running on, and also allows you to + control various OpenDoors settings. For example, EX_VOTE.C + compares the current user name (od_control.od_user_name) with + the name of the system operator (od_control.od_sysop_name) to + determine whether it is the system operator who using the + program. + + EX_VOTE.C uses two data files, the first of which contains a + record for every user, and the second of which contains a record + for every question. EX_VOTE.C accesses these data files in a + controlled manner in order to permit the program to be running + simultaneously on multiple lines on a multi-node BBS system. + When EX_VOTE.C needs to update a data file, it opens it for + exclusive access, so that only one node can access the file at +=============================================================================== +OpenDoors 6.00 Manual End of Page 35 + + any given time. Since the data file could have been changed by + another node since the time that EX_VOTE.C last read the file, + it always reads a record, makes changes to it and then re-writes + the record while it has the file open for exclusive access. It + then closes the file as soon as possible after opening the file, + in order to permit other nodes to once again access the file. + Because EX_VOTE.C keeps track of which questions each user has + voted on, along with the questions and results of voting on each + question, its data file format is more complex than many door + programs (although not as complex as others). + + EX_VOTE.C also uses color. One of the easiest ways to use + different colors in an OpenDoors program is to use the + OpenDoor's print color-setting extensions. You can change the + color of text display at any point in an od_printf() format + string using by enclosing the name of new display color in back + quote characters (`, not '). For example: + + od_printf("`red`This is in red `green`This is green\n\r"); + + Would cause the words "This is in red" to be displayed in red, + and the words "This is in green" to be displayed in green. + + EX_VOTE.C also takes advantage of a number of OpenDoors + capabilities that you can optionally choose to include in your + door programs. You will notice that there are a number of new + lines at the beginning of the main() function, all of which + change settings in the OpenDoors control structure. The line: + + od_control.od_config_file = INCLUDE_CONFIG_FILE; + + causes the OpenDoors configuration file system to be included in + your program. Using this system, OpenDoors automatically reads a + configuration file that can be used by the system operator to + change various program settings. Refer to the included door.cfg + file for an example OpenDoors configuration file. In addition to + the configuration file settings automatically supported by the + configuration file system, you can also add your own + configuration file settings. To do this, you simply supply + OpenDoors with a callback function that it will call whenever it + encounters an unrecognized keyword in the configuration file. + The line: + + od_control.od_config_function = CustomConfigFunction; + + Causes OpenDoors to call the function CustomConfigFunction() in + EX_VOTE.C for this purpose. You will notice that the + CustomConfigFunction() receives two parameters - the first is + the unrecognized keyword, and the second is any parameters that + follow the keyword in the configuration file. EX_VOTE.C checks + for two special configuration file lines - one to set whether or + +=============================================================================== +OpenDoors 6.00 Manual End of Page 36 + + not users can add questions, and one to set whether or not users + can view the results of a question before voting on it. + + The next line in the main() function, + + od_control.od_mps = INCLUDE_MPS; + + causes the OpenDoors "Multiple Personality System" to be + included in program. This allows the sysop to choose from a + number of status line / sysop function key "personalities" that + mimic a number of different BBS systems, using the Personality + setting in the configuration file. + + + The line: + + od_control.od_logfile = INCLUDE_LOGFILE; + + causes the OpenDoors log file system to be included in the + program. The OpenDoors log file system automatically records the + date and time of program startup, exit and other major actions + in the specified file. EX_VOTE.C also writes its own log file + entries by calling the od_log_write() function. + + EX_VOTE.C also provides the ability for the sysop to provide + their own ASCII/ANSI/AVATAR/RIP files to be displayed in place + of the normal main menu. EX_VOTE.C uses the od_hotkey_menu() + function to display a VOTE.ASC/.ANS/.AVT/.RIP file for the main + menu, if such a file exists. If the file is not available, the + normal EX_VOTE.C menu is used instead. The od_hotkey_menu() + function will automatically select the appropriate file + (.ASC/.ANS/.AVT/.RIP) for the current display mode, and the user + is able to make a menu choice at any time. If a menu choice is + made before the menu is entirely displayed, the function will + stop displaying the menu and return immediately. + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 37 + +OTHER EXAMPLE PROGRAMS INCLUDED WITH OPENDOORS +------------------------------------------------------------------------------ + + In addition to the EX_VOTE.C program, which is discussed in + detail in the previous section, a number of other example + programs are included with OpenDoors. These programs help to + demonstrate what is possible with OpenDoors. They can also serve + as excellent tools to help you learn OpenDoors. In addition, you + are free to include any portions of any of these example + programs in your own programs. Below is a summary of each of + these example programs: + + +------------------------------------------------------------------------------- +EX_HELLO.C This an example of a very simple door program that displays a + short message and prompts for the user to press a key. After the + user presses a key, the door exits and control is returned to + the main BBS software. Despite the fact that it only consists of + a few lines of code, EX_HELLO remains a fully functional door + program. For information on compiling an OpenDoors door program, + see the section that begins on page 22. + + +------------------------------------------------------------------------------- +EX_CHAT.C This program is an example of a multi-window full-screen chat + door written with OpenDoors. EX_CHAT demonstrates the ease of + using sophisticated ANSI / AVATAR / RIP terminal features within + OpenDoors programs. For instructions on how to compile this + program, see the section that begins on page 22. + + This program create two windows on the screen, separated by a + bar with user name / sysop name information. This program + permits communication between the local sysop and remote user by + displaying the text typed by the user in one window, and the + text typed by the sysop in the other window. When either + person's typing reaches the bottom of the window, the contents + of the window is scrolled up to provide more room for typing. + Words are also wrapped when either typist reaches the end of a + line. The advantage of a split-screen chat program is that it + permits both sysop and user to type at the same time without + difficulty. The chat function automatically invokes OpenDoor's + internal chat mode if ANSI, AVATAR or RIP modes are not + available. The display colors, window sizes and locations, and + distance to scroll a window's contents are configurable by + setting the appropriate variables, below. When the Sysop invokes + a DOS shell, a pop-up window is displayed to indicate to the + user that the door program has been suspended. + + The chat feature of this program can also be easily integrated + into other doors you write, and may be used to replace the + existing OpenDoors line-oriented chat system. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 38 + + +------------------------------------------------------------------------------- +EX_MUSIC.C This example door demonstrates how to play "ANSI" music and + sound effects in an OpenDoors door. Included in this program is + a function to send "ANSI" music to the remote system, and a + function to text the remote system's ability to play "ANSI" + music. You may use both of these functions in your own doors, if + you wish to add music or sound effect capabilities. This program + can be compiled by following the instructions that begin on page + 22. + + +------------------------------------------------------------------------------- +EX_SKI.C This is a simple but addictive online game that is written using + OpenDoors. In this action game, the player must control a skier + through a downhill slalom course. The user may turn the skier + left or right, and the game ends as soon as the player skis + outside the marked course. The game begins at an easy level, but + quickly becomes more and more difficult as the course to be + navigated becomes more and more narrow. The game maintains a + list of players with high scores, and this list may be viewed + from the main menu. + + +------------------------------------------------------------------------------- +EX_VOTE.C The EX_VOTE.C file contain the source code for the Vote example + door, as is described beginning on page 38. The Vote example + door allows users to vote on up to 200 different "polls", view + the results of voting on each question, and optionally add their + own questions for other users to answer. + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 39 + + 444 + 4444 + 44 44 + 44444444 + 44 + 44 + 44 +------------------------------------------------------------------------------- +CHAPTER 4 - THE OPENDOORS API FUNCTIONS + + + + +OVERVIEW +------------------------------------------------------------------------------ + + OpenDoors provides a wide set of features that you can take + advantage of in your program. You control these features and + access OpenDoors from your program using two facilities - the + OpenDoors API functions, and the OpenDoors control structure. In + general, the API functions are used to actually accomplish a + task, such as displaying something to the user, or retrieving + input from the user. The OpenDoors control structure, on the + other hand, is used to alter OpenDoors settings or retrieve + specific information. + + Any program written with OpenDoors makes use of the OpenDoors + API functions for all of its door-related input and output. In + addition to the common input and output tasks, the OpenDoors API + functions provide access to many special capabilities, such as + displaying ASCII/ANSI/AVATAR/RIP files, providing pop-up windows + and menus, and much more. Much of the information about the user + who is online, information about the system your door is running + on, and settings which customize OpenDoor's behavior are + controlled through the OpenDoors control structure. The control + structure is described in the section beginning on page 148. + + This chapter is divided into the following sections: + + i.) TABLE OF MOST COMMONLY USED FUNCTIONS (Page 41) + ii.) TABLE OF ALL OPENDOORS FUNCTIONS (Page 42) + iii.) DETAILED INFORMATION ON EACH FUNCTION (Pages 47 - 147) + + The two tables list the names of the OpenDoors functions, along + with a brief description of the task performed by each function, + and the page number on which the detailed description of that + function can be found. The first table lists only the most + commonly used OpenDoors functions, to allow you to quickly find + the function you are most likely looking for. The second table + lists all of the OpenDoors functions, grouped according to + general categories of functionality. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 40 + + The section containing detailed information lists all of the + functions in alphabetical order, with the information about each + function beginning on a new page. This section includes a brief + description of each function's purpose, a detailed description + of how to use the function, the function call format, a list of + related functions, and in many cases example source code showing + you a typical use of the function. + + + + +TABLE OF MOST COMMONLY USED FUNCTIONS +------------------------------------------------------------------------------ + + od_printf() Displays text, with the ability to change + display color. (page 110) + + od_clr_scr() Clears the screen. (Page 57) + + od_input_str() Inputs a string of one or more characters + from the user. (Page 95) + + od_get_answer() Inputs a single key from a list of possible + choices ignoring upper/lower case. (Page 81) + + od_get_key() Inputs any single key from the user. + (Page 82) + + od_set_cursor() Positions the cursor in ANSI/AVATAR/RIP + modes. (Page 134) + + od_hotkey_menu() Displays an ASCII/ANSI/AVATAR/RIP file, with + the option of watching for a keypress from + the user. (Page 90) + + od_popup_menu() Displays a popup menu in ANSI/AVATAR/RIP + modes. (Page 105) + + od_window_create() Creates a popup window in ANSI/AVATAR/RIP + modes. (Page 145) + + od_window_remove() Removes a popup window in, restoring screen + contents "underneath" window. (Page 147) + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 41 + +TABLE OF ALL FUNCTIONS +------------------------------------------------------------------------------- +OUTPUT TEXT DISPLAY FUNCTIONS +FUNCTIONS ---------------------- + od_disp_str() Displays a normal, NULL-terminated + string. (page 63) + + od_disp() Sends the specified number of + characters to the modem, with or + without local echo. (page 60) + + od_printf() Performs formatted output, as the + printf() function does. Also allows + imbedded codes to change display color. + (page 110) + + od_putch() Displays a single character. (page 115) + + od_disp_emu() Displays a string, interpreting + imbedded ANSI/AVATAR terminal emulation + codes. (page 62) + + od_repeat() Displays the same character any number + of times, using AVATAR optimization, if + possible. (page 118) + + COLOR AND CURSOR CONTROL + ------------------------ + od_set_color() Sets current color to specified + foreground and background settings. + (page 131) + + od_set_attrib() Sets current color to specified IBM-PC + display attribute. (page 128) + + od_set_cursor() Sets the position of the cursor, if + ANSI/AVATAR/RIP mode is enabled. (page + 134) + + SCREEN MANIPULATION + ------------------- + od_clr_scr() Clears the screen, if user has screen + clearing enabled. (page 57) + + od_save_screen() Stores the current contents of the + screen, to be later redisplayed using + od_restore_screen(). Works in all + display modes. (page 121) + + od_restore_screen() Restores the contents of the screen, as + previously stored using + +=============================================================================== +OpenDoors 6.00 Manual End of Page 42 + + od_save_screen(). Works in all display + modes. (page 120) + + BLOCK MANIPULATION + ------------------ + od_clr_line() Clears the remainder of current line. + (page 55) + + od_gettext() Stores any area of the screen, to later + be displayed by od_puttext(). Requires + ANSI/AVATAR/RIP graphics mode. (page + 89) + + od_puttext() Displays text with color information, + as previously stored using + od_gettext(). Requires ANSI/AVATAR/RIP + graphics mode. (page 116) + + od_scroll() Scrolls a portion of the screen in + ANSI/AVATAR/RIP graphics modes. (page + 123) + + POPUP WINDOWS AND MENUS + ----------------------- + od_draw_box() Draws a box on the screen in + ANSI/AVATAR/RIP graphics mode. (page + 65) + + od_window_create() Displays a popup window, storing the + screen contents "under" the window. + Requires ANSI/AVATAR/RIP graphics mode. + (page 145) + + od_window_remove() Removes a popup window displayed with + od_window_create(), restoring the + original screen contents "under" the + window. Requires ANSI/AVATAR/RIP + graphics mode. (page 147) + + od_popup_menu() Displays a menu in a popup window, + allowing the user to choose menu items + either by pressing a "hot" key, or + moving a highlighted selection bar. + After menu selection, the menu may be + removed, restoring the original screen + contents "under" the window. Requires + ANSI/AVATAR/RIP graphics mode. (page + 105) + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 43 + + FILE DISPLAY FUNCTIONS + ---------------------- + od_send_file() Displays an ASCII/ANSI/AVATAR/RIP file + (for instance, an .ANS file created by + a program such as "TheDraw" (page 124) + + od_hotkey_menu() Displays an ASCII/ANSI/AVATAR/RIP menu + file, with hotkeys active. (page 90) + + od_list_files() Lists the files available for download + in an area, using a FILES.BBS file. + (page 98) + + +------------------------------------------------------------------------------- +INPUT od_get_answer() Inputs a single key from the keyboard, +FUNCTIONS allowing only particular responses. + (page 81) + + od_get_input() A more flexible version of + od_get_key(), that also supports + extended keys such as arrow keys, + insert, etc. (page 82) + + od_get_key() Inputs a single key from the keyboard, + optionally waiting if a key is not + available. (page 82) + + od_input_str() Inputs a string of specified length, + from the keyboard. (page 95) + + od_edit_str() Formatted string editing function, + requiring ANSI/AVATAR/RIP graphics. + (page 68) + + od_multiline_edit() Provides a text editor that allows the + user to enter or edit text that spans + multiple lines, such as email messages + or text files. (page 101) + + od_clear_keybuffer() Removes any waiting keys from the + keyboard input queue. (page 53) + + +------------------------------------------------------------------------------- +COMMON od_page() Allows the user to page the sysop. +DOOR (page 101) +ACTIVITY +FUNCTIONS od_spawn() OpenDoors "quick" spawn function. + Executes an external program (eg. file + compressor, external protocol, etc.) on + +=============================================================================== +OpenDoors 6.00 Manual End of Page 44 + + a separate screen, restoring the + OpenDoors screen afterwards. (page 139) + + od_spawnvpe() OpenDoors full-featured spawn function. + Executes an external program on a + separate screen, searching the path for + the program, allowing you to specify an + environment to pass to the child + process, and returning the errorlevel + returned by the child process. (page + 143) + + od_log_write() Adds an entry to the end of the log + file. (page 100) + + od_parse_cmd_line() Handle standard command line options. + (page 105) + + +------------------------------------------------------------------------------- +SPECIAL od_init() Begins door operation by setting up +CONTROL the OpenDoors control structure, +FUNCTIONS setting up the local screen, + initializing the serial port (if + applicable), and reading the door + information file. (page 92) + + od_color_config() Transfers a color configuration line to + a color attribute value. (page 59) + + od_add_personality() Adds a custom status line/control key + personality to OpenDoors. (page 47) + + od_set_statusline() Temporarily alters the setting of the + current OpenDoors status line. (page + 137) + + od_autodetect() Automatically determines the remote + terminal software's graphical + capabilities. (page 48) + + od_kernel() The central OpenDoors control function, + which should be executed every few + seconds. (page 97) + + od_exit() Ends door operations, closing the + serial port driver, re-writing the door + information file, and optionally + returning control to the BBS. (page 79) + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 45 + + od_carrier() Allows detection of carrier signal in + programs that have disabled OpenDoors + internal checking. (page 51) + + od_set_dtr() Controls the DTR signal to the modem. + Can be used to manually disconnect a + remote user, in order to perform + activities such as call back + verification. (page 135) + + od_chat() Forces OpenDoors to enter chat mode, + even if sysop did not press the "chat" + key. (page 50) + + od_sleep() Suspends program execution, yielding + control to other tasks in a + multitasking environment. (page 139) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 46 + +OD_ADD_PERSONALITY() +------------------------------------------------------------------------------- + +PURPOSE Installs a custom status line / sysop function key personality + into OpenDoors. + + +FORMAT BOOL od_add_personality(char *pszName, BYTE btOutputTop, + BYTE btOutputBottom, OD_PERSONALITY_PROC *pfPerFunc); + + +RETURNS TRUE on success + FALSE on failure + + +DESCRIPTION If used, this function should be called before any other + OpenDoors API functions. This function installs a new + personality into OpenDoors. The first parameter specifies the + string that will be used to identify the personality. This is + the string that the user will be able to supply in the + configuration file to select this personality, and is also the + string that can be passed to od_set_personality() to manually + switch to this personality. The second and third parameters + specify the 1-based to and bottom line numbers of the output + window to be used with this personality. For instance, a top + value of 1 and bottom value of 23 would cause all door output to + be displayed on the first 23 lines of the screen, leaving the + bottom two lines for use by the personality's status line. The + last parameter is a pointer to the personality function, which + OpenDoors will call to perform various operations with that + involve the personality. For more information on personalities + and the OpenDoors Multiple Personality System, see the section + which begins on page 233. + + This function only has an effect under the DOS version of + OpenDoors. + +SEE ALSO od_set_personality(), od_set_statusline() + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 47 + +OD_AUTODETECT() +------------------------------------------------------------------------------- + +PURPOSE Attempts to automatically determine the terminal capabilities of + the remote system. + + +FORMAT void od_autodetect(int nFlags); + + +RETURNS N/A + + +DESCRIPTION This function can be used to determine whether or not the remote + terminal supports ANSI and/or RIP (Remote Imaging Protocol) + graphics modes. This information is usually supplied to the door + by the BBS software, through the door information file. For this + reason, most door programs do not need to make used of this + function. However, if your door will be running under any BBS + software that does not report the ANSI or RIP capabilities of + the remote system, you may wish to use this function. + od_autodetect() will set either of the following OpenDoors + control structure variables to TRUE if the corresponding + graphics mode is detected: + + od_control.user_ansi - TRUE if ANSI mode is available + od_control.user_rip - TRUE if RIP mode is available + + However, if either of these variables have previously been set + to TRUE (either explicitly by your program, or due to the + corresponding modes being enabled in the door information file), + and od_autodetect() does not detect the corresponding graphics + mode, they will not be set to FALSE. Not all terminal software + that supports ANSI or RIP graphics mode will necessarily have + the ability to report their graphics mode capabilities to the + door. For this reason, failure to detect either of these modes + does not necessarily indicate that they are not available. + However, if these modes are detected by od_autodetect(), it is + safe to assume that the remote system does support the detected + mode. + + The nFlags parameter is reserved for future use, and should + always be set to DETECT_NORMAL. + + This function cannot auto-detect AVATAR mode, because there is + no standard means of determining whether a remote system + supports AVATAR mode. + + +EXAMPLE Below is an example of using od_autodetect() in determining the + remote terminal's graphics capabilities. Since not all terminal + software supports auto-detection, this example will also prompt +=============================================================================== +OpenDoors 6.00 Manual End of Page 48 + + the user to determine their software's capabilities if + od_autodetect() fails to detect ANSI mode. This code assumes + that if the terminal software supports the autodetection of ANSI + mode, that it will also support the autodetection of RIP mode. + OpenDoors assumes that ANSI mode is always available in + conjunction with RIP mode. + + /* Call the automatic terminal detection function */ + od_autodetect(); + + /* If ANSI mode was not detected, ask the user about + if(!od_control.user_ansi) + { + /* Prompt the user for ANSI capabilities */ + od_clr_scr(); + od_printf("Does your system support ANSI graphics?"); + od_printf(" (Y/N)"); + + /* If the user chooses [Y]es */ + if(od_get_answer("YN") == 'Y') + { + /* Turn on ANSI mode */ + od_control.user_ansi = TRUE; + + /* Since ANSI mode is present, RIP mode may also */ + /* be available. Prompt the user for RIP. */ + od_printf("\r\n\n"); + od_printf("Does your system support RIP graphics?"); + od_printf(" (Y/N)"); + + /* If the user chooses [Y]es */ + if(od_get_answer("YN") == 'Y') + /* Turn on RIP mode */ + od_control.user_rip = TRUE; + + /* Since ANSI mode is present, AVATAR mode may */ + /* also be available. Prompt the user for AVATAR. */ + od_printf("\r\n\n"); + od_printf("Does your system support AVATAR "); + od_printf("graphics? (Y/N)"); + + /* If the user chooses [Y]es */ + if(od_get_answer("YN") == 'Y') + /* Turn on AVATAR mode */ + od_control.user_avatar = TRUE; + } + + od_printf("\r\n\n"); + } + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 49 + +OD_CHAT() +------------------------------------------------------------------------------- + +PURPOSE Manually invokes sysop chat mode. + + +FORMAT void od_chat(void); + + +RETURNS N/A + + +DESCRIPTION Normally, the OpenDoors sysop chat mode will only be invoked + when the sysop explicitly requests it using the sysop chat key. + However, there may be some cases where you wish to manually + invoke the sysop chat mode. One example is when you are + replacing the OpenDoors built-in chat mode with your own, but + still wish to use the OpenDoors chat mode under some + circumstances. For instance, you may wish to use your own split- + screen chat routine if ANSI, AVATAR or RIP graphics mode is + available, and use the OpenDoors line-oriented chat mode if only + ASCII mode is available. + + +SEE ALSO od_page() + + +EXAMPLE For an example of using the od_chat() function, see the + ex_chat.c example door, which is described on page 38. + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 50 + +OD_CARRIER() +------------------------------------------------------------------------------- + +PURPOSE To determine the status of the carrier detect signal, in + programs where OpenDoors' internal carrier detection has been + disabled. + + +FORMAT BOOL od_carrier(void); + + +RETURNS TRUE if a carrier is present, or + FALSE if no carrier is present, or in local mode. + + +DESCRIPTION Usually, you will not have any use for the od_carrier() + function, as OpenDoors automatically monitor's the carrier + detect signal, and will correctly recover if the carrier detect + signal is lost while the door is operating in remote mode. + However, in some programs, you may wish to disable OpenDoors' + internal carrier detection routines, using the + od_control.od_disable variable. Two such cases in which you + might want to do this, are a call-back verification door, which + disconnects the user and attempts to call them back, or in a + terminal program, which is in fact not a door at all (and as + such you would not want to have OpenDoors exit when the carrier + detect signal is lost). In cases like these, you will then be + able to use the od_carrier() function in order to determine the + state of the carrier detect signal. + + This function will return a Boolean value (for more information + on Boolean values, see the Glossary which begins on page 256), + of either TRUE or FALSE. If a carrier detect signal is present + when the function is called, it will return TRUE, and if no + carrier detect signal is detected, it will return FALSE. Since + there is no remote connection, and thus no carrier when + OpenDoors is operating in local mode, this function will always + return a value of FALSE in local mode. + + +SEE ALSO od_set_dtr() + + +EXAMPLE As an example of the use of this function, let us consider a + call back verification door, which hangs up on the user, and + then calls the user back at their entered phone number, in order + to verify the correctness of that number. This program would + probably contain a function that is responsible for + disconnecting the user, waiting for the connection to be broken, + and then phoning the user. At some point in this function, + likely just prior to the point where the function hangs up on + +=============================================================================== +OpenDoors 6.00 Manual End of Page 51 + + the user, you would disable OpenDoors' internal carrier + detection, using the line: + + od_control.od_disable |= DIS_CARRIERDETECT; + + You would then want to have a piece of code which would simply + wait up to a given amount of time for the carrier signal to + drop. If this occurs, you would continue to place the call, and + if it does not occur, you would probably try your hangup + procedure one or two more times. In this example, the function + will return with a value of FALSE if the carrier signal does not + drop, and will return a value of TRUE if it does. + + char hangup(void) + { + clock_t timer; + char to_return = FALSE; + + od_set_dtr(FALSE); /* Hangup modem */ + + /* Wait up to 30secs */ + timer = clock() + CLOCKS_PER_SEC * 30; + while(timer >= clock()) + { /* If carrier has been lost, return with success */ + if(!od_carrier()) + { + to_return = TRUE; + break; + } + } + + od_set_dtr(TRUE); /* Re-enable DTR signal */ + return(to_return); + } + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 52 + +OD_CLEAR_KEYBUFFER() +------------------------------------------------------------------------------- + +PURPOSE Function to clear the input keyboard buffer + + +FORMAT void od_clear_keybuffer(void); + + +RETURNS N/A + + +DESCRIPTION OpenDoors maintains its own keyboard input buffer, in order to + permit the user to "type ahead" - to send input to the door + prior to the time when it is ready to process those key presses. + For example, the user could begin to type a command while a menu + is still being displayed, and when your door reaches the point + of inputting the menu command, the characters already typed by + the user will already be waiting for the OpenDoors input + functions. Note that the keyboard input buffer will include both + the keys hit by the user on-line, and the non-function keys (ie, + Alt-C will not appear in the OpenDoors keyboard buffer), hit by + the sysop. This allows both the user on-line and the sysop to + control the door at any time. If the sysop wishes to temporarily + prevent the user from having any control over the door, the + sysop may use the Alt-K (user-keyboard off) key. The key strokes + placed in the OpenDoors type-ahead buffer will be retrieved by + the od_get_key() and od_input_str() functions. The keyboard + buffer can contain a maximum of 64 user keystrokes in this + version of OpenDoors, after which any additional keystrokes will + simply be discarded by OpenDoors. + + There are times, however, when you will want to erase any keys + that have been hit by the user, to prevent them from typing + ahead. For example, if your door has been busy doing some + processing for a few moments, they user may have been pressing + keys on their keyboard - perhaps in the hope that doing so will + speed things up. These keys will be waiting in the type-ahead + buffer, and if one of the keys the user entered was a valid + response to the next prompt in your door, the user may find that + they have accidentally made a choice they did not wish to. A + well designed door will simply erase the contents of the type- + ahead buffer after any long period of internal processing, etc. + Keep in mind that too much use of the od_clear_keybuffer() + function can be just as undesirable as not using it all, as + there are times when the presence of the keyboard buffer can + prove to be very useful for the user of a door. + + To erase the contents of the type-ahead buffer, you simply call + the od_clear_keybuffer() function. This function takes no + parameters, and does not return any value. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 53 + + + +SEE ALSO od_get_key(), od_input_str(), od_edit_str() + + +EXAMPLE For one example of the use of the od_clear_keybuffer() function, + see the example program EX_VOTE.C, which is described beginning + on page 38. Below is another example of using this function. In + this case, we present a simple function, wait_for_return(), + which simply pauses for the user to press their [Enter]/[Return] + key. The function begins by displaying a prompt asking for the + [Enter] or [Return] key to be pressed. The function then clears + the keyboard input buffer, and waits until the user presses the + carriage return key, using the od_get_key() function. Note also + that this function will only continue if the user has pressed + the correct key. This is a good idea in all door programs, as it + allows your door to distinguish between a character pressed by + the user, and a "line noise" character. + + void wait_for_return(void) + { /* Display prompt */ + od_disp_str("Please Press [Enter] to continue...\n\r"); + od_clear_keybuffer(); /* Clear keyboard buffer */ + while(od_get_key(TRUE) != 13); /* Wait for Enter key */ + } + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 54 + +OD_CLR_LINE() +------------------------------------------------------------------------------- + +PURPOSE Clears the rest of the current display line + + +FORMAT void od_clr_line(void); + + +RETURNS N/A + + +DESCRIPTION This function clears the line that the cursor is on, from the + cursor position to the end of the line. After the rest of the + line is cleared, the cursor is automatically returned to the + position it was at prior to issuing the command. Hence, if the + display line the cursor was located on looked as follows, with + the underscore (_) character representing the cursor position: + + This is a_line of text! + + With the cursor between the words "a" and "line", after the + od_clr_line command is issued, the line would appear as follows: + + This is a_ + + With the cursor directly following the word "a". Note that this + function places a space character at the cursor location, and + every location up to the end of the line. + + When the door is running in plain ASCII mode, this command will + simply clear the rest of the line by manually sending a series + of space and backspace characters. When ANSI, AVATAR or RIP + modes are active, the corresponding ANSI/AVATAR control sequence + will be sent in order to accomplish the line clear. Since the + graphics mode sequences are much shorter than the sequence that + would be required to clear the line manually, the use of this + function will cause your door's graphics to display much more + quickly when ANSI, AVATAR or RIP modes are active. Also note + that in ANSI, AVATAR or RIP graphics modes, the line will be + cleared with the currently selected color attribute. Thus, if + you wanted to place a blue background on a particular line, you + would use the od_set_color() (or od_set_attrib()) function, then + use the od_set_cursor() function to locate the cursor at the + beginning of the desired line, followed by the od_clr_line() + function. Just such a procedure is demonstrated in the example, + below. + + +SEE ALSO od_clr_scr(), od_set_cursor() + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 55 + +EXAMPLE Below, is an example of a function that clears an entire line + with a specified color. Since this function performs operations + that require ANSI, AVATAR or RIP graphics mode, it should only + be used in a case where these modes are known to be available. + For example, this function would be useful in a full-screen + editor or viewer, or when performing ANSI animations. The + function accepts three parameters: the line to be cleared (where + 1 is the first line, 2 the second, and so on), the foreground + color of this line, and the background color of this line. + + This function differs from the od_clr_line() function itself in + several important manners. First of all, this function clears + the entire line, whereas the od_clr_line() function can be used + to clear only the remaining characters of the line, after any + particular location. Also, as mentioned before, this function + selects a color to clear the line to, and moves the cursor to + the line which is to be cleared - neither of which is done by + the od_clr_line() function. + + + void clear_line(char line_number,char foreground,char + background) + { + od_set_cursor(line_number,1); /* move to correct line */ + od_set_color(foreground,background); /* set color */ + od_clr_line(); /* clear entire line */ + } + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 56 + +OD_CLR_SCR() +------------------------------------------------------------------------------ + +PURPOSE The OpenDoors clear screen function + + +FORMAT void od_clr_scr(void); + + +RETURNS N/A + + +DESCRIPTION The od_clr_scr() function can be used to clear the output + screen. (ie, the user's screen and local screen with the + exception of the status line are cleared.) This function will + only clear the screen if screen clearing is enabled. If your + program will be running under BBS systems that do not pass the + user's screen clearing setting to the door, you may wish to + determine yourself whether or not the user's system supports + screen clearing codes, during the first time the user uses the + door. You will then be able to store this setting in a data + file. The example below demonstrates how to detect whether or + not the user's system supports screen clearing. + + You should note that the ability for the user's terminal to + support screen clearing codes is independent of the user's ANSI + / AVATAR / RIP graphics mode settings. + + For more information on the user's screen clearing setting, + please refer to the user_attrib variable in the OpenDoors + Control Structure chapter of this manual. If you wish to force a + screen clear, regardless of the user's screen clearing setting, + simply use the function call: + + od_disp_emu("\xc", TRUE); + + +SEE ALSO od_clr_line() + + +EXAMPLE Below is an example of a function which determines whether or + not the user's system supports screen clearing. This function + will return a value of TRUE if screen clearing is supported, and + will return a value of FALSE if screen clearing is not + supported: + + int user_supports_screen_clearing(void) + { + char answer; + /* display instructions to user */ + od_disp_str("In order for this door to function\n\r"); + od_disp_str("correctly, we must know whether or not\n\r"); +=============================================================================== +OpenDoors 6.00 Manual End of Page 57 + + od_disp_str("your system supports screen clearing.\n\r"); + od_disp_str("In a moment, we will attempt to clear\n\r"); + od_disp_str( + "your screen in order to test your system's\n\r"); + od_disp_str("capabilities.\n\r\n\r"); + + od_disp_str("Please press [Enter]/[Return] when you\n\r"); + od_disp_str("are ready to perform this test.\n\r"); + while(od_get_key(TRUE)!=13); /* wait for [Return] key */ + + od_clr_scr(); /* attempt to clear screen */ + /* ask user if their screen cleared */ + od_disp_str("Did your screen just clear? (Y/N)\n\r"); + for(;;) /* loop until user chooses [Y]es or [N]o */ + { + answer=od_get_key(TRUE); /* Get user's answer */ + if(answer=='y' || answer=='Y') return(TRUE); + if(answer=='n' || answer=='N') return(FALSE); + } + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 58 + +OD_COLOR_CONFIG() +------------------------------------------------------------------------------- + +PURPOSE Parses a color configuration line from the configuration file, + generating a color attribute value. + + +FORMAT BYTE od_color_config(char *pszColorDesc); + + +RETURNS Color attribute value + + +DESCRIPTION This function will be of use if you are using the configuration + file system of OpenDoors, and wish to allow the sysop to specify + text colors to be used in your door. While OpenDoors + automatically recognizes color configuration settings for things + such as sysop chat mode and FILES.BBS listings, you may wish to + add additional color configuration options. In this case, you + could call the od_color_config() function from your custom line + function. For more information on the custom line function, see + the section on the OpenDoors configuration file system, which + begins on page 224. + + To use this function, simply pass the configuration file line + you wish to have parsed to the function in it's single + parameter. The function will then return a color attribute value + in the same format that is used but the od_set_attrib() + function. Colors are specified using a string of the format: + + {Flashing} {Bright} [foreground] on [background] + + Where "Flashing" is an optional keyword indicating that the text + should be flashing. "Bright" is an optional keyword indicating + that the foreground color should be bright. Foreground is the + name of a foreground color, and background is the name of a + background color. Case (upper or lower) is not significant. + + The color keywords are language configurable, using the array + od_control.od_color_names. + + +EXAMPLE See the example accompanying in the section on the OpenDoors + configuration file system, which begins on page 224. + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 59 + +OD_DISP() +------------------------------------------------------------------------------ + +PURPOSE Sends a buffer of text with optional local echo + + +FORMAT void od_disp(char *pachBuffer, INT nSize, BOOL bLocalEcho); + + +RETURNS N/A + + +DESCRIPTION This function allows you to send a buffer of text of any + specified length, with the option of enabling or disabling local + echo. You will probably have little use for this function - + instead you will most likely display strings using either the + od_disp_str() or od_printf() functions, depending on whether or + not you wish to use printf()'s formatting options. For a + breakdown of the uses of the various OpenDoors display + functions, see the description of the od_disp_str() function, on + page 63. + + There are two cases when this function will come in useful: + + 1.)If you wish to display a buffer of characters of known + length, which may contain null (ASCII 0) characters. + Since this character is used by the C language to + indicate the end of a string, the other two string + display functions (od_disp_str() and od_printf()) will + not send this character to the remote system. + + 2.)If you wish to send text to the remote system without + having it displayed on the local screen, or if you wish + to send strings to the modem when it is in command + mode, without having these characters displayed on the + local screen. + + The od_disp() function is called with three parameters. The + first parameter, pachBuffer, is a pointer to a buffer of + characters you wish to have displayed. The second parameter, + nSize, is simply the number of characters in the buffer to be + displayed. If the third parameter, bLocalEcho, is set to TRUE, + then all characters sent to the modem will also be displayed on + the local screen. If the third parameter is set to FALSE, then + the buffer will be sent to the modem without being echoed to the + sysop's screen. + + +SEE ALSO od_disp_str(), od_printf(), od_putch(), od_repeat(), + od_disp_emu() + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 60 + +EXAMPLES The following are a few examples of the use of the od_disp() + function: + + In order to display a single character, contained in the + variable "character", without echo to the local screen: + + od_disp(&character,1,FALSE); + + + In order to send a command to the modem (only if you know that + the modem is in command mode), with the command contained in the + null-terminated string "string": + + od_disp(string,strlen(string),FALSE); + + + In order to send exactly 5 characters from the buffer "buffer", + WITH echo to the local screen: + + od_disp(buffer,5,TRUE); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 61 + +OD_DISP_EMU() +------------------------------------------------------------------------------- + +PURPOSE Displays a string with ANSI/AVATAR terminal emulation + + +FORMAT void od_disp_emu(char *pszToDisplay, BOOL bRemoteEcho); + + +RETURNS N/A + + +DESCRIPTION The od_disp_emu() function allows you to display your own ANSI / + AVATAR graphics sequences. This function passes the characters + you wish to display to the OpenDoors terminal emulator, which is + fully documented in the description of the od_send_file() + function, on page 124. This function can be used to send these + control sequences to the user's terminal, and also have them + displayed on the local screen as they will appear to the user. + + The string passed to od_disp_emu() contains any stream of text + to display, and may include both normal text and terminal + emulation control sequences. If the bRemoteEcho parameter is set + to TRUE, the string passed to od_disp_emu() will be sent to the + remote terminal in addition to being displayed locally. If this + parameter is set to FALSE, the string will only be displayed + locally. + + Note that if you wish to display an entire file containing + ANSI/AVATAR/RIP graphics sequences (perhaps as your program's + menu or title screen), you can use the od_send_file() function. + + +SEE ALSO od_send_file(), od_disp(), od_disp_str() od_printf(). + + For a breakdown of the uses of the various OpenDoors display + functions, see the od_disp_str() function, on page 63. + + +EXAMPLE For an example of the use of the od_disp_emu() function, see the + SpaceRight() and MoveLeft() functions included in the example + program ex_ski.c. + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 62 + +OD_DISP_STR() +------------------------------------------------------------------------------- + +PURPOSE Displays a string to the screen (remote and local) + + +FORMAT od_disp_str(char *pszToDisplay); + + +RETURNS N/A + + +DESCRIPTION The two functions most often used for displaying strings within + a door are the od_disp_str() and od_printf() functions. The + od_printf() function allows for formatted output, whereas the + od_disp_str function simply displays the actual contents of the + string passed to it. If you wish to display a single character, + use the od_putch() function. If you wish to send a string or + buffer to the modem without local echo, use the od_disp() + function. If you wish to send a sequence of the same character + to the modem, the od_repeat() function will use graphics control + codes, if available to display the sequence much faster than + simply sending the same character in repetition. Also, if you + wish to send ANSI, AVATAR or RIP graphics control codes, and + have them emulated on the local screen, use the od_disp_emu() + function. + + The od_disp_str() function displays the contents of the null- + terminated string pointed to by *string. Display is sent to both + the local screen and modem (presuming the door is not running in + local mode). + + An important thing to keep in mind when using the od_disp_str() + function, is that you should use "/n/r" instead of simply "/n" + for a new line. This is due to the fact that terminal programs + usually require a carriage-return line-feed sequence (/n/r), + instead of just a line-feed (/n). For example, instead of using: + + od_disp_str("Hello world!\n"); + + You should use: + + od_disp_str("Hello world!\n\r"); + + To change the cursor color or location of output with the + od_disp_str() function, refer to the od_set_cursor() and the + od_set_attrib() functions. + + +SEE ALSO od_disp(), od_printf(), od_putch(), od_repeat(), od_disp_emu() + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 63 + +EXAMPLES Below are a few examples of various uses of the od_disp_str() + function: + + Displaying three string constants on separate lines: + + od_disp_str("This is an example\n\r"); + od_disp_str("of the OpenDoors\n\r"); + od_disp_str("od_disp_str() function\n\r"); + + + Displaying three string constants on the same line: + + od_disp_str("Another "); + od_disp_str("od_disp_str() "); + od_disp_str("example\n\r"); + + + Displaying a string variable: + + char string[80]; + + strcpy(string,"This is a string!\n\r"); + od_disp_str(string); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 64 + +OD_DRAW_BOX() +------------------------------------------------------------------------------- + +PURPOSE Draws a box on the screen in ANSI, AVATAR or RIP graphics modes. + + +FORMAT BOOL od_draw_box(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE + btBottom); + + +RETURNS TRUE on success, FALSE on failure + + +DESCRIPTION This function is for use in ANSI, AVATAR or RIP graphics modes. + This function will draw a box in the current display attribute, + at the specified location on the screen. The boarder of the box + is made up of the characters specified in the od_control. + od_box_chars[] array. If AVATAR graphics mode is available, this + function uses AVATAR control codes to display the box in less + than 1/10 the length of time required to display the box in ANSI + mode. + + The first two parameters of this function, btLeft and btTop, + specify the coordinates of the top, left-hand corner of the box + to be draw. The third and fourth parameters, btRight and + btBottom, specify the coordinates of the bottom, left-hand + corner of the box. Like the values passed to the od_set_cursor() + function, these coordinates are relative to the upper left-hand + corner of the screen, with the position (1,1) being this corner. + + As mentioned above, this function will display the window in the + current text color. Thus, before calling this function, you + should use either the od_set_color() or the od_set_attrib() + function to specify the color in which you would like to have + the window displayed. + + Normally, the boarder of the window will be displayed using the + IBM extended ASCII characters which produce a single line + boarder. However, you may wish to have the boarder displayed + using different characters. In this case, the characters used to + display the boarder can be specified by the od_control. + od_box_chars variable, described in the OpenDoors control + structure section of this manual. + +SEE ALSO od_set_color(), od_set_attrib(), od_clr_scr(), od_edit_str(), + od_set_cursor() + + +EXAMPLE As an example of the use of the od_draw_box() function in + conjunction with the od_edit_str() function, we show a portion + of a program which displays a window, and allows the user to + input the name of a file they would like to upload, a +=============================================================================== +OpenDoors 6.00 Manual End of Page 65 + + description of the file, and whether they want it to be a + private upload. The user is able to move among fields using the + tab key, and select a "continue" button when they are finished. + The function returns TRUE if the user selects continue, and + FALSE if the user presses [ESCape]. + + // Main "dialog box" function + int get_information(char *filename, char *description, + char *private) + { + char current_field=1; // Currently selected field + int choice; // User's choice + + od_set_color(L_WHITE,D_BLUE); // Display window + od_draw_box(10,5,70,13); + + od_set_cursor(5,25); // Display window title + od_set_color(L_GREEN,D_BLUE); + od_disp_str(" ENTER FILENAME INFORMATION "); + + od_set_color(L_CYAN,D_BLUE); // Display fields and titles + od_set_cursor(6,15); + od_disp_str("FILENAME : "); + od_repeat(176,13); + od_set_cursor(7,12); + od_disp_str("DESCRIPTION : "); + od_repeat(176,43); + od_set_cursor(8,16); + od_disp_str("PRIVATE : "); + od_repeat(176,2); + draw_button(); + + filename[0]='\0'; // Blank out contents of input variables + description[0]='\0'; + private[0]='\0'; + + for(;;) // Main dialog box loop + { + if(current_field==4) // If field is the button + { + od_set_color(L_GREEN,D_BLUE); // Highlight button + draw_button(); + + do // Loop until user presses [TAB], [ENTER], or [ESC] + { + choice=od_get_key(TRUE); + } while(choice!=9 && choice!=13 && choice!=27); + + od_set_color(L_CYAN,D_BLUE); // Un-highlight button + draw_button(); + + if(choice==13) return(TRUE); // If [ENTER] was pressed +=============================================================================== +OpenDoors 6.00 Manual End of Page 66 + + if(choice==27) return(FALSE); // If [ESC] was pressed + current_field=1; // Otherwise, [TAB] was pressed + } + + switch(current_field) // According to selected field + { // Input from the appropriate line + case 1: + choice=od_edit_str(filename,"FFFFFFFFFFFF",6,26, + 0x1b,0x1a,176, + EDIT_FLAG_EDIT_STRING| + EDIT_FLAG_ALLOW_CANCEL| + EDIT_FLAG_FIELD_MODE| + EDIT_FLAG_KEEP_BLANK); + break; + case 2: + choice=od_edit_str(description, + "*******************", + 7,26,0x1b,0x1a,176, + EDIT_FLAG_EDIT_STRING| + EDIT_FLAG_ALLOW_CANCEL| + EDIT_FLAG_FIELD_MODE| + EDIT_FLAG_KEEP_BLANK); + + break; + case 3: + choice=od_edit_str(private,"Y",8,26, + 0x1b,0x1a,176, + EDIT_FLAG_EDIT_STRING| + EDIT_FLAG_ALLOW_CANCEL| + EDIT_FLAG_FIELD_MODE); + } + // If user pressed [ESCape] + if(choice==EDIT_RETURN_CANCEL) return(FALSE); + // If user choice to go to previous field + if(choice==EDIT_RETURN_PREVIOUS) + { + if(current_field==1) // If at first field + current_field=4; // Go to last field + else // If not at first field + --current_field; // Go to previous field + } + else // If user chose next field + ++current_field; // Go to next field + } + } + + void draw_button(void) // Function to display the button + { + od_draw_box(12,10,23,12); // Draw box for button + od_set_cursor(11,14); + od_disp_str("Continue"); // Display text in button + } +=============================================================================== +OpenDoors 6.00 Manual End of Page 67 + +OD_EDIT_STR() +------------------------------------------------------------------------------- + +PURPOSE Allows you to perform formatted input with full line editing + features, etc., in ANSI/AVATAR/RIP graphics mode. + + +FORMAT WORD od_edit_str(char *pszInput, char *pszFormat, INT nRow, + INT nColumn, BYTE btNormalColor, BYTE btHighlightColor, + char chBlank, WORD nFlags); + + +RETURNS This function will return one of the following values: + + EDIT_RETURN_ERROR Indicates that an error has occurred, + and the edit function was unable to + run. This will occur if there is an + error in one of the parameters, or if + ANSI/AVATAR/RIP graphics is not + available + + EDIT_RETURN_CANCEL Indicates that the user pressed the + cancel key [ESC], and that the string + was left unaltered. + + EDIT_RETURN_ACCEPT Indicates that the user pressed the + accept key [Enter], or that the auto- + enter feature was activated. + + EDIT_RETURN_PREVIOUS Indicates that the user wishes to move + to the previous field, by pressing [UP + ARROW], [SHIFT]-[TAB], etc. + + EDIT_RETURN_NEXT Indicates that the user wishes to move + to the next field, by pressing [DOWN + ARROW], [TAB], etc. + + +DESCRIPTION To perform string input within OpenDoors, one of two functions + can be used, od_input_str() and od_edit_str(). The first + function, od_input_str(), allows simple line input and editing, + and can be used in ASCII, ANSI, AVATAR and RIP modes. The second + function, od_edit_str(), allows many formatted input options, + advanced line editing, and other features, but requires the use + of ANSI, AVATAR or RIP terminal modes. + + As mentioned above, the od_edit_str() function allows for + advanced line editing, such as inputting and deleting text from + the middle of the string (whereas the od_input_str() function + only allows editing from the end of the string, such as + backspacing to erase a mistake). The edit functions available + from the od_edit_str() are listed below. Note that some of these +=============================================================================== +OpenDoors 6.00 Manual End of Page 68 + + functions may or may not be available, depending upon the + capabilities of the user's terminal program. While there is no + single standard used for the transmission of special edit keys + such as the arrow keys, the od_edit_str() function makes as much + effort as possible to make all of the edit features available to + most terminal programs. Many of the edit functions can be + accesses using either [CONTROL]-key combinations or special keys + such as the arrow keys, delete key, and so on. OpenDoors will + recognize most of these special control keys when sent as either + an ANSI control sequence (which is sent by most terminal + programs), or as a DoorWay style scan code / ASCII code sequence + (which is also available from many terminal programs, but is not + usually required). The od_edit_str() edit functions are as + follows. Note that all edit functions are always available from + the local keyboard. + + HOME - Moves the cursor to the beginning of the line being + edited. Press the [HOME] key, either in DoorWay mode + or from the local keyboard. + + END - Moves the cursor to the end of the line being edited. + Press the [END] key, either in DoorWay mode or from + the local keyboard. + + DELETE CHARACTER - Deletes the character under the cursor. Press + [DELete] on the local keyboard, in DoorWay mode, and + under many terminal programs without DoorWay mode. + Alternatively, press [CONTROL]-[G]. + + BACKSPACE - Deletes the character left of the cursor. Press + [BACKSPACE] or [CONTROL]-[H]. + + TOGGLE INSERT MODE - Switches the od_edit_str() function between + insert mode and overwrite mode. Press [INSert], either + in DoorWay mode, or from the local keyboard. + Alternatively, press [CONTROL]-[V]. + + CURSOR LEFT - Moves the cursor left one character. Press [LEFT + ARROW] on the local keyboard, in DoorWay mode, and + under many terminal programs without DoorWay mode. + Alternatively, press [CONTROL]-[S]. + + CURSOR RIGHT - Moves the cursor right one character. Press + [RIGHT ARROW] on the local keyboard, in DoorWay mode, + and under many terminal programs without DoorWay mode. + Alternatively, press [CONTROL]-[D]. + + ERASE ENTIRE LINE - Press [CONTROL]-[Y]. + + ACCEPT INPUT - Press the [ENTER] / [RETURN] line to accept the + input. Alternatively, press [CONTROL]-[Z]. Note that + this key will only work when the current input is +=============================================================================== +OpenDoors 6.00 Manual End of Page 69 + + "valid" (ie, it conforms to the format string, which + is described below) + + CANCEL INPUT - Only available if specifically enabled on the + od_edit_str() command line. Press [ESCape]. + + NEXT FIELD - If enabled, allows the user to move to the next + field in a dialog box / form. Press [DOWN ARROW] in + DoorWay mode and under many terminal programs without + DoorWay mode. Alternatively, press [TAB]. Note that + the [DOWN ARROW] key is NOT usually available from the + local keyboard, as it is usually used to adjust the + user's remaining time. + + PREVIOUS FIELD - If enabled, allows the user to move to the + previous field in a dialog box / form. Press [UP + ARROW] in DoorWay mode and under many terminal + programs without DoorWay mode. Alternatively, press + [SHIFT]-[TAB] on the local keyboard or in DoorWay + mode. Again, note that the [UP ARROW] key is NOT + usually available from the local keyboard, as it is + usually used to adjust the user's remaining time. + + + Let us now look at the parameters which the od_edit_str() + function accepts. The first parameter, pszInput, is a pointer to + the string where the user's input should be stored. It is + important that this string be long enough to accommodate the + longest input your format string will permit, including the '\0' + C string terminator (ie, the string should be one character + greater than the length of the format string, not including the + format string's ' and " characters). + + The second parameter, pszFormat, is a pointer to a string which + specifies the format and maximum length of the input the + od_edit_str() function should accept. Using the format string, + not only do you specify the length of the input field, but you + can also force the user's input into certain formats. For + example, if you wished to input a North American style phone + number, you could use a format string of "###-###-####". Then + regardless of whether the user typed any dash character or not, + their input would be converted, as they type, to the format of + the phone number 613-599-5554. You could also specify a format + string such of "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM", which would + permit the user to enter a name of up to 30 characters. Note + that since the cursor can be moved to the position immediately + following the last character, a the input field for a 30 + character string will occupy 31 columns on the screen. The + od_edit_str() function would then automatically capitalize the + name, so that the first character of each word is capitalized, + and the remain characters of the word is in lower case. Even if + the user were to move the cursor to the middle of the string +=============================================================================== +OpenDoors 6.00 Manual End of Page 70 + + they had entered, and add or delete a space (and thus either + make one work two or two words one), od_edit_str() would re- + format the string to reflect the change. The valid characters + for the format sting, along with their meanings, are listed + below. Note that the format string is NOT case sensitive (except + for literal strings delimited by the '' or "" characters), and + space characters can be added at any point to increase + legibility. + + # Indicates that numeric characters from '0' to '9' are valid + for this position + + % Indicates that numeric characters from '0' to '9', and the + space character (' ') are valid for this position. + + 9 Indicates that numeric characters from '0' to '9', along + with '.', '-' and '+' are valid for this position. This + format style is intended for floating-point numeric input. + + ? Indicates that any character is valid for this position. + + * Indicates that any printable character, from ASCII 32 to + ASCII 127, is valid for this position. + + A Indicates that alphabetical characters 'A' to 'Z', 'a' to + 'z' and space (' ') are valid for this position. + + C Indicates that city name characters are valid for this + position. As with the 'M' format character, words are + automatically capitalized so that the first letter is in + upper case, and all subsequent letters are in lower case. + In addition to permitting alphabetical characters and the + space (' ') character, the ',' and '.' characters are also + accepted in this position. + + D Indicates that date characters '0' to '9', '-' and '/' are + valid for this position. + + F Indicates that MS-DOS filename characters are valid for + this position. + + H Indicates that hexidecimal character '0' to '9', 'A' to 'F' + and 'a' to 'f' are valid for this position. + + L Indicates that only lower case alphabetical characters 'a' + to 'z', and the space (' ') character is valid for this + position. However, if the user attempts to enter an upper + case alphabetical character in this position, it will + automatically be converted to the lower case equivalent. + + M Indicates that name characters are valid for this position. + These characters are the alphabetical characters 'A' to +=============================================================================== +OpenDoors 6.00 Manual End of Page 71 + + 'Z', 'a' to 'z', and the space character (' '). A + character's case is converted such that the first character + of a word is in upper case, and all other letters are in + lower case. + + T Indicates that telephone number character '0' to '9', '(', + ')', '-' and ' ' are valid for this position. + + U Indicates that only upper case alphabetical characters 'A' + to 'Z', and the space (' ') character is valid for this + position. However, if the user attempts to enter a lower + case alphabetical character in this position, it will + automatically be converted to the upper case equivalent. + + W Indicates that MS-DOS filename characters are permitted in + this position, including the '*' and '?' wildcard + characters. + + X Indicates that alphanumeric characters 'A' to 'Z', 'a' to + 'z', '0' to '9' and ' ' are valid for this position. + + Y Indicates that yes/no characters 'Y', 'N', 'y', 'n' are + valid for this position. The characters are automatically + converted to upper case. + + '/" Single or double quotes can be used to specify sequences of + characters that should appear at the same location in the + input string (referred to elsewhere as "literal strings"). + When the user is entering the string, these characters are + automatically supplied, and the user is not required to + type them. Literal strings must begin and end with the same + quote character. Remember that the double quote (") + character must be imbedded in C strings by preceding the + quote character with a \ (backslash) character. + + The third and fourth parameters, nRow and nColumn specify the + location on the screen where the first (left most) character of + the input field should be located. These parameters are + identical to the nRow and nColumn parameters passed to the + od_set_cursor() function. In other words, nRow specifies the + line number on the screen, where 1 is the first line, and + nColumn specifies the column across the screen, where 1 is the + first column. + + The fifth and sixth parameters, btNormalColor and + btHighlightColor, allow you to specify the color of the input + field. The fifth parameter, btNormalColor, specifies the color + of the input field when input is not taking place and the sixth + parameter, btHighlightColor, specifies the color of the field + while input is taking place. Thus, if you had several input + fields on the screen at one time, you would be able to make is + easier for the user to identify the currently active field by +=============================================================================== +OpenDoors 6.00 Manual End of Page 72 + + having the field currently accepting input highlighted in a + color distinct from the other fields. When the od_edit_str() + function begins, it will change the current color of the field + from the normal color to the highlighted color. Then, when the + od_edit_str() function exits, it will change the current color + of the field back to its normal color. If you do not wish to + have the field highlighted, you can set both of these parameters + to the same value, and disable field re-drawing by using the + eighth parameter, flags. + + The seventh parameter accepted by the od_edit_str() function, + chBlank, will serve one of two purposes. Normally, this + parameter will specify a background character to display in the + unfilled portion at the end of the input field. This can be set + to a character, such as the ASCII 177 grey block character, to + produce a visual background to the field. Doing this will show + the user visually how long the field is, and how many character + they will be permitted to type into the field. Normally, this + field will be displayed during input, and removed when the + od_edit_str() function exits. However, you may cause the + background to remain in place using the eighth parameter, flags. + If you do not wish to have this "background" visual field + effect, simply set the character parameter to a space (ASCII + 32). In password input mode, this parameter will instead specify + the character to display in place of characters typed by the + user. In this case, the background display character defaults to + the space (ASCII 32) character. + + The eighth, and last, parameter accepted by the od_edit_str() + function is the nFlags parameter. This parameter is a bit-mapped + flags variable which allows you to control special features of + the od_edit_str() function. More than one of these settings may + be specified by listing a chain of the values, separated by the + bitwise-or (|) operator. If you do not wish to turn on any of + these modes, simply pass the EDIT_FLAG_NORMAL value as the flags + parameter. + + EDIT_FLAG_NORMAL - Default setting, use this value of none of + the other flags below are active. + + EDIT_FLAG_NO_REDRAW - When set, prevents the od_edit_str() + function from re-drawing the input string and field + when it starts up and exits. If you set this flag, the + normal color and highlight color should contain the + same value. If background character (the character + parameter) is not a space (ASCII 32) character, you + must draw the field background prior to calling + od_edit_str(). Also, if you are calling od_edit_str() + with the EDIT_FLAG_EDIT_STRING flag set, you must + display the existing string in the field prior to + calling od_edit_str(). + +=============================================================================== +OpenDoors 6.00 Manual End of Page 73 + + EDIT_FLAG_FIELD_MODE - Setting this flag specifies that + od_edit_str() should operate in field input mode. In + field input mode, the user may finish entering their + input by pressing the previous field or next field + button (arrow keys, tab keys, etc.), as described + above. If the user chooses to finish and accept their + input by pressing one of these keys, the od_edit_str() + return value will reflect which choice they made. This + will allow you to make it possible for the user to + move between a number of input fields in a form / + dialog box, as demonstrated in the example + accompanying the od_draw_box() function. + + EDIT_FLAG_EDIT_STRING - Setting this flag specifies that + od_edit_str() should edit a pre-existing string, + instead of starting with a blank string. In this case, + the input_string parameter MUST point to an + initialized string. This string may either contain + some text, or be empty, but od_edit_str() will expect + to find a string terminator ('\0') character, and will + begin editing the contents of the string prior to that + character. If you do not set the EDIT_FLAG_EDIT_STRING + flag, the previous contents of the input_string + parameter is not significant, as od_edit_str() will + automatically start with a blank string. + + EDIT_FLAG_STRICT_INPUT - Setting this flag causes the + od_edit_str() function to operate in "strict" input + mode, which may be desirable if your input format + contains more than one type of input. Normally, if you + were inputting such a string, the user would be able + to move to the middle of the string, and insert any + text. Doing so would cause the rest of the input line + to shift right. However, in cases where your format + string specifies different types of character to be + permitted in different positions, this can cause the + input to be changed so that it no longer conforms to + the format string. In this case, the user's input will + no longer be valid, and the user will not be able to + exit the function by pressing [ENTER] (although + [ESCAPE] will still be available, if you activated it) + until they change their input. However, when strict + input mode is turned on, od_edit_str() will restrict + the ways in which the user is permitted to edit the + string, to prevent just such a case from occurring. + + EDIT_FLAG_PASSWORD_MODE - Setting this flag causes the + od_edit_str() function to operate in "password" mode. + In password mode, the characters typed by the user + will be hidden, displayed instead as the blank + character specified in the "character" parameter. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 74 + + EDIT_FLAG_ALLOW_CANCEL - When this flag is set, the user will be + able to cancel their current input and abort the + editing process by pressing their [ESCAPE] key. When + they do so, any changes they have made to the input + field will be canceled, and replaced by the original + contents of the string. The od_edit_str() function + will then exit, indicating that the user has canceled + their input. + + EDIT_FLAG_FILL_STRING - When set, this flag will force the user + to enter a string that fills the entire length of the + format string. Normally, the user will be able to + enter a string of any length up to the maximum length + specified by the format string. However in some cases, + such as when inputting a date, you will want to have + the input field filled. (Otherwise, the user would be + able to enter only the first part of the date.) + + EDIT_FLAG_AUTO_ENTER - When set, this flag will cause the + od_edit_str() function to automatically simulate + pressing of the [ENTER] key when the string is filled. + This can be used to cause the od_edit_str() function + to finish inputting as soon as a valid string is + entered, instead of having to wait for the user to + press [ENTER] / [RETURN]. + + EDIT_FLAG_AUTO_DELETE - When set, along with the + EDIT_FLAG_EDIT_STRING flag, this flag will activate + the auto-delete feature of the od_edit_str() function. + When auto-delete is active, if the first key pressed + by the user is not an edit control key, the existing + text will automatically be deleted, and a totally new + string accepted from the user. This could be useful + when you are allowing the user to go back to edit a + previous input. If the user wishes to only change part + of the old string, they can move the cursor to the + location where they wish to make the change, and + perform their editing. However, if the user wishes to + completely replace the old string with a new one, they + can simply begin to type, and the old string will + automatically be deleted, and the new string accepted. + + EDIT_FLAG_KEEP_BLANK - Normally, OpenDoors will only display the + input field background (as passed in the "character" + parameter) while the user is editing the string, and + will remove it when the od_edit_str() function exits. + However, you may wish to continue having this field + displayed after input has taken place, and the + od_edit_str() function has exited. In this case, + setting this flag will cause the background characters + to remain visible after input has finished. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 75 + + EDIT_FLAG_PERMALITERAL - When the format string contains literal + characters (such as forcing a ':' character to be + added to a time input by using the format string + "##':'##':'##"), the od_edit_str() function can + operate in one of two modes. In the default mode, the + literal characters will only be displayed when they + have been automatically added to the string. For + instance, if you were inputting the current time using + the above format string, this mode would result in the + input field initially being blank. When the user types + the first digit of the time, that number would appear. + When the user types the second digit of the time, that + number will appear, and then the colon character will + automatically be added by OpenDoors. However, you can + also set the od_edit_str() function to operate in + "PermaLiteral" mode, by setting this flag. When the + EDIT_FLAG_PERMALITERAL flag is set, the input field + will initially contain the literal characters (ie, the + colons in our example), with the cursor still located + at the leftmost position in the input field. In this + mode, the literal character become a permanent part of + the input field, and can not be moved or deleted by + the user - instead the cursor simply skips over the + literal character's position. + + EDIT_FLAG_LEAVE_BLANK - This flag applies to the special case + where the first character or characters of the format + string are literals. By default, the od_edit_str() + function will always return a string containing at + least these first literal characters. However, you can + alter this behaviors by setting this flag. When set, + if no non-literal characters have been entered in the + string, od_edit_str() will return an empty string. + + EDIT_FLAG_SHOW_SIZE - Normally, od_edit() adds an extra blank to + the end of the input field, to give the cursor a space + to move into when the field is full. However, you may + prefer to have the input field be shown as exactly the + maximum size of input that is permitted. Setting + EDIT_FLAG_SHOW_SIZE does just this. In this case, the + cursor will be positioned immediately past the end of + the input field when the maximum number of characters + have been entered. + + +SEE ALSO od_input_str(), od_get_char(), od_clear_keybuffer() + + +EXAMPLE Below are several examples of typical uses of the od_edit_str() + function. For the sake of simplicity, all of these examples + perform their input beginning at the top, left hand corner of + the screen, and store the user's input in the string variable +=============================================================================== +OpenDoors 6.00 Manual End of Page 76 + + named "string". For an example of the user of the od_edit_str() + function in a dialog-box / form entry application, see the + example accompanying the od_draw_box() function. + + To input a name with a maximum of 25 characters, having the + first letter of each word automatically capitalized: + + od_edit_str(string, "MMMMMMMMMMMMMMMMMMMMMMMMM", 1, 1, + 0x03, 0x21, 176, EDIT_FLAG_NORMAL); + + To input a North American style phone number, requiring that all + digits be filled, and running in "strict input" mode: + + od_edit_str(string, "###'-'###'-'####", + 1, 1, 0x03, 0x21, 176, + EDIT_FLAG_FILL_STRING| + EDIT_FLAG_STRICT_INPUT); + + To allow the user to edit a previously entered 20 character + string, with auto-delete mode on. Any characters will be + permitted in the string. Remember that when the + EDIT_FLAG_EDIT_STRING flag is set, the string must be + initialized prior to calling the od_edit_str() function. + + od_edit_str(string, "????????????????????", + 1, 1, 0x03, 0x21, 176, + EDIT_FLAG_EDIT_STRING| + EDIT_FLAG_AUTO_DELETE); + + + To input a password of up to 16 characters from the user. Here, + the password will only be permitted to contain upper case + characters, and the od_edit_str() password mode is used, with a + small block displayed in place of any characters typed: + + od_edit_str(string, "UUUUUUUUUUUUUUUU", + 1, 1, 0x03, 0x21, 254, + EDIT_FLAG_PASSWORD_MODE); + + To input a two-digit number from the user, requiring that both + digits be filled, and automatically accepting the input after + the two digits have been entered (not requiring the user to + press [ENTER]): + + od_edit_str(string, "##", 1, 1, 0x03, 0x21, 176, + EDIT_FLAG_FILL_STRING| + EDIT_FLAG_AUTO_ENTER); + + To input a filename to download, as a field in a dialog box. + Here, the filename will be permitted to contain valid filename + characters, and the od_input_str() function will operate in + field mode, with the cancel [ESCape] key enabled. Also, string +=============================================================================== +OpenDoors 6.00 Manual End of Page 77 + + edit mode will be enabled, allowing the user to edit a + previously entered line, and the EDIT_FLAG_KEEP_BLANK flag will + be set, causing the field background to remain displayed after + the user exits. This time, however, auto-delete mode will not be + used. Note that this combination of parameters expects that the + field and it's contents will have already been displayed, prior + to calling the od_edit_str() function. + + od_edit_str(string, "WWWWWWWWWWWW", + 1, 1, 0x03, 0x21, 176, + EDIT_FLAG_EDIT_STRING| + EDIT_FLAG_FIELD_MODE| + EDIT_FLAG_ALLOW_CANCEL| + EDIT_FLAG_KEEP_BLANK); + + To input a string without the field background and line + redrawing before and after input takes place: + + od_edit_str(string, "******************************", + 1, 1, 0x07, 0x07, ' ', + EDIT_FLAG_NO_REDRAW); + + To input a date, using PermaLiteral mode. Here, the month is + entered by a three digit short form ("JAN", "FEB", etc.), and + the literal characters such as the '-' and the "19" are a + permanent part of the input field: + + od_edit_str(string,"UUU'-'##'-19'##", + 1, 1, 0x03, 0x21, 176, + EDIT_FLAG_PERMALITERAL| + EDIT_FLAG_FILL_STRING); + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 78 + +OD_EXIT() +------------------------------------------------------------------------------- + +PURPOSE The OpenDoors program termination function + + +FORMAT void od_exit(INT nErrorLevel, BOOL bTermCall); + + +RETURNS N/A + + +DESCRIPTION You MUST USE THIS FUNCTION when you want your program to exit. + This function will close the serial port, re-write changed + information to the door information (drop), call your end-of- + program function (if any), and then exit with the errorlevel + specified in the first parameter. + + Also, if the second parameter, bTermCall, is set to TRUE, + od_exit() will also log the user off (for options such as + logging off within the door - as shown in the example below). + This is accomplished by lowering the DTR line to the modem, + causing the modem to hangup. When control is returned to the + BBS, it will then detect that the user is no longer online, and + will carry out its own logoff processing. + + If you wish for your program to always perform any activities + prior to exiting, such as updating or closing data files, you + should set a function to be executed from within the od_exit() + function. This is accomplished by using the od_control. + od_before_exit variable, as described in the section on the + OpenDoors control structure in chapter 5. Use of this variable + will allow your program to always carry out these activates, + even if OpenDoors decides to call the od_exit() function itself, + such as when a user hangs up on the door. + + Note that in special cases, you may use the + od_control.od_disable variable to prevent the od_exit() function + from re-writing the door information file. Also, you may use the + od_control.od_noexit variable to shutdown door operations + without actually exiting your program. Both of these variables + are described in chapter 5. + + +SEE ALSO od_init() + + +EXAMPLE The example below demonstrates a function which a door could + execute when the user chooses to exit the door. This function + will ask the user whether they wish to exit the door and return + to the BBS, simply logoff of the BBS, or continue using the + door. The example function will then call od_exit() if the user +=============================================================================== +OpenDoors 6.00 Manual End of Page 79 + + wishes to exit the door, or return control to the function which + called it, if the user does not wish to exit: + + void goodbye(void) + { + char pressed; + /* Display choices to user */ + od_disp_str("You have chosen to exit this door.\n\r"); + od_disp_str("Do you wish to:\n\r"); + od_disp_str(" [R]eturn to the BBS\n\r"); + od_disp_str(" [L]ogoff of the BBS\n\r"); + od_disp_str(" [C]ontinue using the door\n\r"); + + for(;;) /* loop until user makes valid choice */ + { + pressed=od_get_key(TRUE); /* Get key from user */ + + /* If user selects R, exit without hanging up */ + if(pressed=='R' || pressed=='r') od_exit(40,FALSE); + + /* If user selects L, hangup and then exit */ + if(pressed=='L' || pressed=='l') od_exit(41,TRUE); + + /* If user selects C, return and allow door to continue */ + if(pressed=='C' || pressed=='c') return; + } + } + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 80 + +OD_GET_ANSWER() +------------------------------------------------------------------------------- + +PURPOSE Function to allow the user to respond to a prompt using only + certain keys. + + +FORMAT char od_get_answer(char *pszOptions); + + +RETURNS Character that user entered + + +DESCRIPTION This function can be used to get a response from the user, when + only particular responses should be accepted. The parameter to + the od_get_answer() function is simply a string listing the + valid responses. The function will wait until the user selects + one of the valid responses, and then return that response. The + function is case insensitive, and will return the character in + the same case that was supplied to it in the string. + + +SEE ALSO od_get_key(), od_hotkey_menu() + + +EXAMPLES od_get_answer("YN"); + - If the user presses 'y', will return 'Y'. + + od_get_answer("yn"); + - If the user presses 'y', will return 'y'. + + od_get_answer("ABC 123\n\rZ"); + - Valid responses will be: [A], [B], [C], [SPACE], + [1], [2], [3], [ENTER], [Z] + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 81 + +OD_GET_INPUT() +------------------------------------------------------------------------------- + +PURPOSE This function allows a single input event (e.g. keystroke) to be + retrieved, optionally translating extended key sequences such as + arrow keys and the insert key. + + +FORMAT BOOL od_get_input(tODInputEvent *pInputEvent, + tODMilliSec TimeToWait, WORD wFlags); + + +RETURNS TRUE on success, FALSE if no input event was retrieved. + + +DESCRIPTION Like od_get_key(), od_get_input() can be used to retrieve a + single key of input from the user. However, od_get_input() has + been designed to be easily extended in future versions of + OpenDoors. The information retrieved by this new function is + placed in a structure, which contains information on whether the + input event was generated by the remote user or the local + console, and what type of input event it was. This function also + has built-in the ability to recognize and translate the multiple- + character sequences that are generated when the user presses + extended keys such as arrow keys, insert, delete, etc. + + The first parameter points to a tODInputEvent structure, which is + defined as follows: + + typedef struct + { + tODInputEventType EventType; + BOOL bFromRemote; + char chKeyPress; + } tODInputEvent; + + When od_get_input() successfully retrieves an input event, this + structure is filled with information about the input. The + EventType member can be either EVENT_CHARACTER (indicating a + single character keystroke) or EVENT_EXTENDED_KEY (indicating an + extended key, such as an arrow key). In the case of + EVENT_CHARACTER, chKeyPress is set to the character that was + received. In the case of EVENT_EXTENDED_KEY, chKeyPress is set to + one of the following values: + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 82 + + +------------------+---------------+-------------------------+ + | chKeyPress Value | Meaning | Control Key Alternative | + +------------------+---------------+-------------------------+ + | OD_KEY_F1 | [F1] | None | + | OD_KEY_F2 | [F2] | None | + | OD_KEY_F3 | [F3] | None | + | OD_KEY_F4 | [F4] | None | + | OD_KEY_F5 | [F5] | None | + | OD_KEY_F6 | [F6] | None | + | OD_KEY_F7 | [F7] | None | + | OD_KEY_F8 | [F8] | None | + | OD_KEY_F9 | [F9] | None | + | OD_KEY_F10 | [F10] | None | + | OD_KEY_UP | [UP ARROW] | [CTRL]-[E] | + | OD_KEY_DOWN | [DOWN ARROW] | [CTRL]-[X] | + | OD_KEY_LEFT | [LEFT ARROW] | [CTRL]-[S] | + | OD_KEY_RIGHT | [RIGHT ARROW] | [CTRL]-[D] | + | OD_KEY_INSERT | [INSERT] | [CTRL]-[V] | + | OD_KEY_DELETE | [DELETE] | [CTRL]-[G] | + | OD_KEY_HOME | [HOME] | None | + | OD_KEY_END | [END] | None | + | OD_KEY_PGUP | [PAGE UP] | None | + | OD_KEY_PGDN | [PAGE DOWN] | None | + | OD_KEY_SHIFTTAB | [SHIFT]-[TAB] | None | + +------------------+---------------+-------------------------+ + + The bFromRemote member of the tODInputEvent structure will be set + to TRUE if the input event originated from the remote system, or + FALSE if the event originated from the local system. + + The second parameter, TimeToWait specifies how long the function + should wait for input before returning, in milliseconds. A value + of 0 causes the function to return immediately if no input is + waiting in OpenDoor's internal input buffer. The is equivalent to + a value of FALSE being passed to the od_get_key() function. A + value of OD_NO_TIMEOUT causes this function to wait and only + return after the next input event has been received. This is + equivalent to a value of TRUE being passed to the od_get_key() + function. An other value specifies the maximum number of + milliseconds that od_get_input() should wait for input. If input + is received before this time elapses, od_get_key() will return + immediately with a value of TRUE, and the tODInputEvent structure + will be fill accordingly. If no input is received before this + time elapses, od_get_key() will return FALSE. The number of + milliseconds to wait is rounded to the nearest 55 milliseconds in + the DOS version of OpenDoors. + + The third parameter allows you to specify flags to further + control the behavior of od_get_input(). Normally, this parameter + will be set to GETIN_NORMAL. However, you can disable all + translation of extended keystrokes by setting this value to + GETIN_RAW. In this mode, od_get_input() works just like +=============================================================================== +OpenDoors 6.00 Manual End of Page 83 + + od_get_key(), returning every individual character received from + the remote system. + + Since extended keys are not directly supported by all terminal + programs, od_get_input() provides alternatives for some of the + extended keys, in the form of control-key combinations. The + control key combinations recognized by od_get_input() are listed + in the table above. However, these control key alternatives can + be ignored by setting the GETIN_RAWCTRL flag. + + The od_get_input() function is used internally by + od_popup_menu(), od_edit_str() and od_multiline_edit(). + + +SEE ALSO od_get_key(), od_clear_keybuffer() + + +EXAMPLE The following example shows the structure of how od_get_input() + might be used in your program: + + tODInputEvent InputEvent; + od_get_input(&InputEvent, OD_NO_TIMEOUT, GETIN_NORMAL); + if(InputEvent.EventType == EVENT_EXTENDED_KEY) + { + switch(InputEvent.chKeyPress) + { + case OD_KEY_UP: + /* The up arrow key has been pressed. */ + break; + case OD_KEY_DOWN: + /* The down arrow key has been pressed. */ + break; + } + } + else if(InputEvent.EventType == EVENT_CHARACTER) + { + /* A single character key has been pressed, and is */ + /* stored in InputEvent.chKeyPress. */ + } + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 84 + +OD_GET_KEY() +------------------------------------------------------------------------------- + +PURPOSE Function to input a key from the user + + +FORMAT char od_get_key(BOOL bWait); + + +RETURNS The next key waiting from the keyboard, or 0 if none. + + +DESCRIPTION This function retrieves the next key waiting in the OpenDoors + keyboard buffer (see the description of the od_clear_keybuffer() + function, on page 53, for more information on the OpenDoors + keyboard buffer). The od_get_key() function allows your door to + retrieve both those keystrokes pressed by the user, and the + keystrokes pressed on the sysop keyboard (other than the sysop + function keys), in the sequence they were pressed. Since input + is accepted from both sources, it is possible for the sysop, as + well as the remote user, to make selections and control the + door. + + Door input with OpenDoors can be accomplished with this + function, with the od_input_str() function or with the + od_edit_str() function. The od_input_str() and od_edit_str() + functions is used to input an entire sequence of characters from + the user (a string), and requires the user to press the [Enter] + key when they are finished typing their input. On the other + hand, the od_get_key() function is used to input a single + keystroke (one character) from the user, and allows the user to + make choices without having to press the enter key. + + The od_get_key() function accepts a single parameter, which + determines whether or not it should wait for the user to press a + key, if they have not already done so. If you pass a FALSE value + to od_get_key(), then the function will not wait for a key to be + pressed at the keyboard, but instead return a 0 if there are no + keys waiting in the buffer. If you pass a TRUE value to + od_get_key(), then this function will instead wait for a key to + be pressed. Also, while waiting for the user to press a key, the + od_get_key() function will give up the processor to other + waiting programs, if you door is running under DesqView. + + If you are waiting for the user to make a choice from a menu or + list of options, you will most likely pass a TRUE to the + od_get_key() function, indicating that you wish for it to wait + until a key is pressed. However, if you wish to continue other + processing if no key is yet available from the keyboard, you + should pass a FALSE to the od_get_key() function. For example, + if you are displaying a screen of text, and wish to allow the + user to pause or abort the display, you would simply call the +=============================================================================== +OpenDoors 6.00 Manual End of Page 85 + + od_get_key() function every few moments, passing it a value of + FALSE. You would then be able to check if any control keys have + been pressed, and if not, continue displaying text. + + The od_get_key() function returns the ASCII value representing + the keystroke that was made. If you are waiting for the user to + make a particular choice, perhaps from a menu, you will most + likely store the value returned by od_get_key() in a variable of + type char. For example: + + char key; + ... + key=od_get_key(TRUE); + + You would then be able to determine which key the user pressed + by testing the value of key, either by comparing it's numerical + ASCII value, or by comparing it to a character constant. If you + are testing for a non-character key, such as [ESCape], [Tab] or + [Return], you may wish to use the ASCII value of that key. For + example, if you wished to take some action in the case that the + user presses the [Enter]/[Return] key, who's ASCII value is 13, + you could do: + + key=od_get_key(TRUE); /* Get keypress from user */ + if(key==13) /* If key was [Enter]/[Return] */ + { + ... /* Whatever you want to do */ + } + + If you wish, instead, to respond to the user pressing a + character key (perhaps as a choice from a menu), you can do so + by using character constants, such as 'c', '6', or 'F'. Also, + when testing for an alphabetical character, you will probably + want to check for the user pressing either the upper or lower- + case version of the letter. For example, if you wished to have + the user press the [Y] key to continue, you could test for + either an upper or lower-case Y as follows: + + key=od_get_key(TRUE); /* Get keypress from user */ + if(key=='y' || key=='Y') /* If key was [y]/[Y] */ + { + ... /* Whatever you want to do */ + } + + + + + +The charts on the following page lists the decimal value and corresponding +keystroke(s) of each of the ASCII values from 0 to 127. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 86 + +ASCII KEYSTROKE | ASCII KEYSTROKE +----- ------------------------------ | ----- ---------------------- + 0 [Control]-[@] | 15 [Control]-[O] + 1 [Control]-[A] | 16 [Control]-[P] + 2 [Control]-[B] | 17 [Control]-[Q] + 3 [Control]-[C] | 18 [Control]-[R] + 4 [Control]-[D] | 19 [Control]-[S] + 5 [Control]-[E] | 20 [Control]-[T] + 6 [Control]-[F] | 21 [Control]-[U] + 7 [Control]-[G] | 22 [Control]-[V] + 8 [Control]-[H]/[Backspace] | 23 [Control]-[W] + 9 [Control]-[I]/[Tab] | 24 [Control]-[X] + 10 [Control]-[J] | 25 [Control]-[Y] + 11 [Control]-[K] | 26 [Control]-[Z] + 12 [Control]-[L] | 27 [ESCape] + 13 [Control]-[M]/[Enter]/[Return] | 32 [SpaceBar] + 14 [Control]-[N] | + + + +ASCII KEYSTROKE | ASCII KEYSTROKE | ASCII KEYSTROKE | ASCII KEYSTROKE +----- --------- | ----- --------- | ----- --------- | ----- --------- + 33 '!' | 57 '9' | 80 'P' | 104 'h' + 34 '"' | 58 ':' | 81 'Q' | 105 'i' + 35 '#' | 59 ';' | 82 'R' | 106 'j' + 36 '$' | 60 '<' | 83 'S' | 107 'k' + 37 '%' | 61 '=' | 84 'T' | 108 'l' + 38 '&' | 62 '>' | 85 'U' | 109 'm' + 39 '\'' (') | 63 '?' | 86 'V' | 110 'n' + 40 '(' | 64 '@' | 87 'W' | 111 'o' + 41 ')' | 65 'A' | 88 'X' | 112 'p' + 42 '*' | 66 'B' | 89 'Y' | 113 'q' + 43 '+' | 67 'C' | 90 'Z' | 114 'r' + 44 ',' | 68 'D' | 91 '[' | 115 's' + 45 '-' | 69 'E' | 92 '\\' (\) | 116 't' + 46 '.' | 70 'F' | 93 ']' | 117 'u' + 47 '/' | 71 'G' | 94 '^' | 118 'v' + 48 '0' | 72 'H' | 95 '_' | 119 'w' + 49 '1' | 73 'I' | 96 '`' | 120 'x' + 50 '2' | 74 'J' | 98 'b' | 121 'y' + 51 '3' | 75 'K' | 99 'c' | 122 'z' + 52 '4' | 76 'L' | 100 'd' | 123 '{' + 53 '5' | 77 'M' | 101 'e' | 124 '|' + 54 '6' | 78 'N' | 102 'f' | 125 '}' + 55 '7' | 79 'O' | 103 'g' | 126 '~' + 56 '8' | | | 127 [DELete] + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 87 + + + + + +SEE ALSO od_get_input(), od_input_str(), od_edit_str(), + od_clear_keybuffer() + + +EXAMPLE For examples of the use of the od_get_key() function, see the + examples in the description portion, above, and the examples for + the od_exit() and od_clear_keybuffer() functions. For further + examples of this function, see the example program EX_VOTE.C, + described in the section beginning on page 38. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 88 + +OD_GETTEXT() +------------------------------------------------------------------------------- + +PURPOSE Stores a rectangular region of the screen in an array, to later + be redrawn using od_puttext(). Requires ANSI, AVATAR or RIP + modes. + + +FORMAT BOOL od_gettext(INT nLeft, INT nTop, INT nRight, INT nBottom, + void *pBlock); + + +RETURNS TRUE on success + FALSE on failure + + +DESCRIPTION This function stores the contents (both text and color + information) of the rectangular portion of the screen denoted by + the variables nLeft, nTop, nRight and nBottom into the buffer + pointed to by pBlock. The saved portion of the screen may then + be restored using od_puttext(). The buffer must be large enough + to store two bytes for every character in the specified + rectangle. In other words, the required size of the buffer, in + bytes, is: + + length * width * 2 + + The parameters nLeft and nRight are column numbers from 1 to 80, + and the parameters nTop and nBottom are row numbers between 1 + and 23. + + This function has no effect on the current text color or cursor + position. ANSI, AVATAR or RIP mode is required for this + function. If you wish to save and restore the entire screen, you + may use the od_save_screen() and od_restore_screen() functions, + which can be used in all display modes. + + If this function fails for any reason, a value of FALSE is + returned, and the od_control.od_error variable is set to + indicate the reason for the failure. For more information on the + od_control.od_error variable, see page 185. + + +SEE ALSO od_puttext(), od_save_screen(), od_restore_screen(), + od_scroll(), od_window_create(), od_window_remove() + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 89 + +OD_HOTKEY_MENU() +------------------------------------------------------------------------------- + +PURPOSE Function to display a menu file with hotkeys + + +FORMAT char od_hotkey_menu(char *pszFileName, char *pszHotKeys, BOOL + bWait); + + +RETURNS Key pressed in response to menu, or '\0' if none. + + +DESCRIPTION This function can be used to display a menu from an ASCII, ANSI, + AVATAR or RIP file, allowing the user to select an option at any + time while the menu is being displayed. The od_hotkey_menu() + function is quite similar to the od_send_file() function, and + you should probably familiarize yourself with that function if + you are going to use od_hotkey_menu(). Like od_send_file(), + od_hotkey_menu() will display the file specified by pszFileName, + using the appropriate terminal emulation. If no extension is + provided for the filename, OpenDoors will automatically search + for matching files ending in .ASC, .ANS and .AVT extensions. + OpenDoors will the select the appropriate file to display, based + on the available files and available terminal emulation. + + The second parameter, pszHotKeys, is a string specifying the + valid responses to the menu, in the same format as the string + passed to the od_get_answer() function. If any of the characters + listed in this string are pressed, either uppercase or lowercase + versions, OpenDoors will immediately stop displaying the menu, + and return with the value of the key pressed. The case (upper or + lower) returned will always be identical to the case used in the + hotkeys string. You can include the [ENTER] key as a valid hot + key by including the \n character in the hotkey string. + + The third parameter passed to od_hotkey_menu(), bWait, specifies + whether OpenDoors should wait after displaying the menu for the + user to make a valid selection from the menu (TRUE), or if it + should exit immediately (FALSE). Normally, you will want to use + the TRUE value when calling this function. This will allow you + to use a single function call that will display the menu and + always return the user's selection. If you wish to gain control + as soon as OpenDoors has displayed the menu, you may specify + FALSE for this parameter. In this case, if the user does not + press any of the valid hot keys while the menu is being sent, + the function will return the character '\0'. + + +SEE ALSO od_send_file(), od_get_answer() + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 90 + +EXAMPLE As an example of the use of the od_hotkey_menu() function, + consider the following code fragment: + + + for(;;) /* Main program loop */ + { /* Display menu and get user's choice */ + char choice=od_hotkey_menu("MAINMENU","123Q",TRUE"); + + switch(choice) /* Perform the appropriate action */ + { + case '1': + od_printf("You selected one.\n\r"); + break; + + case '2': + od_printf("You selected two.\n\r"); + break; + + case '3': + od_printf("You selected three.\n\r"); + break; + + case 'Q': + od_exit(FALSE,10); + } + } + + This is an example of the main menu loop of a simple door that + uses the od_hotkey_menu() function. The program will continue + executing the for(;;) loop until the user chooses to exit the + door. On each iteration of the loop, the od_hotkey_menu() + function is called, to display the door's menu from the file + MAINMENU.A??. The appropriate .ASC/.ANS/.AVT file will be chosen + and displayed as the menu. The possible choices that may be made + from the menu are specified by the string "123Q". Thus, whenever + the user presses one of the keys [1], [2], [3] or [Q], the + od_hotkey_menu() function will return immediately with the value + of the key pressed. If the menu is still being displayed at the + time when the key was pressed, menu display will cease at that + moment. The program then executes a case statement, to respond + to the user's key appropriately. If the user presses [1], [2] or + [3] this door will output a simple message to the screen. If the + user presses the [Q] key, the door will pass control back to the + BBS. + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 91 + +OD_INIT() +------------------------------------------------------------------------------- + +PURPOSE To initialize OpenDoors activities + + +FORMAT void od_init(void); + + +RETURNS N/A + + +DESCRIPTION This function initializes OpenDoors. This function must be + called manually if you wish to access data about the user, etc., + before you call any other OpenDoors functions. However, if you + do not explicitly call the od_init() function, it will be called + automatically on the first call to most other OpenDoors + functions. The only functions that should be called before + od_init() are od_add_personality() and od_parse_cmd_line(). The + od_init() function reads information from the door information + file, initializes communications with the modem, displays the + status line, and sets up OpenDoors' internal data structures. + For more information on what data is and is not available before + od_init() has been called, please refer to the chapter on the + OpenDoors control structure, which begins on page 148. + + The od_init() function will read the door information file which + is located in the directory specified by the variable + od_control.info_path. If this variable has not been set prior to + calling the od_init() function, OpenDoors will expect to find + the door information file in the current directory. Thus, if you + wish your door to be able to be run in a directory other than + the BBS system directory, it would be a good idea to allow the + sysop using your door to specify the location of the door + information file. For an example of setting the + od_control.info_path variable, please see the example program + located on page 150. + + Also note that you can prevent the od_init() function from + carrying out some of it's normal activities, such as attempting + to read a door information file, by the use of the + od_control.od_disable variable, as described in the section on + the OpenDoors control structure, which begins on page 148. + + +SEE ALSO od_exit() + + +EXAMPLE At times, you may wish to write a door program which will + require a maintenance utility to be run on a regular basis. For + example, a game door may have to have its system files updated + on a daily basis, by having a utility program run in a system +=============================================================================== +OpenDoors 6.00 Manual End of Page 92 + + event each day at midnight. One way of accomplishing this would + be to have your door package include two .EXE files, one being + the actual door program, and the other being a utility program. + However, another option would be to have both the door and + maintenance functions to be accessible from a single .EXE file, + in order to simplify use of the door for the sysop. In this + case, you would want to test the command line to determine + whether your program should run in door mode or maintenance + mode. You would then only execute the od_init() function, along + with the rest of your door code, if you program were running in + "door mode". + + The program below demonstrates one method of doing just this. In + this case, the program would include two functions, door(), + which would carry out all of the door-related activities, and + maint(), which would carry out all of the maintenance-related + activities. In this simple example, if the command line includes + a "-M" or "/M", the program will run in maintenance mode, + otherwise it will run in door mode. Also, if it is running in + door mode, the program will take the first command-line + parameter, if any, as a path to the location of the door + information file. + + + #include "opendoor.h" + + void door(void); + void maint(void); + + + int main(int argc, char *argv[]) + { + int counter; + + /* Check any command line parameters for /M or -M */ + for(counter=1;counter1) strncpy(od_control.info_path,argv[1],59); + + od_init(); /* call the od_init() function */ + door(); /* Run the door portion of the program */ + od_exit(30,FALSE); /* Shutdown the door */ +=============================================================================== +OpenDoors 6.00 Manual End of Page 93 + + } + + + void maint(void) + { + ... /* Carry out maintenance activities here */ + } + + + void door(void) + { + ... /* Carry out door activities here */ + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 94 + +OD_INPUT_STR() +------------------------------------------------------------------------------- + +PURPOSE Inputs a string from the user + + +FORMAT void od_input_str(char *pszInput, INT nMaxLength, + unsigned char chMin, unsigned char chMax); + + +RETURNS N/A + + +DESCRIPTION To perform string input within OpenDoors, one of two functions + can be used, od_input_str() and od_edit_str(). The first + function, od_input_str(), allows simple line input and editing, + and can be used in ASCII, ANSI, AVATAR and RIP modes. The second + function, od_edit_str(), allows many formatted input options, + advanced line editing, and other features, but requires the use + of ANSI, AVATAR or RIP graphics modes. + + The od_input_str() function allows you to input a string from + the user. The string will be permitted to have up to the number + of characters specified by the max_len parameter, and all + characters must be between the values of the min_char and + max_char parameters. This function will wait until the user + presses the [Enter] key to finish inputting the string. + + The first parameter passed to this function should be a pointer + to the string where the user's input should be stored. So, if + you wanted to store a string of up to 30 characters inputted by + the user, you might define this string as follows: + + char input_string[31]; + + Notice here than the string must be long enough to hold the + thirty characters which can be entered by the user, along with + the additional "null" character which is used to indicate the + end of a string in C. Hence, the length of the string should + always be at least one greater than the total number of + characters the user is permitted to enter, passed in the + nMaxLength parameter. + + The second parameter passed to the od_input_str() function + should be an integer value indicating the maximum number of + characters which can be input by the user. For example, if this + parameter had a value of 10, the user would be able to enter a + string containing any number of characters up to and including + 10 characters. If this parameter had a value of 1, the user + would only be able to enter a single character. However, the + user would be able to backspace, change the character, and press + [Enter] when they were satisfied with their entry. Note that +=============================================================================== +OpenDoors 6.00 Manual End of Page 95 + + even if you only ask the od_input_str() function to input a + single character, it will still expect a STRING to be passed to + it, and will return a string with either zero or one character, + followed by a null (string terminator) character. + + The third and fourth parameters passed to this function allow + you to control what characters the user will be permitted to + enter as part of the string. For example, you could set the + minimum character to the '0' character and the maximum character + to the '9' character, permitting the user to only enter numeric + characters. On the other hand, you could permit the user to + enter all ASCII characters in the range from 32 to 127. The + od_input_str() function will permit characters in the range + beginning with the character passed as minchar, up to and + including the character passed as maxchar. + + +SEE ALSO od_edit_str(), od_get_key(), od_clear_keybuffer() + + +EXAMPLE Below are a number of examples of the use of the od_input_str() + function in various applications: + + - To input a two character number (only digits from 0-9): + + od_input_str(string, 2, '0', '9'); + + - To input a 35 character name (characters from Space to + ASCII 127): + + od_input_str(string, 35, 32, 127); + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 96 + +OD_KERNEL() +------------------------------------------------------------------------------- + +PURPOSE The OpenDoors Central Control function. + + +FORMAT void od_kernel(void); + + +RETURNS N/A + + +DESCRIPTION In the DOS version of OpenDoors, the od_kernel() function is + responsible for many vital OpenDoors tasks, such as monitoring + the carrier detect signal, monitoring the amount of time that + the user has remaining, updating the status line, responding to + sysop hotkeys, and reading characters which are received from + the modem. The od_kernel() function is automatically called on a + frequent basis by the other OpenDoors functions, so most often + you will not need to be concerned with this function. However, + in order that OpenDoors can carry out the activities mentioned + above with a quick response, it is important that od_kernel(), + or some other OpenDoors function be called at least once every + second. Thus, if your program will be carrying out some + processing, in which it will not be calling any OpenDoors + functions for more than a second or so, you should call the + od_kernel() function yourself. The example below demonstrates + one method of doing just this. + + Note that if for some reason or other, it is not possible for + your program to call the od_kernel() function, or any other + OpenDoors functions for a period of several seconds, this will + not cause your door to crash or fail in any way. The only + problem will be that OpenDoors will not be able to respond to + any action, such as the sysop pressing a function key, or the + user dropping carrier, until such time as you next call + od_kernel(), or some OpenDoors function. Hence, use of the + od_kernel() function will improve the quality and response time + of your program, but calling it or some OpenDoors function on a + regular basis is not absolutely vital. + + This function has no effect in the Win32 version of OpenDoors. + + +SEE ALSO od_sleep() + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 97 + +OD_LIST_FILES() +------------------------------------------------------------------------------- + +PURPOSE Lists files in a particular file area (using FILES.BBS) + + +FORMAT BOOL od_list_files(char *pszFileSpec); + + +RETURNS TRUE if successful, FALSE if unsuccessful + + +DESCRIPTION This function allows you to display a list of files available + for download from a particular file area, as any BBS system + would. The file names and descriptions are taken from the + FILES.BBS located in the directory pointed to by pszFileSpec. + Thus, to list the files available for download in + C:\BBS\FILES\UPLOADS, simply: + + od_list_files("C:\\BBS\\FILES\\UPLOADS"); + + OpenDoors uses a third-generation FILES.BBS format, that is + compatible with other FILES.BBS formats, but adds some + additional features. Each line in the FILES.BBS file lists a + filename, along with it's description. Thus, a typical FILES.BBS + file might look as follows: + + PKZ110.EXE PKZip file compressor, version 1.10 + ODOORS60.ZIP The newest version of OpenDoors + REC*.ZIP A Record file + C:\BBS\*.* All BBS files. + + When displayed, OpenDoors will list the size of each file found + in the FILES.BBS file beside it's name, if the file is found. If + the file does not exist, then a "[OFFLINE]" string is displayed + in the file size column. Title lines may also be added to the + FILES.BBS, by indenting them one or more columns. Thus, you + could have something like: + + NEWEST UPLOADS + ~~~~~~~~~~~~~~ + PKZ110.EXE PKZip file compressor, version 1.10 + ODOORS60.ZIP The newest version of OpenDoors + REC*.ZIP A Record file + C:\BBS\*.* All BBS files. + + In addition to this standard FILES.BBS format, OpenDoors will + also permit wildcards to be used in FILES.BBS filenames (ie + FNEWS???.*), or full directory paths to allow files from several + different directories to be included in the same files area. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 98 + + You may alter the colors used to display the various portions of + the files list using the od_control variables: + od_control.od_list_title_col + od_control.od_list_name_col + od_control.od_list_size_col + od_control.od_list_comment_col + od_control.od_list_offline_col + + which are documented in the OpenDoors control structure section + on this manual, which begins on page 148. + + +SEE ALSO od_send_file() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 99 + +OD_LOG_WRITE() +------------------------------------------------------------------------------- + +PURPOSE Function to write an entry to the log file + + +FORMAT BOOL od_log_write(char *pszMessage); + + +RETURNS TRUE on success, or FALSE on failure + + +DESCRIPTION This function can be used to write entries to the log file. If + the logfile has not already been opened when you call this + function for the first time, OpenDoors will automatically open + the log file at that time. + + To create an entry in the log file, simply call the + od_log_write() function, passing to it the string of the text + you wish to write. You should not include any control characters + in this string, simply the text that should appear on the line. + OpenDoors will automatically format the log file, adding the + time information and other control characters. It is recommended + that the length of the string passed to od_log_write() not + exceed 67 characters, in order that logfile lines will all be + less than 80 characters in length. + + Log file entries do not usually contain periods or other + punctuation at the end of the line. Also, log file entries are + usually written in the present tense. The first character of the + entry is usually upper-case, with all other entries in lower + case. Also, since excessive numbers or lengths of log file + entries can quickly use a lot of disk space, it is best to think + carefully about what events should be recorded in the log file. + It is also a good idea to minimize the number of words used in + the entry, without being too cryptic. As an example, "User + entering options menu" should be used instead of "user entered + the options menu." + + +SEE ALSO Page 224. + + +EXAMPLE Calling the od_log_write() function is as simple as follows: + + od_log_write("Awarding user with 5 minutes more time"); + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 100 + +OD_MULTILINE_EDIT() +------------------------------------------------------------------------------- + +PURPOSE Provides a multiple line text editor which can be used for + entering editing any text that spans more than one line, such as + messages or text files. + + +FORMAT INT od_multiline_edit(char *pszBufferToEdit, UINT unBufferSize, + tODEditOptions *pEditOptions); + + +RETURNS OD_MULTIEDIT_SUCCESS on success, or OD_MULTIEDIT_ERROR on + failure + + +DESCRIPTION This function provides a text editor with optional word wrap + capabilities. This editor can be used for entering or editing + text files, messages or other information that spans multiple + lines. The editor can be configured to operate in full-screen + mode, or to occupy any smaller area of the screen that you + specify. It provides the navigation (home / end / page up / arrow + keys) features and editing features (insert / overwrite mode, + Ctrl-Y to delete a line, etc.) that you would expect. + + The od_multiline_edit() function is designed to be both easy to + use and very flexible. To that end, the function only takes three + parameters. The first two parameters are required, and the third + parameter is an optional options structure. The first parameter, + pszBufferToEdit, is a pointer to the buffer of text to edit. This + buffer must always be a '\0'-terminated string. This buffer must + be initialized before calling od_multiline_edit(). The second + parameter, unBufferSize, indicates the size of the buffer that is + passed in pszBufferToEdit. Note that this should be the total + amount of space that is available in the buffer for text entered + by the user, not the length of data that is actually initially in + the buffer. If you do not wish to customize any of the + od_multiline_edit() options, then you may simply set the third + parameter to 0. Hence, a simple example of how to use + od_multiline_edit() is: + + char szMyEditBuffer[4000] = ""; + od_multiline_edit(szMyEditBuffer, sizeof(szMyEditBuffer), + NULL); + + If you wish to customize od_multiline_edit(), you should pass a + pointer to a tODEditOptions structure as the third parameter. You + should initialize this entire structure to zeros before + attempting to use it. You can then set any values of this + structure which you wish to change from their default. Any values + that are left at 0 will automatically revert to their defaults. + For example, if you wanted to specify a text format other than +=============================================================================== +OpenDoors 6.00 Manual End of Page 101 + + the default, you could create, initialize and pass in a + tODEditOptions structure as follows: + + char szMyEditBuffer[4000] = ""; + tODEditOptions MyEditOptions; + memset(&MyEditOptions, 0, sizeof(MyEditOptions)); + MyEditOptions.TextFormat = FORMAT_LINE_BREAKS; + od_multiline_edit(szMyEditBuffer, sizeof(szMyEditBuffer), + &MyEditOptions); + + The definition of the tODEditOptions structure is as follows: + + typedef struct + { + INT nAreaLeft; + INT nAreaTop; + INT nAreaRight; + INT nAreaBottom; + tODEditTextFormat TextFormat; + tODEditMenuResult (*pfMenuCallback)(void *pUnused); + void * (*pfBufferRealloc)(void *pOriginalBuffer, + UINT unNewSize); + DWORD dwEditFlags; + char *pszFinalBuffer; + UINT unFinalBufferSize; + } tODEditOptions; + + nAreaLeft, nAreaTop, nAreaRight, nAreaBottom allows you to + specify the portion of the screen that the text editor should + use. This defaults to 1, 1 - 80, 23. + + TextFormat allows you to specify what format the text should be + stored in the buffer using. The default is + FORMAT_PARAGRAPH_BREAKS, which specifies that a line break only + appears at the end of each paragraph, and that the contents of a + paragraph are word wrapped. FORMAT_LINE_BREAKS specifies that a + line break appears at the end of each line of text on the screen, + and that newly entered text is word wrapped. FORMAT_NO_WORDWRAP + is equivalent to FORMAT_LINE_BREAKS, except that newly entered + text is not word wrapped. Instead, lines may be arbitrarily long. + For each of these text formats, od_multiline_edit() automatically + decides whether line breaks should take the form of a carriage + return ('\r'), line feed ('\n'), or some combination of these, + based on what it sees in the buffer that you supply. If no line + breaks are found in the buffer, then the default is to use just a + line feed ('\n') character. FORMAT_FTSC_MESSAGE specifies a FTSC- + compliant message, such as is used in a *.MSG message file. Among + other things, this specifies that carriage returns ('\r') end + paragraphs, and that line feeds ('\n') should be ignored. + + pfMenuCallback allows you to provide a callback function that + will be called when the user presses the escape (or control-Z) +=============================================================================== +OpenDoors 6.00 Manual End of Page 102 + + key. This allows you to provide a menu that can be accessed from + within the text editor. This function should return + EDIT_MENU_DO_NOTHING if the editor should continue normally, or + EDIT_MENU_EXIT_EDITOR if the od_multiline_edit() should return. + If no menu callback function is provided, then + od_multiline_edit() always returns when the escape or control-z + key is pressed. + + pfBufferRealloc allows you to provide a function which will + attempt to reallocate a larger buffer if the user enters more + text than will fit in the originally supplied buffer. You should + only do this if you have dynamically allocated the buffer that + you initially passed into od_multiline_edit(). If you allocated + the buffer using malloc() or calloc(), then pfBufferRealloc can + be set to point to the realloc() function. If you allocated the + buffer using the C++ new operator, then you must write a your own + reallocation function which obeys the same semantics as the C + realloc() function. If no buffer reallocation function is + provided, then od_multiline_edit() will never allow the user to + enter more text than will fit in the buffer that you initially + supply. If you are using the buffer reallocation option, you can + obtain a pointer to the final buffer, and the size of the final + buffer, from the pszFinalBuffer and unFinalBufferSize members. + + +SEE ALSO od_input_str(), od_edit_str(), od_get_input() + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 103 + +OD_PAGE() +------------------------------------------------------------------------------- + +PURPOSE Function to allow user to page the sysop + + +FORMAT void od_page(void); + + +RETURNS N/A + + +DESCRIPTION This function can be called to allow the user to page the sysop. + This function will ask the user why they wish to chat with the + sysop, and then page the sysop. The sysop will then be free to + break into chat at any time. Sysop paging will also be aborted + by the user, simply by pressing [Enter] when asked for a reason + for chat. When the user pages the sysop, the [Wants-Chat] + indicator will begin to flash on the main status line, and the + status line will switch to show the user's reason for wanting to + chat. Also, the user's total number of pages will be + incremented. + + Depending upon the setting of the od_control.od_okaytopage + variable, this function will also optionally check sysop paging + hours, and only allow the user to page the sysop during valid + paging hours. For information on the variables containing the + user's total number of pages, the user's want-chat status, valid + sysop paging hours, and the od_control.od_okaytopage variable, + see the section on the OpenDoors control structure, which begins + on page 148. + + +EXAMPLE For an example of the use of the od_page() function, see the + EX_VOTE.C example program, which is described beginning on page + 38. + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 104 + +OD_PARSE_CMD_LINE() +------------------------------------------------------------------------------- + +PURPOSE Handles standard command line options. + + +FORMAT Under DOS Version: + void od_parse_cmd_line(INT nArgCount, char *papszArguments[]); + + Under Win32 Version: + void od_parse_cmd_line(LPSTR pszCmdLine); + + +RETURNS N/A + + +DESCRIPTION This is the only OpenDoors function that uses a different + calling format in the DOS and Win32 versions of OpenDoors. The + reason for this is that od_parse_cmd_line() always allows you to + pass command line parameters in the same format that the + operating system passes them to you. Under the DOS version of + OpenDoors, you should pass the argc and argv values that were + passed to your main function as the two parameters to + od_parse_cmd_line(). Under the Win32 version of OpenDoors, you + should pass the pszCmdLine values that were passed to your + WinMain() function as the one parameter to od_parse_cmd_line(). + + The od_parse_cmd_line() function should be called before your + first call to any other OpenDoors function, with the possible + exception of the od_add_personality() function. + + It is recommended that any program which uses OpenDoors call + od_parse_cmd_line() as part of its startup procedure. This + allows your program to automatically handle many common command + line options that will make it easier to setup and run your + program. Among the helpful command line options processed by + od_parse_cmd_line() are options to set serial port information + (including information on non-standard serial port setups), + specify the location of configuration and drop files, force the + program to run in silent mode (without no local display), pass + in user information, and the ability to start the program in + local mode without a drop file. For a complete list of the + options supported by od_parse_cmd_line(), run the example Vote + door that is included in the OpenDoors packages, specifying - + help on the command line. + + If you wish to process your own command line parameters in + addition to those supported by OpenDoors, simply check the + command-line for your own parameters after calling + od_parse_cmd_line(). You can do this in the same way that you + would handle command line options if you weren't using + od_parse_cmd_line(). The od_parse_cmd_line() function does not +=============================================================================== +OpenDoors 6.00 Manual End of Page 105 + + generate an error message if it encounters unrecognized command + line options. You can supply your own text to display when the + user chooses the /Help option by setting + od_control.od_cmd_line_help to point to your own string. Separate + lines in your string with the \n character, and align text using + the \t character. + + +SEE ALSO od_init() + + +EXAMPLE The following example shows how a program that uses + od_parse_cmd_line() should be structured in order to compile + under either DOS or Win32 versions of OpenDoors: + + #include "opendoor.h" + + /* main() or WinMain() function - Program begins here. */ + #ifdef ODPLAT_WIN32 + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) + #else + int main(int argc, char *argv[]) + #endif + { + #ifdef ODPLAT_WIN32 + #endif + + /* Set program's name for use by OpenDoors. */ + #ifdef ODPLAT_WIN32 + /* In Windows, pass in nCmdShow value to OpenDoors. */ + od_control.od_cmd_show = nCmdShow; + + /* Call od_parse_cmd_line. */ + od_parse_cmd_line(lpszCmdLine); + #else + od_parse_cmd_line(argc, argv); + #endif + + + /* Start the rest of your program here. */ + + + } + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 106 + +OD_POPUP_MENU() +------------------------------------------------------------------------------- + +PURPOSE Creates a popup menu which allows the user to make a selection + by pressing a single key, or selecting the item with a highlight + bar. After the user has made a selection, the menu may be + removed from the screen, restoring the original screen contents + "beneath" the window. + + +FORMAT INT od_popup_menu(char *pszTitle, char *pszText, INT nLeft, + INT nTop, INT nLevel, WORD uFlags); + + +RETURNS POPUP_ERROR On error (od_control.od_error is set to + indicate type of error). + POPUP_ESCAPE If user exited menu by pressing [ESCape]. + POPUP_LEFT If user exited menu by pressing the left arrow + key. + POPUP_RIGHT If user exited menu by pressing the right arrow + key. + + Or, a postive integer indicating the menu item that was chosen + if a selection was made. + + +DESCRIPTION od_popup_menu() creates a popup window with a menu of choices, + for use in ANSI/AVATAR/RIP modes. The user is able to choose an + item from the menu by moving the highlighted selection bar with + the arrow keys, or by pressing a key associated with a + particular menu item. The contents of the menu are defined by + the string pointed to by the pszText parameter. This menu + definition string contains each menu option, separated by a '|' + (pipe) character. Keys associated with each menu entry can be + defined by proceeding the letter with a '^' (carat) character. + For example, the string: + + "^Save|^Load|E^xit" + + would produce a menu with three options: Save, Load and Exit. + The user would be able to select the Save option by pressing the + [S] key, the Load option by pressing the [L] key, and the Exit + option by pressing the [X] key. Furthermore, the characters + corresponding to each menu item would be displayed in a + highlighted color. + + Menus displayed with od_popup_menu() may optionally have a + title, as specified by the pszTitle parameter. If this parameter + is set to NULL, no title will be displayed. If this parameter is + not NULL, the specified string will be displayed as a title on + the window. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 107 + + The nLeft and nTop parameters specify the left and top locations + of the menu window, were 1, 1 is the upper right corner of the + screen. The bottom and right corners of the menu are + automatically determined by the size and number of menu entries + in the menu definition string. + + The nLevel parameter specifies the menu level, an integer from 0 + to 10. Unless you are using the MENU_KEEP flag, this parameter + can always be 0. + + The uFlags parameter specifies one or more of the following + options, joined by the bitwise-OR operator (|). + + MENU_NORMAL Has no effect. + MENU_ALLOW_CANCEL Allow user to exit menu with [ESCape]. + MENU_PULLDOWN Allow exit with arrow keys. + MENU_KEEP Leave menu active on selection. + MENU_DESTROY Remove a currently active menu. + + If you are not using any of the other flags, you can use + MENU_NORMAL as a place-holder for this parameter. If you specify + MENU_ALLOW_CANCEL, the user will be able to exit the menu + without making a selection by pressing the [ESCape] key. If the + user presses [ESCape], od_popup_menu() returns POPUP_ESCAPE. + + You can use the MENU_PULLDOWN option with od_popup_menu() to + implement a set of pulldown menus. In this case, if the user + presses the left arrow key or right arrow key while the menu is + being displayed, od_popup_menu() returns with POPUP_LEFT or + POPUP_RIGHT, allowing you to display a different menu. + + Normally, od_popup_menu() will remove the menu from the screen + as soon as the user makes a selection. However, there may be + some cases when you want the menu to continue to be visible + after the user makes a selection. For example, you may want some + menu options to lead to further sub-menus, or you may wish to + display a popup window, and return to this menu after the user + has exited from the popup window. If the MENU_KEEP flag is + specified, the menu will remain active (on-screen) after the + user makes a selection. However, the menu will still be + destroyed if the user cancels out of the menu (this will only + happen if you have specified MENU_ALLOW_CANCEL), or if the user + moves to another menu by pressing the left or right arrow keys + (this will only happen if you have specified MENU_PULLDOWN). If + MENU_KEEP has been specified, and the user makes a selection, + you must eventually either return to the menu, or destroy it by + calling MENU_DESTROY. If you want to return to the menu, simply + call od_popup_menu() again with the same level value that was + used to originally create the menu. The user will now be able to + make another selection from the menu, and od_popup_menu() will + once again return that selection to you. If you want to destroy + the menu, simply call od_popup_menu() with the MENU_DESTROY flag +=============================================================================== +OpenDoors 6.00 Manual End of Page 108 + + set, and the same level value that was used to create the + original menu. If you wish to create another popup menu while + the first one is still active, simply call od_popup_menu() + again, this time with a different level value. The colors used + by the od_popup_menu() function are set by the following + OpenDoors control structure settings: + + char od_control.od_menu_title_col; + char od_control.od_menu_border_col; + char od_control.od_menu_text_col; + char od_control.od_menu_key_col; + char od_control.od_menu_highlight_col; + char od_control.od_menu_highkey_col; + + +SEE ALSO od_window_create(), od_window_remove(), od_draw_box(), + od_hotkey_menu() + + +EXAMPLE The following example shows the use of multiple-level menus: + + #include + #include "opendoor.h" + main() + { + for(;;) + { + switch(od_popup_menu("Main Menu", + "^Files|^Electronic Mail|^News|E^xit", + 20, 5, 0, MENU_NORMAL | MENU_KEEP)) + { + case 1: + od_popup_menu("Files Menu", + "^Search For Files|^Download|^Upload", + 30, 7, 2, MENU_NORMAL | MENU_ALLOW_CANCEL); + break; + case 2: + od_popup_menu("EMail Menu", + "Get ^New Mail|^Send Mail|Send ^Fax", + 30, 8, 1, MENU_NORMAL | MENU_ALLOW_CANCEL); + break; + case 3: + od_popup_menu("News Menu", + "Choose News^Group|^Read News|^Post News", + 30, 9, 1, MENU_NORMAL | MENU_ALLOW_CANCEL); + break; + case 4: + od_popup_menu(NULL, NULL, 0, 0, 0, MENU_DESTROY); + return(0); + } + } + } +=============================================================================== +OpenDoors 6.00 Manual End of Page 109 + +OD_PRINTF() +------------------------------------------------------------------------------- + +PURPOSE Performs formatted output (remote & local), with the ability to + change display colors. + + +FORMAT void od_printf(char * pszFormat,...); + + +RETURNS N/A + + +DESCRIPTION This is one of two OpenDoors function which allows you to + display a string of characters, the other being the + od_disp_str() function. For a complete comparison of the various + OpenDoors display function, see the description of the + od_disp_str() function, on page 63. Like the od_disp_str() + function, the od_printf() function will display its output both + on the local screen, and on the remote user's screen (if the + door is not operating in local mode). However, the od_printf() + function also allows for formatted output, just as the printf() + function does. In addition to providing all of the features of + the normal C printf() function, the od_printf() function allows + you to include codes to change the color of the display of text. + This unique feature allows you to display multi-colored text, + without having to use chains of alternating od_disp_str() and + od_set_color() calls. + + As with the printf() function, the od_printf() function accepts + one or more parameters, the first parameter being the format + string to be displayed, and the additional parameters being data + to be displayed within the string. The OpenDoors od_printf() + function recognizes all of the control characters and options + recognized by the normal printf() function. For example, to + display the amount of time that a user has left online, the + following line would be a valid use of the od_printf() function: + + od_printf("Time Left:%d\n\r", od_control.user_timelimit); + + Note that a full discussion of the printf() function is beyond + the scope of this manual. For more information on using + printf(), please see your Turbo C(++) / Borland C++ manuals. + + In addition to the normal control sequences, such as "%s", "%d", + or "%12.12s", the od_printf() function also allows you to + include special color-setting codes within the format string. + These color code sequences BEGIN and END with a delimiter + character, which is used to indicate that the sequence is a + color setting. Consider, for example, the following line of + code, which displays text in various colors: + +=============================================================================== +OpenDoors 6.00 Manual End of Page 110 + + od_printf("`blue`Blue `green`Green `red`Red \n\r"); + + In this case (assuming of course that a color monitor is being + used) the word "Blue" will be displayed in the color blue, the + word "Green" will be displayed in the color green, and the word + "Red" will be displayed in the color red. In this case, the + sequence `blue` sets the display color to dark blue on black. + Here, the back-quote (`) is the delimiter character which + indicates the beginning and end of the color sequence. Be sure + not to confuse the back-quote character (`) with the normal + forward quote ('). THIS IS THE MOST COMMON DIFFICULTY + EXPERIENCED WITH THE OD_PRINTF() FUNCTION. The text between the + back-quote characters indicates the color that should be set. + This text can include the name of the foreground color, the name + of the background color, the "bright" keyword and the "flashing" + keyword. The first color mentioned is taken to be the foreground + color, and the second the background color. Case is not + sensitive, additional words can be included for legibility. + Thus: + + `bright white cyan` + + is equivalent to: + + `Bright white on a cyan background`. + + The "bright" keyword indicates that the foreground color should + be displayed in high intensity, and the "flashing" keyword + indicates that the text should be flashing. If no background is + specified, the background color defaults to black. If no + foreground or background colors are specified, the color + defaults to white on black. + + The od_printf() function will automatically determine whether + the user has ANSI, AVATAR or RIP graphics enabled, and will send + the appropriate color codes to change the color of displayed + text. If the user does not have either ANSI or AVATAR graphics + modes turned on, then the od_printf() function will not send any + color codes. Thus, a door program using color codes would work + just as well when ANSI/AVATAR/RIP graphics are not available, + except that all text will appear in the same color. + + You may prefer to set colors by using the od_set_color() or + od_set_attrib() functions, instead of using these cryptic color + codes imbedded in od_printf() functions. In some cases, however, + it will be much more advantageous to place the color codes + within your od_printf() strings. As a case in point, consider + the single od_printf() statement in the example, above. To + accomplish the same result using the od_disp_str() and + od_set_color() functions, you would have to use the following + SIX function calls: + +=============================================================================== +OpenDoors 6.00 Manual End of Page 111 + + od_set_color(D_BLUE,D_BLACK); + od_disp_str("Blue "); + od_set_color(D_GREEN,D_BLACK); + od_disp_str("Green "); + od_set_color(D_RED,D_BLACK); + od_disp_str("Red \n\r"); + + While this method MAY be easier understand, it certainly + requires many more line of code to accomplish. However, either + method will work, and the choice is up to you as to which method + you prefer. Keep in mind, however, that if the color to be set + is stored in a variable, instead of always being the same color, + you must use either the od_set_color() or od_set_attrib() + function to set the display color. + + While the back-quote (`) character is normally used to delimit a + color sequence in the od_printf() function, you may wish to be + able to print a back-quote character using the od_printf() + function. In this case, you may configure OpenDoors to use a + different character to represent color code sequences. To do + this, simply use the od_control.od_color_delimiter variable, + which is described in the OpenDoors control structure section, + beginning on page 148. For example, if you wished to use the + tilde (~) character instead of the back-quote character to + change colors, simply place the following line within your + program, at some point after having called od_init() or some + OpenDoors function: + + od_control.od_color_delimiter='~'; + + Also, you may disable the color code interpretation within the + od_printf() function altogether, by setting the + od_control.od_color_delimiter variable to 0. + + Note that the od_printf() function interprets the color codes + AFTER parsing the other control sequences, such as "%d" or "%s". + Thus, if you used the command: + + od_printf("%s",string); + + Any color codes contained in the string "string" would also be + interpreted. If you did not wish to have any color code + characters which might be contained in the string "string" + treated as such, you could again disable od_printf()'s color + code interpretation, by setting the od_control.od_color_char + variable to 0. + + Note that the string to be displayed by od_printf() should not + exceed 511 characters in size, including the size of color + sequences and expanded % fields. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 112 + +SEE ALSO od_disp_str(), od_disp(), od_putch(), od_repeat(), od_disp_emu() + + +EXAMPLE Below is a simple example of a user statistics door program, + which displays various pieces of information to the user, by + using the od_printf() function. Notice the use of color code + sequences in order to display the titles in a different color + from the information fields. Note that since the information + available to this door will depend on the BBS system under which + it is running, not all of the information displayed by this door + will be available under all BBS systems. For a description of + what information is available under what BBS systems, see the + OpenDoors control structure portion of this manual, which begins + on page 148. + + +#include "opendoor.h" + +int main(int argc,char *argv[]) + { + od_init(); /* Begin OpenDoors program */ + + od_printf("`bright white` YOUR STATISTICS\n\r"); /* Display title */ + od_printf("---------------\n\r\n\r"); + + /* Display statistics */ + od_printf("`red`NAME : `blue`%s\n\r",od_control.user_logintime); + od_printf("`red`LOCATION : `blue`%s\n\r",od_control.user_location); + od_printf("`red`PHONE NUMBER : `blue`%s\n\r",od_control.user_homephone); + od_printf("`red`LAST CALL : `blue`%s\n\r",od_control.user_lastdate); + od_printf("`red`NUMBER OF CALLS : `blue`%u\n\r",od_control.user_numcalls); + od_printf("`red`NUMBER OF PAGES : `blue`%u\n\r",od_control.user_numpages); + od_printf("`red`REMAINING TIME : `blue`%d\n\r",od_control.user_timelimit); + od_printf("`red`# OF DOWNLOADS : `blue`%u\n\r",od_control.user_downloads); + od_printf("`red`# OF UPLOADS : `blue`%u\n\r",od_control.user_uploads); + od_printf("`red`KBYTES DL TODAY : `blue`%u\n\r",od_control.user_todayk); + + /* Ask user to press [Enter] */ + od_printf("`bright green on green`Press [Enter] to return to BBS...\n\r"); + + while(od_get_key(TRUE)!=13); /* Wait for user to press [Enter] */ + + od_exit(20,FALSE); /* Return to BBS */ + } + + +HELPFUL This section demonstrates use of the od_printf() color +HINT sequences imbedded directly in the printf() format string, such + as: + + od_printf("Hello `bright green` there!"); + +=============================================================================== +OpenDoors 6.00 Manual End of Page 113 + + However, there are also other ways that you can take advantage + of this feature. For example, the C programming language + concatenates string constants that are separated only by white + space or carriage returns. For instance, + + "Hello " "`bright green`" " there!" + + is equivalent to: + + "Hello `bright green` there!" + + For this reason, you can create macros for common color + sequences in your program, such as: + + #define HIGHLIGHT "`bright green`" + + You can then use such constants when calling the od_printf() + function, as follows: + + od_printf("Hello " HIGHLIGHT " there!"); + + You may find this method of setting the display color to be + easier to read, and more easily configurable than including the + color sequence directly in the format string. Below another use + of the color sequences is describe, which allows the colors used + by od_printf() not be "hard-wired". + + + Since color control sequences are evaluated by od_printf() after + it evaluates all format sequences (such as "%d"). For this + reason, it is possible to change the display color using a + string variable, instead of using a fixed color in the string. + For example, if you program had the variable: + + char highlight[40]; + + which was set at some point to be equal to: + + "`bright green`" + + you would be able to use od_printf() as follows: + + od_printf("Hello %s there!", highlight); + + The display color would then be changed at the location where + the "%s" appears in the od_printf() format string. The advantage + of using this method to change display colors is that unlike + other methods, the value of the highlight variable can be + changed. This could be used, for example, to allow the sysop to + configure the colors they wish your door to use. You would only + need to change the value of the highlight variable in order to + change the color set by od_printf(). +=============================================================================== +OpenDoors 6.00 Manual End of Page 114 + +OD_PUTCH() +------------------------------------------------------------------------------- + +PURPOSE Function to display a single character. + + +FORMAT void od_putch(int chToDisplay); + + +RETURNS N/A + + +DESCRIPTION This function performs a similar function to the other OpenDoors + display functions. For information on the uses of the various + OpenDoors display functions, see the description of the + od_disp_str() function, on page 63. This function is most + similar to the od_disp() and od_disp_str() functions, except + that it only displays a single character at a time. + + This function will display the character passed to it at the + cursor position in the output window, and then advance the + cursor to the next display position. If OpenDoors is not + operating in local mode, the character will also be sent to the + modem, and thus displayed on the user's screen in the same + manner that it is displayed on the local screen. If ANSI, AVATAR + or RIP graphics mode is activated the character will be + displayed in the current color. + + +SEE ALSO od_disp_str(), od_disp(), od_printf(), od_repeat(), + od_disp_emu() + + +EXAMPLE Below is an example of the use of the od_putch() function. This + example is a function which you could use in place of the + od_get_key() function. This function inputs a single character + from the keyboard, just as the od_get_key() function does. + However, if the character entered is a printable character, the + function will also echo the character to the local screen, using + the od_putch() function. + + char get_key_with_echo(int wait) + { + char pressed=od_get_key(wait); /* Get key from user */ + + if(pressed>=32 && pressed<=126) /* If key is printable */ + { + od_putch(pressed); /* Display the character */ + } + + return(pressed); /* Return key pressed by user */ + } +=============================================================================== +OpenDoors 6.00 Manual End of Page 115 + +OD_PUTTEXT() +------------------------------------------------------------------------------- + +PURPOSE Displays a rectangular region of text and color information, as + previously stored using od_gettext() + + +FORMAT BOOL od_puttext(INT nLeft, INT nTop, INT nRight, INT nBottom, + void *pBlock); + + +RETURNS TRUE on success + FALSE on failure + + +DESCRIPTION This function "pastes" a rectangular block of text and color + information that has been previously retrieved using + od_gettext(). The block is placed at the screen location + indicated by the variables nLeft, nTop, nRight and nBottom, + where nLeft and nRight are column numbers from 1 - 80, and nTop + and nBottom are row numbers from 1 - 23. The length and width of + the rectangle specified by nLeft, nTop, nRight and nBottom must + be the same as the length and width of the rectangle passed to + od_gettext() when storing the block of text. + + This function attempts to display the pasted block as quickly as + possible, only transmitting information on portions of the block + that are different than the original screen contents. When this + function returns, it leaves the cursor at its original position, + and the display color at its original setting. This function + requires ANSI or AVATAR mode. + + The control structure variable od_control.od_full_put may be set + to TRUE to force od_puttext() to always send all characters in + the block to be displayed, instead of only displaying the + portions of the block that differ from the original screen + contents. If you wish to save and restore the entire screen, you + can use od_save_screen() and od_restore_screen(), which work in + all display modes. + + You may also use the od_puttext() to display a rectangular block + of text that you generate manually, instead of retrieving using + od_gettext(). To do this, you pass an array which contains the + text and color information for the rectangular area to be + painted, in the pBlock parameter. The array passed to + od_puttext() contains a two-byte sequence of information for + each character in the rectangle. The first byte contains the + ASCII code of the character to be displayed. The second byte + contains the color attribute value of the character, in the same + format as used by the od_set_attrib() function (described on + page 128). These two byte sequences are stored in the order in + which English is written; the array begins with the two byte +=============================================================================== +OpenDoors 6.00 Manual End of Page 116 + + sequences for all of the characters on the first line, from left + to right, followed by the characters for the second line, and so + on. The length of each line must be exactly equal to the width + of the rectangular region to be painted. + + +SEE ALSO od_gettext(), od_save_screen(), od_restore_screen(), + od_scroll(), od_window_create(), od_window_remove() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 117 + +OD_REPEAT() +------------------------------------------------------------------------------- + +PURPOSE Repeatedly display the specified character any number of times, + using special graphics codes for greater speed, if possible. + + +FORMAT void od_repeat(char chValue, BYTE btTimes); + + +RETURNS N/A + + +DESCRIPTION This display function will repeatedly display the character + chValue, btTimes times. For a complete breakdown of the various + OpenDoors display functions, see the description of the + od_disp_str() function, located on page 63. + + The advantage of using this function to display a series of + identical characters is that this function will use special + graphics-mode control sequences to display the repeated + character very efficiently, if the required graphics mode is + available. For example, in AVATAR mode, this function can + display an entire line of one character, by sending a control + sequence to the modem that is only three characters long. If + graphics mode is not turned on, then the od_disp_str() function + will simply send the specified character the appropriate number + of times. As with the other display functions, the output of + this function is sent to both the local and remote screens. + + +SEE ALSO od_putch(), od_disp_str(), od_disp(), od_printf(), od_disp_emu() + + +EXAMPLE The example function below demonstrates the use of the + od_repeat() function in drawing a window (a square box) on the + screen. This function is essentially a simplified version of the + od_draw_box() function, which is described on page 65. Unlike + this function, the od_draw_box() function allows the + customization of the characters used to draw the box's boarder, + and if possible uses additional AVATAR graphics codes to display + the window even faster than this function does. Thus, the + function below is really provided for demonstration purposes + only. + + This function accepts four parameters, which indicate the + location of the upper left and lower right corners of the window + to be displayed. The function then displays the window with the + current color attribute settings. Since this function uses the + od_repeat() function, if AVATAR graphics are available, it can + display the entire window in a fraction of a second, even if it + is displaying a window the size of the entire screen at slow +=============================================================================== +OpenDoors 6.00 Manual End of Page 118 + + baud rates. Note that this window display function requires that + the user has ANSI, AVATAR or RIP graphics mode enabled. + + void draw_window(char left, char top, char right, char bottom) + { + char line_counter; /* Number of current line being drawn */ + char between_size=(right-left)-1; /* X size of window */ + + od_set_cursor(top,left); /* move to top corner */ + od_putch(218); /* display corner character */ + od_repeat(196,between_size); /* display top line */ + od_putch(191); /* display corner character */ + /* loop through middle lines of window */ + for(line_counter=top+1;line_counter1) strncpy(od_control.info_path,argv[1],59); + + od_disp_str("This is a sample OpenDoors door.\n\r"); + od_disp_str("Press any key to continue...\n\r"); + od_get_key(TRUE); + od_exit(20); + } + + + +------------------------------------------------------------------------------- +od_info_type char od_control.od_info_type; + + This variable indicates the type of information file from which + OpenDoors has obtained the BBS and caller information that is + found elsewhere in the OpenDoors control structure. This + variable will have one of the following values, indicating that + the door information file was of the corresponding type: + + +----------------+----------------------------+ + | od_info_type | Door Information File Type | + | Value | | + +----------------+----------------------------+ + | DORINFO1 | DORINFO?.DEF | + | EXITINFO | EXITINFO.BBS (Normal) | + | RA1EXITINFO | EXITINFO.BBS (Extended) | + | RA2EXITINFO | EXITINFO.BBS (RA 2.x) | + | QBBS275EXITINFO| EXITINFO.BBS (QuickBBS) | + | CHAINTXT | CHAIN.TXT | + | SFDOORSDAT | SFDOORS.DAT | + | CALLINFO | CALLINFO.BBS | + | DOORSYS_GAP | DOOR.SYS (GAP/PC-Board) | + | DOORSYS_DRWY | DOOR.SYS (Doorway style) | + | DOORSYS_WILDCAT| DOOR.SYS (WildCat standard)| + | CUSTOM | Custom door information | + | | file, defined in config | + | | file. | + | NO_DOOR_FILE | No drop file was found. | + +----------------+----------------------------+ + + The value of this variable is only valid AFTER od_init() or some + OpenDoors function has been called. + + Note that this variable should be treated as a read-only + variable, and should not normally be altered by your program. + Altering this variable may cause OpenDoors to re-write a + different type of door information file upon exiting, than was + read upon startup. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 151 + + +------------------------------------------------------------------------------- +od_node char od_control.od_node; + + This variable indicates the node number that the door is running + under. If this information is supplied by the BBS in the door + information file, the node number will be automatically by + OpenDoors. Specifically, the node number can be determined + automatically from systems that produce an SFDOORS.DAT, PC- + Board/GAP style DOOR.SYS or Wildcat style DOOR.SYS door + information file. If this information is not supplied in the + door information file, but is provided by the sysop in the + door's configuration file, OpenDoors will use the value found + there. Alternatively, you can set this variable manually. + + On systems that produce a DORINFO?.DEF file, OpenDoors will use + this variable to determine which DORINFO?.DEF file to search + for. For instance, if od_control.od_node is set to 3, OpenDoors + will first search for a DORINFO3.DEF file. If this file is not + found, OpenDoors will then default to the DORINFO1.DEF filename. + + + + +------------------------------------------------------------------------------- +user char od_control.user_timeofcreation[6]; +_timeof +creation This variable contains the time of day at which the door + information file was created. This variable is available only + when the door is running under a system that produces an + EXITINFO.BBS file. To determine what type of door information + file your door is running under, see the od_control.od_info_type + variable, below. + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 152 + +CONTROL STRUCTURE - SERIAL PORT SETTINGS +------------------------------------------------------------------------------- + + The following OpenDoors control structure items store the + communications settings that OpenDoors uses to communicate with + the modem. These values are normally set upon the first call to + an OpenDoors function, during the od_init() procedure. However, + you may need to manual set this variables if: + + - you wish to allow greater configurability of your door + - you are reading the door information file yourself + - you are using the OpenDoors to write a non-door + program + + Some of these variables are always used by OpenDoors, while + others are only relevant if OpenDoor's built-in serial + communications code is being used instead of a FOSSIL driver. + Those that are only used when no FOSSIL driver is present are + denoted by an [*] in the list below. + + The control structure variables controlling OpenDoor's serial + port settings are as follows: + + od_control.baud Serial Port BPS rate + + od_control.od_connect_sppedThe modem connection BPS rate + + od_control.od_com_address Serial Port address [*] + + " " .od_com_fifo_trigger 16550A FIFO trigger size + + " " .od_com_flow_control Type of flow control to use. + + od_control.od_com_irq Serial Port IRQ number [*} + + od_control.od_com_method Is FOSSIL or built-in serial I/O + being used + + od_control.od_com_no_fifo Disables use of 16550A FIFOs [*] + + od_control.od_com_rx_buf Size of receive buffer [*] + + od_control.od_com_tx_buf Size of transmit buffer [*] + + od_control.od_no_fossil Prevents OpenDoors from using a + FOSSIL driver, even if one is + available. + + od_control.od_open_handle Allows a live serial port handle to + be passed to OpenDoors. + + od_control.port Serial port number, 0 based. +=============================================================================== +OpenDoors 6.00 Manual End of Page 153 + + + + +------------------------------------------------------------------------------- +baud unsigned long od_control.baud; + + This variable contains the BPS rate at which the computer is + communicating with the modem, not to be confused with the BPS + rate at which the local modem is communicating with the remote + modem. + + A value of 0 indicates that the program is operating in local + mode. + + If a FOSSIL driver is being used for serial I/O, this value is + ignored if it does not correspond to one of the baud rates that + an application can directly set a FOSSIL driver to. The BPS + rates recognized by FOSSIL drivers are: 300, 600, 1200, 2400, + 4800, 9600, 19200, 38400. If any other BPS rate is to be used, + the FOSSIL driver must be locked at that BPS from the FOSSIL + driver command-line. When locked, FOSSIL drivers ignore any + attempt by an application to change the BPS rate of the locked + port. For this reason, the od_control.baud setting has no effect + on the FOSSIL driver if it is locked. + + + +------------------------------------------------------------------------------- +od_com_ int od_control.od_com_address; +address + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the serial port address can be set from the FOSSIL driver + command line). + + This variable may optionally be set to specify the base address + of the serial port to be used. For ports COM1: through COM4:, + OpenDoors can normally determine the serial port address + automatically. However, for other serial ports, the port address + must be specified using this variable. If you are not specifying + a serial port address with this variable, do not change it's + default value of 0. + + + +------------------------------------------------------------------------------- +od_com_ char od_control.od_com_fifo_trigger; +fifo_trigger + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the IRQ line can be set from the FOSSIL driver command + line). +=============================================================================== +OpenDoors 6.00 Manual End of Page 154 + + + This variable sets the number of bytes that will be placed in + the 16550A UART FIFO buffers before an interrupt is triggered, + if the 16550A UART FIFOs are used. Valid values are 1, 4, 8 and + 14. + + + +------------------------------------------------------------------------------- +od_com_ unsigned char od_control.od_com_flow_control; +flow_control + This variable sets the type of serial I/O flow control to use. + By default, this variable is set to COM_DEFAULT_FLOW, which + specifies the default mode of flow control. Most often, this + will be RTS/CTS flow control. A value of COM_RTSCTS_FLOW + explicitly enables RTS/CTS flow control. A value of COM_NO_FLOW + disables all flow control. If you are going to change the value + of this variable, it should be set prior to your first call to + any OpenDoors function. + + + +------------------------------------------------------------------------------- +od_com_ unsigned char od_control.od_com_irq; +irq + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the IRQ line can be set from the FOSSIL driver command + line). + + This variable may optionally be set to specify the IRQ line to + be used for the serial port. By default, OpenDoors uses the + normal IRQ 4 line for ports COM1: and COM3:, and IRQ 3 for ports + COM2: and COM4:. To override this default, the IRQ line can be + set using this variable. If you are not specifying an IRQ line + with this variable, do not change it's default value of 0. + + + +------------------------------------------------------------------------------- +od_com_ char od_control.od_com_method; +method + This read-only variable reports the method that OpenDoors is + using for serial I/O. This variable is set during od_init() or + the first call to an OpenDoors function. This variable can be + one of the following values: + + COM_FOSSIL - Indicates that a FOSSIL driver is being + used + COM_INTERNAL - Indicates that OpenDoor's internal serial I/O + code is being used. + COM_WIN32 - Indicates that the Win32 communication system +=============================================================================== +OpenDoors 6.00 Manual End of Page 155 + + is being used. + + + +------------------------------------------------------------------------------- +od_com_ char od_control.od_com_no_fifo; +no_fifo + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the receive buffer size can be set from the FOSSIL driver + command line). + + Normally, OpenDoors will use a 16550A FIFO buffer if a 16550A + UART is installed. You can disable the use of the 16550A FIFO + buffer by setting this variable to TRUE. + + + +------------------------------------------------------------------------------- +od_com_ unsigned int od_control.od_com_rx_buf; +rx_buf + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the receive buffer size can be set from the FOSSIL driver + command line). + + This variable allows you to set the size of OpenDoor's serial + I/O receive buffer. If you do not set this buffer size, a + default value of 256 characters is used. Normally, this buffer + size is more than large enough for door programs. However, if + you find that inbound characters are lost before they can be + processed by your program, you may wish to increase the size of + this buffer. + + This variable should only be changed before your first call to + od_init() or any other OpenDoors function. + + + +------------------------------------------------------------------------------- +od_com_ unsigned int od_control.od_com_tx_buf; +tx_buf + This variable is only used when OpenDoors is NOT performing + serial I/O using a FOSSIL driver. (When a FOSSIL driver is being + used, the receive buffer size can be set from the FOSSIL driver + command line). + + This variable allows you to set the size of OpenDoor's serial + I/O transmit buffer. If you do not set this buffer size, a + default value of 1024 characters is used. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 156 + + This variable should only be changed before your first call to + od_init() or any other OpenDoors function. + + + +------------------------------------------------------------------------------- +od_connect_ DWORD od_control.od_connect_speed; +speed + This variable contains the best guess at the current modem + connection speed. This information is currently only accurate if + a DOOR.SYS file is being used. In other situations, it will + always be set to be equal to od_control.baud. + + + +------------------------------------------------------------------------------- +od_open_ DWORD od_control.od_open_handle; +handle + Under platforms where this is supported (currently only the + Win32 version of OpenDoors), this variable can be used to pass a + live serial port handle to OpenDoors, which OpenDoors will use. + OpenDoors will not close this handle when it exits. If this + value is set to 0, OpenDoors will open and close the serial port + itself. + + + +------------------------------------------------------------------------------- +port char od_control.port; + + This variable contains the serial port number that the modem is + connected. This number is 0 based, so that a value of 0 + corresponds to COM1:, a value of 1 corresponds to COM2:, and so + on. This value will normally be set by the od_init() function, + when the door information file is read, and should not be + changed after modem initialization has been carried out by the + od_init() function. + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 157 + +CONTROL STRUCTURE - BBS AND CALLER INFORMATION +------------------------------------------------------------------------------- + + As we have already described, there are two types of variables + in the OpenDoors control structure. Some of the variables are + simply used to allow you to customize OpenDoor's various + features, such as altering colors, prompts, timeouts, etc. Other + variables in the OpenDoors control structure serve to provide + you with information about the user who is online and the BBS + system your door is running under. This section deals with those + variables that provide you with information about the BBS and + the user. + + The information in these variables is read from the door + information file, a small file created by the BBS specifically + for the purpose of communicating with door programs. Depending + on what BBS system your door is running under, the type of door + information file will vary. Since different door information + files do not all provide the same pieces of information, some + variables in this section will only be available when your door + is running under particular BBS systems. Other variables will + be available with many or all BBS systems. In the description of + each variable in this section, we indicate under which door + information files the particular variable will be . So, if you + wish to access a variable that is only under certain door + information files, your program should test whether or not the + required information is available under the particular door + information file that was found. In order to determine which + door information file your door is running under, you should use + the od_control.od_info_type variable. This variable is described + in the section which begins on page 150. If you test the value + of the od_control.od_info_type variable, and find that the + required information is not available, you may wish to simply + use some sort of default value for the variable, or + alternatively, not allow your door to run under certain BBS + systems. Another possibility, if the required information is not + available, is imply to obtain this information from the user + yourself. For example, if you wished to know the length of the + user's screen, when this information is not available from the + door information file, you could simply prompt the user for + their screen length the first time they use your door. This + information could then be stored in your door's data files for + future reference. + + As an example of testing what door information file your door is + running under, consider the case where you wanted to display the + user's birthday. The example below will display the user's + birthday if it is known, and otherwise, print the string + "unknown". + + if(od_control.od_info_type == RA1EXITINFO + od_control.od_info_type == RA2EXITINFO) +=============================================================================== +OpenDoors 6.00 Manual End of Page 158 + + { + od_disp_str(od_control.user_birthday); + } + else + { + od_disp_str("Unknown"); + } + + The chart below lists the door information file formats that + OpenDoors recognizes, along with example BBS systems that + produce these files and a reference letter for each type. Thus, + an OpenDoors door can run DIRECTLY under ANY BBS SYSTEM that + produces one of these files formats, and under ANY OTHER BBS + system when used in conjunction with a door information file + conversion utility. + ++--------------------------+----------------------------------------+ +| FILE FORMAT | EXAMPLE BBS SYSTEMS | ++--------------------------+----------------------------------------+ +| CHAIN.TXT | WWIV | ++--------------------------+----------------------------------------+ +| DORINFO1.DEF | RBBS-PC | ++--------------------------+----------------------------------------+ +| DORINFO1.DEF | QuickBBS | +| & | Remote Access (versions 0.01-0.04) | +| EXITINFO.BBS (Std. Ver.) | | ++--------------------------+----------------------------------------+ +| DOOR.SYS (DoorWay Style) | Remote Access | ++--------------------------+----------------------------------------+ +| DOOR.SYS (PCB/GAP Style) | PC-Board | +| | GAP | ++--------------------------+----------------------------------------+ +| DOOR.SYS (WildCat Style) | Wildcat 3.00 and above | +| | Telegard | ++--------------------------+----------------------------------------+ +| SFDOORS.DAT | Spitfire | +| | TriBBS | ++--------------------------+----------------------------------------+ +| CALLINFO.BBS | WildCat 2.xx | ++--------------------------+----------------------------------------+ +| DORINFO1.DEF | Remote Access (versions 1.00 and later)| +| & | | +| EXITINFO.BBS (Ext. Ver.) | | ++--------------------------+----------------------------------------+ + + + + The chart on the following page lists all of the OpenDoors + control structure variables in this section, along with a brief + description of their use. The variables are then described in + detail, below. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 159 + ++-----------------------+-----------------------------------------------+ +| VARIABLE NAME | VARIABLE CONTENTS | ++-----------------------+-----------------------------------------------+ +| EMSI INFORMATION | Information on current IEMSI session | +| event_status | The status of the next system event | +| event_starttime | The start time of the next system event | +| event_errorlevel | The errorlevel of the next system event | +| event_days | The days of the week to execute the event | +| event_force | Whether the next system event is forced | +| event_last_run | When the next system event was last run | +| sysop_name | The name of the BBS's sysop | +| system_calls | Total number of calls BBS has received | +| system_last_caller | The name of the last caller to the BBS | +| system_last_handle | The handle (alias) of the last caller | +| system_name | The name of the BBS | +| TIMELOG VARIABLES | The times at which the BBS has been most busy | +| user_ansi | Whether the user has ANSI graphics mode on | +| user_attribute | User attribute bit-mapped flags | +| user_attrib2 | Second set of user attribute bit-mapped flags | +| user_attrib3 | Third set of user attribute flags | +| user_avatar | Whether the user has AVATAR graphics mode on | +| user_birthday | The date the user was born | +| user_callsign | The user's amateur radio call sign | +| user_combinedrecord | The user's combined message areas settings | +| user_comment | Sysop's comment about the user | +| user_credit | Amount of NetMail credit the user has | +| user_dataphone | The user's data phone number | +| user_date_format | Format user wishes to have dates displayed in | +| user_deducted_time | Total time that has been subtracted from user | +| user_downk | Total Kilobytes downloaded by the user | +| user_downlimit | User's daily download limit | +| user_downloads | Total number of files downloaded by the user | +| user_echomailentered | Whether or not the user has entered EchoMail | +| user_error_free | Whether or not connection is error-free | +| user_file_area | The user's current file area | +| user_firstcall | Date of the user's first call to the BBS | +| user_flags | User's sysop-defined flag settings | +| user_forward_to | Name to forward user's mail to | +| user_group | User's group number | +| user_handle | User's alias | +| user_homephone | User's home telephone number | +| user_language | User's language setting | +| user_last_pwdchange | Total calls since last password change | +| user_lastdate | Date of the user's last call | +| user_lastread | Highest message number read by user | +| user_lasttime | Time of the user's last call | +| user_location | Name of the city where the user lives | +| user_logindate | Date on which the current call began | ++-----------------------+-----------------------------------------------+ + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 160 + + + + ++-----------------------+-----------------------------------------------+ +| VARIABLE NAME | VARIABLE CONTENTS | ++-----------------------+-----------------------------------------------+ +| user_loginsec | User's security at the beginning of this call | +| user_logintime | Time at which the current call began | +| user_logonpassword | User's password at the beginning of this call | +| user_menustack | Contents of the user's current menu stack | +| user_menustackpointer | Pointer to the top of the menu stack | +| user_messages | Total number of messages written by the user | +| user_msg_area | The user's current message area | +| user_name | The user's name | +| user_net_credit | The user's remaining netmail credit | +| user_netmailentered | Whether or not the user has entered NetMail | +| user_num | The user's record number in the user file | +| user_numcalls | Number of calls the user has made to the BBS | +| user_numpages | Number of times the user has paged the sysop | +| user_password | The user's current password | +| user_pending | The value of unsent NetMail written by user | +| user_reasonforchat | The reason the user wishes to chat with sysop | +| user_rip_ver | RIP protocol version being used | +| user_screen_length | The length of the user's screen | +| user_screenwidth | The width of the user's screen | +| user_security | The user's security access level | +| user_sex | The user's gender | +| user_subdate | The date the user's subscription expires | +| user_timelimit | The user's daily time limit | +| user_todayk | Kilobytes downloaded by the user today | +| user_upk | Total Kilobytes uploaded by the user | +| user_uploads | Total number of files uploaded by the user | +| user_wantchat | Whether or not the user wishes to chat | +| user_xi_record | The user's record in the USERSXI.BBS file | ++-----------------------+-----------------------------------------------+ + + + + +------------------------------------------------------------------------------- +EMSI char od_control.ra_emsi_session; +INFORMATION char od_control.ra_emsi_crtdef[41]; + char od_control.ra_emsi_protocols[41]; + char od_control.ra_emsi_capabilities[41]; + char od_control.ra_emsi_requests[41]; + char od_control.ra_emsi_software[41]; + char od_control.ra_hold_attr1; + char od_control.ra_hold_attr2; + char od_control.ra_hold_len; + + These variables provide your door with information pertaining to + an interactive EMSI session that has been established. Note that +=============================================================================== +OpenDoors 6.00 Manual End of Page 161 + + these variables are only available under systems that produce an + RA 1.00 and later style extended EXITINFO.BBS door information + file. + + If an IEMSI session has been established, the Boolean variable + od_control.ra_emsi_session will be TRUE, and if no session has + not been established, this variable will be FALSE. + + A full discussion of the IEMSI protocol is beyond the scope of + this manual. Specifications for the IEMSI protocol are available + from the OpenDoors support BBS. + + + +------------------------------------------------------------------------------- +event_days unsigned char od_control.event_days; + + This variable is a bit-mapped flag of the days of the week on + which the next system event is run. The bit-map bits are as + follows: + + +-----+------+-----------+ + | BIT | MASK | MEANING | + +-----+------+-----------+ + | 0 | 0x01 | Sunday | + | 1 | 0x02 | Monday | + | 2 | 0x04 | Tuesday | + | 3 | 0x08 | Wednesday | + | 4 | 0x10 | Thursday | + | 5 | 0x20 | Friday | + | 6 | 0x40 | Saturday | + | 7 | 0x80 | All Days | + +-----+------+-----------+ + + For more information on bit-mapped flags, see the glossary item + entitled "BIT-MAPPED FLAGS". + + This variable is only available under systems that produce an + EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +event_ unsigned char od_control.event_errorlevel; +errorlevel + This variable contains the ErrorLevel associated with the next + system event. This variable is only available under systems that + produce an EXITINFO.BBS door information file. + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 162 + +------------------------------------------------------------------------------- +event char od_control.event_force; +_force + This variable indicates whether the next system event should be + forced to run at a particular time. If this variable contains a + value of TRUE, then the user should be forced off-line in order + to accommodate the event, and if this variable is false, then + the event can wait until after the user logs off normally. This + variable is only available under systems that produce an + EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +event char od_control.event_last_run[9]; +_last_run + This variable contains a string representing the date on which + the next system event was last run, and is in the same format as + the user_lastdate variable. This variable is only available + under systems that produce an EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +event char od_control.event_starttime[6]; +_starttime + This variable contains a string representing the time at which + the next system event is scheduled to start, in the same format + as the user_lasttime variable. This variable is only available + under systems that produce an EXITINFO.BBS or Wildcat style + DOOR.SYS door information file. + + + +------------------------------------------------------------------------------- +event unsigned char od_control.event_status; +_status + This variable represents the status of the next system event, + and will be equal to the value + + ES_ENABLED + + if and only if the other event information contained in the + control structure is valid. This variable is only available + under systems that produce an EXITINFO.BBS file. + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 163 + +------------------------------------------------------------------------------- +sysop_name char od_control.sysop_name[40]; + + The od_control.sysop_name variable contains the name of the + sysop of the BBS under which your door is running. This variable + is available under any BBS system that produces a DORINFO?.DEF + (including RA & QBBS which process both DORINFO1.DEF and + EXITINFO.BBS files), or Wildcat style DOOR.SYS file. + + + +------------------------------------------------------------------------------- +system_calls long od_control.system_calls; + + This variable contains the total number of calls that have been + placed to the BBS, and is available under any BBS which produces + an EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +system_last char od_control.system_last_caller[36]; +_caller + This string contains the name of the previous caller to the BBS, + on any line, and is available under EXITINFO.BBS. + + + +------------------------------------------------------------------------------- +system_last char od_control.system_last_handle[36]; +_handle + This string contains the handle (alias) of the previous caller + to the BBS, on any line, and is available under EXITINFO.BBS. + + + +------------------------------------------------------------------------------- +system_name char od_control.system_name[40]; + + The od_control.system_name variable contains the name of the BBS + under which your door is running. This variable is available + under any BBS system that produces a DORINFO?.DEF (including RA + & QBBS which process both DORINFO1.DEF and EXITINFO.BBS files). + + + +------------------------------------------------------------------------------- +TIMELOG char od_control.timelog_start_date[9]; +VARIABLES + This string contains the date of the beginning of the time + period for which the time log is recorded. This variable is + available under any system that produces an EXITINFO.BBS file. +=============================================================================== +OpenDoors 6.00 Manual End of Page 164 + + + + int od_control.timelog_busyperhour[24]; + + This variable is an array of 24 elements, with each element + indicating the total number of times the BBS was in use during + each of the 24 hours of the day. Element 0 corresponds to the + time period of 0:00-1:00, element 1 corresponds to the time + period of 1:00-2:00, and so on. In order to determine the + frequency of system use during any hour as a percentage, simply + calculate the total of all 24 entries in the array, and divide + any given entry by the total, in order to come up with an + average. This variable is available under any system that + produces an EXITINFO.BBS file. + + + int od_control.timelog_busyperday[7]; + + This variable is an array of 7 elements, with each element + indicating the total number of times the BBS was in use during + each of the 7 days of the week. Here, elements 0 corresponds to + Sunday, element 1 to Monday, and so on. In order to calculate + the frequency of system use during any day of the week, use the + same method as for calculating the frequency of calls during + each hour, as described above. This is only available under + systems that produces an EXITINFO.BBS file. Note that at least + some, if not all, versions of RemoteAccess do not maintain this + variable correctly, and thus even with the presence of an + EXITINFO.BBS file, this array may contain all zero entries. + + + +------------------------------------------------------------------------------- +user_ansi char od_control.user_ansi; + + This variable contains a Boolean value, indicating whether or + not the user has ANSI mode turned on. If ANSI graphics mode is + enabled, this variable will contain a value of TRUE, and if ANSI + graphics mode is disabled, this variable will contain a value of + FALSE. Many of the OpenDoors functions test the setting of this + variable in order to determine whether or not they should send + ANSI-graphics control characters. Also, if this variable + contains a TRUE value, OpenDoors will display an "[ANSI]" + indicator on the status line. + + You may change the value of this variable at any time after the + first call to od_init() or any other OpenDoors functions. + Depending upon what BBS system your door is running under, + changes to this variable may or may not result in changes to the + user's ANSI setting upon return to the BBS. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 165 + + This variable is available under all door information file + formats. + + + +------------------------------------------------------------------------------- +user_ unsigned char od_control.user_attribute; +attribute + This variable is a bitmap of eight flags, each of which + represent individual pieces of information pertaining to the + user that is currently online. These flags are as follows: + + +-----+------+-----------------------+ + | BIT | MASK | DESCRIPTION | + +-----+------+-----------------------+ + | 0 | 0x01 | Is the user deleted | + | 1 | 0x02 | Is screen clearing on | + | 2 | 0x04 | Is "more" prompt on | + | 3 | 0x08 | Is ANSI mode on | + | 4 | 0x10 | User no-kill setting | + | 5 | 0x20 | Transfer-priority | + | 6 | 0x40 | Full screen editor | + | 7 | 0x80 | Quiet mode | + +-----+------+-----------------------+ + + For more information on using and setting bit-mapped flags, + please see the entry entitled "BITMAPED FLAGS" in the glossary + of this manual. + + Note that this variable is only available under systems that + produce and EXITINFO.BBS format door information file. + + + +------------------------------------------------------------------------------- +user_ unsigned char od_control.user_attrib2; +attrib2 + See the user_attrib variable for more information. This variable + is like the user_attrib variable, except that it contains + different information. The bit-mapped flags for the + od_control.user_attrib2 variable are as follows: + + +-----+------+-----------------------+ + | BIT | MASK | DESCRIPTION | + +-----+------+-----------------------+ + | 0 | 0x01 | User hot-keys setting | + | 1 | 0x02 | Is AVATAR graphics on | + | 2 | 0x04 | Full screen reader | + | 3 | 0x08 | Hidden from userlist | + +-----+------+-----------------------+ + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 166 + + Note that this variable is only available under systems that + produce an EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_ unsigned char od_control.user_attrib3; +attrib3 + This variable contains user attribute flags when a RA 2.50 or + later EXITINFO.BBS file is used. + + + +------------------------------------------------------------------------------- +user_avatar char od_control.user_avatar; + + This variable is a Boolean value indicating whether or not + AVATAR graphics mode is on. If AVATAR graphics is available, + then many of the OpenDoors functions will make use of AVATAR + graphics codes for greater display speed. If AVATAR graphics + mode is on, a [AVT] indicator will appear on the status line. If + your door is running under a system which produces an RA 1.00+ + style extended EXITINFO.BBS door information file, the + user_avatar variable is set automatically. If the extended + EXITINFO.BBS file is not available, this value will default to + FALSE. In this case, you may wish to ask the user whether or not + they wish to use AVATAR graphics, and thus set this variable + yourself. + + + +------------------------------------------------------------------------------- +user char od_control.user_birthday[9]; +_birthday + This variable is a string, in the same format as the + od_control.user_lastcall variable, which stores the date of the + user's birthday, if it is available. This variable is only + available under systems that produce an RA 1.00 and later style + extended EXITINFO.BBS or Wildcat style DOOR.SYS file. + + + +------------------------------------------------------------------------------- +user char od_control.user_callsign[12]; +_callsign + This variable is a string which contains the user's amateur + radio call sign, if any. This variable is only available under + systems that produce a CHAIN.TXT file. + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 167 + +------------------------------------------------------------------------------- +user_combined unsigned char od_control.user_combinedrecord[25]; +record + This variable is an array of bit-mapped flags, with each flag + corresponding to an individual message area. In this case, the + first bit of od_control.ra_combinedrecord[0] corresponds to the + first message area, the second bit to the second message area, + and so on. If any given bit-flag is turned on, then the user has + corresponding message area enabled for combined access, and if + the bit is turned off, the user does not have the area enabled + for combined access. A detailed description of the combined + message access is beyond the scope of this manual. This variable + is only available under systems that produce an RA 1.00 or later + style extended EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_comment char od_control.user_comment[81]; + + This variable is a string which contains the sysop's comment + about the user that is currently online. This comment may be + displayed on the OpenDoors status line, if this variable is + available. This variable is available under systems that produce + an RA 1.00 and later style extended EXITINFO.BBS or Wildcat + style DOOR.SYS file. + + + +------------------------------------------------------------------------------- +user_credit unsigned int od_control.user_credit; + + This variable contains the total amount of NetMail credit that + the caller has left. Changes to this variable will be by the BBS + when your door exits and control is returned to the BBS. This + variable is only available under systems that produce an + EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_ char od_control.user_dataphone[13]; +dataphone + This string contains the user's data or business phone number, + if available. This value is only available under system that + produce EXITINFO.BBS, PC-Board/GAP style DOOR.SYS and WildCat + DOOR.SYS format door information files. + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 168 + +------------------------------------------------------------------------------- +user int od_control.user_deducted_time; +_deducted +_time This variable contains a signed integer value, which indicates + the total amount of time that has been deducted from the user + during this call. This variable is only available under systems + that produce an RA 1.00 and later style extended EXITINFO.BBS + door information file. + + + +------------------------------------------------------------------------------- +user_downk unsigned int od_control.user_downk; + + This variable contains the total kilobytes of files that the + current user has downloaded from the BBS, and is available under + systems that produce EXITINFO.BBS, Wildcat style DOOR.SYS or + SFDOORS.DAT format door information files. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_downlimit; +_downlimit + This variable contains the total number of kilobytes that the + caller is permitted to download during this call. If your door + allows files do be downloaded, you will probably want to compare + the value of this variable to the size of any file to be + transferred and the total kilobytes already downloaded, as + stored in the od_control.user_todayk variable. This variable is + only available under systems that produce an EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_downloads; +_downloads + This variable contains the total number of files that the + current user has downloaded from the BBS, and is available under + systems that produce EXITINFO.BBS, PC-Board/GAP style DOOR.SYS, + WildCat style DOOR.SYS or SFDOORS.DAT format door information + files. + + + +------------------------------------------------------------------------------- +user_echo char od_control.user_echomailentered; +mailentered + This variable is a Boolean value, indicating whether or not the + user has entered new EchoMail during this call. If this variable + has a value of TRUE, then EchoMail has been entered, and if it + has a value of FALSE, then EchoMail has not been entered. This +=============================================================================== +OpenDoors 6.00 Manual End of Page 169 + + variable will contain a valid value only after od_init() or some + OpenDoors function has been called. Any changes made to this + variable will be reflected within the BBS software when control + is returned to the BBS. This variable is accessible only under + systems which produce an EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_error char od_control.user_error_free; +_free + This variable contains a Boolean value indicating whether or not + the user is connected to the BBS via an error free connection + (eg. a V.42/MNP or similar modem protocol). This variable is + only available under systems that produce an SFDOORS.DAT, + Wildcat style DOOR.SYS or RA 1.00 or later style extended + EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_first char od_control.user_firstcall[9]; +call + This variable is a string which contains the date of the user's + first call, in the same format as the od_control. user_lastcall + variable. This variable is only available under systems which + produce an RA 1.00 and later style extended EXITINFO.BBS door + information file. + + + +------------------------------------------------------------------------------- +user_ unsigned char od_control.user_flags[4]; +flags + The od_control.user_flags variable is an array of four sysop + defined bit-mapped flags, which represent some sort of + information about the user. od_control.user_flags[0] stores + flags A1 - A8 in bits 0 through 7, respectively. Likewise, + od_control.user_flags[1] stores flags B1 - B8, and so on. This + variable is only available under systems that produce + EXITINFO.BBS format door information files. + + + +------------------------------------------------------------------------------- +user_handle char od_control.user_handle[36]; + + This variable contains the user's alias or handle name, if any. + If the user does not have and alias or handle, this variable + will be blank. This variable is only available under systems + that produce a CHAIN.TXT, RA 1.00 and later extended + EXITINFO.BBS or Wildcat style DOOR.SYS door information file. +=============================================================================== +OpenDoors 6.00 Manual End of Page 170 + + + + +------------------------------------------------------------------------------- +user_ char od_control.user_homephone[13]; +homephone + This string contains the user's home or data phone number, if + available. This value is only available under system that + produce one of the following door information files: + EXITINFO.BBS, PC-Board/GAP style DOOR.SYS, WildCat style + DOOR.SYS or SFDOORS.DAT. + + + +------------------------------------------------------------------------------- +user unsigned char od_control.user_last_pwdchange; +_last +_pwdchange This variable contains the number of calls that the user has + made since they last changed their password. This variable is + only available under EXITINFO.BBS files. + + + +------------------------------------------------------------------------------- +user char od_control.user_lastdate[9]; +_lastdate + This variable is a string containing the date of the user's last + call to the BBS, and should always be of the format: + + "MM-DD-YY" + + Where MM is two digits representing the number of the month of + the user's call, with 1 being January, 2 being February, and so + on. DD should be two digits representing the day of the month of + the user's last call, beginning with 1, and MM should be the + last two digits of the year of the user's last call. + + This variable is only available under systems that produce one + of the following door information files: CHAIN.TXT, + EXITINFO.BBS, PC-Board/GAP style DOOR.SYS or WildCat style + DOOR.SYS files. + + + +------------------------------------------------------------------------------- +user_ unsigned int od_control.user_lastread; +lastread + This variable contains the number of the highest message number + that the user has read, and is only available under EXITINFO.BBS + format door information files. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 171 + + +------------------------------------------------------------------------------- +user char od_control.user_lasttime[6]; +_lasttime + This variable contains a string representing the time of the + user's last call to the BBS, and should always be of the format: + + "HH:MM" + + Where HH is two digits representing the 24-hour format hour of + the user's last call, and MM is two digits representing the + minute of the user's last call. Thus, the following strings + would be valid entries for this string: + + "00:01" (12:01 am) + "03:47" (3:47 am) + "18:20" (6:20 pm) + + This variable is only available under systems that produce an + EXITINFO.BBS or Wildcat style DOOR.SYS format door information + file. + + + +------------------------------------------------------------------------------- +user char od_control.user_location[26]; +_location + This string contains the name of the location from which the + current user is calling from. This will usually be the name of + the city, region (province, state, etc.) and sometimes country + where the user lives. The contents of this variable are + displayed on the OpenDoors status line. The value of this + variable is valid after od_init() or any other OpenDoors + function has been called. Also, you may change the value of this + variable if you wish. However, not that these changes may not + immediately be reflected in the status line, and may or may not + cause the setting to be changed after the user returns to the + BBS. This variable is available under systems that produce one + of the following door information files: DORINFO?.DEF, + EXITINFO.BBS, PC-Board/GAP style DOOR.SYS, WildCat style + DOOR.SYS SFDOORS.DAT and CALLINFO.BBS, but is not available + under CHAIN.TXT or DoorWay style DOOR.SYS files. + + + +------------------------------------------------------------------------------- +user char od_control.caller_logindate[9]; +_logindate + This variable contains a string representing the date on which + the current call to the BBS began. This variable is in the same + format as the od_control.user_lastdate variable, described + +=============================================================================== +OpenDoors 6.00 Manual End of Page 172 + + below. This variable is only available under systems which + produce an EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +user long od_control.user_loginsec; +_loginsec + This variable contains the user's security at login, and can be + used to detect changes by the sysop or other programs during the + course of the call, by comparing it's value with the + od_control.user_security variable. This variable is only + available under systems which produce an EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +user char od_control.user_logintime[6]; +_logintime + This variable contains a string representing the time of day at + which the current call to the BBS began. This variable is in the + same format as the od_control.user_lasttime variable, which is + also described below. This variable is available under systems + which produce an EXITINFO.BBS, a Wildcat style DOOR.SYS, or an + SFDOORS.DAT file. + + + +------------------------------------------------------------------------------- +user char od_control.user_logonpassword[16]; +_logon +password This variable is a string which contains the user's password + at the time at which the current call to the BBS began. This + variable can be used to detect changes by the sysop or other + programs to the user's password, which have taken place during + the course of the call. In order to detect such changes, simply + compare the contents of this string with the contents of the + od_control.user_password variable. This variable is only + available under systems which produce an EXITINFO.BBS format + door information file. + + + +------------------------------------------------------------------------------- +user char od_control.user_menustack[50][9]; +_menustack + This variable is an array of 50 strings, containing the stack of + BBS menus that have been executed, and is used to record the + current position of the user within the BBS's menu system. Each + string contains just the base portion of the filename of the + menu, without the extension. The od_control.ra_menustackpointer + variable points to the top of the menu stack. However, a +=============================================================================== +OpenDoors 6.00 Manual End of Page 173 + + complete discussion of the menu stack is beyond the scope of + this manual. This variable is only available under systems that + produce an RA 1.00 and later style extended EXITINFO.BBS door + information file. + + + +------------------------------------------------------------------------------- +user unsigned char od_control.user_menustackpointer; +_menustack +pointer This variable points to the top of the current menu stack. For + more information on the menu stack, please refer to the + od_control.ra_menustack variable, above. This variable is only + available under systems that produce an RA 1.00 and later style + extended EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_messages; +_messages + This variable contains a value representing the total number of + messages that have been written by the user, and is available + under EXITINFO.BBS or Wildcat style DOOR.SYS format door + information files. + + + +------------------------------------------------------------------------------- +user_name char od_control.user_name[36]; + + This string contains the name of the user that is currently on- + line, and is used by OpenDoors to display the current user name + on the status line, and will most likely be used by your door + for differentiating among different users. In most cases, you + should probably not change the value of this variable, as a + user's name does not usually change, and doing so could results + in problems when returning to some BBS systems. For an example + of using this variable, see the EX_VOTE.C example program. This + variable is available under all BBS systems. + + + +------------------------------------------------------------------------------- +user_net_ unsigned int od_control.user_net_credit; +credit + This variable contains the amount of NetMail credit that the + current user has to his or her name. This variable is only + available under systems that produce an EXITINFO.BBS file. + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 174 + + Note that if you wish to change the value of the user's + remaining NetMail credit, you should use the od_control. + user_credit variable, instead of this variable. + + + +------------------------------------------------------------------------------- +user_net char od_control.user_netmailentered; +mailentered + This variable is a Boolean value, indicating whether or not the + user has entered new NetMail or GroupMail during this call. If + this variable has a value of TRUE, then NetMail/GroupMail has + been entered, and if it has a value of FALSE, then + NetMail/GroupMail has not been entered. This variable will + contain a valid value only after od_init() or some OpenDoors + function has been called. Any changes made to this variable will + be reflected within the BBS software when control is returned to + the BBS. This variable is accessible only under systems which + produce an EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_num unsigned int od_control.user_num; + + This variable contains the number of the user's record in the + user database file, where 0 is the first record. This can be + useful for changing user settings that are not re-read by the + BBS, such as the user's phone number or security level which + might be altered by a call back verification door. However, the + value of this variable itself should not be altered. + + This variable is available under systems which produce any of + the following door information file formats: CHAIN.TXT, PC- + Board/GAP style DOOR.SYS, Wildcat style DOOR.SYS SFDOORS.DAT and + EXITINFO.BBS. + + + +------------------------------------------------------------------------------- +user_ unsigned int od_control.user_numcalls; +numcalls + This variable contains the total number of calls that the + current user has placed to the BBS, and is available under + systems that produce EXITINFO.BBS or PC-Board/GAP and Wildcat + style DOOR.SYS door information files. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 175 + +------------------------------------------------------------------------------- +user unsigned int od_control.user_numpages; +_numpages + The value of this variable contains the total number of times + that the user has paged the sysop, and can be used to limit the + number of times that the user is permitted to page the sysop. + OpenDoors increments this variable every time that the user + pages the sysop, via the od_page() function. This variable is + used with all types of door information files. However, this + variable will only reflect the value within the BBS if an + EXITINFO.BBS file is produced. Otherwise, the variable will only + contain the number of times that the user has paged within the + door, but not the total number of times the user has paged. + Under EXITINFO.BBS systems, changes to the value of this + variable will be reflected within the BBS upon return by the + DOOR. + + + +------------------------------------------------------------------------------- +user char od_control.user_password[16]; +_password + This variable contains the user's password for accessing the + BBS. OpenDoors does not use this value itself. This variable + will contain a valid value only after od_init() or some + OpenDoors function has been called. You may change the value of + this variable. Note, however, that changes in this variable may + or may not cause the setting to be changed when control returns + to the BBS - this will depend upon the particular BBS system + your door is running under. This variable is only available + under systems that produce one of the following door information + files: EXITINFO.BBS, PC-Board/GAP and Wildcat style DOOR.SYS, + SFDOORS.DAT, and CALLINFO.BBS. + + + +------------------------------------------------------------------------------- +user_pending unsigned int od_control.user_pending; + + This variable represents the total value of NetMail that has + been written by the current user, but not yet exported from the + message base. This variable is only available under systems that + produce an EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user_reason char od_control.user_reasonforchat[78]; +forchat + This variable is a string, containing the reason for which the + user wishes to chat with the sysop, as they entered at the time + of paging the sysop. This variable will contain an empty string +=============================================================================== +OpenDoors 6.00 Manual End of Page 176 + + if the user has not paged the sysop, or if the reason the user + wishes to chat is unknown. See also the od_control.user_wantchat + variable. This variable is available under all BBS systems, + regardless of what style of door information file they produce. + However, this variable will not be passed between the door and + BBS, and thus the user's reason for chat within the door will + not necessarily correspond to their reason for chat outside the + door. + + + +------------------------------------------------------------------------------- +user_rip char user_rip; + + This variable is set to TRUE if the user has RIP (Remote Imaging + Protocol) graphics enabled, and FALSE if they do not. This + setting can be determined from the door information (drop) file + in many cases. In other cases, you can automatically determine + whether or not the user's system supports RIP graphics using the + od_autodetect() function (see page 48). + + + +------------------------------------------------------------------------------- +user_rip_ver BYTE user_rip_ver; + + This variable contains the version of the RIP protocol that is + in use. This variable is only available under a RemoteAccess + 2.50 EXITINFO.BBS file. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_screen_length; +_screen +_length This value of this variable represents the total number of + lines that can be displayed on the user's screen at once, and is + usually either 24 or 25. You may wish to make use of this + variable to allow your door to pause the display of long pieces + of text after every screen length, in order to allow the user to + read this information before it passes off of their screen. In + this case, you would simply maintain a counter of the total + number of lines displayed, and when this value reaches one less + than the length of the user screen, display a prompt asking the + user to whether or not they wish to continue. + + This variable is set to the user's setting within the BBS under + systems that produce any of the following door information file + formats: CHAIN.TXT, EXITINFO.BBS, PC-Board/GAP and Wildcat style + DOOR.SYS and CALLINFO.BBS files. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 177 + + This variable is used by the OpenDoors function, + od_list_files(). If this variable contains a valid value, + OpenDoors will pause the listing of files after every screen, + and give the user the option of continuing, aborting, or + disabling the "Continue?" prompt for the rest of the file + listing. Thus, if you are using the od_list_files() under a + system that does not produce one of the door information files + listed above, you may wish to obtain the user's screen length + from the user themselves. If the screen length is not available + from the particular type of door information file that is found, + and you do not set this value yourself, this variable will + default to 23. If you are going to set the value of this + variable yourself, you should do so after having called + od_init() or some OpenDoors function. + + + +------------------------------------------------------------------------------- +user_ unsigned char od_control.user_screenwidth; +screenwidth + This variable contains a value representing the width of the + user's screen, and will most often be equal to 80. This variable + is only available under systems that produce a CHAIN.TXT or RA + 1.00 and later style extended EXITINFO.BBS door information + file. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_security; +_security + This variable contains a numerical value representing the user's + security access level on the BBS. You may wish to use this value + to determine whether or not the current user of your door should + have access to certain sysop-only functions. In this case, you + may wish to have a configuration file used by your door, in + which the sysop may define the minimum security level for sysop + access. You would then be able to compare this configuration + setting to the security level stored in this variable, in order + to determine whether or not sysop function should be available. + An alternative method, used by the EX_VOTE.C sample door, of + determining whether or not the current user is the sysop is to + compare the user's name with the value of the + od_control.sysop_name variable. This method has the advantage of + not requiring a configuration program, but the disadvantage that + the door will not function correctly under all BBS systems, as + the od_control.sysop_name variable is not available under all + BBS systems. + + The od_control.user_security variable is available under BBS + systems that produce any of the following door information file + +=============================================================================== +OpenDoors 6.00 Manual End of Page 178 + + formats: CHAIN.TXT, EXITINFO.BBS, PC-Board/GAP and Wildcat style + DOOR.SYS, SFDOORS.DAT or CALLINFO.BBS. + + + +------------------------------------------------------------------------------- +user_sex char od_control.user_sex; + + This variable contains a single character representing the + gender of the user that is currently online. This variable will + contain an upper-case 'F' if the user is female, and an upper- + case 'M' if the user is male. This variable is available under + systems that produce a CHAIN.TXT or RA 2.x style EXITINFO.BBS + file. + + + +------------------------------------------------------------------------------- +user_subdate char od_control.user_subdate[9]; + + This variable is a string, in the same format as the + od_control.user_lastdate variable, which stores the date of + expiry of the user's subscription to the BBS. This variable is + only available under systems which produce a PC-Board/GAP and + Wildcat style DOOR.SYS or RA 1.00 and later style extended + EXITINFO.BBS door information file. + + + +------------------------------------------------------------------------------- +user int od_control.user_timelimit; +_timelimit + This variable contains the amount of time, in minutes, that the + user has left in the door. Note that this value may or may not + be equal to the total amount of time that the user has left on + the BBS, depending upon whether the BBS or a third-party door + manager program only allows a limited amount of time in this + door. This variable contains a valid value after od_init() or + some OpenDoors function has been called. OpenDoors uses this + variable to keep track of how much time the user has left in the + door, and will automatically warn the user when nearly all of + his or her time has been used up. OpenDoors will also force the + user out of the door when their time in the door has expired. + OpenDoors automatically subtracts one minute from this variable + every minute that OpenDoors is active, unless chat mode has been + activated (in which case the user's time will freeze), and also + adjusts the value of this variable when the sysop uses the time + adjustment function keys. Hence, you will not normally have any + need to alter the value of this variable yourself. However, + there may be some cases in which you wish to subtract a penalty + or add a bonus to the user's time, such as in a "timebank" door + or a door game that permits the user to "gamble time". +=============================================================================== +OpenDoors 6.00 Manual End of Page 179 + + + Depending on which BBS system your door is running under, the + value of this variable may or may not effect the user's time + left upon return to the BBS. The BBS system will either reset + the user's time to the value re-written to the door information + file (this variable), or will always subtract the amount of time + spent in the door from the user's remaining time. + + This variable is available under all door information file + formats. + + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_todayk; +_todayk + This variable contains the total kilobytes of files that the + current user has downloaded from the BBS during the current day, + and is available under systems that produce EXITINFO.BBS, PC- + Board/GAP and Wildcat style DOOR.SYS, or SFDOORS.DAT format door + information files. + + + +------------------------------------------------------------------------------- +user_upk unsigned int od_control.user_upk; + + This variable contains the total kilobytes of files that the + current user has uploaded to the BBS, and is available under + systems that produce EXITINFO.BBS, Wildcat style DOOR.SYS or + SFDOORS.DAT files. + + + +------------------------------------------------------------------------------- +user_uploads unsigned int od_control.user_uploads; + + This variable contains the total number of files that the + current user has uploaded to the BBS, and is available under + systems that produce EXITINFO.BBS, PC-Board/GAP and Wildcat + style DOOR.SYS, or SFDOORS.DAT format door information files. + + + +------------------------------------------------------------------------------- +user char od_control.user_wantchat; +_wantchat + This variable is a Boolean value which indicates whether or not + the user wishes to chat with the sysop (ie, the user has paged + the sysop, but has yet to receive a chat with the sysop). This + variable is used under all door information file formats. + However, changes to this variable are only reflected on the BBS +=============================================================================== +OpenDoors 6.00 Manual End of Page 180 + + when the door is running under a system that produces an + EXITINFO.BBS door information file. + + This variable is automatically turned on (ie., set to TRUE), + when the user begins to page the sysop for chat, within the + od_page() function, and is automatically turned off (ie., set to + FALSE), when the sysop breaks in for chat via the chat function + key. Also, setting this variable to TRUE will turn on the + flashing want-chat indicator on the OpenDoors status line. + + +------------------------------------------------------------------------------- +user unsigned int od_control.user_xi_record; +_xi_record + This variable contains the number of the user's record in the + USERXI.BBS file, if any. This variable is only available under + system that produce a Remote Access 1.00 and later style + extended door information file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 181 + +CONTROL STRUCTURE - DOOR SETTINGS +------------------------------------------------------------------------------- + + This section deals with those variables in the OpenDoors control + structure which reflect the current door settings. These + variables are as follows: + + od_cur_attrib The current display attribute, or -1 if + unknown. + + od_okaytopage Controls whether the user is currently + permitted to page the sysop. + + od_pageendmin End of valid paging hours. + + od_pagestartmin Start of valid paging hours. + + od_silent_mode Turns off local user interface. + + od_user_keyboard_on Controls whether OpenDoors will + currently accept input from the remote + user's keyboard. + + od_update_status_now Forces immediate update of the status + line. + + sysop_next Indicates whether or not the sysop has + reserved use of the system after the + current calls. + + + +------------------------------------------------------------------------------- +od_cur int od_control.od_cur_attrib; +_attrib + This read-only values stores the current display color + attribute, or the value -1 if the current display color is + unknown (such as when the door first begins execution). + + + +------------------------------------------------------------------------------- +od char od_control.od_okaytopage; +_okaytopage + This variable allows you to control whether or not the user is + currently permitted to page the sysop via the od_page() + function. A value of PAGE_ENABLE indicates that paging is + currently permitted, regardless of the sysop page hours setting. + A value of PAGE_DISABLE indicates that paging is not current + permitted. A value of PAGE_USE_HOURS indicates that the + od_page() function should check the values of the + +=============================================================================== +OpenDoors 6.00 Manual End of Page 182 + + od_pagestartmin and od_pageendmin variables in order to + determine whether or not paging should be permitted. + The od_okaytopage variable should only be set after you call + od_init() or some other OpenDoors function. The default value is + PAGE_USE_HOURS. For more information on the od_page() function + itself, see page 101. + + + +------------------------------------------------------------------------------- +od unsigned int od_control.od_pageendmin; +_pageendmin + This variable can be used to set the beginning of valid sysop + paging hours within the od_page() function. If the + od_control.od_okaytopage variable (which is described above) is + set to MAYBE, then OpenDoors will check the value of this + variable prior to paging the sysop via the od_page() function. + This variable should contain the time at which the valid sysop + paging hours end, represented as the a number of minutes since + midnight. For more information on the od_page() function itself, + see page 101. + + + +------------------------------------------------------------------------------- +od unsigned int od_control.od_pagestartmin; +_pagestartmin + This variable can be used to set the beginning of valid sysop + paging hours within the od_page() function. If the + od_control.od_okaytopage variable (which is described above) is + set to MAYBE, then OpenDoors will check the value of this + variable prior to paging the sysop via the od_page() function. + This variable should contain the time at which the valid sysop + paging hours begin, represented as the a number of minutes since + midnight. For more information on the od_page() function itself, + see page 101. + + + +------------------------------------------------------------------------------- +od_silent BOOL od_control.od_silent_mode; +_mode + If this variable is set to TRUE prior to the first call to any + OpenDoors function, OpenDoors will operate in silent mode, where + the local display and sysop commands are not used. Silent mode + is automatically disabled if the program is running in local + mode. + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 183 + +------------------------------------------------------------------------------- +od_update char od_control.od_update_status_now; +_status_now + Setting this variable to TRUE forces OpenDoors to update the + status line during the next od_kernel() execution. When the + status line is updated, this variable is reset to its default + value of FALSE. + + + +------------------------------------------------------------------------------- +od_user char od_control.od_user_keyboard_on; +_keyboard_on + This variable is a Boolean value, indicating whether OpenDoors + will currently accept input from a remote user. OpenDoors + provides a function key (usually [ALT]-[K], unless you have + changed the default), which will allow the sysop to temporarily + prevent the user from having any control over the door. When the + sysop activates this feature, a flashing [Keyboard-Off] + indicator will appear on the status line, and this variable will + be set to FALSE. When the sysop presses the [ALT]-[K] + combination a second time, to toggle the user's keyboard back + on, the flashing indicator will disappear, and this variable + will be set back to TRUE. + + + +------------------------------------------------------------------------------- +sysop_next char od_control.sysop_next; + + This variable is a Boolean value, indicating whether or not the + "sysop next" feature has been activated. The "sysop next" + feature, which reserves the system for the sysop after the call + has ended, can be toggled on and off within OpenDoors by use of + a function key (Alt-N by default). Also, when the "sysop next" + feature has been activated, an indicator will appear on the + OpenDoors status line. This variable is only available under + systems that produce an SFDOORS.DAT or RA 1.00 and later style + extended EXITINFO.BBS door information file. For more + information on testing the type of door information file + available, please see page 158. + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 184 + +CONTROL STRUCTURE - DIAGNOSTICS +------------------------------------------------------------------------------- + + To help in diagnosing problems in your OpenDoors programs, + OpenDoors stores information on the most recent error which + occurred. When any of the OpenDoors functions return an "error" + or "failure" state, the reason for this failure is recorded. + + The following OpenDoors control structure variable provides + diagnostics information: + + od_error Stores a "reason code" for the last + failed OpenDoors API function call. + + + + +------------------------------------------------------------------------------- +od_error int od_control.od_error; + + When any of the OpenDoors API functions return an "error" or + "failure" state (usually denoted by either of the values FALSE + or NULL), the reason for the failure is recorded in this + variable. Since successful function calls do not alter the value + of the od_control.od_error variable, you must be careful not + only to check the value of the od_control.od_error variable, but + also to check the OpenDoors function return codes, in order to + determine which function failed. + + This variable will always store the reason for the most recent + function call failure, or ERR_NONE if no functions have failed. + od_error may take on any of the following values: + + ERR_NONE Indicates that no error has occurred + yet. + + ERR_MEMORY Function was unable to allocate + required memory. This usually indicates + that there is not enough available + memory. This failure may also be due to + memory corruption caused by your + program inadvertently overwriting heap + structures. If your program has been + compiled in either the small or the + medium memory model, try recompiling it + in the compact, large, or huge memory + models. If your program is already + compiled in the compact, large, or huge + memory models, try making more system + memory available to your program. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 185 + + ERR_NOGRAPHICS This setting indicates that the + function called requires ANSI, AVATAR + or RIP graphics mode, but none of these + modes are active. + + ERR_PARAMETER An invalid parameter was passed to an + OpenDoors functions. Check the + function's description in chapter four, + to determine the required values for + each function parameter. + + ERR_FILEOPEN OpenDoors was unable to open a file. + This can be due to the specified + filename not existing, due to the file + being locked for exclusive access by + another process, or due to a hardware + failure. + + ERR_FILEREAD OpenDoors was able to open the + specified file, but unable to read the + required data from the file. This error + may be due to an invalid file format, + due to a portion of the file being + locked by another process, or due to a + hardware failure. + + ERR_LIMIT An internal function limit has been + exceeded. Refer to the function's + description in chapter four for + information on the function's + limitations. + + ERR_NOREMOTE Indicates that a function has been + called which is not valid in local + mode, such as od_carrier() or + od_set_dtr(). + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 186 + +CONTROL STRUCTURE - OPENDOORS CUSTOMIZATION +------------------------------------------------------------------------------- + + The OpenDoors control structure provides many variables which + allow you to customize OpenDoor's behavior and appearance. These + customization variables fit into one of the following + categories: + + General Behavior Customization Variables + Sysop Function Keys Customization Variables + Color Customization Variables + Language-Specific Prompts Customization Variables + + This section deals with those variables that fit into the first + category, "General Behavior Customization Variables". The other + categories are dealt with in the following sections of this + chapter. + + Below is a brief overview of the variables grouped into this + section of the OpenDoors control structure. Following the + overview is a detailed description of each of these variables. + + + od_app_icon Program icon for Win32 version. + + od_box_chars Array of characters used by the + od_draw_box() function. + + od_before_exit Function to call prior to exiting. + + od_cafter_chat Function to call after sysop chat. + + od_cafter_shell Function to call after DOS shell. + + od_cbefore_chat Function to call prior to sysop chat. + + od_cbefore_shell Function to call prior to DOS shell. + + od_cfg_lines Sets the configuration file's custom + door information file line keywords. + + od_cfg_text Sets the built-in configuration file + keywords that OpenDoors will recognize. + + od_chat_active Controls whether or not sysop chat mode + is active. + + od_clear_on_exit Controls whether the screen is cleared + upon door exit. + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 187 + + od_color_delimiter Indicates what character should delimit + imbedded color codes for the + od_printf() function. + + od_color_names Strings which OpenDoors recognizes as + the names of various text colors. + + od_config_file Used to enable or disable the OpenDoors + configuration file system. + + od_config_filename Sets the filename that will be read by + the configuration file system. + + od_config_function The callback function that OpenDoors + will call to allow your program to + process custom configuration file + entries. + + od_default_personality Sets the default personality to be used + with the OpenDoors Multiple Personality + System, and also sets the personality + to use when the MPS is not active. + + od_default_rip_win Whether OpenDoors should use the + default 43-line RIP window for ANSI + text (TRUE), or a 23-line window + (FALSE). + + od_disable Disable OpenDoors activities such as + reading door information file and + monitoring carrier detect / remaining + time. + + od_disable_dtr Specifies the string that will be sent + to the modem to prevent the modem from + hanging up when DTR is lowered. + + od_emu_simluate_modem Simulates modem display speed for + emulation functions such as + od_send_file(), od_disp_emu() and + od_hotkey_menu(). + + od_errorlevel Sets the errorlevel OpenDoors exits + with under various conditions. + + od_force_local Forces door to operate in local mode, + ignoring any door information file and + using default user settings. + + od_help_callback Allows you to provide a help menu item + under the Win32 version of OpenDoors + +=============================================================================== +OpenDoors 6.00 Manual End of Page 188 + + od_in_buf_size Sets size of OpenDoor's internal + local/remote inbound buffer. + + od_inactive_warning Number of seconds before hanging up + that OpenDoors displays the inactivity + timeout warning. + + od_inactivity Controls user inactivity timeout. + + od_ker_exec Is called whenever od_kernel() + executes. + + od_last_input Indicates whether the last input came + from the remote user (==0) or the local + sysop (==1). + + od_list_pause Controls whether or not the user may + pause display within the + od_list_files() and od_send_file() + functions by using the [P] key. + + od_list_stop Controls whether or not the user may + terminate display within the + od_list_files() and od_send_file() + functions using [S], [CTRL]-[K], etc. + + od_logfile Enables or disables the OpenDoors log + file system. + + od_logfile_disable Prevents the logfile from being opened, + even if the logfile is enabled by + od_logfile. + + od_logfile_messages Array of message strings that OpenDoors + will use when writing log file entries. + + od_logfile_name Contains the filename and possibly path + of the logfile. + + od_maxtime Indicates the maximum length of time + any user is permitted to use the door. + + od_maxtime_deduction Indicates the amount of time that has + temporarily been taken away from the + user's remaining time, as a result of + the maximum door time setting. + + od_mps Enables or disables the OpenDoors + Multiple Personality System. + + od_no_file_func Called when no door information file + can be read. +=============================================================================== +OpenDoors 6.00 Manual End of Page 189 + + + od_no_ra_codes Disables translation of RA/QBBS control + codes. + + od_nocopyright Prevents OpenDoors from displaying it's + name and version number when a door + program begins execution. + + od_noexit Prevents OpenDoors from exiting when + the od_exit() function is called. + + od_page_len Controls length of the sysop page beep. + + od_page_pausing Enables or disables page pausing in + od_send_file(), od_hotkey_menu() and + od_list_files() functions. + + od_page_startmin Indicates the time of day at which + sysop paging is first enabled. + + od_page_statusline Which status line (if any) is activated + when the user pages the sysop. + + od_page_endmin Indicates the time of day at which + sysop paging is disabled. + + od_prog_name Stores the name of your program. + + od_prog_version Stores the version number of your + program. + + od_prog_copyright Place your copyright information here. + + od_reg_key Stores the registration key that you + receive when purchasing OpenDoors. + + od_reg_name Stores your name or your companies name + when you have purchased an OpenDoors + license (registration). + + od_spawn_freeze_time Indicates whether the user's time + remaining continues to be decreased + during the execution of the + od_spawn...() functions (FALSE), or if + the timer should be "frozen" (TRUE). + + od_swapping_disable Disables swapping during DOS shell and + od_spawn...() functions. + + od_swapping_noems Prevents swapping form being done to + EMS expanded memory. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 190 + + od_swapping_path Location where disk swap file should be + created. + + od_status_on Controls whether the status line sub- + system is active. + + od_time_msg_func Called instead of displaying time limit + warning messages. + + + + +------------------------------------------------------------------------------- +od_app HICON od_control.od_app_icon; +_icon + Normally, the Win32 version of OpenDoors displays its own icon + on the application title bar, on the Windows taskbar, and in the + help|about dialog box. You can supply your own icon by setting + this variable to point to the handle of the icon, as returned by + LoadIcon(); + + + +------------------------------------------------------------------------------- +od_box char od_control.od_box_chars[8]; +_chars + This variable allows you to specify which character the + od_draw_box() function uses in drawing the boarder of a window. + The elements of this array are as follows: + + od_box_chars[BOX_UPPERLEFT] - Upper left corner of box + od_box_chars[BOX_TOP] - Top horizontal line + od_box_chars[BOX_UPPERRIGHT] - Upper right corner of box + od_box_chars[BOX_LEFT] - Left Vertical line + od_box_chars[BOX_LOWERLEFT] - Lower left corner of box + od_box_chars[BOX_LOWERRIGHT] - Lower right corner of box + od_box_chars[BOX_BOTTOM] - Bottom horizontal line + od_box_chars[BOX_RIGHT] - Right horizontal line + + + +------------------------------------------------------------------------------- +od_before void (*od_control.od_before_exit)(); +_exit + This variable contains a pointer to a function which OpenDoors + should call prior to exiting, or NULL if you do not wish to have + any function called at exit time. For an example of the use of + this variable, see the description of the EX_VOTE.C example + program, which begins on page 38. + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 191 + +------------------------------------------------------------------------------- +od_cafter void (*od_control.od_cafter_chat)(); +_chat + The function pointed to by this variable will be called after + sysop chat mode has ended. This may be useful for allowing you + to save the user's screen contents prior to chat, and restoring + the afterwards. If this variable contains its default value of + NULL, no function will be called. To alter the string of text + which is displayed after sysop chat, see the + od_control.od_after_chat variable, which is described in the + section on the prompts customization portion of the control + structure. + + + +------------------------------------------------------------------------------- +od_cafter void (*od_control.od_cafter_shell)(); +_shell + The function pointed to by this variable will be called after + the sysop has returned from a DOS shell. If this variable + contains its default value of NULL, no function will be called. + To alter the string of text which is displayed after a DOS + shell, see the od_control.od_after_shell variable, which is + described in the section on the prompts customization portion of + the control structure. + + + +------------------------------------------------------------------------------- +od_cbefore void (*od_control.od_cbefore_chat)(); +_chat + The function pointed to by this variable will be called prior to + entering sysop chat mode. This may be useful for allowing you to + save the user's screen contents prior to chat, and restoring the + afterwards. If this variable contains its default value of NULL, + no function will be called. To alter the string of text which is + displayed prior to sysop chat, see the od_control.od_before_chat + variable, which is described in the section on the prompts + customization portion of the control structure. To replace the + OpenDoors sysop chat facility with your own, simply activate + your chat mode when this function is called. Your chat mode + facility should remain active until OpenDoors sets the + od_control.od_chat_active variable to FALSE. If you wish to + terminate chat mode prior to this variable being set to FALSE, + you should set this variable to FALSE yourself if you do not + wish OpenDoors to activate its own chat mode. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 192 + +------------------------------------------------------------------------------- +od_cbefore void (*od_control.od_cbefore_shell)(); +_shell + The function pointed to by this variable will be called prior to + executing a sysop DOS shell. If this variable contains its + default value of NULL, no function will be called. To alter the + string of text which is displayed before a DOS shell, see the + od_control.od_before_shell variable, which is described in the + section on the prompts customization portion of the control + structure. + + + +------------------------------------------------------------------------------- +od_cfg_lines char od_control.cfg_lines[25][33]; + + This array contains the strings for the keywords that represent + various lines in the definition of a custom door information + file. Each keyword must be 32 character or less in length. These + keywords are not case sensitive. See page 230 for more + information on defining custom door information (drop) file + formats. The default values for this array are as follows: + + [0] "Ignore" + [1] "ComPort" + [2] "FossilPort" + [3] "ModemBPS" + [4] "LocalMode" + [5] "UserName" + [6] "UserFirstName" + [7] "UserLastName" + [8] "Alias" + [9] "HoursLeft" + [10] "MinutesLeft" + [11] "SecondsLeft" + [12] "ANSI" + [13] "AVATAR" + [14] "PagePausing" + [15] "ScreenLength" + [16] "ScreenClearing" + [17] "Security" + [18] "City" + [19] "Node" + [20] "SysopName" + [21] "SysopFirstName" + [22] "SysopLastName" + [23] "SystemName" + [24] "RIP" + + If you wish to change any of these variable, you must do so + before calling any OpenDoors functions. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 193 + + + +------------------------------------------------------------------------------- +od_cfg_text char od_control.od_cfg_text[47][33]; + + This array of strings contains the built-in configuration file + keywords that are recognized by OpenDoors. These keywords may be + up to 32 characters in size, and are not case sensitive. If you + wish to change any of these settings, you must do so before + calling any OpenDoors functions. The default values for this + array are as follows: + + [0] "Node" + [1] "BBSDir" + [2] "DoorDir" + [3] "LogFileName" + [4] "DisableLogging" + [5] "SundayPagingHours" + [6] "MondayPagingHours" + [7] "TuesdayPagingHours" + [8] "WednesdayPagingHours" + [9] "ThursdayPagingHours" + [10] "FridayPagingHours" + [11] "SaturdayPagingHours" + [12] "MaximumDoorTime" + [13] "SysopName" + [14] "SystemName" + [15] "SwappingDisable" + [16] "SwappingDir" + [17] "SwappingNoEMS" + [18] "LockedBPS" + [19] "SerialPort" + [20] "CustomFileName" + [21] "CustomFileLine" + [22] "InactivityTimeout" + [23] "PageDuration" + [24] "ChatUserColor" + [25] "ChatSysopColor" + [26] "FileListTitleColor" + [27] "FileListNameColor" + [28] "FileListSizeColor" + [29] "FileListDescriptionColor" + [30] "FileListOfflineColor" + [31] "Personality" + [32] "NoFossil" + [33] "PortAddress" + [34] "PortIRQ" + [35] "ReceiveBuffer" + [36] "TransmitBuffer" + [37] "PagePromptColor" + [38] "LocalMode" + [39] "PopupMenuTitleColor" +=============================================================================== +OpenDoors 6.00 Manual End of Page 194 + + [40] "PopupMenuBorderColor" + [41] "PopupMenuTextColor" + [42] "PopupMenuKeyColor" + [43] "PopupMenuHighlightColor" + [44] "PopupMenuHighKeyColor" + [45] "NoFIFO" + [46] "FIFOTriggerSize" + [47] "DiableDTR" + [48] "NoDTRDisable" + + + +------------------------------------------------------------------------------- +od_chat char od_control.od_chat_active; +_active + This variable is set to TRUE when sysop chat mode is active, and + is set to FALSE when sysop chat mode is not active. This + variable can be used to determine whether or not chat mode is + active, and to force chat mode to end. When the sysop presses + the chat mode key ([ALT]-[C] if the default personality is being + used) while chat mode is active, this variable is set to FALSE. + + + +------------------------------------------------------------------------------- +od_clear char od_control.od_clear_on_exit; +_on_exit + This variable contains a Boolean value, which indicates whether + or not you wish OpenDoors to clear the screen prior to exiting. + This variable defaults to a value of TRUE, which causes the + screen to be cleared when a door program exits. However, you may + wish to set this variable to a value of FALSE, which will cause + the contents of the screen to remain unchanged when the door + exits. While setting this variable to FALSE will probably result + in a messy display if the door is to return control to a batch + file, if the door returns directly to the BBS, it will result in + a smoother transition from the door back to the BBS (as the + sysop is not left with a blank screen). If your door has a + configuration file or configuration program, you may wish to + have an option which will allow the individual sysop to + determine whether or not the screen should be cleared when the + door exits. + + + +------------------------------------------------------------------------------- +od_color char od_control.od_color_delimiter; +_delimiter + This variable sets the character that is used to delimit color + codes in the od_printf() function, and defaults to the back- + quote (`) character. If you wish to be able to display the back- + quote (`) character using the od_printf() function, and thus +=============================================================================== +OpenDoors 6.00 Manual End of Page 195 + + wish to use a different character to delimit color codes in the + od_printf() function, simply set this variable to the + alternative character you wish to use. If you wish to disable + the imbedded color codes feature of the od_printf() function, + simply set this variable to a value of zero. For more + information on od_printf() imbedded color codes, see the + description of the od_printf() function, which begins on page + 110. + + + +------------------------------------------------------------------------------- +od_color char od_control.od_color_names[12][33]; +_names + This array sets the strings that OpenDoors will recognize as + color description keywords. These are the keywords that can be + imbedded in od_printf() format strings, and are also the + keywords that can be used to change color settings in the + OpenDoors configuration file. If you wish to change these + keywords, you will normally do so before calling any OpenDoors + functions. These keywords should always be supplied in upper- + case characters. The defaults values for this array are as + follows: + + [0] "BLACK" + [1] "BLUE" + [2] "GREEN" + [3] "CYAN" + [4] "RED" + [5] "MAGENTA" + [6] "YELLOW" + [7] "WHITE" + [8] "BROWN" + [9] "GREY" + [10] "BRIGHT" + [11] "FLASHING" + + + +------------------------------------------------------------------------------- +od_config void (*od_control.od_config_file)(void); +_file + Set this variable to INCLUDE_CONFIG_FILE to enable the OpenDoors + configuration file system, or set it to NO_CONFIG_FILE to + disable the configuration file system. This variable should only + be set prior to your first call to an OpenDoors function. For + more information on the OpenDoors configuration file system, see + page 224. + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 196 + +------------------------------------------------------------------------------- +od_config char *od_control.od_config_filename; +_filename + If set, this variable should point to a string containing the + filename that you wish the OpenDoors configuration file system + to read. If this variable has its default value of NULL, the + filename DOOR.CFG will be used by default. + + + +------------------------------------------------------------------------------- +od_config void (*od_control.od_config_function)(char *keyword, char +_function *options); + + If set, this variable should point to the function that + OpenDoors should call when lines with unrecognized keywords are + encountered in the configuration file. This allows you to add + your own configuration file keywords. The first parameter to + this function will be a pointer to a string containing the + unrecognized keywords, and the second parameter will be a + pointer to a string containing any options that were specified + after the keyword. If no options were specified after the + keyword, this string will have a length of 0. + + + +------------------------------------------------------------------------------- +od_default void (*od_control.od_default_personality)(unsigned char +_personality operation); + + This variable sets the default personality that OpenDoors will + use if the multiple personality system is active. If the + multiple personality system is not active, the personality set + by this variable will be the only personality available. This + variable should only be set prior to calling an OpenDoors + function. This variable can be set to point to your own + personality function, or it can be set to one of the manifest + constants that represent one of the built-in personalities: + + PER_OPENDOORS + PER_PCBOARD + PER_RA + PER_WILDCAT + + For more information on the OpenDoors Multiple Personality + System, see page 230. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 197 + +------------------------------------------------------------------------------- +od_default char od_control.od_default_rip_win; +_rip_win + This variable defaults to FALSE. When set to FALSE, OpenDoors + resets the RIP text window to a 23-line window that is most + appropriate for doors that support both RIP-graphics and non-RIP + mode. When this variable is set to TRUE, OpenDoors will use the + default sized text output window, 43 lines in size. + + + +------------------------------------------------------------------------------- +od_disable unsigned int od_control.od_disable; + + This variable is a bit-mapped flag which can be used to disable + certain OpenDoors features which are normally active, in order + to allow for maximum customization of OpenDoors. Each bit of + this variable represents a different feature that can be + disabled. To DISABLE a feature, you set the bit that corresponds + to the particular feature. To ENABLE the feature, the bit is + reset. Each bit is represented by a keyword, as follows: + + DIS_INFOFILE - Setting the DIS_INFOFILE bit of the + od_control.od_disable variable allows you to prevent + OpenDoors from reading or re-writing a door information + file. If you wish to disable OpenDoors' reading of the door + information file, you must do so prior to calling + od_init() or any other OpenDoors door-driver functions. At + the same time, you must also manually set any required + variables that are normally set by the information obtained + from the door information file, such as the comm port + number, baud rate, user name, and so on. You may wish to + disable reading of the door information file in a number of + cases. For example, you may wish to manually read another + format of door information file not supported by OpenDoors, + or to obtain the necessary door information from your + program's command line. Also, if you are using OpenDoors to + write a non-door communications program, such as a terminal + program, you want to prevent OpenDoors from attempting to + read a door information file on startup. + + DIS_CARRIERDETECT - Setting this bit allows you to prevent + OpenDoors from exiting when it the carrier detect signal + from the modem disappears. This bit may be set or rest at + any time. If you use this bit to disable OpenDoors' carrier + detection, you will probably want to monitor the state of + the carrier detect signal yourself, using the od_carrier() + function, which is described on page 51. + + DIS_TIMEOUT - This flag allows you to prevent OpenDoors from + exiting when the user runs out of time. As with the + DIS_CARRIERDETECT flag, you may set or reset this bit at +=============================================================================== +OpenDoors 6.00 Manual End of Page 198 + + any time. You will most often want to use this setting when + writing a non-door program, which you would not want to + have exit after a particular amount of time has elapsed. Be + sure that you do not confuse this flag with the user's + inactivity timeout. To disable the inactivity timeout, set + the do_control.od_inactivity variable to 0. + + DIS_LOCAL_OVERRIDE - This setting affects OpenDoors' behavior + when a locked BPS rate is specified in the configuration + file, and another BPS rate is specified in the door + information file. By default, OpenDoors will initialize the + modem at the BPS rate specified in the configuration file, + unless the BPS rate specified in the door information file + is 0. In this case, the 0 BPS rate is used to indicate that + the door is operating in local mode, and will override the + BPS rate specified in the configuration file. Setting this + flag disables the local mode override, causing the modem to + always be initialized at the locked BPS rate, even when the + door information file specifies that local mode should be + used. + + DIS_BPS_SETTING - When used with a FOSSIL driver, OpenDoors + normally changes the BPS rate to that passed from the BBS + (if the BBS passes a valid FOSSIL BPS rate). Setting the + DIS_BPS_SETTING flag disables this BPS rate setting. + + DIS_LOCAL_INPUT - The local keyboard may be disabled by setting + this bit. This only affects the sysop's input in + circumstances that input is also accepted from the remote + user; this setting has no effect on the sysop function + keys. + + DIS_SYSOP_KEYS - This setting also disables the local keyboard. + However, unlike the DIS_LOCAL_INPUT, this function disables + both sysop function keys and door input from the local + keyboard. + + DIS_DTR_DISABLE - This setting prevents OpenDoors from + disabiling DTR response from the modem. Even if not + specified, OpenDoors only disables DTR response in the when + exiting under the Win32 version if an open serial port + handle was not provided to OpenDoors at startup. + + DIS_NAME_PROMPT - Prevents OpenDoors from prompting for a user + name when operating in automatic local mode (by setting + od_force_local to TRUE or specifying -local on the command + line). + + Note that in order to disable the OpenDoors status line, the + od_control.od_status_on variable is used, instead of the + od_disable variable. You may also disable the user's inactivity + timeout by setting the od_control.od_inactivity variable to 0. +=============================================================================== +OpenDoors 6.00 Manual End of Page 199 + + The od_control.od_status_on variable is described later in this + section. + + + +------------------------------------------------------------------------------- +od_disable_ char od_control.od_disable_dtr[40]; +dtr + Unles the DIS_DTR_DISABLE od_disable flag is set, the Win32 + version of OpenDoors will attempt to disable DTR response by the + modem when closing the serial port, if the serial port was + opened by OpenDoors. This is done by sending a series of + commands to the modem, and possibly waiting for responses to the + command. The string format specifies each command, followed by + the required response. The command and response is separated by + a single space character. If no response is required between two + commands, then those commands may be separated by two space + characters. A '|' character is translated into a carriage + return, and a '~' character is translated into a one second + pause. The default value of this string is "~+++~ AT&D0 ATO". + + + +------------------------------------------------------------------------------- +od_emu_ BOOL od_control.od_emu_simulate_modem; +simulate_modem + When this flag is set to its default value of FALSE, the + OpenDoors terminal emulator displays text at full speed. When + this flag is set to TRUE, the emulation functions will display + text at approximately the same speed as it would be displayed + when sent over the modem, based on the current connect speed. In + local mode, an average modem speed of 9600bps is assumed. This + allows animations to be displayed locally at the same speed as + they would appear on the remote system. This switch affects the + following functions: + od_disp_emu() + od_send_file() + od_hotkey_menu() + + + +------------------------------------------------------------------------------- +od unsigned char od_control.od_errorlevel[8]; +_errorlevel + Allows you to configure the errorlevel (program exit code) which + OpenDoors exits with under various circumstances. The elements + of this array are as follows: + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 200 + + [ERRORLEVEL_ENABLE] Enables or disables custom errorlevels + [ERRORLEVEL_CRITICAL] Critical error errorlevel + [ERRORLEVEL_NOCARRIER] Carrier lost errorlevel + [ERRORLEVEL_HANGUP] Sysop manually terminated call + [ERRORLEVEL_TIMEOUT] User time expired errorlevel + [ERRORLEVEL_INACTIVITY] Keyboard inactivity timeout errorlevel + [ERRORLEVEL_DROPTOBBS] Sysop returned user to BBS errorlevel + [ERRORLEVEL_NORMAL] Door has exited normally + + If you wish to override the default errorlevels used by + OpenDoors, you should set element [ERRORLEVEL_ENABLE] of this + array to TRUE, and set the remaining array elements to the + appropriate errorlevels. Note that the settings in this array + only affect the errorlevels which OpenDoors uses when it causes + the door to exit for one of the reasons listed above. This + setting has no effect on the errorlevel returned when your + program explicitly exits by calling the od_exit() function, or + your program returns by calling exit() or returning from the + main() function. + + + +------------------------------------------------------------------------------- +od char od_control.od_force_local; +_force_local + This variable defaults to FALSE, which causes OpenDoors to + behave normally. When this variable is set to TRUE prior to + calling od_init() or any other OpenDoors functions, OpenDoors + will operate in local mode. In this case, no door information + file will be read. Also, the user name will be used if + od_control.user_name has not been set prior to calling od_init() + or the first OpenDoors function. + + The default OpenDoors settings when od_control.od_force_local is + set are as follows: + + - ANSI mode is on + - Time limit is 60 minutes + - User's location is the name of the BBS, or "Unknown Location" + otherwise if BBS name is not known. + - User name is set to sysop's name ("Sysop" if no sysop name is + specified in the configuration file). + + You may wish to add a "-local" type parameter to your program's + command line, which will permit the sysop to easily operate the + door in local mode, as an interface to the + od_control.od_force_local setting. + + + +------------------------------------------------------------------------------- +od_help void (*od_control.od_help_callback)(void); +=============================================================================== +OpenDoors 6.00 Manual End of Page 201 + +_callback + If this variable is set to a non-NULL value, the Win32 version + of OpenDoors will provide a Contents item on the help menu, and + call the function pointed to by this variable when the user + chooses the Contents menu item. + + + +------------------------------------------------------------------------------- +od_in_buf unsigned int od_control.od_in_buf_size; +_size + Specifies the size, in characters, of the OpenDoor's internal + local/remote inbound buffer size. Two bytes of storage are + required for each character in this buffer. This variable should + only be changed prior to calling od_init() or the first + OpenDoors function. If not set, this variable defaults to a + value of 256. + + The buffer corresponding to this variable should not be confused + with the FOSSIL or internal communications receive buffer (which + is set by od_control.od_com_rx_buf). Unlike the serial I/O + receive buffer, which is used only for characters received from + the remote system, this buffer serves as a queue for input from + both the remote system and the local keyboard. If you find that + characters are lost when information is being set to your door + from the user, you may wish to increase the size of this buffer. + + + +------------------------------------------------------------------------------- +od unsigned int od_control.od_inactivity; +_inactivity + OpenDoors has a built in user-inactivity timeout facility, which + will automatically disconnect a user who appears .to be sleeping + at the keyboard. If the user has not pressed any keys on their + keyboard for to great a length of time, they will be warned that + they are about to be disconnected due to inactivity. If they + still do not respond after another few seconds, OpenDoors will + automatically disconnect the user and return control to the BBS + software. The od_control.od_inactivity variable allows you to + set the maximum length of time, in seconds, after which the user + will be disconnected for inactivity. This variable defaults to a + value of 200 seconds. You may disable OpenDoors' inactivity + timeout altogether, by setting the od_control.od_inactivity + variable to a value of 0. + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 202 + +------------------------------------------------------------------------------- +od_inactive int od_control.od_inactive_warning. +_warning + This variable sets the number of seconds prior to hanging up + that OpenDoors displays the inactivity timeout warning. This + variable should only be changed after your first call to an + OpenDoors API function. If not explicitly set by your program, + this setting defaults to 10 seconds. + + + +------------------------------------------------------------------------------- +od_ker_exec void (*od_control.od_ker_exec)(void); + + When od_control.od_ker_exec is set to point to a function, + OpenDoors will call this function whenever od_kernel() executes. + This provides any easy way for you to perform your own + processing on a regular basis during door execution. The + od_control.od_ker_exec variable defaults to NULL. + + + +------------------------------------------------------------------------------- +od_last char od_control.od_last_input; +_input + Indicates whether the last key retrieved using the od_get_key() + function originated from the remote user, or the local sysop. If + the input originated from the remote, this variable is set to 0. + If the input originated from the local keyboard, this variables + is set to 1. + + + +------------------------------------------------------------------------------- +od_list char od_control.od_list_pause; +_pause + This variable contains a Boolean value, which allows you to + control whether or not the user may pause displaying within the + od_list_files() and od_send_file() function. When this variable + is set to its default value of TRUE, the user will be able to + pause the display by pressing the [P] key, and resume display by + pressing any other key. However, the pause feature may be + disabled by setting this variable to FALSE. + + + +------------------------------------------------------------------------------- +od_list char od_control.od_list_stop; +_stop + This variable contains a Boolean value, which allows you to + control whether or not the user may abort displaying within the + od_list_files() and od_send_file() function. When this variable +=============================================================================== +OpenDoors 6.00 Manual End of Page 203 + + is set to its default value of TRUE, the user will be able to + pause the display by pressing the [S], [CTRL]-[K] or [CTRL]-[C] + keys. However, the stop feature may be disabled by setting this + variable to FALSE. + + + +------------------------------------------------------------------------------- +od_local void (*od_control.od_local_input)(int); +_input + If set, this function is called whenever the sysop presses a + non-sysop-function key on the local keyboard. The key pressed is + passed to the function in the single int parameter that it + accepts. + + + +------------------------------------------------------------------------------- +od_logfile void *(od_control.od_logfile)(void); + + To make the OpenDoors log file system available in your program, + set this variable to INCLUDE_LOGFILE, prior to calling any + OpenDoors functions. If not set, or if set to NO_LOGFILE, the + OpenDoors log file system will not automatically be enabled. + + + +------------------------------------------------------------------------------- +od_logfile char od_control.od_logfile_disable; +_disable + This variable defaults to the value of FALSE, unless the + "LogfileDisable" option is specified in the configuration file, + in which case the variable will be set to TRUE. If this variable + is set to TRUE, OpenDoors will not write to a logfile, even if + the logfile system is enabled using od_control.od_logfile. + + + +------------------------------------------------------------------------------- +od_logfile char *od_control.od_logfile_messages[14]; +_messages + This array of pointers to strings contains the messages that + OpenDoors will automatically write to the log file, if the log + file system is enabled. If you wish to change the settings of + this array, you should do so before calling any OpenDoors + functions. The default strings for this array are as follows: + + [0] "Carrier lost, exiting door" + [1] "System operator terminating call, exiting door" + [2] "User's time limit expired, exiting door" + [3] "User keyboard inactivity time limit exceeded, exiting door" + [4] "System operator returning user to BBS, exiting door" +=============================================================================== +OpenDoors 6.00 Manual End of Page 204 + + [5] "Exiting door with errorlevel %d, + [6] "Invoking operating system shell" + [7] "Returning from operating system shell" + [8] "User paging system operator" + [9] "Entering sysop chat mode" + [10] "Terminating sysop chat mode" + [11] "%s entering door" + [12] "Reason for chat: %s" + [13] "Exiting door" + + + +------------------------------------------------------------------------------- +od_logfile char od_control.od_logfile_name[80]; +_name + This variable specifies the filename, and optionally the full + path of the logfile where OpenDoors should perform logging. This + variable only has an effect when set prior to calling any + OpenDoors functions. If the log file name is specified in the + configuration file, that name will be stored in this variable. + If you do not set this variable, and the log file name is not + specified in the configuration file, the default name "DOOR.LOG" + will be used. If you wish to set this variable, you should do so + prior to calling od_init() or any OpenDoors function. + + + +------------------------------------------------------------------------------- +od_ unsigned int od_control.od_maxtime; +maxtime + This variable specifies the maximum length of time that any user + is permitted to use the door, and is normally set from a + configuration file option. If upon entering the door, the user's + time remaining online is greater than the od_maxtime setting, + their time remaining is temporarily decreased to the maximum + value. Then upon exit of the door, the number of subtracted + minutes is added back onto the user's remaining time. If the + user's remaining time is less than this value, then the setting + has no effect. A value of 0 disables the maximum time setting + altogether. + + + +------------------------------------------------------------------------------- +od_maxtime int od_control.od_maxtime_deduction; +_deduction + This variable store the amount of time that should be added to + the user's time upon exit of the door, as a result of the + maximum time deduction, described above. If the maximum time + feature is not used, this variable will be given a value of 0. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 205 + + +------------------------------------------------------------------------------- +od_mps void (*od_control.od_mps)(void); + + To make the OpenDoors Multiple Personality system available in + your program, set this variable to INCLUDE_MPS before calling + any OpenDoors functions. If this variable is not set, or is set + to NO_MPS, the Multiple Personality System will be disabled. For + more information on the OpenDoors Multiple Personality System, + see page 233. + + + +------------------------------------------------------------------------------- +od_no_ void (*od_control.od_no_file_func)(); +file_func + If od_no_file_func is set to point to a function, that function + will be called whenever a door information (drop) file cannot be + located or read. This provides an easy mechanism to add your own + door information file reader, or to provide a local login prompt + when no drop file is present. If you wish the door to operate in + local mode, you should set od_control.od_force_local to TRUE + prior to returning from your function. If you have successfully + read your own door information file format, you should set + od_control.od_info_type to CUSTOM. If neither of these variables + are set by the od_no_file_function, OpenDoors will report that + it is unable to find or read a door information file and will + exit immediately. + + + +------------------------------------------------------------------------------- +od_no_ra char od_control.od_no_ra_codes; +_codes + This variable defaults to FALSE. When set to TRUE, the + translation of the RemoteAccess/QuickBBS control codes by the + functions od_send_file(), od_hotkey_menu() and od_disp_emu() is + disabled. + + + +------------------------------------------------------------------------------- +od_ char od_control.od_nocopyright; +nocopyright + This variable is a Boolean value that allows you to prevent + OpenDoors from displaying its name, version number, copyright + notice and registration information when the program begins + execution. Set this variable to TRUE to disable the display of + copyright and associated information. When this variable is set + to TRUE, OpenDoors also does not change the initial display + color on startup. For obvious reasons, this variable does not + take effect when OpenDoors is operating in unregistered mode. +=============================================================================== +OpenDoors 6.00 Manual End of Page 206 + + + + +------------------------------------------------------------------------------- +od_noexit char od_control.od_noexit; + + This variable contains a Boolean value, which allows you to + prevent OpenDoors from exiting when shutting down. This may be + useful when you want to have your program to do more processing + after you have called the od_exit() function, or if you do not + wish to have your program exit automatically when the user drops + carrier. Normally, this variable will default to a value of + FALSE, indicating that OpenDoors will exit normally when the + od_exit() function is called. However, you may optionally set + this variable to TRUE after od_init() or some OpenDoors function + has been called. In this case, when the od_exit() function is + called, either by your program manually, or automatically by + OpenDoors in response to the user dropping carrier, etc., + OpenDoors will not exit. However, the normal operations of + closing the serial port and re-writing the door information file + will be carried out. If you set the od_noexit variable to TRUE, + you will probably have to provide some mechanism to allow your + program to detect when OpenDoors shutdowns due to the loss of + carrier, etc. The best way of doing this is to provide a + function which is to be called at the beginning of the od_exit() + function, by setting the od_control.od_before_exit pointer, + described above. + + + +------------------------------------------------------------------------------- +od_page char od_control.od_page_len; +_len + This variable allows you to control the length, in seconds, of + the sysop page beep produced when the user pages the sysop via + the od_page() function. + + + +------------------------------------------------------------------------------- +od_page char od_control.od_page_pausing; +_pausing + This variable contains a Boolean value that indicates whether or + not page pausing is enabled in the od_send_file(), + od_hotkey_menu() and od_list_files() functions. The default + value of TRUE indicates that page pausing is enabled. A value of + FALSE indicates that page pausing is disabled. + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 207 + +------------------------------------------------------------------------------- +od_page int od_control.od_pagestartmin; +startmin int od_control.od_pageendmin; + +od_page These variables indicate the start and end times for sysop +endmin paging, expressed as the number of minutes past midnight. + Sysop paging will be available through the od_page() function + from the start time, up to but not including the end time. + + + +------------------------------------------------------------------------------- +od_page char od_control.od_page_statusline; +_statusline + This variable controls which status line, if any, is activated + when the user pages the system operator (via the od_page() + function). A value between 0 and 9 causes the corresponding + status line to be activated. A value of -1 prevents any change + from being made to the current status line setting. This + variable will normally be set by personality functions (see page + 233). + + + +------------------------------------------------------------------------------- +od_prog_ char od_control.od_prog_copyright[40]; +copyright + This variable should contain your program's copyright notice, + such as "(C) Copyright 1996 by Your Name". This information is + used in the Help|about dialog box under the Win32 version of + OpenDoors, and may be used in other places in future versions of + OpenDoors. + + + +------------------------------------------------------------------------------- +od_prog_name char od_control.od_prog_name[40]; + + This variable should contain the full name of your program, up + to 39 characters. If not set, OpenDoors will use the string + "OpenDoors" in place of this variable. If used, this variable + should be set prior to calling any OpenDoors functions, and + should not include your program's version number. This + information is used to write your program's name in the log file + and to indicate your program's name on various windows, among + other places. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 208 + + + + +------------------------------------------------------------------------------- +od_prog_version char od_control.od_prog_version[40]; + + This variable should contain the version information of your + program. If used, this variable should be set prior to calling + any OpenDoors functions. This information is used in the + Help|About dialog box under the Win32 version of OpenDoors, + among other places. + + + +------------------------------------------------------------------------------- +od_reg_key unsigned log od_control.od_reg_key; + + When you purchase an OpenDoors licence (registration), this + variable should be set to your registration key, prior to + calling any OpenDoors functions. + + + +------------------------------------------------------------------------------- +od_reg_name char od_control.od_reg_name[36]; + + When you purchase an OpenDoors licence (registration), this + variable should be set to your name, or your company's name, as + is listed in your OpenDoors registration record. + + + +------------------------------------------------------------------------------- +od_spawn char od_control.od_spawn_freeze_time; +_freeze_time + This variable is a Boolean value which indicates whether or not + the user's time remaining is frozen during the execution of one + of the od_spawn...() functions. If this variable is set to TRUE, + the user's time remaining will not decrease during the time that + the od_spawn...() function is executing. However, if this + variable is set to FALSE, the user's time remaining will + continue to be subtracted during the execution of the + od_spawn...() function. The default value of this variable is + FALSE. + + + +------------------------------------------------------------------------------- +od_swapping char od_control.od_swapping_disable; +_disable + This variable is a Boolean value which specifies whether or not + OpenDoors will attempt to swap itself and your entire door upon +=============================================================================== +OpenDoors 6.00 Manual End of Page 209 + + DOS shell or a call to one of the od_spawn...() functions. This + variable defaults to FALSE. If set to TRUE, OpenDoors will not + attempt to perform swapping activities. + + + +------------------------------------------------------------------------------- +od_swapping char od_control.od_swapping_noems; +_noems + This variable is a Boolean value which can be used to prevent + OpenDoors from swapping to EMS memory. This variable defaults to + the value FALSE. If set to TRUE, OpenDoors will not attempt to + use EMS memory for swapping, and will only swap to disk. + + + +------------------------------------------------------------------------------- +od_swapping char od_control.od_swapping_path; +_path + This variable specifies the drive and directory where OpenDoors + should create its disk swapping file, if applicable. More than + one path can be specified, by separating the paths with a semi- + colon (;) character. + + + +------------------------------------------------------------------------------- +od_status char od_control.od_status_on; +_on + This variable is a Boolean value which allows your program to + completely disable the OpenDoors status line. The variable + defaults to a value of TRUE, which causes the OpenDoors status + line to be controllable by function keys, displayed and updated + as it would normally be. However, if this variable is set to + FALSE, then OpenDoors will not update the status line, nor will + it allow the status line to be re-displayed as a result of one + of the status line ([F1] through [F10]) keys being pressed. When + you change the value of this variable from FALSE to TRUE, + OpenDoors will automatically redisplay the status line. Note, + however, that the status line isn't automatically removed when + the value of this variable is changed from TRUE to FALSE. In + order to erase the status line after resetting the value of this + variable, you should reset the output window to the full screen, + by calling the function window(1,1,25,80). Then manually erase + the old status line either by clearing the bottom two lines of + the screen, or by clearing the entire screen. + + It is important that you do not confuse the use of this variable + with the od_set_statusline() function, which is described on + page 137. When the status line is enabled, the sysop can change + which status line, if any, is being displayed, using the + function keys [F1] through [F10]. The od_set_statusline() +=============================================================================== +OpenDoors 6.00 Manual End of Page 210 + + function allows your program to make the same changes to the + status line setting which the sysop can make by pressing one of + the function keys. The status line can be removed from the + screen, allowing a full 25 lines of text to be displayed, by + pressing the [F10] key, or by making the appropriate call to the + od_set_statusline() function. Note, however, than when this is + done, the status line is still enabled, and can be turned on by + pressing any of the other function keys. On the other hand, if + the status line is turned off using this variable + (od_control.od_status_on), the status line sub-system will be + disabled, and pressing function keys will not "bring it back". + So, if you were writing a program where a status line would be + undesirable - such as a non-door communications program, you + would use the od_control.od_status_on variable. On the other + hand, if you only wanted to temporarily remove the status line - + say in order that all 25 lines of a door program's output could + be viewed - while still allowing the status line to be turned on + with the sysop function keys, you would use the + od_set_statusline() function. For more information on the + od_set_statusline() function, see page 137. + + + +------------------------------------------------------------------------------- +od_time void (*od_control.od_time_msg_func)(char *string) +_msg_func + This variable defaults to a value of NULL. If set to point to a + function, OpenDoors will call this function INSTEAD OF + displaying time limit warning messages to the user. The messages + redirected to this function are: + + - Inactivity timeout warning + - Inactivity timeout expired + - Less than 4 minutes left today + - Daily time limit expired + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 211 + +CONTROL STRUCTURE - FUNCTION KEYS +------------------------------------------------------------------------------- + + Within OpenDoors, as with most BBS software and doors, the sysop + has access to a number of function keys, which permits the sysop + to carry out various functions such as entering chat mode, + hanging up on the user, shelling to DOS, and so on. The + variables in this section allow you to customize which keys + carry out the standard sysop functions, allowing you to + customize your door's interface to mimic any BBS package. By + default, OpenDoors emulates the function keys used by the Remote + Access BBS package, but you may choose, for example, to have + your door use the key combinations used by PC-Board. In + addition, OpenDoors provides an interface which allows you to + add your own function keys which will be accepted by the door. + This could allow you to add additional features, such as giving + the sysop access to a status screen which displays information + about your door. + + Many of the variables in this section are unsigned ints, which + represent a sysop key combination such as [ALT]-[H], [F8], or + [CTRL]-[P]. These values are in the same format as is returned + by the Turbo C(++) / Borland C++ bioskey() function. The high- + order byte represents the scan code of the key, and the low- + order byte represents the ASCII value, if any, of the key + combination. Note that a complete tutorial on these key codes is + beyond the scope of this manual. For more information on these + key codes, you should see the documentation on the bioskey() + function, which accompanies your compiler. If you wish to + determine the key code which corresponds to a particular + keystroke, there is a simple program, listed below, which you + can compile and use. This program will simply display the key + code for any key pressed, until you press the [ESCape] key. So, + in order to determine the code for [SHIFT]-[F8], you would + simply run this program, press the [SHIFT]-[F8] key combination + on your keyboard, and record the value displayed on your screen. + + #include + #include + main() + { + int nKey; + + do + { + nKey = bioskey(0); + printf("%d (from: %x, %x)\n", + nKey, nKey>>8, nKey&0xff); + } while((nKey & 0xff) != 27); + } + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 212 + + +------------------------------------------------------------------------------- +BUILT IN These variable allow you to customize the sysop function keys +FUNCTION which control functions such as hanging up on the user, shelling +KEYS to DOS, and so on. All of these variable will be assigned + default values, which correspond to the same function keys used + by the RemoteAccess BBS package. However, you may change the + values of these variables in order to customize the key + combinations which carry out these functions in your own door + program. Remember that if you wish to change the value of any of + these variables, you must do so after having called od_init() or + some OpenDoors function. Each of these variables contain a scan- + code / ASCII-code combination representing a keystroke, as is + described above. These variables are as follows: + + +---------------------+----------------------------------------+ + | VARIABLE | CORRESPONDING FUNCTION | + +---------------------+----------------------------------------+ + | od_control. | Enter sysop chat mode | + | key_chat | (Normally [ALT]-[C] | + | | | + | od_control. | Invoke sysop DOS shell | + | key_dosshell | (Normally [ALT]-[J] | + | | | + | od_control. | Return to the BBS without hanging up | + | key_drop2bbs | (Normally [ALT]-[D]) | + | | | + | od_control. | Hangup on the user | + | key_hangup | (Normally [ALT]-[H]) | + | | | + | od_control. | Turn off the user's keyboard | + | key_keyboardoff | (Normally [ALT]-[K]) | + | | | + | od_control. | Decreases the user's remaining time | + | key_lesstime | (Normally [DOWN-ARROW]) | + | | | + | od_control. | Lock the user out of the BBS system | + | key_lockout | (Normally [ALT]-[L]) | + | | | + | od_control. | Increases the user's remaining time | + | key_moretime | (Normally [UP-ARROW]) | + | | | + | od_control. | Array of eight function keys to set the| + | key_status[8] | current status line. | + | | (Normally [F1], [F2], [F3], [F4], [F5],| + | | [F6], [F9], [F10]) | + | | | + | od_control. | "Sysop next" toggle key | + | key_sysopnext | (Normally [ALT]-[N]) | + +---------------------+----------------------------------------+ + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 213 + + +------------------------------------------------------------------------------- +CUSTOM In addition to the sysop function keys built into OpenDoors, you +FUNCTION may wish to add your own function keys to your door. For +KEYS example, you might wish to have the [ALT]-[Z] combination + display a window of information about your door, or you may wish + to add your own user editor to your door, accessible through the + [ALT]-[E] combination. The four variables: + + unsigned char od_control.od_num_keys; + unsigned int od_control.od_hot_key[16]; + unsigned int od_control.od_last_hot; + void (*od_control.od_hot_function[16])(void); + + provide your program with an interface to add your own sysop + function keys (not accessible by the remote user) to the door + you have written. + + OpenDoors allows you to define up to sixteen custom sysop + function keys. The key codes (as described at the beginning of + this section) are stored in the od_control.od_hot_key[] array, + and the od_control.od_num_keys variable records the number of + keys which have been defined. The od_control.od_num_keys + variable defaults to a value of 0. So, in order to add your own + function keys, simply place the key codes for these keys in the + first n elements of the od_control.od_hot_key[] array, and set + the od_control.od_num_keys variable to the number of keys you + have defined. OpenDoors will then watch the keyboard for any of + your predefined sysop function keys being pressed. If one of + these keys is pressed, OpenDoors will place the key code of the + pressed key in the od_control.od_last_hot variable. Your program + will then be able to respond to one of your custom function keys + being pressed by checking the value of the + od_control.od_last_hot variable. At any time this variable + contains a non-zero value. If this is the case, you will then be + able to determine which of your function keys has been pressed + by checking the key code contained in this variable. After + taking the appropriate action for the key pressed, you should be + sure to reset the value of the od_control.od_last_hot variable + back to zero, which will indicate to OpenDoors that your program + has received and responded to the function key which was + pressed. + + As an alternative to testing the contents of the + od_control.od_last_hot variable, you can also have your program + respond to custom sysop function keys by providing a callback + function in the array: void + (*od_control.od_hot_function[16])(void); + + The Nth element in this array corresponds to the Nth element in + the od_control.od_hot_key array. To use this mechanism, simply + set the appropriate element of this array to point to the +=============================================================================== +OpenDoors 6.00 Manual End of Page 214 + + function that you wish to have OpenDoors call when the sysop + presses the corresponding function key. For instance, assume + that the following function is included in your program's source + code: + + void addPoints(void) + { + /* add ten points to the user's score */ + currentUser->points += 10; + } + + If you wanted to have this function called when the sysop + presses the [Page Up] key, you could do the following: + + /* get number of new sysop function key, and increment */ + /* total number of keys */ + int new_key = od_control.od_num_keys++; + + /* Set next sysop hotkey to Page Up */ + od_control.od_hot_key[new_key] = 0x4900; + + /* Set corresponding function to addPoints() */ + od_control.od_hot_function[new_key] = addPoints; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 215 + +CONTROL STRUCTURE - COLOR CUSTOMIZATION +------------------------------------------------------------------------------- + + These variables allow you to customize the color of text + displayed by OpenDoors. Each of these variables are assigned + color attributes, in the format used by od_set_attrib() + (described on page 128). These variables are as follows: + + +---------------------+----------------------------------------+ + | VARIABLE | WHERE COLOR IS USED | + +---------------------+----------------------------------------+ + | od_control. | Text typed by the sysop and user in | + | od_chat_color1 & 2 | chat mode. | + | | | + | od_control. | File description fields in FILES.BBS | + | od_list_comment_col | listings | + | | | + | od_control. | Color of page pausing prompt that is | + | od_continue_col | displayed at the end of each page | + | | | + | od_control. | Filename fields in FILES.BBS listings | + | od_list_name_col | | + | | | + | od_control. | "Missing" string in FILES.BBS listings | + | od_list_offline_col | | + | | | + | od_control. | File size fields in FILES.BBS listings | + | od_list_size_col | | + | | | + | od_control. | Title fields in FILES.BBS listings | + | od_list_title_col | | + | | | + | od_control. | Color of the window title as displayed | + | od_menu_title_col | by od_popup_menu() | + | | | + | od_control. | Color of the window border as | + | od_menu_border_col | displayed by od_popup_menu() | + | | | + | od_control. | Color of the normal text displayed | + | od_menu_text_col | by od_popup_menu() | + | | | + | od_control. | Color of the shortcut keys displayed | + | od_menu_key_col | by od_popup_menu() | + | | | + | od_control. | Color of the selection bar as | + | od_menu_highlight_ | displayed by od_popup_menu() | + | col | | + | | | + | od_control. | Color of the shortcut keys displayed | + | od_menu_highkey_col | on the selected line by od_popup_menu()| + +---------------------+----------------------------------------+ + +=============================================================================== +OpenDoors 6.00 Manual End of Page 216 + +CONTROL STRUCTURE - TEXT CUSTOMIZATION +------------------------------------------------------------------------------- + + In addition to the other aspects of OpenDoors which may be + customized by use of the OpenDoors control structure, all of the + text displayed by OpenDoors may also be customized. This may be + done either to create doors with OpenDoors that use languages + other than English, or to simply give your doors a "personal + touch". The variables described in this section allow you to + define what text you want to have displayed by OpenDoors at any + time. All of these variables are pointers to strings, and are + set to default values in the od_init() function. Thus, if you + wish to change the string pointed to by any of these variables, + you must do so after od_init() or some OpenDoors API function + has been called. To set any of these variables, you can simply + set them to point to a string-constant in your program. For + example, to set the text displayed by OpenDoors prior to a DOS + shell, you could: + + od_control.od_before_shell=(char *)"\n\rJust a moment...\n\r"; + + The chart below lists each of the text customization variables + (without the "od_control." prefix, for the sake of brevity), + along with their default strings. + + Note that some of these strings MUST always be the same length + as their default string. You may not display longer text within + these strings, and if you wish to display shorter text, you must + pad the remaining space in the string with spaces, in order to + preserve its length. Those string which must be of fixed length + also have their length listed in the chart below. Any strings + which have an asterisk (*) in their length column may be any + length. + + Also keep in mind that any string with "printf-style" formatting + sequences, such as "%s", must retain the same sequences in the + same order. + + In addition, four of these pointers - od_after_chat, + od_after_shell, od_before_chat and od_before_shell - can be set + to a value of NULL. In this case, OpenDoors will not display any + string where this variable's string is normally displayed. + ++-----------------------+-----+----------------------------------------------+ +| VARIABLE NAME | LEN | DEFAULT VALUE | ++-----------------------+-----+----------------------------------------------+ +| od_after_chat | * | "\n\rChat mode ended...\n\r\n\r" | +| | | | +| od_after_shell | * | "\n\r...Thanks for waiting\n\r\n\r" | +| | | | +| od_before_chat | * | "\n\rSysop breaking in for chat...\n\r\n\r" | +| | | | +=============================================================================== +OpenDoors 6.00 Manual End of Page 217 + +| od_before_shell | * | "\n\rPlease wait a moment...\n\r" | +| | | | +| od_chat_reason | * | " Why would you " | +| | | "like to chat?\n\r" | +| | | | +| od_continue | * | "Continue? [Y/n/=]" | +| | | | +| od_continue_no | char| 'N' | +| | | | +| od_continue_nonstop | char| '=' | +| | | | +| od_continue_yes | char| 'Y' | +| | | | +| od_day[0] | 3 | "Sun" | +| | | | +| od_day[1] | 3 | "Mon" | +| | | | +| od_day[2] | 3 | "Tue" | +| | | | +| od_day[3] | 3 | "Wed" | +| | | | +| od_day[4] | 3 | "Thu" | +| | | | +| od_day[5] | 3 | "Fri" | +| | | | +| od_day[6] | 3 | "Sat" | +| | | | +| od_hanging_up | * | "Terminating Call" | +| | | | +| od_help_text | 80 | " Alt: [C]hat [H]angup [L]ockout [J]Dos " | +| | | "[K]eyboard-Off [D]rop to BBS " | +| | | | +| od_help_text2 | 79 | " OpenDoors 6.00 - (C)Copyright 1992, " | +| | | "Brian Pirie - Registered Version " | +| | | | +| od_inactivity_timeout | * | "User sleeping at keyboard, inactivity " | +| | | "timeout...\n\r\n\r" | +| | | | +| od_inactivity_warning | * | "Warning, only %d minute(s) remaining " | +| | | "today...\n\r\n\r" | +| | | | +| od_month[0] | 3 | "Jan" | +| | | | +| od_month[1] | 3 | "Feb" | +| | | | +| od_month[2] | 3 | "Mar" | +| | | | +| od_month[3] | 3 | "Apr" | +| | | | +| od_month[4] | 3 | "May" | +| | | | +| od_month[5] | 3 | "Jun" | +=============================================================================== +OpenDoors 6.00 Manual End of Page 218 + +| | | | +| od_month[6] | 3 | "Jul" | +| | | | +| od_month[7] | 3 | "Aug" | +| | | | +| od_month[8] | 3 | "Sep" | +| | | | +| od_month[9] | 3 | "Oct" | +| | | | +| od_month[10] | 3 | "Nov" | +| | | | +| od_month[11] | 3 | "Dec" | +| | | | +| od_no_keyboard | 10 | "[Keyboard]" | +| | | | +| od_no_sysop | * | "\n\rI'm afraid the sysop is not available " | +| | | "at this time.\n\r" | +| | | | +| od_no_response | * | " No response.\n\r\n\r" | +| | | | +| od_no_time | * | "Sorry, you have used up your time for " | +| | | "today...\n\r\n\r" | +| | | | +| od_offline | 10 | "[OFFLINE] " | +| | | | +| od_paging | * | "\n\rPaging Sysop for Chat" | +| | | | +| od_press_key | * | "Press [Enter] to continue..." | +| | | | +| od_sending_rip | * | "\xb4 Sending RIP File \xc3" | +| | | | +| od_status_line[0] | 80 | " " | +| | | " [Node: " | +| | | | +| od_status_line[1] | * | "%s of %s at %u BPS" | +| | | | +| od_status_line[2] | 79 | "Security: Time: " | +| | | " [F9]=Help " | +| | | | +| od_sysop_next | 5 | "[SN] " | +| | | | +| od_time_left | 10 | "%d mins " | +| | | | +| od_time_warning | * | "Warning, only %d minute(s) remaining tod" | +| | | "ay...\n\r\n\r" | +| | | | +| od_want_chat | 11 | "[Want-Chat]" | ++-----------------------+-----+----------------------------------------------+ + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 219 + + 66 + 66 + 66 + 66666 + 66 66 + 66 66 + 6666 +------------------------------------------------------------------------------- +CHAPTER 6 - SPECIAL TOPICS + + + + +ADDITIONAL INFORMATION ON THE WIN32 VERSION +------------------------------------------------------------------------------- + + This section provides additional information on the Win32 + version of OpenDoors that isn't found elsewhere in this manual. + If you are working with the Win32 version of OpenDoors, you + should take the time to read this entire section. You should + also read the sections in chapter 3 that describe how to compile + and run Win32 programs that use OpenDoors. + + The Win32 version of OpenDoors has been designed to be as + similar as possible to the DOS version of OpenDoors. This means + that where possible, you can compile the same source code to + produce both a DOS and a Windows program. However, if you are + porting an existing DOS OpenDoors-based program to the Win32 + platform, there are some important things to keep in mind. + + The first thing to note is that under DOS, the program's + execution begins in the main() function, whereas under Windows, + it begins in the WinMain() function. To allow the same source + file to build both DOS and Windows versions you can use + conditional compilation. OpenDoor.h defines a constant of the + form ODPLAT_xxx, indicating which version of OpenDoors is being + used. Currently, this will be either ODPLAT_DOS, or + ODPLAT_WIN32. However, if a OS/2 or Unix version of OpenDoors + were created, they would use definitions such as ODPLAT_OS2, or + ODPLAT_UNIX. Under the Win32 version, you should pass the + nCmdShow parameter that is passed to WinMain into OpenDoors, + through od_control.od_cmd_show. If you do not do this, the + program will always start with the main window maximized, + regardless of what the user has requested. Also, you will + probably want to use the new od_parse_cmd_line() function in + both DOS and Windows programs, to allow standard command-line + options to be processed. The od_parse_cmd_line() function + accepts command line information in the same format as it is + passed to the main or WinMain() function. So, the general + structure of an OpenDoors program that can be compiled under + either DOS or Win32 now becomes: + +=============================================================================== +OpenDoors 6.00 Manual End of Page 220 + + /* Add your own #includes here. */ + + #include "opendoor.h" + + #ifdef ODPLAT_WIN32 + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) + #else + int main(int argc, char *argv[]) + #endif + { + /* Add local variables here. */ + + #ifdef ODPLAT_WIN32 + od_control.od_cmd_show = nCmdShow; + + od_parse_cmd_line(lpszCmdLine); + #else + od_parse_cmd_line(argc, argv); + #endif + + /* Add the rest of your program after this point. */ + } + + If you are porting existing OpenDoors programs over to the Win32 + version of OpenDoors, another issue that you will have to pay + careful attention to is the fact that you are now working in the + 32-bit world. While 32-bit programming under a flat memory model + has many advantages (no more 64K segments and related + limitations, for example), you must be aware that the size of + basic data types that you are used to using may have changed. + For example, an int is now 32-bits wide instead of 16-bits wide. + One of the places where this difference becomes very important + is if you are performing file-I/O by directly dumping a + structure to or from disk using functions such as fread() and + fwrite(). In this case, you must declare your structures using + types that are of the same size between the 16-bit and 32-bit + worlds, in order for your file formats to be compatible between + the DOS and Win32 versions of your program. For example, the + EX_VOTE.C example program declares its structure using fixed- + sized types that are always available to any program including + "opendoor.h". These types are the following size, regardless of + what platform you are compiling under: + + INT8 - 8-bit signed integer. + INT16 - 16-bit signed integer. + INT32 - 32-bit signed integer. + BYTE - 8-bit unsigned integer. + WORD - 16-bit unsigned integer. + DWORD - 32-bit unsigned integer. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 221 + + (NOTE: Obviously, the many details of 32-bit programming and + Windows programming are beyond the scope of this document. For + more information on the issues discussed here, you will probably + wish to consult other sources of information on Win32 + programming.) + + As you are probably aware, the Win32 edition of OpenDoors makes + extensive use of multithreading. The number of threads will + depend on what mode OpenDoors is operating in. In some + situations, all of the following threads may exist: + + - The client thread(s), which executes the code that you write + in your program, along with the OpenDoors API functions. + - The local screen thread, which is responsible for drawing + your program's output on the screen, and receiving input from + the local keyboard. + - The frame window thread, which handles the OpenDoors menus, + toolbar, status bar and sysop function keys. + - The remote input thread, which receives input from the serial + port and adds it to OpenDoors common local/remote input + queue. + - The carrier detection thread, which blocks and only executes + if the carrier detect signal goes low. + - The time update thread, which updates the user's time + remaining online, and monitors user timeouts. + + Since most of these threads only execute when the operating + system determines that there is actually something for them to + do, the Win32 version of OpenDoors provides very high + performance and responsiveness. + + You may also want to make use of multithreading directly within + your program. If you do this, please note that while you may use + threads to perform background processing, OpenDoors requires + that you only call OpenDoors API functions from one thread. + + If you wish to customize the information that is displayed in + the Help|About dialog box (including your program's name and + copyright information), provide your own application icon, or + add online help to the help menu, refer to the sections in the + manual on the following od_control variables: + + od_control.od_app_icon + od_control.od_help_callback + od_control.od_prog_name + od_control.od_prog_version + od_control.od_prog_copyright + + The section that describes how to run Windows based door + programs under DOS-based BBS package indicates that + COMAutoAssign=0 should be set in the system.ini file. The + explanation for this is as follows: The default value for this +=============================================================================== +OpenDoors 6.00 Manual End of Page 222 + + setting in Windows 95 is -1, which prevents any Windows-based + program from accessing a serial port which has previously been + used by a non-Windows-based program, until the window that + program was running in is closed. By setting this value to 0, + you are allowing the Windows-based door program to immediately + use the modem, even while the MS-DOS session (VM) is still + active. A value of greater than 0 will allow Windows-based + programs to access the serial port, only if the DOS-based + program has not accessed the serial port for at least + seconds. For example, the default setting in Windows 3.1 was + COM1AutoAssign=2, which allowed Windows-based programs to access + the serial port if no DOS program had used it for at least 2 + seconds. + + The section that describes how to run Windows based door + programs under DOS-based BBS package also indicates that the + DTRON utility should be run after the start command returns. The + reason for this is that when a Windows program exits and closes + the serial port (by calling the CloseHandle() function), Windows + 95 lowers the DTR line on the serial port. Most modems are + configured to respond to this by hanging up on the remote user. + From talking to other people, it seems that this "feature" (or + fundamental design flaw, depending on how you want to look at + it) is unique to Windows 95, and won't effect OpenDoors when + running under Windows NT. However, the majority of people will + undoubtedly be using the Win32 version of OpenDoors under + Windows 95. This is unfortunate, since the Win32 communications + facilities are otherwise _very_ well designed. There is a rumor + that Microsoft's next upgrade to Windows 95 will fix this + problem. However, I must stress that this is only a rumor, and + that I haven't received any confirmation about this from + Microsoft. + + OpenDoors currently provides two solutions to this problem. + + First of all, OpenDoors has the ability to use an already open + serial port handle, if that information is supplied to it. + Hopefully, all Windows 95-based BBS software will provide the + option of running a door program with the serial port still + open, and allow you to pass that serial port handle on the door + program's command line. OpenDoors allows the serial port handle + to be passed on the command line, or set directly in the + od_control structure, as is described later in this manual. On + BBS systems where this form of hot sharing of the serial port is + supported, the serial port can remain open at all times, and so + the CloseHandle() problem is avoided. + + This means that the only situation where the CloseHandle() + problem still has to be dealt with is when OpenDoors is running + on a Windows 95 system and OpenDoors has to open the serial port + itself (and so must close the serial port before exiting). This + would be the case for most MS-DOS based BBS systems running +=============================================================================== +OpenDoors 6.00 Manual End of Page 223 + + under Windows 95, unless some intermediate layer is provided. By + default, in this situation OpenDoors will disable DTR response + by the modem just before it closes the serial port, by sending + the AT&D0 command to the modem. The exact sequence of commands + used by OpenDoors to do this is specified by the + od_control.od_disable_dtr string. This DTR response disabling + may be turned off by setting the DIS_DTR_DISABLE + od_control.od_disable flag. Since many programs (OpenDoors + included) assume that they can hangup the modem by lowering the + DTR signal, a small utility will usually be run after the door, + which first raises the DTR signal again, and then re-enables DTR + response by the modem. Such a utility is included in this + package, named DTRON.EXE. I wrote the DTRON utility so that you + can freely redistributed it with your programs. + + So, to summarize, the DTR disabling by OpenDoors and subsequent + reenabling by DTRON is only required for the Win32 version of + OpenDoors running under Windows 95 when the modem is configured + to hangup if the DTR signal is lowered, and the BBS software + does not have the ability to pass a live serial port handle to a + door program. Setting COMAutoAssign in system.ini is only + required for the Win32 version of OpenDoors when it is being + called from an MS-DOS session that has previously accessed the + serial port. + + Note that the Win32 version of OpenDoors requires Windows 95 or + Windows NT. It will not run under Windows 3.x, even with Win32s. + This is because OpenDoors makes use of the Windows 95/NT + multitasking and multithreading services that are not available + under Win32s. + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 224 + +CONFIGURATION FILE SYSTEM +------------------------------------------------------------------------------- + + One of the most useful OpenDoors features that you can + optionally choose to include in your programs is the OpenDoors + configuration file system. All that is required to enable the + configuration file system is to include the following line + before your first call to any OpenDoors function: + + od_control.od_config_file = INCLUDE_CONFIG_FILE; + + OpenDoors will now search for and read an OpenDoors + configuration file. If you do not specify the name of this file, + the default name of DOOR.CFG will be used. Using this + configuration file, the sysop can set a wide variety of options, + such as modem and system configuration information, maximum time + limits for the door, and even define custom door information + (drop) file formats. The example DOOR.CFG file included in your + OpenDoors package shows the format and all options that are + automatically supported by the configuration file system. This + configuration file format is designed to be easy to use, and the + example configuration file contains comments which provide a + complete description of each option. Feel free to redistribute + DOOR.CFG or a modified version of this file with your door + programs. In addition to the many configuration file settings + already supported, you can add your own settings that are + specific to your particular program. + + To specify your own filename for the configuration file, use the + od_config_filename control structure variable. For example, the + following line: + + od_control.od_config_filename = "MYDOOR.CFG" + + causes OpenDoors to look for the configuration file MYDOOR.CFG + instead of the default DOOR.CFG. + + OpenDoors fill first search for the configuration file in the + directory specified in the od_config_filename variable, if a + specific directory name was supplied. If not found, it will then + search the current directory. If the configuration file system + is unable to locate a configuration file, or if any settings are + omitted from the file, the default values for these settings + will be used automatically. This means that the configuration + file is always optional, unless your program has custom settings + that it requires in order to run. + + The format for the configuration file is as follows. Blank lines + and any text following the semi-colon (;) character are ignored. + Configuration options are specified using a keyword, possibly + followed by one or more options. The keywords are not case + sensitive, but some of the options are. The order of options in +=============================================================================== +OpenDoors 6.00 Manual End of Page 225 + + the configuration file is not significant, with the exception of + the "CustomFileLine" option. For more information on the + "CustomFileLine" setting, see the section that begins on page + 230. The built-in configuration options are as follow: + + BBSDir - BBS System directory. Indicates where the door + information file (drop file) can be found. + + DoorDir - The door's working directory. This is where the door's + system files are located. OpenDoors will automatically + perform a chdir into this directory at initialization, and + will return to the original directory on exit. + + LogFileName - Specifies the filename (path optional) where the + door should record log information. + + DisableLogging - Prevents door from writing to a log file. + + Node - BBS node number that the door is running on. Only used if + OpenDoors is unable to determine the node number by some + other means. + + ???dayPagingHours - Specifies sysop paging hours. Sysop paging + will be permitted beginning at the start time, up until, + but not including, the end time. Times should be in the 24- + hour format. To disable paging on a particular day, set the + paging start and end times to the same time. ???day can be + one of Sunday, Monday, Tuesday, Wednesday, Thursday, Friday + or Saturday. + + PageDuration - Duration of sysop page. Value indicates the + number of beeps that compose the sysop page alarm. + + MaximumDoorTime - Maximum length of time a user is permitted to + access the door. If the user's total remaining time on the + BBS is less than this value, the user will only be + permitted to access the door for this shorter length of + time. This option is disabled by commenting out the line. + + InactivityTimeout - Specifies the maximum number of seconds that + may elapse without the user pressing a key, before the user + will automatically be disconnected. A value of 0 disables + inactivity timeouts. + + SysopName - Name of the sysop. OpenDoors can usually determine + the sysop's name from the door information (drop) file. + How3ever, some BBS packages do not supply this information. + In such cases, if the sysop's name is required by the door, + it may be supplied here. + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 226 + + SystemName - Like the sysop's name, this option can usually be + determined from the door information file. If it is not + available, the sysop my supply the information here. + + ChatUserColor - Specifies the color of text typed by the user in + sysop chat mode. The format of the color name is included + in the description of the od_color_config() function. + + ChatSysopColor - Specifies the color of test typed by the sysop + in chat mode. + + FileListTitleColor - Files.BBS listing colors. + FileListNameColor + FileListSizeColor + FileListDescriptionColor + FileListOfflineColor + + SwappingDir - Directory where disk swapping will be done. + + SwappingNoEMS - Disables swapping to EMS memory. + + SwappingDisable - Disables swapping entirely. + + LockedBPS - BPS rate at which door should communicate with the + modem. Valid rates are 300, 600, 1200, 2400, 4800, 9600, + 19200 and 38400. A value of 0 forces the door to always + operate in local mode. This option is not normally needed, + as the information is usually available from the door + information file. + + FossilPort - Specifies the FOSSIL driver port number that the + modem is connected to. FOSSIL port 0 usually corresponds to + COM1, port 1 to COM2, and so on. This option is not + normally needed, as the information is usually available + from the door information file. + + CustomFileName - Specifies the filename used by the custom door + information file format. Described in more detail below. + + CustomFileLine - Specifies the contents of a particular line in + the custom door information file format. + + The last two configuration file options, "CustomFileName" and + "CustomFileLine" allow you or the system operator using your + program to define your own door information (drop) file formats. + For more information on this topic, see the section which begins + on page 230. + + You can also extend OpenDoor's configuration file format to add + your own options, by supplying a callback function that will be + called whenever OpenDoors encounters an unrecognized + +=============================================================================== +OpenDoors 6.00 Manual End of Page 227 + + configuration file keyword. The prototype of this function + should be as follows: + + custom_line_function(char *keyword, char *options) + + To cause OpenDoors to use your function, you would include the + following line before your first call to any OpenDoors function: + + od_control.od_config_function = custom_line_function; + + (You can use a different function name if you wish.) When + OpenDoors encounters unrecognized keyword, it will now call your + function, passing a pointer to an upper case version the keyword + string in the first parameter, and a pointer to any options that + follow the keyword in the second parameter. For instance, if the + following line were encountered in the configuration file: + + RegisteredTo John Smith ; Sysop's name + + The parameters passed to your function would be: + + char *keyword = "REGISTEREDTO" + char *options = "John Smith" + + Your custom line function should be written in such a way that + if OpenDoors passes a configuration option to your function that + your function does not recognize, that option would simply be + ignored. + + The example program below demonstrates how to use the custom + line function to add your own configuration file options. This + program looks for three custom configuration file options, + "RegistrationKey", "DefaultColor" and "DisplayWinners". If the + "RegistrationKey" option is present, the numerical value + following this option is stored in the global variable "key". If + the "DefaultColor" option is present, the color description + (such as "Bright Red on Black") is translated to an + od_set_attr() color code using od_color_config(). This color + setting is stored in the global variable default_color. Since + this variable is initialized to 0x07 (the value for dark white + on black), if this option is omitted, that color is used by + default. If the "DisplayWinners" option is included in the + configuration file, the global variable display_winners is set + to TRUE, regardless of any options that may follow this keyword. + + + #include "opendoor.h" /* Include opendooor.h */ + /* Prototype for custom line function */ + void custom_line_function(char *keyword, char *options); + + unsigned long key=0L; /* Variables for our own config option */ + unsigned char default_color=0x07; +=============================================================================== +OpenDoors 6.00 Manual End of Page 228 + + char display_winners=FALSE; + + main() /* Program's execution begins here */ + { /* Begin door operations, reading config file */ + od_control.od_config_file = INCLUDE_CONFIG_FILE; + /* Tell OpenDoors to use custom line function */ + od_control.od_config_function = custom_line_function; + od_init(); + /* Main program's operations go here */ + od_exit(10, FALSE); /* Exit program */ + } + /* Code for custom line function */ + void custom_line_function(char *keyword, char *options) + { /* If option is registration key */ + if(stricmp(keyword,"REGISTRATIONKEY")==0) + { + key=atol(options); /* Store key in variable */ + } /* If option is text color */ + else if(stricmp(keyword,"DEFAULTCOLOR")==0) + { /* Get color value using od_color_config() */ + default_color=od_color_config(options); + } /* Example of option enabled by just the keyword */ + else if(stricmp(keyword,"DISPLAYWINNERS")==0) + { /* If keyword is present, turn on option */ + display_winners=TRUE; + } + } + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 229 + +DEFINING CUSTOM DOOR INFORMATION FILE FORMATS +------------------------------------------------------------------------------- + + As is mentioned in the previous section, the OpenDoors + configuration file system provides two settings which allow the + sysop to define a custom door information file format. This + permits OpenDoors doors to operate directly on any BBS system + that produces a door information file format not directly + supported by OpenDoors. A custom door information file format is + defined using the "CustomFileName" option, followed by one or + more lines beginning with the "CustomFileLine" option. + + The "CustomFileName" option specifies the filename used to + distinguish this file format from other file formats. This + filename should not include a path. To specify the path where + the door information file is located, the sysop should use the + BBSDir configuration file setting. If the filename of the custom + format is the same as that of one of the built-in formats, the + custom format will override the built-in format. + + The actual format of the custom file is specified using a number + of lines that begin with the keyword "CustomFileLine". Each of + these lines will correspond to a single line in the door + information file, with the option following the "CustomFileLine" + keyword specifying the information that can be found on that + line. This can be one of the following keywords: + + Ignore - Causes the next line in the door information file + to be ignored. Use on lines for which none of the + options below apply. + + COMPORT - COM? port the modem is connected to (0 indicates + local mode) + + FOSSILPORT - Fossil port number the modem is connected to + + MODEMBPS - BPS rate at which to communicate with modem (0 + or non-numerical value indicates local mode) + + LOCALMODE - 1, T or Y if door is operating in local mode + + USERNAME - Full name of the user + + USERFIRSTNAME - First name(s) of the user + + USERLASTNAME - Last name of the user + + ALIAS - The user's pseudonym / handle + + HOURSLEFT - Hours user has left online + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 230 + + MINUTESLEFT - Minutes user has left online, or time left + online in format hh:mm + + SECONDSLEFT - Seconds user has left online, or time left + online in format hh:mm:ss or format mm:ss (If more + than one of the above time options are used, the user + time left is taken to be the total of all of these + values.) + + ANSI - 1, T, Y or G for ANSI graphics mode + + AVATAR - 1, T or Y for AVATAR graphics mode + + PAGEPAUSING - 1, T or Y if user wishes a pause at end of + screen + + SCREENLENGTH - Number of lines on user's screen + + SCREENCLEARING - 1, T or Y if screen clearing mode is on + + SECURITY - The user's security level / access level + + CITY - City the user is calling from + + NODE - Node number user is connected to + + SYSOPNAME - Full name of the sysop + + SYSOPFIRSTNAME - The sysop's first name(s) + + SYSOPLASTNAME - The sysop's last name + + SYSTEMNAME - Name of the BBS + + As an example of how to define custom door information file + formats, consider the following imaginary file format, which we + will name DROPINFO.TXT: + + Brian Pirie <-- User name + 0 <-- Local mode + COM1: <-- Serial port to use + 9600 <-- BPS rate + 22:30:15 05-08-95 <-- File creation time + 35 <-- Time remaining (in minutes) + 1 <-- ANSI mode + Ottawa, Canada <-- Location + + This format would be defined in an OpenDoors configuration file + as follows: + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 231 + + CustomFileName DROPINFO.TXT + CustomFileLine USERNAME + CustomFileLine LOCALMODE + CustomFileLine COMPORT + CustomFileLine MODEMBPS + CustomFileLine IGNORE + CustomFileLine MINUTESLEFT + CustomFileLine ANSI + CustomFileLine CITY + + Notice that the first "CustomFileLine" keyword in the + configuration file corresponds to the first line in our + DROPINFO.TXT file, the second "CustomFileLine" to the second + line, and so on. Also notice that the keyword "IGNORE" is used + for the line that contains the file creation time, since there + is no CustomFileLine keyword that allows you to read this + information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 232 + +MULTIPLE PERSONALITY SYSTEM +------------------------------------------------------------------------------- + + The OpenDoors Multiple Personality System allows the DOS + version of OpenDoors to support multiple sysop function key / + status line "personalities". Most commonly, you will use this + feature in conjunction with the "Personality" setting in the + OpenDoors configuration file, to allow the sysop to choose one + of the built-in personalities that most closely mimics the BBS + software they are using. OpenDoors includes the following + personalities: + + Configuration Keyword Manifest constant + ----------------------------------------------------------- + Standard PER_OPENDOORS + PCBoard PER_PCBOARD + RemoteAccess PER_RA + Wildcat PER_WILDCAT + + The PCBoard, RemoteAccess and Wildcat personalities mimic the + status lines and function keys used by the BBS packages with + those names. The Standard personality, which is the personality + used by default, is a trimmed down version of the status lines + provided by OpenDoors 4.10 and earlier. + + In addition to using the personalities supplied with OpenDoors, + you can create your own personalities. This simply involves + writing a function which OpenDoors will call to setup the sysop + function keys and to display the status line. + + Include the following line before your first call to any + OpenDoors function: + + od_control.od_mps = INCLUDE_MPS; + + to include the multiple personality system in your program. This + also enables the Personality setting in the configuration file, + if you are using the configuration file system. + + You can set the default personality to be used by OpenDoors by + setting od_control.od_default_personality to one of the manifest + constants listed in the table above. If you have included the + multiple personality system in your program, this setting will + determine the personality to use if the "Personality" option is + not set in the configuration file, and your program does not + later change the personality using the od_set_personality() + function. If you do not include the multiple personality system + in your program, this setting will determine the personality + that will always be used. + + Creating your own personality involves writing a single + function.. Whenever OpenDoors needs to perform an operation that +=============================================================================== +OpenDoors 6.00 Manual End of Page 233 + + involves the personality, it will call this function, passing + one of the following message values: + + PEROP_INITIALIZE Initialize the personality, installing any + custom function keys. + PEROP_DEINITIALIZE Deinitialize the personality, returning any + changed settings to their original values. + PEROP_CUSTOMKEY Indicates that a custom function key has + been pressed. + PEROP_DISPLAYx Where x is a number from 1 to 10. Indicates + that the specified status line should be + drawn from scratch. + PEROP_UPDATEx Where x is a number from 1 to 10. Indicates + that the specified status line should be + updated to reflect any changes. + + If you have enabled the multiple personality system by setting + od_control.od_mps to INCLUDE_MPS, you can install your + personality function into OpenDoors by calling + od_add_personality(). When you call od_add_personality(), you + supply a string containing the name of the personality, along + with the top and bottom output line numbers to use. These line + numbers specify the portion of the screen to use for door + output, leaving the remainder of the screen available for + displaying the personality's status line. Once the personality + has been installed into OpenDoors, it can be selected by the + sysop using the "Personality" configuration file option, or + manually activated using the od_set_personality() function. For + more information on the od_add_personality() function, see page + 47. + + You can make your personality function the default personality + by setting od_control.od_default_personality to point to your + personality function. As is the case with the built-in + personalities, this setting will be used as the default + personality if you have enabled the multiple personality system + by setting od_control.od_mps to INCLUDE_MPS. If you have not + enabled the multiple personality system in this manner, your + personality function will become the one and only personality + used within your program. When creating your own personality, + you can use the od_control.od_page_statusline variable to set + which status line (if any) will be activated when the user pages + the system operator. + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 234 + +LOG FILE SYSTEM +------------------------------------------------------------------------------- + + In order for the system operator to monitor system activity and + diagnose problems that have occurred while the system was + unattended, it is common for BBS software and door programs to + record major events in a log file. This log file typically + records the date and time of evens such as a user logging on or + off, transferring files, sending messages, paging the system + operator, and similar activities. Sometimes the system operator + will configure all of the pieces of software running on a + particular node to write to a single log file. In other cases, + the system operator will prefer to have each program write to + its own log file. However, software serving one line of a multi- + node BBS system should never attempt to write to the same log + file that is used by another node. + + OpenDoors uses the "FrontDoor format" log file standard. This + was chosen as it is a clearly documented format that is quickly + becoming the standard for bulletin board software log files. A + segment from a log file produced by OpenDoors is listed below. + + ---------- Thu 25 Feb 93, Vote 6.00 + > 19:42:23 Brian Pirie entering door + > 19:50:55 User paging system operator + > 19:51:02 Entering sysop chat mode + > 20:05:41 Terminating sysop chat mode + > 20:18:32 User time expired, exiting door + + To enable the OpenDoors log file system, simply include the + following line before your first call to any OpenDoors function: + + od_control.od_logfile = INCLUDE_LOGFILE; + + When OpenDoors is initialized, it will open the log file and + begin logging activities, unless logging has been disabled with + the od_control.od_logfile_disable variable. The log file name + will be taken from the od_control.od_logfile_name variable, + which is usually set by the configuration file. If no logfile + name has been set, OpenDoors will use the logfile named + DOOR.LOG. Upon opening the log file, OpenDoors will write an + entry indicating the time at which the use entered the door. + + The od_control.od_prog_name variable sets the program name that + is written to the log file immediately after the current date + information. If this variable is not set, OpenDoors will write + its own name and version information in this place. + + When the OpenDoors log file system is enabled, OpenDoors will + automatically produce logfile entries for the following events: + + - User paging sysop, beginning of chat, end of chat +=============================================================================== +OpenDoors 6.00 Manual End of Page 235 + + - Sysop entering or returning from DOS shell + - User inactivity timeout or user time expired + - Sysop dropping user back to BBS + - Sysop hanging up on user, sysop locking out user + - User hanging up on BBS + - Your program calling the od_exit() function + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 236 + +MAKING DOORS MULTI-NODE-AWARE +------------------------------------------------------------------------------- + + While the majority of BBS systems have only a single phone line, + allowing only one user to access the system at a time, there are + also many multi-node BBS systems. On such systems, it is quite + possible that more than one user may be using your door program + simultaneously. OpenDoors itself is designed for both single- + node and multi-node operation. However, if you want your program + to operate correctly on multi-node systems, there are a number + of concurrency issues that you must keep in mind when writing + your own code. + + Some door programs are designed to behave on multi-node systems + just as they would on single-line BBSes. Others add special + features only possible in multi-node environments. For instance, + you may want to permit users to interact or chat with one + another in "real time". Many simple doors may not require any + special attention to multi-node capabilities. However, if your + door must access any data files or other resources that are to + be shared among nodes, it is necessary to carefully coordinate + access to these resources. + + There are two primary issues that are often of concern when + creating door programs for multi-node systems. The first issue + discussed below is how to coordinate concurrent file access + between multiple node. The second topic we will deal with is the + installation of door programs on multi-node systems. + + + +CONCURRENT FILE ACCESS +------------------------------------------------------------------------------- + + One of the most important issues that arises when writing door + programs for multi-node systems is how to coordinate + simultaneous access to a single data file by multiple instances + of your program. While it is generally safe to have multiple + nodes reading simultaneously from a single file, having multiple + nodes updating a file without any coordination can lead to lost + updates and other problems. Consider, for example, the EX_VOTE.C + example program that is included in your OpenDoors package. When + the user votes on a poll, EX_VOTE.C must update the total number + of votes for the user's answer. Such a program that is only + intended for single node operation could do this by simply + reading the current number of votes for the appropriate option, + adding one to this total, and writing the updated total back to + the file. However, if this approach where to be used on a multi- + node system, it is quite possible that two users would vote on + the same poll after both nodes have read the poll record into + memory. In this situation, one node would add one to the total + number of votes for the poll record that it has in memory, and +=============================================================================== +OpenDoors 6.00 Manual End of Page 237 + + write the updated information to the file. The second node would + then add one to its total, without reading the updated + information written by the first node. When the second node then + writes this information to the file, it overwrites the first + node's total with its own. The final effect is that the second + user's vote overwrites the first, and so the first user's vote + is lost. + + The solution to this problem is to lock a file unit for the + entire update operation, to prevent other nodes from accessing + the unit at the same time. This unit could be the entire file, + or only a single record in the file. EX_VOTE.C locks its entire + file when performing an update operation, but in other cases it + may be more appropriate to only lock a single record in the + file. The important thing to understand is that when one node + locks a file unit, other nodes much wait until the first node is + finished the update operation. This means that if one node is + updating information that other nodes could possibly need access + to, it should always perform the lock, read, write and unlock + cycle as quickly as possible. + + Let's look again at the approach taken by EX_VOTE.C. After the + user has indicated which option he/she wishes to vote on, Vote + attempts to open the file for exclusive access. By doing this, + EX_VOTE.C in effect locks the entire file for the duration that + it has the file open. If another node attempts to open the file + while one node has it locked, the open operation will fail, and + the C runtime library will set the errno variable to EACCES. + This, in effect, tells you that another node is currently + working on the file, and that you must wait your turn. In this + case, EX_VOTE.C continues to retry the open operation until the + other node is finished its update, at which time the open + operation will succeed. This approach will even work when there + are many nodes that are attempting to update the file at the + same time. Whichever node first attempts to open the file will + gain exclusive access to the file, and any additional nodes are + forced to wait for access to the file. When one node finishes + with the file, another node will gain access to the file + (whichever happens to be the next node to re-attempt the open + operation). This process continues until all waiting nodes have + had a chance to perform their update. EX_VOTE.C will repeatedly + try to open the file for up to 20 seconds, after which time it + will give up, reporting an error which indicate that it is + unable to access the file. During this waiting process, + EX_VOTE.C repeatedly calls od_kernel(), so that sysop function + keys, carrier detection and other essential door operations can + continue to be performed. + + After EX_VOTE.C has successfully secured exclusive access to the + file, it first reads the record that it is going to update. It + is important that this be done after the file unit is locked, in + order to ensure that the copy of the record in memory matches +=============================================================================== +OpenDoors 6.00 Manual End of Page 238 + + what is stored in the file. EX_VOTE.C then updates the record + based on the question on which the user has voted, writes this + information back to the file. EX_VOTE.C then immediately closes + the file, allowing other nodes to also access the file. + EX_VOTE.C is very carefully designed so that the file update + operation can never be interrupted (for instance, no OpenDoors + functions are called, which could detect a time-out and + terminate the program while a file update operation is in + progress), or delayed until the user makes a response. As such, + the file unit is always unlocked (in this case, closed) within a + fraction of a second after it was locked, or order that other + nodes will never have to wait long for access to the file. + + Here I have presented a detailed account of how EX_VOTE.C + handles multi-node file access. While all of the details + involved in coordinating multiple file access can be + overwhelming at first, they will begin to come naturally to you, + as you begin to always think in terms of multi-node scenarios. + To summarize, the important elements that are typically involved + in multi-node file access are: + + A. Decide on an appropriate file unit to lock for your + application. In simple cases, this can be the entire file. + In other cases, you may wish to lock individual file + records, using the appropriate runtime library functions. + + B. Always perform update operations in lock, read, update, + write, unlock cycles on individual file units. If there is a + chance that other nodes will also need to access the file + unit, ensure that the update operation cannot be interrupted + or delayed until a user makes a response. + + After you have designed your program for concurrent file access, + how can you test it? If you don't have a multi-node BBS system + that you have access to, you can perform most of your testing + under a multitasking environment, with multiple copies of your + program running in different windows. + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 239 + +MULTI-NODE CONFIGURATION +------------------------------------------------------------------------------- + + A second issue that you may want to bear in mind is how door + programs are typically setup on multi-node systems. + Unfortunately, this may differ considerable depending upon which + BBS software is being used. However, some of the issues that you + may have to consider discussed below: + + A. Your program must be able to locate the correct door + information file for the appropriate node. Most BBS systems + make separate door information files available to each node + by one of the following means: + + - By naming each node's door information file + uniquely. (e.g. DORINFO1.DEF, DORINFO2.DEF.) + + - By having a separate directory for each node's door + information file. (e.g. \NODE1\DOOR.SYS, + \NODE2\DOOR.SYS, etc.) + + In the first case, OpenDoors can automatically select the + correct door information file, assuming that it knows which + node it is running on (see item C, below). In the later + case, you must tell OpenDoors which directory it must look + in to find the appropriate door information file. You may do + this by any of the following means: + + - By specifying the location of the file on the + command line, if od_parse_cmd_line() is used. + + - By providing a configuration file keyword to set + the door information file location for each node. + + - By providing a different configuration file for + each node (See item B, below). + + B. If you are using the OpenDoors configuration file system, + node-specific options should not be used if each node is + accessing the same configuration file. While it is possible + to have a different configuration file for each node (the + filename can be specified on the command line if + od_parse_cmd_line() is used), in most cases the same + configuration file will be used for all nodes. In this case, + the node number, serial port information, and possible door + information file location operations should not be used. If + you are basing your configuration file on the example + DOOR.CFG file that is included in the OpenDoors package, you + may want to remove these options from the file. + + C. In many cases, your program must also be able to determine + which node it is running under. If this information is +=============================================================================== +OpenDoors 6.00 Manual End of Page 240 + + available in the door information file, or is stored in a + TASK environment variable, OpenDoors will automatically set + the appropriate node number in od_control.od_node. + Otherwise, if your program requires this information, it + should be specified on the program's command line. The + od_parse_cmd_line() function supports this option. Reasons + that your program might need to know the current node number + include: + + - In order for OpenDoors to display this information + correctly on the status line. + + - In order to determine which configuration file to + read or which node directory in which to look for + the door information file. + + - In order for OpenDoors to know which door + information file to read (e.g. DORINFO1.DEF, + DORINFO2.DEF. etc.) + + - In order to provide any form of real-time + interaction between nodes, such as inter-node chat. + + D. If your program is running under MS-DOS, and multi-node file + access is being coordinated by locking part or all of a + file, the SHARE.EXE utility must be installed. + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 241 + + 7777777 + 77 + 77 + 77 + 77 + 77 + 77 +------------------------------------------------------------------------------- +CHAPTER 7 - TROUBLESHOOTING AND GETTING ASSISTANCE WITH OPENDOORS + + + + +ABOUT THIS CHAPTER +------------------------------------------------------------------------------- + + This chapter is perhaps the most important section of this + entire manual. Here, we provide detailed instructions to help + you in tracing the source of problems in programs written with + OpenDoors. Included in this chapter is a step-by-step OpenDoors + troubleshooting guide and a chart listing common problems and + their solutions. Also included in this chapter is information on + the many means available to you for getting more help with + OpenDoors, including the OpenDoors support BBS, the OpenDoors + EchoMail conference, and how to get in touch with me. It is + strongly encouraged that you take the time to read through this + chapter. + + + +TROUBLESHOOTING PROBLEMS +------------------------------------------------------------------------------- + + If you are experiencing difficulty with a program that you are + writing using OpenDoors, it is suggested that you follow the + steps listed below in order to quickly solve your problem. Also, + be sure to check to "solutions to common problems" section of + this manual. There are many common difficulties which people + have with OpenDoors, that can easily be fixed using the + instructions in the "common solutions" section. Also, if you are + having difficulty solving a problem yourself, do not hesitate to + get in touch with me, as I am always happy to help with any + problems. In addition, you may find the other means of OpenDoors + support (described latter in this chapter), invaluable in + solving difficulties with OpenDoors. + + Keep in mind that most programs you write will have some "bugs" + to begin with, and you should expect to spend at least 50% of + any programming project tracing down and solving errors and + bugs. While it would be nice if every program written worked + correctly the first time, it is a fact of life that debugging is + and always has been an important part of the software life- +=============================================================================== +OpenDoors 6.00 Manual End of Page 242 + + cycle. In fact, what most often separates the good programs from + the bad is the amount of time their programmer's spend debugging + and improving them. Unfortunately, it is difficult, if not + impossible, to come up with a "magic formula" for debugging + software. Debugging software is really more of an art than a + science. However, there are some basic guidelines, which if + followed, can greatly ease the task of software debugging. + + As with all problem solving, the secret to software debugging + lies in obtaining as much information about the problem as + possible. While it is sometimes possible to solve a bug by + making intuitive changes in your program, or in re-writing a + piece of code to solve the problem by a different means, + debugging most often requires more of a "planned attack". This + planned attack generally involves little more than learning as + much about what is going wrong as possible. The first step in + solving a bug usually lies in locating the source of the + problem. Once you have located the problem, solving it is often + a relatively simple procedure. In locating the source of your + bug, the use of a software debugger, such as the one built into + the Turbo C(++) / Borland C++ integrated development + environment, can be invaluable. + + When debugging programs written with OpenDoors, you should also + follow the steps listed below, in order to obtain more + information related to the problem you are trying to solve: + + 1.) Re-read the section(s) of this manual, your Turbo C(++) / + Borland C++ manuals and your program's source code, which + apply to the problem you are experiencing. + + 2.) Check the solutions to common problems section below. The + most common problems with OpenDoors can be solved using + this simple chart. + + 3.) Check the value in the od_errno variable, which will often + provide vital clues as to the source of the problem. Use of + the od_errno variable is described in the section below. + + 4.) If you are still stuck, please feel more than free to get + in touch with me! (see the end of this chapter for + information on reaching me) I am always more than happy to + help with any OpenDoors or general programming problems! + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 243 + +SOLUTIONS TO COMMON PROBLEMS +------------------------------------------------------------------------------- + + Below, several common difficulties with OpenDoors are listed, + along with suggested solutions to these problems. If you are + experiencing any difficulty with a program that you have written + with OpenDoors, we would suggest that you read this section + thoroughly. Here, the common problem is listed in the left + margin, and the solutions listed on the right portion of the + page. + + +------------------------------------------------------------------------------- +PROGRAM 1.) Check that the compiler is able to locate the OpenDoors +WON'T header file, "OPENDOOR.H". This can be accomplished either by +COMPILE placing this header file in the same directory as your other + header files (such as STDIO.H, etc.), or by placing the header + file in the current directory. + + 2.) Be sure that you are linking your program with the correct + library for the memory model you are using. (See the section on + compiling with OpenDoors). Also be sure that both the source + code file for your program (such as EX_VOTE.C) and the library + file are listed in your project file, and that the project file + is loaded. For more information on compiling programs written + with OpenDoors, see page 22. + + 3.) If you have tried the above solutions, and your program + still won't compile, then the problem is most likely an error in + your source code file. If you are unable to resolve your + problem, feel free to get in touch with me. + + +------------------------------------------------------------------------------- +SCREEN If you are using the od_clr_scr() function to clear the screen, +WILL NOT but are not getting any results, this is likely because the user +CLEAR online has screen clearing turned off. If you wish to force + screen clearing regardless of the user's screen clearing + settings (this is probably not a good idea), use the function + call od_disp_emu("\xc", TRUE); + + +------------------------------------------------------------------------------- +FIXUP This problem was probably caused by a mismatch between your +OVERFLOW memory model selection in your compiler, and the memory model +ERROR library you are using. See the section on compiling programs + with OpenDoors for more information on the correct library you + should be using for your memory model selection. + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 244 + +OPENDOORS SUPPORT +------------------------------------------------------------------------------- + + The powerful and easy to use door toolkit and this comprehensive + manual are only two portions of how OpenDoors helps you to write + BBS door and similar programs. The third element of OpenDoors is + the extensive OpenDoors support mechanisms. The OpenDoors email + conference and support BBS each give you a chance to share ideas + and source code with other OpenDoors programmers. A lot of + information concerning OpenDoors, along with the newest version + and online registration, is available through the OpenDoors + World Wide Web site. In addition to these sources, I am also + more than happy to answer any of your questions, or hear any + suggestions for future versions of OpenDoors. The remainder of + this chapter provides more information on the various sources of + OpenDoors support. Also keep your eyes open for the "OpenDoors + Tech Journal", that is produced on a regular basis by the users + of OpenDoors. Included in this newsletter is information on + OpenDoors and future versions, questions and answers about + OpenDoors and BBS door / utility programming in general, sample + source code, and much more. + + + +THE OPENDOORS SUPPORT BBS +------------------------------------------------------------------------------- + + One means of receiving OpenDoors support is via the OpenDoors + BBS. Below is an outline of some of what is available from the + OpenDoors BBS: + + - The newest version of this package is always available + for download. + + - Also available for download is example source code and + other files which you may find helpful when writing + programs with OpenDoors. + + - Access to the OpenDoors conference where OpenDoors + programmers can share ideas, source code, and receive + help with difficulties or with learning OpenDoors. + + - Get in touch with me with any questions, comments, + suggestions or bug reports. + + - Other files by yours truly, which may be of use in you + programming, such as a registration key system, and so + on. + + All users receive full access upon their first call to the + OpenDoors BBS. The North American phone number for the support + BBS is: +=============================================================================== +OpenDoors 6.00 Manual End of Page 245 + + + +1 (613) 599-5554 + + The OpenDoors support BBS also has a FidoNet address, 1:243/8. + If you are interested in a list of files available from the + support BBS, simply file-request "FILES". To receive the newest + version of OpenDoors, you can file-request "ODOORS". + + + +THE OPENDOORS WORD WIDE WEB SITE +------------------------------------------------------------------------------- + + The OpenDoors World Wide Web site has been setup to provide up- + to-date information on OpenDoors. This includes news concerning + OpenDoors, OpenDoors tips and techniques, pointers to other + sources of OpenDoors support, online registration and access to + the newest version of OpenDoors. + + The current URL (address) of the OpenDoors Web site is: + + http://omega.scs.carleton.ca/~ug930227/opendoor.html + + However, I plan on moving this to a new location some time this + year. If you are unable to reach the OpenDoors Web site through + the above URL, please get in touch with me, and I will be able + to tell you where it has moved to. + + + +THE OPENDOORS CONFERENCE +------------------------------------------------------------------------------- + + The OpenDoors conference is devoted to OpenDoors and BBS / door + / BBS utility programming in general. The OpenDoors conference + serves as a place where people working with OpenDoors can share + ideas, source code examples, and other tricks and techniques. + Through the OpenDoors conference you can receive help with + OpenDoors and programming in general. Also available through the + OpenDoors conference is information on future versions of + OpenDoors and recent developments of concern to BBS door and + utility programmers. The OpenDoors conference is also a place + for suggestions for future versions of OpenDoors, OpenDoors bug + reports, a place to announce the availability of your programs, + and much more information of interest to programmers working + with OpenDoors. + + You can become involved in the OpenDoors Conference by the + following means: + + - The OpenDoors conference is available as an Internet mailing + list. to subscribe, send email to listserv@hms.com and put +=============================================================================== +OpenDoors 6.00 Manual End of Page 246 + + SUBSCRIBE OPENDOOR in the message body. For help on using the + listserver you can send email to listserv@hms.com and put + HELP in the message body. + + - The OpenDoors conference is available on the FidoNet North + America echo backbone, and so is available to a large number + of BBS systems. FidoNet capable systems may also obtain an + OpenDoors feed directly from the moderator, Brian Pirie. + + +GETTING IN TOUCH WITH ME +------------------------------------------------------------------------------- + + If you have any questions about OpenDoors, would like help with + any programs that your are writing, or have any suggestions for + future versions of OpenDoors, please feel free to get in touch + with me. You can get in touch with me by any of the following + means: + + - The best way to contact me is by Internet email. My primary + email address is: + + pirie@msn.com + + If you have difficulty contacting me through this address, I + may also be reached through the address: + + aa522@freenet.carleton.ca + + - By writing a message to me in the OpenDoors support + conference. For more information on the OpenDoors conference, + see the previous section of this chapter. + + - By calling the OpenDoors support BBS. Information on the + support BBS is provided earlier on in this chapter. + + - By sending your question or comment by Fax. My fax number is: + + +1 (613) 599-5554 + + - By FidoNet NetMail. My address is: + + 1:243/8 + + While I would like to be able to reply to all NetMail + messages by CrashMail, I am afraid I simply can not afford to + do this. So, if you choose to send NetMail, please indicate + whether you would like me to reply by routed NetMail (this + may not work, if routed NetMail is not available in your + area), or to place the message on hold for you to poll and + pick up. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 247 + + - By conventional mail. My postal address is: + + Brian Pirie + 117 Cedarock Drive + Kanata ON K2M 2H5 + Canada + + + I try to respond to all correspondences as soon as possible. + + If you are having some sort of difficulty with OpenDoors, the + more detailed information you supply (such as source code to the + program that is causing the problem, how to duplicate the + problem, and so on), the more quickly I will be able to + determine the source of your problem. Also, before you write + about a problem with OpenDoors, you may wish to be sure that you + have read and followed the instructions in the section on + troubleshooting, found on page 242. While I do not mind taking + the time to answer any questions related to OpenDoors, you may + be able to save yourself the time of writing and waiting for a + response - simply by following the instructions in the + troubleshooting section. More often than not, the answer to + questions I receive is already in this manual. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 248 + + A + AAA + AA AA + AAAAAAA + AA AA + AA AA + AA AA +------------------------------------------------------------------------------- +APPENDIX A - CONTENTS OF PACKAGE + + + + + The main OpenDoors package is distributed in the form of a + single, compressed archive file. Thus, you should have received + this version of OpenDoors in a file whose name began with + ODOORS60. The files listed below should be included in your + OpenDoors package. If any of these files are missing, you will + probably want to look for the most recent version of OpenDoors + from another source. Note that the medium and compact memory + model libraries are now distributed separately from the main + OpenDoors package. + + MISCALENEOUS FILES + FILE_ID.DIZ Description of the OpenDoors package + DORINFO1.DEF Sample door info file for testing programs + DOOR.CFG Sample OpenDoors configuration file + + EXAMPLE PROGRAMS + EX_HELLO.C A simple program using OpenDoors + EX_CHAT.C Split-screen sysop chat program + EX_MUSIC.C Example of ANSI music in OpenDoors + EX_SKI.C Simple slalom skiing action game + EX_VOTE.C Example of an online voting program + VOTEDOS.EXE Compiled version of EX_VOTE.C - DOS version + VOTEWIN.EXE EX_VOTE.C compiled - Windows version + DTRON.EXE Free utility for running Win 95 doors + + THE LIBRARY FILES + ODOORS.LIB DOS, Small memory model library + ODOORL.LIB DOS, Large memory model library + ODOORH.LIB DOS, Huge memory model library + ODOORW.LIB Win32 import library (Microsoft version) + ODOORS60.DLL The OpenDoors Win32 DLL + + THE HEADER FILE + OPENDOOR.H OpenDoors header file + + OPENDOORS DOCUMENATION + ORDER.TXT Easy-to-print order form + OPENDOOR.TXT OpenDoors programmer's manual (this file) + +=============================================================================== +OpenDoors 6.00 Manual End of Page 249 + + BBBBBB + BB BB + BB BB + BBBBBB + BB BB + BB BB + BBBBBB +------------------------------------------------------------------------------- +APPENDIX B - CHANGES FOR THIS VERSION + + + + + Since version 5.00, a lot of work has gone into OpenDoors. Many + months were spent cleaning up and restructuring the OpenDoors + code in a process that has touched nearly every line of the + OpenDoors code. As well as making the OpenDoors source code + easier to maintain, this has also involved making OpenDoors more + easily portable to 32-bit multithreaded platforms. + + After this effort was completed, I began work on a Win32 port of + OpenDoors. The OpenDoors package now includes both DOS and Win32 + versions of the library, giving you the option of developing for + one, the other, or both platforms. The Win32 version of + OpenDoors is highly multithreaded to give you the best possible + performance. With some exciting new BBS packages that are + designed specifically for Windows 95/NT in the works, the Win32 + version of OpenDoors gives you a head start on developing + applications that will integrate smoothly with these new BBS + packages. Even if your programs will only be used with DOS-based + BBS packages, the Win32 version of OpenDoors allows you to take + advantage of the Windows 95 GUI, multithreading capabilities and + flat 32-bit memory model (no more DOS 64K limitations and + different memory models to worry about!). It also allows you to + access services that are only available to Windows based + programs, such as ODBC for easy database access, and MAPI for + email, fax and other messaging. + + While this internal restructuring of OpenDoors and the Win32 + port of the package would be enough alone to count as a major + new version, version 6.00 also includes many exciting new + features, enhancements and bug fixes: + + - A new option, "silent mode", has been added. When operating + in silent mode, OpenDoor's local sysop interface is disabled, + so that no output is displayed on the local screen, and no + input is accepted from the local keyboard. Silent mode can be + activated by setting od_control.od_silent_mode = TRUE prior + to the first call to any OpenDoors function, or by specifying + -SILENT on the command-line (if od_parse_cmd_line() is used). + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 250 + + - OpenDoors now fully supports RTS/CTS flow control, which is + enabled by default. To disable the use of the RTS/CTS lines + for flow control, use od_control.od_com_flow_control. + + - In version 5.00, the built-in serial I/O module would be + unable to initialize the serial port if the "Uses Serial + Ports" option was turned off in DesqView or other + multitasking environments. When this option is turned off, + multitasking environments typically remove the serial port + information from the BIOS data segment. However, it seems + that other serial I/O software commonly uses the default + address for each port if this information is not available + from the BIOS data area. OpenDoors 6.00 has been changed to + do the same thing. + + - OpenDoors now provides a standard command-line processing + function, od_parse_cmd_line(). This function provides a one- + step method of adding support for many common command-line + options to your program. This function handles options such + as serial port information (including non-standard serial + port configurations), node number information, user + information, drop file and configuration file locations, + silent mode (turns off the local interface for efficiency and + privacy), one step local login without a drop file, and more. + For details, run the included example program (votedos.exe or + votewin.exe) with the -help command line option. The + od_parse_cmd_line() function is particularly helpful in + several situations: + + - When your program is being used on a multi-node + system. + - Allows potential users to try your program in local + mode by just specifying -local on the command line. + - Allows door information to be specified on the + command line, rather than through a drop file, as + supported by some BBS systems + - Allows serial port handle to be directly passed to + the program under Windows-based BBS systems that + support this. + - Provides customizable command-line help (in a + window in the Win32 version of OpenDoors). + + - A new function, od_sleep(), allows you to suspend program + execution for the specified number of milliseconds, releasing + time to other processes in a multitasking environment. A call + of od_sleep(0) will yield control to any other processes + without forcing program execution to be suspended if no other + processes are waiting. + + - The sysop page timing mechanism has been reworked. By + default, od_control.od_okaytopage is set to PAGE_USE_HOURS, + only allowing the sysop to be paged during the paging hours +=============================================================================== +OpenDoors 6.00 Manual End of Page 251 + + set by od_pagestartmin and od_pageendmin. Rather than + allowing the sysop to be paged at any time of the day or + night, the default now only permits sysop paging from 8:00am + to 10:00pm. Setting paging start and end time to the same + value now correctly permits paging 24 hours a day. + + - OpenDoors now provides a multi-line editor function, + od_multiline_edit(). This editor allows the user to enter or + edit any information that spans multiple lines, such as email + messages or text files. The editor can be configured to + operate in full screen mode, or in any smaller area of the + screen that you specify. The editor is designed to be both + easy to use, and highly customizable. + + - One new feature of OpenDoors 5.00 was somehow omitted from + the manual. Since version 5.00, it has been possible to set + the name of the drop file to use by including both a path and + filename in the od_control.info_path variable. + + - All known inaccuracies and missing information from the + version 5.00 manual have been corrected. + + - The example program, ex_chat.c, has been expanded to + demonstrate how OpenDoor's standard chat mode can be replaced + with the split-screen chat mode within your own programs. + + - The multiple ex_vote?.c example files have been combined and + simplified into a single example program, as it was prior to + version 5.00. + + - A memory leak in the od_popup_menu() function has been fixed. + + - od_control.od_open_handle can be used to provide OpenDoors + with an already open serial port handle on platforms that + support it. Currently, this only applies to the Win32 version + of OpenDoors. If this variable is not set to a non-zero value + prior to calling the first OpenDoors function (other than + od_parse_cmd_line()), then OpenDoors proceeds normally, + opening the serial port itself, and closing the serial port + before exiting. + + - A new switch, od_emu_simulate_modem, has been added to + od_control. When this is set to its default value of FALSE, + the OpenDoors terminal emulator displays at full speed, as it + has always done. However, when this flag is set to TRUE, the + emulation functions will display text at approximately the + same speed as it would be displayed when sent over the modem, + based on the current connect speed. This allows animations to + be displayed locally at the same speed as they would appear + on the remote system. This switch affects the following + functions: + od_disp_emu() +=============================================================================== +OpenDoors 6.00 Manual End of Page 252 + + od_send_file() + od_hotkey_menu() + + - OpenDoors now distinguishes between the serial port BPS rate + (od_control.baud) and the connection BPS (a new variable, + od_control.od_connect_speed). In situations where a separate + value is available for the connect speed (e.g., this caller + has connected at 14400 bps), OpenDoors will now display that + value on the status line. Currently, a separate connect speed + is only obtained from the DOOR.SYS drop file format. + + - The latest versions of the QBBS EXITINFO.BBS drop file is now + supported. + + - A new od_edit_str() flag, EDIT_FLAG_SHOW_SIZE, has been + added. By default, the fields shown by od_edit_str() are one + character larger than the number of characters that may be + entered. This is for esthetic reasons, so that the cursor + remains within the highlighted field, even after a full + string has been entered. However, you may prefer that the + highlighted area reflect the exact number of characters that + are permitted. This can be accomplished by setting + EDIT_FLAG_SHOW_SIZE. + + - Tab characters ('\t') are now expanded on the local display. + + - The new RemoteAccess 2.50 EXITINFO.BBS fields are now + supported. This has included the addition of the following + new od_control members: user_rip_ver, user_attrib3 and + system_last_handle. + + - When operating in "forced automatic local" mode (where no + door information file used), OpenDoors now displays a window + in which in prompts for the user's name at startup time. This + new feature can be disabled by specifying the DIS_NAME_PROMPT + od_control.od_disable flag. + + - The latest version of the SFDOORS.DAT drop file is now + supported. SFMAIN.DAT, SFSYSOP.DAT, SFFILE.DAT and + SFMESS.DAT, which are in the same format as SFDOORS.DAT, are + also now recognized. + + - A new function, od_get_input(), allows you to easily handle + extended keys in your program, such as arrow keys, insert and + function keys. + + - The OpenDoors configuration file system will now display an + error and exit the program if a particular configuration file + name has been specified, and that configuration file cannot + be found. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 253 + + CCCC + CC CC + CC + CC + CC + CC CC + CCCC +------------------------------------------------------------------------------- + APPENDIX C - FUTURE VERSIONS + + + + + While I cannot make any promises about what features and changes + will be seen in future versions of OpenDoors, I would like to + take a moment to tell you a bit about some of the features you + can expect to see in future versions of OpenDoors + + As you are probably already aware, OpenDoors is a constantly + evolving package. To help meet the needs of programmers working + with OpenDoors, nearly every idea and change that is made to the + package results from the suggestions and comments I receive from + the people using OpenDoors. For this reason, I will most likely + continue to produce new versions of OpenDoors for as long as + there is a demand and ideas for upgrades. There certainly is no + shortage of either of this right now. + + Some of the features that I am considering for upcoming versions + of OpenDoors include: + + -Telnet support. + + - HTML support. + + - Direct interfacing with new Windows 95/NT BBS packages. + + - Further features to help writing multi-node door + programs. + + -Direct interfacing with more BBS systems. + + -Additional RIP graphics support, including possible + display of RIP images on local screen. + + -Possible support for additional programming languages and + operating systems. + + - Improvements to existing OpenDoors features, such as more + configuration file options, multiple log file formats, + and many smaller changes. + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 254 + + DDDDD + DD DD + DD DD + DD DD + DD DD + DD DD + DDDDD +------------------------------------------------------------------------------- + APPENDIX D - SPECIAL THANKS + + + + + There are many people who I would like to thank, for their + suggestions, ideas and assistance in making OpenDoors what it is + today. Among those I would like to thank are: + + - Everyone who has registered OpenDoors. + + - All those who participate in the OpenDoors conference, + who provide many suggestions, bug reports and words of + encouragement. + + - Those who on the OpenDoors beta team. Thank-you for + putting up with the problems along the way. You have + certainly helped to make OpenDoors a better package. The + people who have helped to beta test OpenDoors 6.00 are: + + Robert Bouman + Doug Crone + Greg Diener + Patrick Dixon + Joel Downer + Mike Fenton + Les Howie + Vince Jacobs + Scott Jibben + Dean Mills + Jimmy Rose + Jim Woodward + Timothy Ward + Mark Williams + + - Last but not least, I would like to thank my wife, Pearl, + for her support during the long hours that it has taken + to put OpenDoors together. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 255 + + GGGG + GG GG + GG + GG GGGG + GG GG + GG GG + GGGG +------------------------------------------------------------------------------- +GLOSSARY + +ANSI ANSI is an acronym for "American National Standards Institute". + One of the standards approved by ANSI is a terminal display + protocol which allows (in this case), BBS software to perform + certain display functions such as changing the color of + displayed text, or moving the location of the cursor on the + screen. The majority, though not all, BBS users use terminal + software with ANSI capabilities. Any users that do not have + graphics display capabilities, will be using ASCII mode, + instead. The ANSI terminal protocol is sometimes referred to as + "ANSI graphics". It is graphic in the sense that it provides + more visual control than an ASCII TTY terminal does, but does + not imply any support for bit-mapped nor vector graphics. + Compare ASCII and AVATAR. + + +API API is an acronym for "Application Program(er) Interface". An + API is a set of well documented functions, variables and data + types that you can use to access certain services from your + program. When you write any C program that uses standard C + library functions such as fopen() or strcpy(), you are using a + sort of API. When you use OpenDoors functions such as + od_printf() or od_get_key(), you are using functions that are + part of the OpenDoors API. Operating systems provide their own + APIs that allow programs to gain access to operating system + features such as screen display, file I/O and communications. + The API provided by Microsoft Windows 95 and Windows NT is + called the Win32 API. + + +ASCII ASCII (pronounced "ass-key") is an acronym for "American + Standard Code for Information Interchange", and is a definition + of a set of 128 letters, number and symbols, which can be + displayed by computer systems. Also, when used within the domain + of BBS software, ASCII mode is often used to refer to the lack + of any more advanced display capabilities, such as ANSI or + AVATAR. When ASCII mode is used, characters can only be + displayed in standard Teletype (TTY) fashion, one after another. + Also, color and cursor positioning functions are not available + in ASCII mode. Compare ANSI and AVATAR. + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 256 + +AVATAR AVATAR is an acronym for "Advanced Video Attribute Terminal + Assembler and Recreator". AVATAR is a graphics display protocol, + similar to ANSI. Like ANSI-graphics, AVATAR graphics allow + functions such as cursor positioning, and color changing. + However, AVATAR also offers many capabilities not available from + ANSI, and performs the same functions as ANSI much more quickly. + AVATAR graphics is less common than both ANSI or ASCII, but is + becoming more popular as time goes by. Compare ASCII and ANSI. + + +BAUD "baud" or "baud rate" are generally used as a synonym for "BPS". + + +BPS BPS is an acronym for "Bits Per Second", and refers to the rate + at which data is being sent over a communications medium. There + are two important BPS rates which are relevant to OpenDoors. The + serial port BPS rate (also called the DCE rate) is the speed at + which the computer is communicating with the local modem. The + connect speed, on the other hand, is the speed at which the + local modem is communicating with the remote modem. The serial + port speed must be at least as fast as the connection speed. + Often the serial port speed will be locked at a fixed speed that + is higher than the fastest possible connection speed of the + modem. For example, the serial port might be locked at a speed + of 38400 BPS, while the modem could be connected at 28,800, + 14,400 or slower speeds. OpenDoors usually needs to know the + serial port BPS rate in order to function correctly (as stored + in od_control.baud). Under certain situations, OpenDoors will + also be able to report the connection speed to you (as stored in + od_control.od_connect_speed), although OpenDoors does never + requires this information to operate. + + +BIT-MAPPED As with Boolean values, described below, bit mapped flags +FLAGS are used to indicate whether or not various conditions exist. + (For example, whether or not a certain setting is enabled, or + whether or not a particular event has occurred.) However, unlike + Boolean variables, a single bit-mapped flag represents more than + one of these TRUE/FALSE values. In fact, each bit (BInary + Digit), which makes of the variable can be used to represent a + separate TRUE/FALSE state. (ie, each bit maps to a particular + piece of information, and hence the term "Bit Map"). + + For an example of using bit-mapped flags, let us take a case of + a single "unsigned char" which contains three independent + TRUE/FALSE values. We will call this variable user_info, and it + will indicate whether or not a user has ANSI graphics, whether + or not the user has screen clearing turned on, and whether or + not the user has end-of-page "more" prompts enabled. Internally, + the bits of the user_info variable will be as follows: + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 257 + + Bit: 7 6 5 4 3 2 1 0 + | | | + | | +--- ANSI Graphics + | +----- Screen Clearing + +------- More prompts + + In this case, we will have three constants which we define in + order to simplify access to these bit-mapped flags, as follows: + + #define ANSI_GRAPHICS 0x01 + #define SCREEN_CLEARING 0x02 + #define MORE_PROMPTS 0x04 + + Note that normally within OpenDoors, these constants will be + defined for you, and you will have no need to know what their + values are, nor in which bit which piece of information is + stored. + + Using bit-mapped flags, you are able to set or clear any of the + individual flags, and check whether any of the flags are set, + using these simple methods: (Not that a set flag is the + equivalent of a Boolean value of "True", and a cleared flag is + the equivalent of a Boolean value of "False".) + + Set Flag: variable |= FLAG_CONSTANT; + Clear Flag: variable &=~ FLAG_CONSTANT; + Test Flag: variable & FLAG_CONSTANT + + Where "variable" is the name of the bit-mapped flag variable, + and "FLAG_CONSTANT" is the pre-defined constant for the + individual setting. To return to our example, you could turn on + the user's ANSI graphics setting by using the line: + + user_info |= ANSI_GRAPHICS; + + and to turn off screen clearing you would: + + user_info &=~ ANSI_GRAPHICS; + + To perform an action (such as waiting for the user to press + [Return]/[Enter]) only if "More" prompts are enabled, you would: + + if(user_info & MORE_PROMPTS) + { + ... /* Whatever you want */ + } + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 258 + +BOOLEAN Many of the variables used within OpenDoors contain a +VALUES "Boolean Value". A Boolean value is a two-state variable, who's + states are referred to as "True" and "False'. If the variable + contains a value of "True", it indicates that a certain + condition is so, and if it contains a value of "False", it + indicates that the condition is not so. For example, a Boolean + variable "wait" might be used to indicate whether or not + OpenDoors should wait for the user to press a key, or continue + without waiting. In this case, a value of "True" would indicate + that OpenDoors should wait, and a value of "False" would + indicate that it should not wait. + + Note that in the C programming language, there is no actual + Boolean variable type - usually a char or an int are used to + store Boolean values. + + The constants TRUE and FALSE, as defined in the OPENDOOR.H file, + are used to represent the two states of a Boolean value. Thus, + to set a Boolean variable "wait" to the value of "True", you + would use this line: + + wait=TRUE; + + and to set the variable "wait" to "False", you would: + + wait=FALSE; + + However, you SHOULD NOT test whether a Boolean variable is + "True" or "False" by using the C compare (==) operator, as the + value "True" will not always be the same numerical value. + (Actually, the TRUE constant represents just one of many + possible numerical values for "True"). Instead, to perform an + action of the "wait" Boolean variable is "True", you would: + + if(wait) + { + ... /* Whatever you want */ + } + + and to perform an action if the "wait" Boolean variable is + "False', you would: + + if(!wait) + { + ... /* Whatever you want */ + } + + For interest sake, Boolean values are named after the 19th + century English mathematician, who studied formal logic, and + created Boolean algebra - an algebra which deals with TRUE and + FALSE values. + +=============================================================================== +OpenDoors 6.00 Manual End of Page 259 + + +BPS BPS is an acronym for "Bits Per Second". For our purposes here, + the terms BPS and BAUD refer to the same thing. + + +CARRIER The term "Carrier" or "Carrier Detect" refers to a signal which +DETECT most modems send to the computer, which indicates whether or not + the modem is currently connected to (communicating with) another + modem. The door driver module of OpenDoors, as with most other + BBS software, uses the status of this carrier detect signal in + order to know whether the user is still connected to the BBS + computer. Thus, if the user hangs up, or if something goes wrong + and the connection is lost, OpenDoors is able to detect this + state, and exit to the BBS. The BBS will then also detect that + the carrier signal has been "lost", and will reset itself, and + then again be ready to accept calls. + + +CHAT MODE The term "chat mode" refers to a means by which the sysop can + communicate with a user of the BBS / door. During sysop chat, + anything typed by the sysop will appear on the user's screen, + and likewise, anything typed by the user will appear on the + sysop's screen. Sysop chatting is available on both single and + multi-line systems. Sysop chatting is initiated by the sysop, + either at any time a user is online, or specifically in response + to a sysop page. + + +COMPILE "Compiling" refers to the process of converting the source code + that you write for your program, into an executable file (such + as a .EXE file) that an end user can use. The process of + building an executable file is generally divided into two + stages. In the first stage, called compiling, source files are + converted to object files, often named .OBJ. In the second + stage, called linking, one or more object files are combined, + along with any library files, to produce the final executable + file. + + +DLL DLL is an acronym for "Dynamic Link Library". A dynamic link + library is similar to a static library, in that it contains one + or more functions that an application program can use. Unlike a + static library, the code from a dynamic link library is not + added to the program's executable file at link time. Instead, + the dynamic link library exists as a separate file which must be + loaded when the program is run. The Win32 version of OpenDoors + resides in a DLL. + + See also "Library". + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 260 + +DOOR A "door" is a program that runs as part of a BBS system, but + which is separate from the central BBS software (RemoteAccess, + Maximus, QuickBBS, PC-Board, etc.) itself. A door provides + additional features not built into the BBS software, such as on- + line games, on-line shopping services, voting booths, match + making systems, access to special files or messages, and much + much more. Since the user also communicates with the door + online, as they do with the BBS, it may not necessarily be + obvious to the user that the door is even a separate entity from + the central BBS software itself. + + +DOOR Also referred to as a "drop file", "exit file", or "chain +INFORMATION file". The door information file is a file passed from the +FILE central BBS software to a door program, providing it with + information about the user who is online, the BBS the door is + running under, and the current modem connection. The door + information file may also be used to pass changed information + back to the BBS, such as the amount of time that the user has + used in the door. OpenDoors takes care of all of the work + involved in reading and writing the door information file for + you, as described in the "Basics of Door Programming" section, + in chapter 4. Examples of door information files supported by + OpenDoors include: DOOR.SYS, EXITINFO.BBS, DORINFO?.DAT, + SFDOORS.DAT, CALLINFO.BBS and CHAIN.TXT. + +DTR DTR is an acronym for "Data Terminal Ready". This is a signal + that the computer sends to the modem, indicating that the + computer is ready to send or receive information. Most modems + are configured to hangup if the DTR signal is lowered. This is a + convenient means of hanging up the modem, but cases problems + under Windows 95, where the DTR signal is always lowered when a + program closes the serial port. + + +ECHO See "Local Echo". + + +FOSSIL The FOSSIL driver, or simply FOSSIL, is a TSR program or +DRIVER device driver which OpenDoors can optionally make use of in + order to communicate with the modem. The FOSSIL driver is loaded + prior to starting up the BBS or your door, usually from the + AUTOEXEC.BAT or CONFIG.SYS files. The two most commonly used + FOSSIL drivers are X00 and BNU. (FOSSIL is an acronym for + "Fido/Opus/SEAdog Standard Interface Layer", although it has now + become the standard for nearly all BBS software.) FOSSIL drivers + are also available for other specialized serial port hardware, + such as the popular "DigiBoard" multi-port serial card. + + +IMPORT LIBRARY See "Library". + +=============================================================================== +OpenDoors 6.00 Manual End of Page 261 + + +LIBRARY A "library" or "library file" is a collection of precompiled + functions and variables that can be used by other programs. All + of the features, capabilities and functions of OpenDoors that + you can make use of are contained within the OpenDoors library + files. (Likewise, the C runtime library, consisting of the + familiar functions such as fopen(), printf() and atoi(), is also + contained within a library file.) For more information on the + different OpenDoors library files, see the section that begins + on page 22. + + There are several different kinds of library files. A static + library file is actually a collection of individual object + files. When you compile a program that makes use of a static + library file, only those portions of the library file that your + program actually uses are linked into your program's executable + (.EXE) file. Static library files can be identified by a .LIB + extension. The DOS version of OpenDoors resides in a static + library. + + A dynamic link library, on the other hand, is not combined with + the program's executable file. Instead dynamic link libraries + exist in separate .DLL files that must also be present when the + program is executed. The Win32 version of OpenDoors resides in a + dynamic link library. + + An import library is a small file that describes a dynamic link + library. The most common way for a program to call functions in + a dynamic link library requires that an import library be used a + program link time. + + See also "DLL". + + +LINK "Linking" generally refers to the process of combining several + object files into a final executable file, during which + references to symbol names (such as od_printf()) are resolved to + the address of the corresponding object. See also "Compiling". + + +LOCAL MODE The term "local mode" refers to a mode in which a BBS system or + door program may operate. In local mode, the BBS/door behave as + they would if a user were connected via modem to the BBS, except + that all display and input is done simply on the BBS software, + but not through the modem. Local mode allows the sysop or + another person with direct access to the BBS computer to use the + BBS/door software, either for their own user, or for testing + that the software is running correctly. When programming door + software, local mode can be very useful in testing and debugging + the door, without requiring the door to be connected to a remote + system. All doors written with OpenDoors automatically support + local mode operation. Compare "Remote". +=============================================================================== +OpenDoors 6.00 Manual End of Page 262 + + + +LOCAL ECHO The term "Local Echo" refers to a door displaying the same + characters which are sent to the modem on the local screen + ("Output Window"). This allows the sysop to view the same + information that is sent to the user's system, in the same + manner that it will appear on the user's screen. + + +LOCKED (eg. "Locked Baud Rate", "Locked BPS Rate", "Locked Commport + Speed", etc.) Usually, the communication port to which a modem + is connected is set to transfer data at the same BPS rate as the + rate at which the modem is communicating. However, many high + speed modems allow very high speed data transfer by using built- + in data compression methods. In this case, the actual rate of + data transfer can easily exceed the true BPS rate of the + connection. As a result, the BPS rate of the port is kept a + single speed, faster than any of the true modem connections, in + order to increase modem speed performance. This is referred to + as locking the commport BPS rate. OpenDoors has full support for + the use of locked BPS rates. + + +LOG FILE A log file is a normal text file in which BBS software records + all major activities that have taken place. As such, the log + file permits the sysop, to review what activities have taken + place on the BBS during the time which they have been away from + the computer. A log file can be helpful in identifying system + errors or crashes that have occurred, in alerting the sysop in + the case that any users have been causing problems on the BBS, + or in simply letting the sysop know who has called recently, and + what when they did when they called. + + +MEMORY MODEL C and C++ programs can be compiled under a variety of different + memory models. Each memory model describes how data and program + code are addressed in memory. When writing MS-DOS programs, you + generally have the choice of six different memory models (named + tiny, small, compact, medium, large and huge), each of which + provides a different combination of the maximum sizes of data + and code that your program may have. When writing Win32 + programs, there is a single, flat 32-bit memory model that all + programs use. This memory model allows a program to address (in + theory) up to 4 gigabytes of data and code. + + +MODEM A device connected to a computer which permits it to communicate + with other computers, usually over standard telephone lines. + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 263 + +OBJECT FILE An object file contains the compiled version of a source code + file of a program. The source code file may be a .C file, .CPP + file, .ASM file, .PAS file, .BAS file, or any number of other + extensions associated with other programming languages. When any + of these language's source code files are compiled, a .OBJ file + is created containing information such as the executable code, + and names of symbols (variables and functions) that are to be + shared with other .OBJ files. In order to produce a .EXE file + that may be executed, a process known as linking must be + performed. During the link process, one or more object files + composing your program are combined, along with the necessary + code from any library files being used, in order to produce the + final .EXE file. + + +ONLINE In the case of BBS software and BBS door programs, the term + online refers to the state of a user using the BBS. Usually, the + user will be connected to the BBS from a remote location, using + a modem. However, it is also possible that the user will be + using the actual BBS computer, with the software operating in + "local mode". + + +OUTPUT WINDOW The local screen of the BBS on which BBS software is running is + usually divided into two sections. At the bottom of the screen, + there is often a one or two line status line, which displays + information to the sysop about the BBS and the user who is + currently online. The rest of the screen is usually an "output + window", in which the information which is being displayed to + the user, is also displayed on the local screen. In some cases, + there will be no status line, in which case the entire screen + will be the output window. Usually, the upper 23 lines of the + screen in an OpenDoors door will be the output window, with the + bottom two lines being the status line. However, it is possible + to disable the OpenDoors status line, in which case the entire + screen will be the output window. See also "Status Line" + + +PAGE See "SYSOP PAGE" + + +PARAMETER In the C programming language, many tasks are accomplished by + calling functions. When a function is called, one or more pieces + of information may be passed to a function, in the form of + parameters. For example, a function used to set the foreground + and background color of displayed text might accept two + parameters, one for each of the two color settings. In this + example, a function such as od_set_color(), would be called as + follows: + + od_set_color(D_GREEN,D_RED); + +=============================================================================== +OpenDoors 6.00 Manual End of Page 264 + + In this case, D_GREEN, the foreground color, is the first + parameter, and D_RED, the background color, is the second + parameter. + + In C, parameters are enclosed in parentheses, ( and ), which are + located after the name of the function to be called. Each + parameter is then separated by a comma character. If a function + does not accept any parameters, the parentheses will have + nothing between them. (ie. od_clr_scr() ). + + +REGISTRATION This is a demonstration version of OpenDoors, which may only be + used under limited circumstances, for a limited period of time. + If you wish to continue using OpenDoors after this "evaluation + period", you must "register" it. For more information on + registering OpenDoors, please see chapter 2 of this manual. + + +REMOTE When used in reference to BBS software or door programs, the + term remote is used to refer to a user or computer that is + communicating with the BBS, for a distant location, by use of a + modem. Compare "Local Mode" + + +RIP "RIP", "RIPScrip" or "Remote Imaging Protocol" is a popular + graphical terminal standard that is used with BBS systems. + Unlike other terminal emulation standards, such as the ANSI and + AVATAR modes supported by OpenDoors, RIP operates in bit mapped + graphics mode, allowing features such as lines, circles and + icons to be drawn on the remote screen. OpenDoors provides + support for RIP graphics, although OpenDoors operates in text + mode itself. + + +STATUS LINE Usually, the bottom two lines of the screen, as displayed by an + OpenDoors door, is devoted to a status line (although this + status line may be turned off). This status line will display + information about the user who is online, along with information + about the current state of the BBS system, and a reference to + the sysop function keys. See also "Local Window". + + +SYSOP The term sysop is a short-form for "SYStem OPerator", and refers + to the individual who is responsible for running and maintaining + the BBS system. The sysop is usually the only person who has + direct access to the local keyboard and computer on which the + BBS, BBS utilities and BBS doors are running. + + +SYSOP CHAT See "CHAT MODE". + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 265 + +SOURCE CODE The term "source code" refers to the original file or files that + where used to produce a library or executable program. The + source code files contain the language statements or commands + that are directly written by the programmer. These source code + files are then compiled to produce an executable file that may + be "run". + + +SYSOP PAGE Sysop paging refers to the process whereby a user of the BBS + system may call or page for the sysop's attention, when they + wish to "chat" with the sysop, and can be thought of as being + similar to the ringing of a telephone. When a user pages the + sysop, the BBS system will produce some sort of sound, which the + sysop may elect to respond to if they are within hearing range + of the computer. The most common reasons for a user to page a + sysop include the case that they are having difficulty with some + aspect of the BBS, that they have a question, or if they are + simply interested in having a friendly conversation with the + sysop. Obviously, since the sysop may not wish to be disturbed + by users paging at certain times (such as when they are in bed), + most BBS software provides controls to allow you to control + paging. These features might include the ability to set hours + for each day of the week during which paging will be permitted, + and the ability to temporarily override the ability of some or + all callers to page the sysop. + + +USER When applied to computers in general, the term user simply + refers to any person using the computer hardware and software. + However, when applied particularly to BBSes, the term user + refers specifically to a person who calls the BBS, to carry out + activities such as communicating via messages or chatting, + uploading and downloading files, or using doors. Often, the term + user is used in contrast with the term sysop. In this case, + users are all of the people who call and user the BBS, other + than the sysop themselves. + + +WIN32 Win32 is the name of the API that programs written to run under + Microsoft Windows 95 and Microsoft Windows NT use to access + operating system services. Win32 programs use a flat, 32-bit + memory model and have access to advanced operating system + services such as multithreading. Win32 programs cannot run under + DOS nor OS/2. While some Win32 programs can run under Windows + 3.x using the Win32s system, OpenDoors cannot since it requires + multithreading services that are not provided by Win32s. + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 266 + + IIIIII + II + II + II + II + II + IIIIII +------------------------------------------------------------------------------- +INDEX + + + +A D + +About This Manual ..................21 Debugging 21, 241 +Access Level ......................178 Demo Version........................9 +Alias .............................170 Display Functions..............42, 63 +ANSI Graphics Displaying Text....30, 41, 42, 60, 62 +Archive Contents ..................248 Door Driver Functions..............40 +ASCII Chart ........................86 Door Driver Module..............6, 40 +ASCII Mode ........................255 Door Functions.....................45 +AVATAR Graphics ....118, 134, 167, 256 Door Information File30, 33, 150, 158 + Door Settings.....................182 +B DORINFOx.DEF File..................33 + DOS Shell.........................192 +Baud Rate .........................154 Download Limit....................169 +BBS Information ...................158 +BBS Name ..........................164 E +BBS Systems ........................30 +Before Exit Function ..............191 Error Free Connection.............170 +Box Characters ...............185, 191 Example Program - Changing Only +BPS Rate ..........................154 Foreground/Background Colour ....132 +Built-In Function Keys ............212 Example Program - Choosing Text + Colour ..........................129 +C Example Program - Clearing A Line..56 + Example Program - Dialog Box.......66 +Caller Information ................158 Example Program - Door And Utility In +Carrier Detect .................51, 97 One Program ......................92 +Chat ..........................38, 104 Example Program - Drawing A Window118 +Chat Mode ....................104, 259 Example Program - Exiting A Door...79 +Colour Attribute Codes ............128 Example Program - First Door.......29 +Colour Constants ..................132 Example Program - Hanging Up In CBV +Colour Customization215, 229, 232, 236 Door .............................51 +Colour Functions ...................42 Example Program - Hotkeyed Menu....91 +Colours .................110, 128, 131 Example Program - Input Key.......115 +Common Problems ...................243 Example Program - Setting Door Info +Compiler Errors ...................243 File Location ...................150 +Compiling With OpenDoors ...........22 Example Program - Shelling To DOS.141 +Custom Function Keys ..............213 Example Program - Terminal Emu.....62 + Example Program - Testing Available + Door Information ................158 + +=============================================================================== +OpenDoors 6.00 Manual End of Page 267 + + + +Example Program - Testing Screen M + Clearing Capabilities 57 +Example Program - Transferring A File Memory Models..................23, 24 + Using DSZ........................142 Memory Swapping...................209 +Example Program - User Statistics Modem Port........................157 + Door.............................113 Modem Settings....................153 +Example Program - Vote .............33 +Example Program - Waiting For CR ...54 N +Exiting A Door Program .............79 + New Version.......................249 +F Node Number.......................152 + +Features ............................6 O +Feedback Form ......................19 +File Display Functions .............44 Object File.......................263 +FILES.BBS File .....................98 od_autodetect() Function...........48 +Fossil Driver .....................260 od_carrier() Function..............51 +FOSSIL port .......................157 od_chat() Function.................50 +Function Keys .................97, 211 od_clear_keybuffer() Function......53 +Future Versions ...................253 od_clr_line() Function.............55 + od_clr_scr() Function.........57, 243 +G od_colour_config() Function........59 + od_control Structure..........31, 148 +Getting In Touch With Us ..........246 od_disable Variable...............198 +Graphics Mode ...........165, 167, 255 od_disp() Function.................60 + od_disp_emu() Function.............62 +H od_disp_str() Function.............63 + od_draw_box() Function.............65 +History ...........................249 od_edit_str() Function.............68 +Hotkeys ............................90 od_exit() Function...31, 79, 191, 195 + od_get_answer() Function...........81 +I od_get_input() Function............82 + od_get_key() Function......30, 53, 85 +IBM Colour Attribute Codes ........128 od_gettext() Function..............89 +IEMSI Session Information .........161 od_hotkey_menu() Function..........90 +Inactivity Timeout ......199, 200, 202 od_init() Function.............31, 92 +Input Functions ............44, 81, 85 od_input_str() Function........53, 95 + od_kernal() Function...............31 +K od_kernel() Function...............97 + od_list_files() Function...........98 +Keyboard Buffer ...........53, 97, 115 od_log_write() Function...........100 +Keys ...............................97 od_multiline_edit() Function......101 + od_page() Function...........104, 207 +L od_parse_cmd_line() Function......105 + od_popup_menu() Function..........107 +Language Customization ............216 od_printf() Function.....29, 110, 195 +Learning OpenDoors .................29 od_putch() Function...............115 +Library ...........................261 od_puttext() Function.............116 +LIBrary Files ......................24 od_repeat() Function..............118 +Line Number .......................152 od_restore_screen() Function......120 +Linking ............................23 od_save_screen() Function.........121 +Local Mode ...............33, 200, 261 od_scroll() Function..............123 +Locked ............................262 od_send_file() Function...........124 + od_set_attrib() Function..........128 + +=============================================================================== +OpenDoors 6.00 Manual End of Page 268 + + + +od_set_color() Function ...........131 Solutions To Problems.............243 +od_set_cursor() Function ..........134 Source Code................10, 17, 20 +od_set_dtr() Function .............135 Special Thanks....................254 +od_set_personality() Function .....136 Status Line...104, 137, 209, 210, 264 +od_set_statusline() Function ......137 Stop Key..........................203 +od_sleep() Function ...............139 Support...........................244 +od_spawn Function .................208 Support BBS.............244, 245, 246 +od_spawn() Function ...............141 Swapping..........................209 +od_spawnvpe() Function ............143 Sysop Chat...............38, 104, 192 +od_window_create() Function .......145 Sysop Function Keys...............211 +od_window_remove() Function ..147, 148 Sysop Keys.........................97 +OPENDOOR.H File ............22, 29, 34 Sysop Name........................164 +OpenDoors BBS ................244, 245 Sysop Next Setting................184 +OpenDoors Customization ...........187 Sysop Page........................207 +OPENDOORS Echo ....................245 Sysop Paging.................104, 265 +OpenDoors History .................249 System Event......................162 +Our Address .......................246 System Name.......................164 +Output Functions ...................42 +Output Window .................34, 263 T + +P Terminal Emulator........62, 124, 125 + Terminal Emulator Control Codes...126 +Paging Hours .................182, 183 Text Customization................216 +Paging The Sysop ..................104 Thank-yous........................254 +Pause Key .........................203 Time Left.........................179 +Phone Number ......................171 Timeout............................97 +Printing ..30, 41, 60-63, 90, 110, 115 Troubleshooting....................21 +Printing Manual ....................22 +Problems ...........................21 U +Product Support ...................244 +Project Files ......................23 User Handle (Alias)...............170 + User Information..................158 +R User Keyboard Off Key..............53 + User Keyboard Setting.............184 +Registration ..9, 10, 12, 18, 246, 264 User Name.........................174 +Registration Form ..............15, 18 User Password.....................176 +RIP ...............................264 User Timeout.......................97 +RIPScrip ..........................264 + V +S + Version History...................249 +Screen Functions ...................42 +Screen Length .....................177 W +Screen Width ......................178 +Security Level ....................178 Want-Chat Setting.................180 +Setting Colours .........110, 128, 131 + + + + + + + + + +=============================================================================== +OpenDoors 6.00 Manual End of Page 269 + diff --git a/utils/magiedit/odoors/OpenDoor.def b/utils/magiedit/odoors/OpenDoor.def new file mode 100644 index 0000000..265e4ef --- /dev/null +++ b/utils/magiedit/odoors/OpenDoor.def @@ -0,0 +1,99 @@ +; 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: OpenDoors.def +; +; Description: Module definition file for the OpenDoors Win32 DLL. +; +; Revisions: Date Ver Who Change +; --------------------------------------------------------------- +; Dec 12, 1995 6.00 BP Created. +; Jan 11, 1996 6.00 BP Added exports for undecorated names. +; Feb 19, 1996 6.00 BP Changed version number to 6.00. +; Mar 03, 1996 6.10 BP Begin version 6.10. +; Mar 03, 1996 6.10 BP Added od_get_cursor. +; Mar 21, 1996 6.10 BP Added od_control_get(). +; Oct 19, 2001 6.20 RS Added door32.sys and socket support. +LIBRARY ODOORS62 +DESCRIPTION "OpenDoors" +VERSION 6.2 +EXPORTS + ODConfigInit=_ODConfigInit@0 + ODLogEnable=_ODLogEnable@0 + ODMPSEnable=_ODMPSEnable@0 + od_add_personality=_od_add_personality@16 + od_autodetect=_od_autodetect@4 + od_carrier=_od_carrier@0 + od_chat=_od_chat@0 + od_clear_keybuffer=_od_clear_keybuffer@0 + od_clr_line=_od_clr_line@0 + od_clr_scr=_od_clr_scr@0 + od_color_config=_od_color_config@4 + od_control_get=_od_control_get@0 + od_disp=_od_disp@12 + od_disp_emu=_od_disp_emu@8 + od_disp_str=_od_disp_str@4 + od_draw_box=_od_draw_box@16 + od_edit_str=_od_edit_str@32 + od_emulate=_od_emulate@4 + od_exit=_od_exit@8 + od_get_answer=_od_get_answer@4 + od_get_cursor=_od_get_cursor@8 + od_get_input=_od_get_input@12 + od_get_key=_od_get_key@4 + od_gettext=_od_gettext@20 + od_hotkey_menu=_od_hotkey_menu@12 + od_init=_od_init@0 + od_input_str=_od_input_str@16 + od_kernel=_od_kernel@0 + od_key_pending=_od_key_pending@0 + od_list_files=_od_list_files@4 + od_log_open=_od_log_open@0 + od_log_write=_od_log_write@4 + od_multiline_edit=_od_multiline_edit@12 + od_page=_od_page@0 + od_parse_cmd_line=_od_parse_cmd_line@4 + od_popup_menu=_od_popup_menu@24 + _od_printf=od_printf + od_printf=od_printf + od_putch=_od_putch@4 + od_puttext=_od_puttext@20 + od_repeat=_od_repeat@8 + od_restore_screen=_od_restore_screen@4 + od_save_screen=_od_save_screen@4 + od_scroll=_od_scroll@24 + od_send_file=_od_send_file@4 + od_set_attrib=_od_set_attrib@4 + od_set_color=_od_set_color@8 + od_set_cursor=_od_set_cursor@8 + od_set_dtr=_od_set_dtr@4 + od_set_personality=_od_set_personality@4 + od_set_statusline=_od_set_statusline@4 + od_sleep=_od_sleep@4 + od_spawn=_od_spawn@4 + od_spawnvpe=_od_spawnvpe@16 + od_window_create=_od_window_create@36 + od_window_remove=_od_window_remove@4 + pdef_opendoors=_pdef_opendoors@4 + pdef_pcboard=_pdef_pcboard@4 + pdef_ra=_pdef_ra@4 + pdef_wildcat=_pdef_wildcat@4 + _od_control=od_control DATA + od_control=od_control DATA diff --git a/utils/magiedit/odoors/OpenDoor.h b/utils/magiedit/odoors/OpenDoor.h new file mode 100644 index 0000000..b0a1252 --- /dev/null +++ b/utils/magiedit/odoors/OpenDoor.h @@ -0,0 +1,1123 @@ +/* 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: OpenDoor.h + * + * Description: C/C++ definition of the OpenDoors API. Any program source file + * that uses OpenDoors must #include this file. + * + * Revisions: Date Ver Who Change + * --------------------------------------------------------------- + * Dec 02, 1995 6.00 BP New file header format. + * Dec 09, 1995 6.00 BP Added od_multiline_edit() prototype. + * Dec 12, 1995 6.00 BP Cleaned up, added DLL definitions. + * Dec 12, 1995 6.00 BP Moved ODPLAT_??? to OpenDoor.h. + * Dec 21, 1995 6.00 BP Add ability to use already open port. + * Dec 22, 1995 6.00 BP Added od_connect_speed. + * Dec 23, 1995 6.00 BP Added EDIT_FLAG_SHOW_SIZE. + * Dec 30, 1995 6.00 BP Added ODCALL for calling convention. + * Jan 01, 1996 6.00 BP BCC32 compatibility changes. + * Jan 01, 1996 6.00 BP Added new mulitline editor options. + * Jan 01, 1996 6.00 BP Added od_disable_dtr, DIS_DTR_DISABLE. + * Jan 03, 1996 6.00 BP Further BCC32 compatiblity changes. + * Jan 04, 1996 6.00 BP Added od_get_input() and related defs. + * Jan 07, 1996 6.00 BP Added OD_GLOBAL_CONV. + * Jan 19, 1996 6.00 BP Removed some unused stuff. + * Jan 19, 1996 6.00 BP Added od_internal_debug. + * Jan 23, 1996 6.00 BP Added od_exiting and ERR_UNSUPPORTED. + * Jan 30, 1996 6.00 BP New extern "C" decl for od_control. + * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep(). + * Jan 31, 1996 6.00 BP Added DIS_NAME_PROMPT. + * Jan 31, 1996 6.00 BP Added tODMilliSec, OD_NO_TIMEOUT. + * Jan 31, 1996 6.00 BP Added timeout for od_get_input(). + * Feb 02, 1996 6.00 BP Add RA 2.50-related od_control vars. + * Feb 03, 1996 6.00 BP Added more editor options. + * Feb 06, 1996 6.00 BP Added od_silent_mode. + * Feb 08, 1996 6.00 BP Added editor buffer grow option. + * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter. + * Feb 14, 1996 6.00 BP Recognize Borland's __WIN32__ define. + * Feb 17, 1996 6.00 BP Added OD_KEY_F1 thru OD_KEY_F10. + * Feb 19, 1996 6.00 BP Changed version number to 6.00. + * Feb 27, 1996 6.00 BP Added od_max_key_latency. + * Mar 03, 1996 6.10 BP Begin version 6.10. + * Mar 03, 1996 6.10 BP Fixed OD_COMPONENT for medium mem mod. + * Mar 06, 1996 6.10 BP Added TRIBBS.SYS support. + * Mar 06, 1996 6.10 BP Added COM_DOOR32. + * Mar 11, 1996 6.10 BP Added OD_VERSION. + * Mar 13, 1996 6.10 BP Added od_get_cursor(). + * Mar 13, 1996 6.10 BP Added od_local_win_col. + * Mar 14, 1996 6.10 BP Added od_config_callback. + * Mar 21, 1996 6.10 BP Added od_control_get(). + * Apr 08, 1996 6.10 BP Added command-line parsing callbacks. + * Oct 19, 2001 6.20 RS Added door32.sys and socket support. + * Oct 19, 2001 6.21 RS Fixed socket disconnect bug. + */ + +/* Only parse OpenDoor.h once. */ +#ifndef _INC_OPENDOOR +#define _INC_OPENDOOR + + +/* ========================================================================= */ +/* Version and platform definitions. */ +/* ========================================================================= */ + +/* OpenDoors API version number. */ +#define OD_VERSION 0x624 + +#define DIRSEP '\\' +#define DIRSEP_STR "\\" + +/* OpenDoors target platform. */ +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) +#define ODPLAT_WIN32 +#undef ODPLAT_DOS +#ifdef OD_WIN32_STATIC +#pragma message("Compiling for Win32 static version of OpenDoors") +#else /* !OD_WIN32_STATIC */ +#pragma message("Compiling for Win32 DLL version of OpenDoors") +#define OD_DLL +#endif /* !OD_WIN32_STATIC */ +#else /* !WIN32 */ +#if defined(__unix__) || defined(__NetBSD__) || defined(__APPLE__) +#define ODPLAT_NIX +#undef ODPLAT_DOS +#undef DIRSEP +#define DIRSEP '/' +#undef DIRSEP_STR +#define DIRSEP_STR "/" +#else +#define ODPLAT_DOS +#undef ODPLAT_WIN32 +#pragma message("Compiling for DOS version of OpenDoors") +#endif /* !NIX */ +#endif /* !WIN32 */ + + +/* Include any other headers required by OpenDoor.h. */ +#ifdef ODPLAT_WIN32 +#include "windows.h" +#endif /* ODPLAT_WIN32 */ + +/* For DLL versions, definitions of function or data that is exported from */ +/* a module or imported into a module. */ +#ifdef OD_DLL +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define OD_EXPORT __declspec(dllexport) +#else /* !_MSC_VER || __BORLANDC__ */ +#define OD_EXPORT _export +#endif /* !_MSC_VER */ +#define OD_IMPORT DECLSPEC_IMPORT +#else /* !OD_DLL */ +#define OD_EXPORT +#define OD_IMPORT +#endif /* !OD_DLL */ + +/* Definition of function naming convention used by OpenDoors. */ +#ifdef __cplusplus +#define OD_NAMING_CONVENTION extern "C" +#else /* !__cplusplus */ +#define OD_NAMING_CONVENTION +#endif /* !__cplusplus */ + +/* Definition of function calling convention used by OpenDoors. */ +#ifdef ODPLAT_WIN32 +#define ODCALL WINAPI +#define ODVCALL WINAPIV +#define OD_GLOBAL_CONV WINAPI +#else /* !ODPLAT_WIN32 */ +#define ODCALL +#define ODVCALL +#define OD_GLOBAL_CONV +#endif /* !ODPLAT_WIN32 */ + +/* OpenDoors API function declaration type. */ +#ifdef BUILDING_OPENDOORS +#define ODAPIDEF OD_NAMING_CONVENTION OD_EXPORT +#else /* !BUILDING_OPENDOORS */ +#define ODAPIDEF OD_NAMING_CONVENTION OD_IMPORT +#endif /* !BUILDING_OPENDOORS */ + +/* OpenDoors API global variable definition and declaration types. */ +#define OD_API_VAR_DEFN OD_NAMING_CONVENTION OD_EXPORT + +#ifdef BUILDING_OPENDOORS +#define OD_API_VAR_DECL extern OD_EXPORT +#else /* !BUILDING_OPENDOORS */ +#define OD_API_VAR_DECL extern OD_IMPORT +#endif /* !BUILDING_OPENDOORS */ + +/* Explicitly far pointers. */ +#ifdef ODPLAT_DOS +#define ODFAR far +#else /* !ODPLAT_DOS */ +#define ODFAR +#endif /* !ODPLAT_DOS */ + + +/* ========================================================================= */ +/* Primitive data types. */ +/* ========================================================================= */ + +/* Portable types that are the same size across all platforms */ +#ifndef ODPLAT_WIN32 +#ifndef BYTE +typedef unsigned char BYTE; /* Unsigned, 8 bits. */ +#endif +#ifndef WORD +typedef unsigned short WORD; /* Unsigned, 16 bits. */ +#endif +#ifndef DWORD +typedef unsigned long DWORD; /* Unsigned, 32 bits. */ +#endif +#ifndef CHAR +typedef char CHAR; /* Native character representation. */ +#endif +#define DWORD_DEFINED +#define WORD_DEFINED +#endif /* !ODPLAT_WIN32 */ + +typedef signed char INT8; /* Signed, 8 bits. */ +typedef signed short int INT16; /* Signed, 16 bits. */ +#ifndef ODPLAT_WIN32 /* avoid type redefinition from basetsd.h */ +typedef signed long int INT32; /* Signed, 32 bits. */ +#endif + + +/* Types that vary in size depending on platform. These are guranteed to be */ +/* at least the given size, but may be larger if this platform can */ +/* represent a larger value more efficiently (or as efficiently). */ +#ifndef ODPLAT_WIN32 +typedef int INT; /* Integer, at least 16 bits. */ +typedef unsigned int UINT; /* Unsigned integer, at least 16 bits. */ +#ifndef BOOL +typedef char BOOL; /* Boolean value, at least 1 bit. */ +#endif /* !BOOL */ +#endif /* !ODPLAT_WIN32 */ + +/* TRUE and FALSE manifest constants, for use with BOOL data type. */ +#ifndef FALSE +#define FALSE 0 +#endif /* !FALSE */ +#ifndef TRUE +#define TRUE 1 +#endif /* !TRUE */ + + +/* ========================================================================= */ +/* OpenDoors complex data types and defines. */ +/* ========================================================================= */ + +/* Millisecond time type. */ +typedef DWORD tODMilliSec; + +/* Special value tODMilliSec value for no timeouts. */ +#ifdef ODPLAT_WIN32 +#define OD_NO_TIMEOUT INFINITE +#else /* !ODPLAT_WIN32 */ +#define OD_NO_TIMEOUT 0xffffffffL +#endif /* !ODPLAT_WIN32 */ + + +/* Multi-line editor defintions. */ + +/* Editor text formats. */ +typedef enum +{ + FORMAT_PARAGRAPH_BREAKS + ,FORMAT_LINE_BREAKS + ,FORMAT_FTSC_MESSAGE + ,FORMAT_NO_WORDWRAP +} tODEditTextFormat; + +/* Menu callback function return values. */ +typedef enum +{ + EDIT_MENU_DO_NOTHING + ,EDIT_MENU_EXIT_EDITOR +} tODEditMenuResult; + +/* Editor flags. */ +#define EFLAG_NORMAL 0x00000000 + +/* Optional multi-line editor settings. */ +typedef struct +{ + INT nAreaLeft; + INT nAreaTop; + INT nAreaRight; + INT nAreaBottom; + tODEditTextFormat TextFormat; + tODEditMenuResult (*pfMenuCallback)(void *pUnused); + void * (*pfBufferRealloc)(void *pOriginalBuffer, UINT unNewSize); + DWORD dwEditFlags; + char *pszFinalBuffer; + UINT unFinalBufferSize; +} tODEditOptions; + +/* Editor return values. */ +#define OD_MULTIEDIT_ERROR 0 +#define OD_MULTIEDIT_SUCCESS 1 + + +/* Input event information. */ + +/* Input event types. */ +typedef enum +{ + EVENT_CHARACTER + ,EVENT_EXTENDED_KEY +} tODInputEventType; + +/* Extended key codes. */ +#define OD_KEY_F1 0x3b +#define OD_KEY_F2 0x3c +#define OD_KEY_F3 0x3d +#define OD_KEY_F4 0x3e +#define OD_KEY_F5 0x3f +#define OD_KEY_F6 0x40 +#define OD_KEY_F7 0x41 +#define OD_KEY_F8 0x42 +#define OD_KEY_F9 0x43 +#define OD_KEY_F10 0x44 +#define OD_KEY_UP 0x48 +#define OD_KEY_DOWN 0x50 +#define OD_KEY_LEFT 0x4b +#define OD_KEY_RIGHT 0x4d +#define OD_KEY_INSERT 0x52 +#define OD_KEY_DELETE 0x53 +#define OD_KEY_HOME 0x47 +#define OD_KEY_END 0x4f +#define OD_KEY_PGUP 0x49 +#define OD_KEY_PGDN 0x51 +#define OD_KEY_F11 0x85 +#define OD_KEY_F12 0x86 +#define OD_KEY_SHIFTTAB 0x0f + +/* Input event structure. */ +typedef struct +{ + tODInputEventType EventType; + BOOL bFromRemote; + char chKeyPress; +} tODInputEvent; + + +/* Third option (in addition to TRUE and FALSE) for tri-state options. */ +#define MAYBE 2 + +/* od_spawnvpe() flags. */ +#define P_WAIT 0 +#define P_NOWAIT 1 +#define CURRENT 0 +#define IRET 1 + +/* od_edit_str() flags. */ +#define EDIT_FLAG_NORMAL 0x0000 +#define EDIT_FLAG_NO_REDRAW 0x0001 +#define EDIT_FLAG_FIELD_MODE 0x0002 +#define EDIT_FLAG_EDIT_STRING 0x0004 +#define EDIT_FLAG_STRICT_INPUT 0x0008 +#define EDIT_FLAG_PASSWORD_MODE 0x0010 +#define EDIT_FLAG_ALLOW_CANCEL 0x0020 +#define EDIT_FLAG_FILL_STRING 0x0040 +#define EDIT_FLAG_AUTO_ENTER 0x0080 +#define EDIT_FLAG_AUTO_DELETE 0x0100 +#define EDIT_FLAG_KEEP_BLANK 0x0200 +#define EDIT_FLAG_PERMALITERAL 0x0400 +#define EDIT_FLAG_LEAVE_BLANK 0x0800 +#define EDIT_FLAG_SHOW_SIZE 0x1000 + +/* od_edit_str() return values. */ +#define EDIT_RETURN_ERROR 0 +#define EDIT_RETURN_CANCEL 1 +#define EDIT_RETURN_ACCEPT 2 +#define EDIT_RETURN_PREVIOUS 3 +#define EDIT_RETURN_NEXT 4 + +/* od_popup_menu() flag values. */ +#define MENU_NORMAL 0x0000 +#define MENU_ALLOW_CANCEL 0x0001 +#define MENU_PULLDOWN 0x0002 +#define MENU_KEEP 0x0004 +#define MENU_DESTROY 0x0008 + +/* od_autodetect() flag values. */ +#define DETECT_NORMAL 0x0000 + +/* od_scroll() flags. */ +#define SCROLL_NORMAL 0x0000 +#define SCROLL_NO_CLEAR 0x0001 + +/* OpenDoors status line settings */ +#define STATUS_NORMAL 0 +#define STATUS_NONE 8 +#define STATUS_ALTERNATE_1 1 +#define STATUS_ALTERNATE_2 2 +#define STATUS_ALTERNATE_3 3 +#define STATUS_ALTERNATE_4 4 +#define STATUS_ALTERNATE_5 5 +#define STATUS_ALTERNATE_6 6 +#define STATUS_ALTERNATE_7 7 + +/* OpenDoors color definitions. */ +#define D_BLACK 0 +#define D_BLUE 1 +#define D_GREEN 2 +#define D_CYAN 3 +#define D_RED 4 +#define D_MAGENTA 5 +#define D_BROWN 6 +#define D_GREY 7 +#define L_BLACK 8 +#define L_BLUE 9 +#define L_GREEN 10 +#define L_CYAN 11 +#define L_RED 12 +#define L_MAGENTA 13 +#define L_YELLOW 14 +#define L_WHITE 15 +#define B_BLACK L_BLACK +#define B_BLUE L_BLUE +#define B_GREEN L_GREEN +#define B_CYAN L_CYAN +#define B_RED L_RED +#define B_MAGENTA L_MAGENTA +#define B_BROWN L_YELLOW +#define B_GREY L_WHITE + +/* Door information file formats (od_control.od_info_type). */ +#define DORINFO1 0 /* DORINFO?.DEF */ +#define EXITINFO 1 /* QBBS 2.6? EXITINFO.BBS & DORINFO?.DEF */ +#define RA1EXITINFO 2 /* RA 1.?? EXITINFO.BBS & DORINFO?.DEF */ +#define CHAINTXT 3 /* CHAIN.TXT */ +#define SFDOORSDAT 4 /* SFDOORS.DAT */ +#define CALLINFO 5 /* CALLINFO.BBS */ +#define DOORSYS_GAP 6 /* GAP/PC-Board DOOR.SYS */ +#define DOORSYS_DRWY 7 /* DoorWay DOOR.SYS */ +#define QBBS275EXITINFO 8 /* QuickBBS 2.75+ EXITINFO.BBS */ +#define CUSTOM 9 /* User-defined custom format */ +#define DOORSYS_WILDCAT 10 /* WildCat! DOOR.SYS */ +#define RA2EXITINFO 11 /* RA 2.00+ EXITINFO.BBS */ +#define TRIBBSSYS 12 /* TRIBBS.SYS */ +#define DOOR32SYS 13 /* DOOR32.SYS */ +#define NO_DOOR_FILE 100 /* No door information file was found */ + +/* Error type (od_control.od_error). */ +#define ERR_NONE 0 /* No error yet */ +#define ERR_MEMORY 1 /* Unable to allocate enough memory */ +#define ERR_NOGRAPHICS 2 /* Function requires ANSI/AVATAR/RIP mode */ +#define ERR_PARAMETER 3 /* Invalid value was passed to a function */ +#define ERR_FILEOPEN 4 /* Unable to open file */ +#define ERR_LIMIT 5 /* An internal limit has been exceeded */ +#define ERR_FILEREAD 6 /* Unable to read from file */ +#define ERR_NOREMOTE 7 /* Function may not be called in local mode */ +#define ERR_GENERALFAILURE 8 /* Percise cause of failure is unknown */ +#define ERR_NOTHINGWAITING 9 /* A request for data when none was ready */ +#define ERR_NOMATCH 10 /* No match was found */ +#define ERR_UNSUPPORTED 11 /* Not supported in this version */ + +/* od_control.od_errorlevel indicies. */ +#define ERRORLEVEL_ENABLE 0 +#define ERRORLEVEL_CRITICAL 1 +#define ERRORLEVEL_NOCARRIER 2 +#define ERRORLEVEL_HANGUP 3 +#define ERRORLEVEL_TIMEOUT 4 +#define ERRORLEVEL_INACTIVITY 5 +#define ERRORLEVEL_DROPTOBBS 6 +#define ERRORLEVEL_NORMAL 7 + +/* Special od_popup_menu() return values. */ +#define POPUP_ERROR -1 +#define POPUP_ESCAPE 0 +#define POPUP_LEFT -2 +#define POPUP_RIGHT -3 + +/* od_get_input() flags. */ +#define GETIN_NORMAL 0x0000 +#define GETIN_RAW 0x0001 +#define GETIN_RAWCTRL 0x0002 + +/* od_control.od_box_chars array indicies. */ +#define BOX_UPPERLEFT 0 +#define BOX_TOP 1 +#define BOX_UPPERRIGHT 2 +#define BOX_LEFT 3 +#define BOX_LOWERLEFT 4 +#define BOX_LOWERRIGHT 5 +#define BOX_BOTTOM 6 +#define BOX_RIGHT 7 + +/* od_control.od_okaytopage settings. */ +#define PAGE_DISABLE 0 +#define PAGE_ENABLE 1 +#define PAGE_USE_HOURS 2 + +/* Method used for serial I/O (od_control.od_com_method). */ +#define COM_FOSSIL 1 +#define COM_INTERNAL 2 +#define COM_WIN32 3 +#define COM_DOOR32 4 +#define COM_SOCKET 5 +#define COM_STDIO 6 + +/* Flow control method (od_control.od_com_flow_control). */ +#define COM_DEFAULT_FLOW 0 +#define COM_RTSCTS_FLOW 1 +#define COM_NO_FLOW 2 + +/* Optional component initialization functions. */ +ODAPIDEF void ODCALL ODConfigInit(void); +ODAPIDEF void ODCALL ODLogEnable(void); +ODAPIDEF void ODCALL ODMPSEnable(void); + +/* Optional OpenDoors component settings. */ +typedef void(ODFAR OD_COMPONENT)(void); +#define INCLUDE_CONFIG_FILE (OD_COMPONENT *)ODConfigInit +#define NO_CONFIG_FILE NULL +#define INCLUDE_LOGFILE (OD_COMPONENT *)ODLogEnable +#define NO_LOGFILE NULL +#define INCLUDE_MPS (OD_COMPONENT *)ODMPSEnable +#define NO_MPS NULL + +/* Built-in personality defintion functions. */ +ODAPIDEF void ODCALL pdef_opendoors(BYTE btOperation); +ODAPIDEF void ODCALL pdef_pcboard(BYTE btOperation); +ODAPIDEF void ODCALL pdef_ra(BYTE btOperation); +ODAPIDEF void ODCALL pdef_wildcat(BYTE btOperation); + +/* Personality proc type. */ +typedef void(ODFAR OD_PERSONALITY_PROC)(BYTE); + +/* Personality identifiers. */ +#define PER_OPENDOORS (void *)pdef_opendoors +#define PER_PCBOARD (void *)pdef_pcboard +#define PER_RA (void *)pdef_ra +#define PER_WILDCAT (void *)pdef_wildcat + +/* od_control.od_disable flags. */ +#define DIS_INFOFILE 0x0001 +#define DIS_CARRIERDETECT 0x0002 +#define DIS_TIMEOUT 0x0004 +#define DIS_LOCAL_OVERRIDE 0x0008 +#define DIS_BPS_SETTING 0x0010 +#define DIS_LOCAL_INPUT 0x0020 +#define DIS_SYSOP_KEYS 0x0040 +#define DIS_DTR_DISABLE 0x0080 +#define DIS_NAME_PROMPT 0x0100 + +/* Event status settings. */ +#define ES_DELETED 0 +#define ES_ENABLED 1 +#define ES_DISABLED 2 + +/* Personality proceedure operations. */ +#define PEROP_DISPLAY1 0 +#define PEROP_DISPLAY2 1 +#define PEROP_DISPLAY3 2 +#define PEROP_DISPLAY4 3 +#define PEROP_DISPLAY5 4 +#define PEROP_DISPLAY6 5 +#define PEROP_DISPLAY7 6 +#define PEROP_DISPLAY8 7 +#define PEROP_UPDATE1 10 +#define PEROP_UPDATE2 11 +#define PEROP_UPDATE3 12 +#define PEROP_UPDATE4 13 +#define PEROP_UPDATE5 14 +#define PEROP_UPDATE6 15 +#define PEROP_UPDATE7 16 +#define PEROP_UPDATE8 17 +#define PEROP_INITIALIZE 20 +#define PEROP_CUSTOMKEY 21 +#define PEROP_DEINITIALIZE 22 + + +/* ========================================================================= */ +/* The OpenDoors control structure (od_control) */ +/* ========================================================================= */ + +/* Force byte alignment, if possible */ +#ifdef __TURBOC__ +#if(__TURBOC__ >= 0x295) +#pragma option -a- +#endif /* __TURBOC__ >= 0x295 */ +#endif /* __TURBOC__ */ +#ifdef _MSC_VER +#pragma pack(1) +#endif /* _MSC_VER */ + +typedef struct +{ + /* Location or name of door information file (if one is to be used). */ + char info_path[60]; + + /* Serial port settings. */ + DWORD baud; + DWORD od_connect_speed; + INT16 od_com_address; + BYTE od_com_irq; + BYTE od_com_method; + BYTE od_com_flow_control; + WORD od_com_rx_buf; + WORD od_com_tx_buf; + BYTE od_com_fifo_trigger; + BOOL od_com_no_fifo; + BOOL od_no_fossil; + BOOL od_use_socket; + INT16 port; + DWORD od_open_handle; + + /* Caller and system information. */ + char system_name[40]; + char sysop_name[40]; + INT32 system_calls; + char system_last_caller[36]; + char timelog_start_date[9]; + INT16 timelog_busyperhour[24]; + INT16 timelog_busyperday[7]; + + char user_name[36]; + char user_location[26]; + char user_password[16]; + char user_dataphone[16]; + char user_homephone[16]; + char user_lasttime[6]; + char user_lastdate[9]; + BYTE user_attribute; + BYTE user_flags[4]; + DWORD user_net_credit; + DWORD user_pending; + WORD user_messages; + DWORD user_lastread; + WORD user_security; + DWORD user_numcalls; + DWORD user_uploads; + DWORD user_downloads; + DWORD user_upk; + DWORD user_downk; + DWORD user_todayk; + WORD user_time_used; + WORD user_screen_length; + BYTE user_last_pwdchange; + BYTE user_attrib2; + WORD user_group; + + BYTE event_status; + char event_starttime[6]; + BYTE event_errorlevel; + BYTE event_days; + BYTE event_force; + char event_last_run[9]; + + BYTE user_netmailentered; + BYTE user_echomailentered; + char user_logintime[6]; + char user_logindate[9]; + INT16 user_timelimit; + INT32 user_loginsec; + INT32 user_credit; + WORD user_num; + INT16 user_readthru; + INT16 user_numpages; + INT16 user_downlimit; + char user_timeofcreation[6]; + char user_logonpassword[16]; + BYTE user_wantchat; + BYTE user_ansi; + INT16 user_deducted_time; + char user_menustack[50][9]; + BYTE user_menustackpointer; + char user_handle[36]; + char user_comment[81]; + char user_firstcall[9]; + BYTE user_combinedrecord[200]; + char user_birthday[9]; + char user_subdate[9]; + BYTE user_screenwidth; + BYTE user_language; + BYTE user_date_format; + char user_forward_to[36]; + BYTE user_error_free; + BYTE sysop_next; + BYTE user_emsi_session; + char user_emsi_crtdef[41]; + char user_emsi_protocols[41]; + char user_emsi_capabilities[41]; + char user_emsi_requests[41]; + char user_emsi_software[41]; + BYTE user_hold_attr1; + BYTE user_hold_attr2; + BYTE user_hold_len; + char user_reasonforchat[78]; + char user_callsign[12]; + WORD user_msg_area; + WORD user_file_area; + char user_protocol; + WORD user_file_group; + BYTE user_last_birthday_check; + char user_sex; + DWORD user_xi_record; + WORD user_msg_group; + BYTE user_avatar; + char user_org[51]; + char user_address[3][51]; + INT32 user_pwd_crc; + INT32 user_logon_pwd_crc; + char user_last_cost_menu[9]; + WORD user_menu_cost; + BYTE user_rip; + BYTE user_rip_ver; + BYTE user_attrib3; + BOOL user_expert; + char system_last_handle[36]; + + /* Door information file statistics. */ + BYTE od_info_type; + BYTE od_extended_info; + WORD od_node; + BYTE od_ra_info; + + /* Current program settings. */ + BOOL od_always_clear; + BOOL od_force_local; + BOOL od_chat_active; + BOOL od_current_statusline; + INT16 od_error; + BYTE od_last_input; + BOOL od_logfile_disable; + char od_logfile_name[80]; + WORD od_maxtime; + INT16 od_maxtime_deduction; + BOOL od_okaytopage; + INT16 od_pagestartmin; + INT16 od_pageendmin; + BOOL od_page_pausing; + INT16 od_page_statusline; + BOOL od_user_keyboard_on; + BOOL od_update_status_now; + INT16 od_cur_attrib; + + /* OpenDoors customization settings. */ + char od_box_chars[8]; + char od_cfg_text[48][33]; + char od_cfg_lines[25][33]; + OD_COMPONENT *od_config_file; + const char * od_config_filename; + void (*od_config_function)(char *keyword, char *options); + char od_color_char; + char od_color_delimiter; + char od_color_names[12][33]; + BOOL od_clear_on_exit; + void (*od_cmd_line_handler)(char *pszKeyword, char *pszOptions); + void (*od_cmd_line_help_func)(void); + void (*od_default_personality)(BYTE operation); + BOOL od_default_rip_win; + WORD od_disable; + char od_disable_dtr[40]; + BOOL od_disable_inactivity; + BOOL od_emu_simulate_modem; + BYTE od_errorlevel[8]; + BOOL od_full_color; + BOOL od_full_put; + WORD od_in_buf_size; + INT16 od_inactivity; + INT16 od_inactive_warning; + BOOL od_internal_debug; + tODMilliSec od_max_key_latency; + char od_list_pause; + char od_list_stop; + OD_COMPONENT *od_logfile; + char *od_logfile_messages[14]; + OD_COMPONENT *od_mps; + BOOL od_nocopyright; + BOOL od_noexit; + BOOL od_no_ra_codes; + BYTE od_page_len; + char od_prog_copyright[40]; + char od_prog_name[40]; + char od_prog_version[40]; + DWORD od_reg_key; + char od_reg_name[36]; + BOOL od_silent_mode; + BOOL od_status_on; + BOOL od_spawn_freeze_time; + BOOL od_swapping_disable; + BOOL od_swapping_noems; + char od_swapping_path[80]; + + /* Custom function hooks. */ + void (*od_no_file_func)(void); + void (*od_before_exit)(void); + void (*od_cbefore_chat)(void); + void (*od_cafter_chat)(void); + void (*od_cbefore_shell)(void); + void (*od_cafter_shell)(void); + void (*od_config_callback)(void); + void (*od_help_callback)(void); + void (*od_ker_exec)(void); + void (*od_local_input)(INT16 key); + void (*od_time_msg_func)(char *string); + + /* OpenDoors function key customizations. */ + WORD key_chat; + WORD key_dosshell; + WORD key_drop2bbs; + WORD key_hangup; + WORD key_keyboardoff; + WORD key_lesstime; + WORD key_lockout; + WORD key_moretime; + WORD key_status[9]; + WORD key_sysopnext; + + /* Additional function keys. */ + BYTE od_num_keys; + INT16 od_hot_key[16]; + INT16 od_last_hot; + void (*od_hot_function[16])(void); + + /* OpenDoors prompt customizations. */ + char * od_after_chat; + char * od_after_shell; + char * od_before_chat; + char * od_before_shell; + char * od_chat_reason; + char * od_continue; + char od_continue_yes; + char od_continue_no; + char od_continue_nonstop; + char * od_day[7]; + char * od_hanging_up; + char * od_exiting; + char * od_help_text; + char * od_help_text2; + char * od_inactivity_timeout; + char * od_inactivity_warning; + char * od_month[12]; + char * od_no_keyboard; + char * od_no_sysop; + char * od_no_response; + char * od_no_time; + char * od_offline; + char * od_paging; + char * od_press_key; + char * od_sending_rip; + char * od_status_line[3]; + char * od_sysop_next; + char * od_time_left; + char * od_time_warning; + char * od_want_chat; + char * od_cmd_line_help; + + /* OpenDoors color customizations. */ + BYTE od_chat_color1; + BYTE od_chat_color2; + BYTE od_list_comment_col; + BYTE od_list_name_col; + BYTE od_list_offline_col; + BYTE od_list_size_col; + BYTE od_list_title_col; + BYTE od_local_win_col; + BYTE od_continue_col; + BYTE od_menu_title_col; + BYTE od_menu_border_col; + BYTE od_menu_text_col; + BYTE od_menu_key_col; + BYTE od_menu_highlight_col; + BYTE od_menu_highkey_col; + + /* Platform-specific settings. */ +#ifdef ODPLAT_WIN32 + HICON od_app_icon; + int od_cmd_show; +#endif /* ODPLAT_WIN32 */ +} tODControl; + +/* Restore original structure alignment, if possible. */ +#ifdef _MSC_VER +#pragma pack() +#endif /* _MSC_VER */ + + +/* The od_control external variable. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +OD_API_VAR_DECL tODControl +#ifndef _WIN32 /* warning C4229: anachronism used : modifiers on data are ignored */ +OD_GLOBAL_CONV +#endif +od_control; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +/* ========================================================================= */ +/* OpenDoors API function prototypes. */ +/* ========================================================================= */ + +/* Programs interface with OpenDoors by calling any of the OpenDoors API + * functions. A summary of these functions appears below, followed by the + * function definition prototypes. Full information on these functions is + * provided by the OpenDoors manual. Functions denoted (ANS/AVT) require ANSI + * or AVATAR display modes to be active. + * + * OUTPUT FUNCTIONS - TEXT DISPLAY + * od_printf() - Performs formatted output, with color settings + * od_disp_str() - Displays a normal, nul-terminated string. + * od_disp() - Sends chars to modem, with/without local echo + * od_disp_emu() - Displays a string, translating ANSI/AVT codes + * od_repeat() - Efficiently displays a character repeatedly + * od_putch() - Displays a single character. + * + * OUTPUT FUNCTIONS - COLOUR AND CURSOR CONTROL + * od_set_color() - Sets color according to fore/background values + * od_set_attrib() - Sets color to specified IBM-PC attribute + * od_set_cursor() - Positions cursor on screen (ANS/AVT) + * od_get_cursor() - Estimates the current cursor position on screen + * + * OUTPUT FUNCTIONS - SCREEN MANIPULATION + * od_clr_scr() - Clears the screen + * od_save_screen() - Saves the contents of entire screen + * od_restore_screen() - Restores the contents of entire screen + * + * OUTPUT FUNCTIONS - BLOCK MANIPULATION + * od_clr_line() - Clears the remainder of the current line + * od_gettext() - Gets the contents a block of screen (ANS/AVT) + * od_puttext() - Displays block stored by gettext() (ANS/AVT) + * od_scroll() - Scrolls a portion of the screen (ANS/AVT) + * + * OUTPUT FUNCTIONS - WINDOWS & MENUS + * od_draw_box() - Draws a box on the screen (ANS/AVT) + * od_window_create() - Creates a window, storing underlying (ANS/AVT) + * od_window_remove() - Removes window, restoring underlying (ANS/AVT) + * od_popup_menu() - Displays popup menu with "light" bar (ANS/AVT) + * + * OUTPUT FUNCTIONS - FILE DISPLAY + * od_send_file() - Displays an ASCII/ANSI/AVATAR/RIP file + * od_hotkey_menu() - Displays ASC/ANS/AVATAR/RIP menu, with hotkeys + * od_list_files() - Lists files avail for download using FILES.BBS + * + * INPUT FUNCTIONS + * od_get_answer() - Inputs a key, allowing only specified responses + * od_get_key() - Inputs a key, optionally waiting for next key + * od_get_input() - Obtains next input, with translation + * od_input_str() - Inputs string of specified length from keyboard + * od_edit_str() - Fancy formatted string input function (ANS/AVT) + * od_clear_keybuffer() - Removes any waiting keys in keyboard buffer + * od_multiline_edit() - Edits text that spans multiple lines (ANS/AVT) + * od_key_pending() - Returns TRUE if a key is waiting to be processed + * + * COMMON DOOR ACTIVITY FUNCTIONS + * od_page() - Allows user to page sysop + * od_spawn() - Suspends OpenDoors & starts another program + * od_spawnvpe() - Like od_spawn, but with more options + * od_log_write() - Writes a logfile entry + * od_parse_cmd_line() - Handles standard command-line parameters + * + * SPECIAL CONTROL FUNCTIONS + * od_init() - Forces OpenDoors initialization + * od_color_config() - Translates color description to color value + * od_add_personality() - Adds another local interface personality + * od_set_statusline() - Sets the current status line setting + * od_autodetect() - Determines the remote system terminal type + * od_kernel() - Call when not calling other functions + * od_exit() - Ends OpenDoors program + * od_carrier() - Indicates whether remote connection is present + * od_set_dtr() - Raises / lowers the DTR signal to the modem + * od_chat() - Manually starts chat mode + * od_sleep() - Yield to other processes + * od_control_get() - Returns a pointer to the od_control structure. + */ +ODAPIDEF BOOL ODCALL od_add_personality(const char *pszName, BYTE btOutputTop, + BYTE btOutputBottom, + OD_PERSONALITY_PROC *pfPerFunc); +ODAPIDEF void ODCALL od_autodetect(INT nFlags); +ODAPIDEF BOOL ODCALL od_carrier(void); +ODAPIDEF void ODCALL od_chat(void); +ODAPIDEF void ODCALL od_clear_keybuffer(void); +ODAPIDEF void ODCALL od_clr_line(void); +ODAPIDEF void ODCALL od_clr_scr(void); +ODAPIDEF BYTE ODCALL od_color_config(char *pszColorDesc); +ODAPIDEF tODControl * ODCALL od_control_get(void); +ODAPIDEF void ODCALL od_disp(const char *pachBuffer, INT nSize, BOOL bLocalEcho); +ODAPIDEF void ODCALL od_disp_emu(const char *pszToDisplay, BOOL bRemoteEcho); +ODAPIDEF void ODCALL od_disp_str(const char *pszToDisplay); +ODAPIDEF BOOL ODCALL od_draw_box(BYTE btLeft, BYTE btTop, BYTE btRight, + BYTE btBottom); +ODAPIDEF WORD ODCALL od_edit_str(char *pszInput, char *pszFormat, INT nRow, + INT nColumn, BYTE btNormalColour, + BYTE btHighlightColour, char chBlank, + WORD nFlags); +ODAPIDEF void ODCALL od_exit(INT nErrorLevel, BOOL bTermCall); +ODAPIDEF char ODCALL od_get_answer(const char *pszOptions); +ODAPIDEF void ODCALL od_get_cursor(INT *pnRow, INT *pnColumn); +ODAPIDEF BOOL ODCALL od_get_input(tODInputEvent *pInputEvent, + tODMilliSec TimeToWait, WORD wFlags); +ODAPIDEF BOOL ODCALL od_key_pending(void); +ODAPIDEF char ODCALL od_get_key(BOOL bWait); +ODAPIDEF BOOL ODCALL od_gettext(INT nLeft, INT nTop, INT nRight, + INT nBottom, void *pBlock); +ODAPIDEF char ODCALL od_hotkey_menu(char *pszFileName, char *pszHotKeys, + BOOL bWait); +ODAPIDEF void ODCALL od_init(void); +ODAPIDEF void ODCALL od_input_str(char *pszInput, INT nMaxLength, + unsigned char chMin, unsigned char chMax); +ODAPIDEF void ODCALL od_kernel(void); +ODAPIDEF BOOL ODCALL od_list_files(char *pszFileSpec); +ODAPIDEF BOOL ODCALL od_log_write(char *pszMessage); +ODAPIDEF INT ODCALL od_multiline_edit(char *pszBufferToEdit, + UINT unBufferSize, tODEditOptions *pEditOptions); +ODAPIDEF void ODCALL od_page(void); +#ifdef ODPLAT_WIN32 +ODAPIDEF void ODCALL od_parse_cmd_line(LPSTR pszCmdLine); +#else /* !ODPLAT_WIN32 */ +ODAPIDEF void ODCALL od_parse_cmd_line(INT nArgCount, + char *papszArguments[]); +#endif /* !ODPLAT_WIN32 */ +ODAPIDEF INT ODCALL od_popup_menu(char *pszTitle, char *pszText, + INT nLeft, INT nTop, INT nLevel, WORD uFlags); +ODAPIDEF void ODVCALL od_printf(const char *pszFormat, ...); +ODAPIDEF void ODCALL od_putch(char chToDisplay); +ODAPIDEF BOOL ODCALL od_puttext(INT nLeft, INT nTop, INT nRight, + INT nBottom, void *pBlock); +ODAPIDEF void ODCALL od_repeat(char chValue, BYTE btTimes); +ODAPIDEF BOOL ODCALL od_restore_screen(void *pBuffer); +ODAPIDEF BOOL ODCALL od_save_screen(void *pBuffer); +ODAPIDEF BOOL ODCALL od_scroll(INT nLeft, INT nTop, INT nRight, + INT nBottom, INT nDistance, WORD nFlags); +ODAPIDEF BOOL ODCALL od_send_file(const char *pszFileName); +ODAPIDEF BOOL ODCALL od_send_file_section(char *pszFileName, char *pszSectionName); +ODAPIDEF void ODCALL od_set_attrib(INT nColour); +ODAPIDEF void ODCALL od_set_color(INT nForeground, INT nBackground); +ODAPIDEF void ODCALL od_set_cursor(INT nRow, INT nColumn); +ODAPIDEF void ODCALL od_set_dtr(BOOL bHigh); +ODAPIDEF BOOL ODCALL od_set_personality(const char *pszName); +ODAPIDEF void ODCALL od_set_statusline(INT nSetting); +ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds); +ODAPIDEF BOOL ODCALL od_spawn(const char *pszCommandLine); +ODAPIDEF INT16 ODCALL od_spawnvpe(INT16 nModeFlag, char *pszPath, + char *papszArg[], char *papszEnv[]); +ODAPIDEF void * ODCALL od_window_create(INT nLeft, INT nTop, INT nRight, + INT nBottom, char *pszTitle, BYTE btBorderCol, + BYTE btTitleCol, BYTE btInsideCol, INT nReserved); +ODAPIDEF BOOL ODCALL od_window_remove(void *pWinInfo); + + +/* ========================================================================= */ +/* Definitions for compatibility with previous versions. */ +/* ========================================================================= */ + +/* Alternative spelling for the word color (colour). */ +#define od_chat_colour1 od_chat_color1 +#define od_chat_colour2 od_chat_color2 +#define od_colour_char od_color_char +#define od_colour_delimiter od_color_delimiter +#define od_colour_names od_color_names +#define od_full_colour od_full_color +#define od_colour_config od_color_config +#define od_set_colour od_set_color + +/* Definitions for renamed od_control members and manifest constants. */ +#define key_help key_status[6] +#define key_nohelp key_status[0] +#define user_credit user_net_credit +#define caller_netmailentered user_netmailentered +#define caller_echomailentered user_echomailentered +#define caller_logintime user_logintime +#define caller_logindate user_logindate +#define caller_timelimit user_timelimit +#define caller_loginsec user_loginsec +#define caller_credit user_credit +#define caller_userrecord user_num +#define caller_readthru user_readthru +#define caller_numpages user_numpages +#define caller_downlimit user_downlimit +#define caller_timeofcreation user_timeofcreation +#define caller_logonpassword user_logonpassword +#define caller_wantchat user_wantchat +#define caller_ansi user_ansi +#define ra_deducted_time user_deducted_time +#define ra_menustack user_menustack +#define ra_menustackpointer user_menustackpointer +#define ra_userhandle user_handle +#define ra_comment user_comment +#define ra_firstcall user_firstcall +#define ra_combinedrecord user_combinedrecord +#define ra_birthday user_birthday +#define ra_subdate user_subdate +#define ra_screenwidth user_screenwidth +#define ra_msg_area user_msg_area +#define ra_file_area user_file_area +#define ra_language user_language +#define ra_date_format user_date_format +#define ra_forward_to user_forward_to +#define ra_error_free user_error_free +#define ra_sysop_next sysop_next +#define ra_emsi_session user_emsi_session +#define ra_emsi_crtdef user_emsi_crtdef +#define ra_emsi_protocols user_emsi_protocols +#define ra_emsi_capabilities user_emsi_capabilities +#define ra_emsi_requests user_emsi_requests +#define ra_emsi_software user_emsi_software +#define ra_hold_attr1 user_hold_attr1 +#define ra_hold_attr2 user_hold_attr2 +#define ra_hold_len user_hold_len +#define caller_usernum user_num +#define caller_callsign user_callsign +#define caller_sex user_sex +#define od_avatar user_avatar +#define B_YELLOW L_YELLOW +#define B_WHITE L_WHITE +#define od_rbbs_node od_node +#define STATUS_USER1 STATUS_ALTERNATE_1 +#define STATUS_USER2 STATUS_ALTERNATE_2 +#define STATUS_USER3 STATUS_ALTERNATE_3 +#define STATUS_USER4 STATUS_ALTERNATE_4 +#define STATUS_SYSTEM STATUS_ALTERNATE_5 +#define STATUS_HELP STATUS_ALTERNATE_7 +#define od_registered_to od_control.od_reg_name +#define od_registration_key od_control.od_reg_key +#define od_program_name od_control.od_prog_name +#define od_log_messages od_control.od_logfile_messages +#define od_config_text od_control.od_cfg_text +#define od_config_lines od_control.od_cfg_lines +#define od_config_colours od_control.od_colour_names +#define od_config_colors od_control.od_colour_names +#define config_file od_config_file +#define config_filename od_config_filename +#define config_function od_config_function +#define default_personality od_default_personality +#define logfile od_logfile +#define mps od_mps +#define od_kernal od_kernel + +/* Obsolete functions. */ +#define od_init_with_config(filename,function)\ + od_control.config_file=INCLUDE_CONFIG_FILE;\ + od_control.config_filename=filename;\ + od_control.config_function=function;\ + od_init() +ODAPIDEF BOOL ODCALL od_log_open(void); +ODAPIDEF void ODCALL od_emulate(register char in_char); + +#endif /* _INC_OPENDOOR */ diff --git a/utils/magiedit/odoors/README.NIX b/utils/magiedit/odoors/README.NIX new file mode 100644 index 0000000..e69de29 diff --git a/utils/magiedit/odoors/TODO-v7.txt b/utils/magiedit/odoors/TODO-v7.txt new file mode 100644 index 0000000..2d2d8b4 --- /dev/null +++ b/utils/magiedit/odoors/TODO-v7.txt @@ -0,0 +1,36 @@ +Features/Changes which will break the API and so must go into v7 +---------------------------------------------------------------- +- Do not pack the od_control structure in memory. This is plain silly. +- Do not use the BOOL type in od_control or in any of the public functions. + Using it causes problems with stuff that defines a BOOL as a different + size. For example, xpdev uses int as a BOOL whereas OpenDoors uses a char. +- Support telnet IAC escaping, add an item to the od_control struct to + keep track of the current status of IAC escapes. +- Fix up the local display for Win32. It's horribly slow currently. + Possibly just dust of the DOS stuff and use ciolib? +- Make output functions take an optional position and attribute to cut down + on small send()s. +- Audit for small send()s in general. +- Possibly improve the output thread and make *nix multi-threaded for block + buffering ala Synchronet. +- Change to 24-line default. This means fixing the personalities, and the + screen stuff. +- Autodetect if passed handle is a socket (Like I did for MyCroft doors) +- We need some non-socket way of dealing with I/O for Win32. Something that + operates along the lines of stdio on *nix. When BBSs commonly start doing + SSH, is the door supposed to do SSH also? A local socket would work, but it + seems like the Wrong Thing. The main reason stdio is out is that there's no + standard way of passing hangup info etc. +- Check the timestamp on the dropfile... do not use an old one! Add and + od_control variable to prevent this behaviour. +- Add a bunch of status-line specific functions to allow new personalities: + od_status_set_cursor() + od_status_set_attrib() + od_status_puttext() + od_status_gettext() + od_status_printf() + od_status_disp_str() + od_status_putch() + od_status_addkey() + od_status_delkey() +- OD_DISP_EMU() has problems with ANSI music (of course) diff --git a/utils/magiedit/odoors/Toolbar.bmp b/utils/magiedit/odoors/Toolbar.bmp new file mode 100644 index 0000000..3c0b88c Binary files /dev/null and b/utils/magiedit/odoors/Toolbar.bmp differ diff --git a/utils/magiedit/odoors/buildall.bat b/utils/magiedit/odoors/buildall.bat new file mode 100644 index 0000000..7de401d --- /dev/null +++ b/utils/magiedit/odoors/buildall.bat @@ -0,0 +1,7 @@ +make -fDOS.mak -DTARGET=s > out.txt +make -fDOS.mak -DTARGET=c >> out.txt +make -fDOS.mak -DTARGET=m >> out.txt +make -fDOS.mak -DTARGET=l >> out.txt +make -fDOS.mak -DTARGET=h >> out.txt +set INCLUDE=c:\msdev\include;c:\msdev\mfc\include +nmake -fWin32.mak >> out.txt diff --git a/utils/magiedit/odoors/builddos.bat b/utils/magiedit/odoors/builddos.bat new file mode 100644 index 0000000..15746df --- /dev/null +++ b/utils/magiedit/odoors/builddos.bat @@ -0,0 +1,5 @@ +make -fDOS.mak -DTARGET=s > out.txt +make -fDOS.mak -DTARGET=c >> out.txt +make -fDOS.mak -DTARGET=m >> out.txt +make -fDOS.mak -DTARGET=l >> out.txt +make -fDOS.mak -DTARGET=h >> out.txt diff --git a/utils/magiedit/odoors/ex_chat.c b/utils/magiedit/odoors/ex_chat.c new file mode 100644 index 0000000..3448b26 --- /dev/null +++ b/utils/magiedit/odoors/ex_chat.c @@ -0,0 +1,346 @@ +/* EX_CHAT.C - Example of a multi-window full-screen chat program written */ +/* with OpenDoors. See manual for instructions on how to compile */ +/* a program using OpenDoors. */ +/* */ +/* This program shows how to do the following: */ +/* */ +/* - Replace the standard OpenDoors chat mode with your own */ +/* chat mode implementation. See instructions below. */ +/* - How to scroll a portion of the screen, leaving the rest */ +/* of the screen unaltered. */ +/* - How to determine whether input came from the local or */ +/* remote keyboard. */ +/* - How to display a popup window with a message in it when */ +/* the sysop shells to DOS. (DOS version only.) */ +/* - How to save and restore the entire contents of the */ +/* screen. */ +/* */ +/* Conditional compilation directives allow this program to */ +/* be compiled as a stand-alone chat door, or as a */ +/* replacement chat mode to be integrated into any OpenDoors */ +/* program. If STANDALONE is #defined, ex_chat.c will be */ +/* compiled as a split-screen chat door that can be run like */ +/* any door program. If STANDALONE is not #defined, the chat */ +/* mode function will be compiled as a replacement chat mode */ +/* for the chat mode built into OpenDoors. In this case, the */ +/* demo mainline function simply displays a prompt, and will */ +/* exit the door as soon as you press the [ENTER] key. While */ +/* the program is running, if you invoke chat mode (press */ +/* [ALT]-[C]), the current screen will be saved and the */ +/* split-screen chat mode will be activated. When you press */ +/* [ESC] the split-screen chat mode will end, and the */ +/* original screen will be restored. To integrate this chat */ +/* mode into your own program, you should simply set */ +/* od_control.od_cbefore_chat to point to the */ +/* fullscreen_chat function, as shown, and remove the mainline */ +/* (main()/WinMain()) function from this file. The compile this */ +/* file into your program after removing the #define STANDALONE */ +/* line. */ + +/* Include required header files. */ +#include "OpenDoor.h" +#include + + +/* The following #define forces this code to compile as a stand-alone door */ +/* program. If you wish to use this code to replace the standard OpenDoors */ +/* chat mode in your own program, remove this #define. */ +#define STANDALONE + + +/* Full-screen chat function prototypes. */ +void fullscreen_chat(void); +void chat_new_line(void); +void display_shell_window(void); +void remove_shell_window(void); + + + +/* The main() or WinMain() function: program execution begins here. */ +#ifdef ODPLAT_WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +#else +int main(int argc, char *argv[]) +#endif +{ + /* Handle standard command-line options and perform other needed setup. */ +#ifdef ODPLAT_WIN32 + od_control.od_cmd_show = nCmdShow; + od_parse_cmd_line(lpszCmdLine); +#else + od_parse_cmd_line(argc, argv); +#endif + +#ifdef STANDALONE /* If compiled as a stand-alone chat program */ + od_init(); /* Initialize OpenDoors */ + + fullscreen_chat(); /* Invoke full-screen chat function */ + +#else /* If compiled as replacement for OpenDoors chat mode */ + /* Setup OpenDoors to use our custom chat mode instead */ + od_control.od_cbefore_chat=fullscreen_chat; + + od_printf("Press [Enter] to exit door, or invoke chat mode.\n\r"); + od_get_answer("\n\r"); +#endif + + od_exit(0, FALSE); /* Exit program. */ + return(0); +} + + + + + + /* FULL-SCREEN CHAT CUSTOMIZATION OPTIONS */ + +char window_colour[2]={0x0b,0x0c}; /* Text colour used for each person */ +char bar_colour=0x70; /* Colour of window seperation bar */ +char top_line[2]={13,1}; /* Specifies location of each window on screen */ +char bottom_line[2]={23,11}; /* Line number of bottom of each window */ +char bar_line=12; /* Line number of window seperation bar */ +char scroll_distance=2; /* Distance to scroll window when required */ +char shell_window_title=0x1a; /* Colour of title of DOS shell notice window */ +char shell_window_boarder=0x1f; /* Colour of DOS shell window boarder */ +char shell_window_text=0x1b; /* Colour of text in DOS shell window */ + + + +int cursor_window; /* FULL-SCREEN CHAT INTERNAL VARIABLES */ +char current_word[2][81]; +int word_length[2]; +int cursor_col[2]; +int cursor_line[2]; +unsigned char key; +int old_chat_key; +void *shell_window; +char *before_shell_text; +char *after_shell_text; +#ifndef STANDALONE /* If compiled as replacement for OpenDoors chat mode */ +char screen_buffer[4004]; +#endif + + /* FULL-SCREEN CHAT FUNCTION */ +void fullscreen_chat(void) +{ + cursor_window=0; /* Reset working variables */ + word_length[0]=word_length[1]=0; + cursor_col[0]=cursor_col[1]=1; + cursor_line[0]=top_line[0]; + cursor_line[1]=top_line[1]; + + + /* If ANSI or AVATAR graphics mode is not available */ + if(!od_control.user_ansi && !od_control.user_avatar) + { /* Then use OpenDoor's line chat mode instead */ +#ifdef STANDALONE /* If compiled as a stand-alone chat program */ + od_chat(); +#endif + return; + } + + od_control.od_cbefore_shell=display_shell_window; /* Set shell settings */ + od_control.od_cafter_shell=remove_shell_window; + before_shell_text=od_control.od_before_shell; + after_shell_text=od_control.od_after_shell; + od_control.od_before_shell=NULL; + od_control.od_after_shell=NULL; + od_control.od_chat_active=TRUE; + +#ifdef STANDALONE /* If compiled as a stand-alone chat program */ + old_chat_key=od_control.key_chat; /* Prevent internal chat mode from */ + od_control.key_chat=0; /* being invoked */ + +#else /* If compiled as replacement for OpenDoors chat mode */ + od_save_screen(screen_buffer); /* Save current screen contents. */ +#endif + + /* DRAW THE CHAT SCREEN */ + od_set_attrib(window_colour[0]); + od_clr_scr(); /* Clear the screen */ + + od_set_cursor(bar_line,1); /* Draw window separation bar */ + od_set_attrib(bar_colour); + od_clr_line(); + od_set_cursor(bar_line,67); + od_printf("Ctrl-A: Clear"); + od_set_cursor(bar_line,1); + od_printf(" Top : %-.28s Bottom : %-.28s ", + od_control.sysop_name, od_control.user_name); + + od_set_cursor(top_line[0],1); /* Locate cursor where typing will begin */ + od_set_attrib(window_colour[0]); /* Set appropriate text colour */ + + /* MAIN CHAT LOOP */ + for(;;) /* (Repeats for each character typed) */ + { + do + { + key=(char)od_get_key(FALSE); /* Get next keystroke from keyboard */ + + /* CHECK FOR SYSOP ABORT */ + if((key==27 && od_control.od_last_input==1) /* If sysop pressed ESC */ + || !od_control.od_chat_active) + { + od_set_attrib(0x07); /* Reset display colour */ + od_clr_scr(); /* Clear the screen */ + + od_control.od_cbefore_shell=NULL; /* Restore DOS shell settings */ + od_control.od_cafter_shell=NULL; + od_control.od_before_shell=before_shell_text; + od_control.od_after_shell=after_shell_text; +#ifdef STANDALONE /* If compiled as a stand-alone chat program */ + od_control.key_chat=old_chat_key;/* Re-enable internal chat mode */ + +#else /* If compiled as replacement for OpenDoors chat mode */ + od_control.od_chat_active=FALSE; /* Turn off chat mode */ + od_restore_screen(screen_buffer); /* Restore orignal screen */ +#endif + return; /* Exit full-screen chat */ + + } + } while(key==0); + + /* CHECK FOR NEW TYPIST */ + if(od_control.od_last_input!=cursor_window)/* If new person typing now */ + { /* Switch cursor to appropriate window */ + cursor_window=od_control.od_last_input; /* Set current typist */ + + /* Move cursor to new window */ + od_set_cursor(cursor_line[cursor_window],cursor_col[cursor_window]); + + od_set_attrib(window_colour[cursor_window]); /* Change text colour */ + } + + + if(key==13 || key==10) /* IF USER PRESSED [ENTER] / [RETURN] */ + { + word_length[cursor_window]=0; /* Enter constitutes end of word */ + + chat_new_line(); /* Move to next line */ + } + + + else if(key==8) /* IF USER PRESS [BACKSPACE] */ + { + if(cursor_col[cursor_window] > 1) /* If not at left of screen */ + { + --cursor_col[cursor_window]; /* Move cursor back on character */ + if(word_length[cursor_window] > 0) --word_length[cursor_window]; + od_printf("\b \b"); /* Erase last character from screen */ + } + } + + + else if(key==32) /* IF USER PRESSED [SPACE] */ + { + word_length[cursor_window]=0; /* [Space] constitutes end of word */ + + if(cursor_col[cursor_window]==79) /* If at end of line */ + chat_new_line(); /* Move cursor to next line */ + else /* If not at end of line */ + { + ++cursor_col[cursor_window]; /* Increment cursor position */ + od_putch(32); /* Display a space */ + } + } + + + else if(key==1) /* IF USER PRESSED CLEAR WINDOW KEY */ + { /* Clear user's window */ + od_scroll(1,top_line[cursor_window],79,bottom_line[cursor_window], + bottom_line[cursor_window]-top_line[cursor_window]+1,0); + + word_length[cursor_window]=0; /* We are no longer composing a word */ + + cursor_col[cursor_window]=1; /* Reset cursor position */ + cursor_line[cursor_window]=top_line[cursor_window]; + od_set_cursor(cursor_line[cursor_window],cursor_col[cursor_window]); + } + + + else if(key>32) /* IF USER TYPED A PRINTABLE CHARACTER */ + { /* PERFORM WORD WRAP IF NECESSARY */ + if(cursor_col[cursor_window]==79) /* If cursor is at end of line */ + { + /* If there is a word to wrap */ + if(word_length[cursor_window]>0 && word_length[cursor_window]<78) + { + /* Move cursor to beginning of word */ + od_set_cursor(cursor_line[cursor_window], + cursor_col[cursor_window]-word_length[cursor_window]); + + od_clr_line(); /* Erase word from current line */ + + chat_new_line(); /* Move cursor to next line */ + + /* Redisplay word */ + od_disp(current_word[cursor_window],word_length[cursor_window], + TRUE); + cursor_col[cursor_window]+=word_length[cursor_window]; + } + + else /* If there is no word to "wrap" */ + { + chat_new_line(); /* Move cursor to next line */ + word_length[cursor_window]=0; /* Start a new word */ + } + } + + /* ADD CHARACTER TO CURRENT WORD */ + /* If there is room for more character in word */ + if(strlen(current_word[cursor_window])<79) /* Add new character */ + current_word[cursor_window][word_length[cursor_window]++]=key; + + /* DISPLAY NEWLY TYPED CHARACTER */ + ++cursor_col[cursor_window]; + od_putch(key); + } + } +} + + + + /* FUNCTION USED BY FULL-SCREEN CHAT TO START A NEW INPUT LINE */ +void chat_new_line(void) +{ /* If cursor is at bottom of window */ + if(cursor_line[cursor_window]==bottom_line[cursor_window]) + { /* Scroll window up one line on screen */ + od_scroll(1,top_line[cursor_window],79, bottom_line[cursor_window], + scroll_distance, 0); + cursor_line[cursor_window]-=(scroll_distance - 1); + } + + else /* If cursor is not at bottom of window */ + { + ++cursor_line[cursor_window]; /* Move cursor down one line */ + } + + /* Move cursor's position on screen */ + od_set_cursor(cursor_line[cursor_window],cursor_col[cursor_window]=1); + + od_set_attrib(window_colour[cursor_window]); /* Change text colour */ +} + + +void display_shell_window(void) +{ + if((shell_window=od_window_create(17,9,63,15,"DOS Shell", + shell_window_boarder, shell_window_title, + shell_window_text, 0))==NULL) return; + + od_set_attrib(shell_window_text); + od_set_cursor(11,26); + od_printf("The Sysop has shelled to DOS"); + od_set_cursor(13,21); + od_printf("He/She will return in a few moments..."); +} + + +void remove_shell_window(void) +{ + od_window_remove(shell_window); + od_set_cursor(cursor_line[cursor_window],cursor_col[cursor_window]); + od_set_attrib(window_colour[cursor_window]); +} diff --git a/utils/magiedit/odoors/ex_diag.c b/utils/magiedit/odoors/ex_diag.c new file mode 100644 index 0000000..f6208f4 --- /dev/null +++ b/utils/magiedit/odoors/ex_diag.c @@ -0,0 +1,578 @@ +/* ex_diag.c - Diagnostic door program, written to test environment in which + * an OpenDooors door will run. Reads configuration settings from + * command line and configuration file, and displays diagnostic + * information on the local (and when possible, remote) screens. + */ + +#include +#include +#include + +#include "OpenDoor.h" + +/******************/ +/* Wrapper macros */ +/******************/ +#if defined(__unix__) + #if !defined(stricmp) + #define stricmp(x,y) strcasecmp(x,y) + #define strnicmp(x,y,z) strncasecmp(x,y,z) + #endif +#endif + +typedef enum +{ + kParamLocal, + kParamBPS, + kParamPort, + kParamNode, + kParamHelp, + kParamPersonality, + kParamMaxTime, + kParamAddress, + kParamIRQ, + kParamNoFOSSIL, + kParamNoFIFO, + kParamDropFile, + kParamUserName, + kParamTimeLeft, + kParamSecurity, + kParamLocation, + kParamUnknown +} tCommandLineParameter; + +char *BoolAsStr(int bValue); +void ParseStandardCommandLine(int nArgCount, char *papszArguments[]); +static void AdvanceToNextArg(int *pnCurrentArg, int nArgCount, + char *pszOption); +static void GetNextArgName(int *pnCurrentArg, int nArgCount, + char *papszArguments[], char *pszString, + int nStringSize); +static tCommandLineParameter GetCommandLineParameter(char *pszArgument); + + +int main(int argc, char *argv[]) +{ + char sz[80]; + int n; + + /* Parse command-line. */ + ParseStandardCommandLine(argc, argv); + + /* Initialize OpenDoors. */ + od_init(); + + od_clr_scr(); + + od_printf("OpenDoors has been initialized.\n\r"); + for(;;) + { + od_printf("\n\rPOST-INITIALIZATION DIAGNOSTIC INFORMATION:\n\r"); + od_printf(" Running in REMOTE mode : %s\n\r", + BoolAsStr(od_control.baud)); + od_printf(" Port <-> Modem BPS Rate : %lu\n\r", od_control.baud); + od_printf(" Serial Port Number : %d (COM%d:)\n\r", od_control.port, + od_control.port + 1); + od_printf(" Serial I/O Method : "); + switch(od_control.od_com_method) + { + case COM_FOSSIL: + od_printf("FOSSIL Driver\n\r"); + break; + case COM_INTERNAL: + od_printf("OpenDoors Internal I/O Module\n\r"); + break; + case COM_SOCKET: + od_printf("TCP Socket/Telnet\n\r"); + break; + default: + od_printf("Unknown\n\r"); + break; + } + od_printf(" Drop File Type : "); + switch(od_control.od_info_type) + { + case DORINFO1: + od_printf("DORINFO?.DEF\n\r"); + break; + case EXITINFO: + od_printf("Basic EXITINFO.BBS & DORINFO1.DEF\n\r"); + break; + case RA1EXITINFO: + od_printf("RA 1.x EXITINFO.BBS & DORINFO1.DEF\n\r"); + break; + case CHAINTXT: + od_printf("CHAIN.TXT\n\r"); + break; + case SFDOORSDAT: + od_printf("SFDOORS.DAT\n\r"); + break; + case CALLINFO: + od_printf("CALLINFO.BBS\n\r"); + break; + case DOORSYS_GAP: + od_printf("GAP style DOOR.SYS\n\r"); + break; + case DOORSYS_DRWY: + od_printf("DoorWay DOOR.SYS\n\r"); + break; + case QBBS275EXITINFO: + od_printf("QuickBBS 2.75+ EXITINFO.BBS\n\r"); + break; + case CUSTOM: + od_printf("User-Defined Custom Format\n\r"); + break; + case DOORSYS_WILDCAT: + od_printf("WildCat! DOOR.SYS\n\r"); + break; + case RA2EXITINFO: + od_printf("RA 2.x+ EXITINFO.BBS & DORINFO1.DEF\n\r"); + break; + case NO_DOOR_FILE: + od_printf("No Drop File in Use\n\r"); + break; + case DOOR32SYS: + od_printf("Door32.sys\n\r"); + break; + default: + od_printf("Unknown Type\n\r"); + break; + } + od_printf(" ANSI Mode Available : %s\n\r", + BoolAsStr(od_control.user_ansi)); + od_printf(" AVATAR Mode Available : %s\n\r", + BoolAsStr(od_control.user_avatar)); + od_printf(" RIP Graphics Available : %s\n\r", + BoolAsStr(od_control.user_rip)); + od_printf(" User's Time Limit : %d\n\r", od_control.user_timelimit); + od_printf(" User's Full Name : %s\n\r", od_control.user_name); + + od_printf("\n\rChoose Option: [E]xit, [T]yping Test,"); + if(od_control.od_com_method == COM_INTERNAL) + { + od_printf(" [I]nternal I/O Diags,"); + } + od_printf("\n\r"); + od_printf(" [A]utodetect ANSI/RIP, [R]e-Display, [D]isplay Tests\n\r"); + n=od_get_answer("eitard"); + switch(n) + { + case 'e': + od_clr_scr(); + od_printf("\n\rExit - Are You Sure (Y/N)? "); + if(od_get_answer("yn") == 'y') + { + return(0); + } + break; + + case 'i': + od_clr_scr(); + od_printf("INTERNAL SERIAL I/O DIAGNOSTIC INFORMATION:\n\r"); + od_printf(" Serial Port Base Address : %x\n\r", + od_control.od_com_address); + od_printf(" IRQ Line Number : %d\n\r", + od_control.od_com_irq); + od_printf(" Receive Buffer Size : %d\n\r", + od_control.od_com_rx_buf); + od_printf(" Transmit Buffer Size : %d\n\r", + od_control.od_com_tx_buf); + od_printf(" Use FIFO Buffer, if avail : %s\n\r", + BoolAsStr(!od_control.od_com_no_fifo)); + od_printf(" FIFO Trigger Size : %d\n\r", + od_control.od_com_fifo_trigger); + + od_printf("\n\rPress [ENTER] to return.\n\r"); + od_get_answer("\n\r"); + break; + + case 't': + od_clr_scr(); + od_printf("\n\rTyping Test - Type any text below:\n\r"); + od_printf("[------------------------------------------------------" + "-----------------------]\n\r"); + od_input_str(sz, 79, 0, 255); + od_printf("\n\rEntered Text:\n\r%s\n\r", sz); + od_printf("\n\rPress [ENTER] to return.\n\r"); + od_get_answer("\n\r"); + break; + + case 'a': + od_clr_scr(); + od_printf("\n\rAutodetecting ANSI/RIP mode ...\n\r"); + od_printf("(Detected modes will be turned on.)\n\r"); + od_autodetect(0); + od_printf("\n\rDone, press [ENTER] to return.\n\r"); + od_get_answer("\n\r"); + break; + + case 'd': + od_clr_scr(); + od_printf("CLEAR SCREEN TEST\n\r"); + od_printf("About to test clear screen. The screen should\n\r"); + od_printf("be cleared before the next test if screen\n\r"); + od_printf("clearing is enabled.\n\r"); + od_printf("\n\rPress [ENTER] to perform test.\n\r"); + od_get_answer("\n\r"); + od_clr_scr(); + + od_printf("CARRIAGE RETURN TEST:\n\r"); + od_printf("This should not be visible\r"); + od_printf("This should cover it up...\n\r\n\r"); + od_printf("The text \"This should not be visible\" will\n\r"); + od_printf("appear above if this test failed.\n\r"); + od_printf("\n\rPress [ENTER] to perform next test.\n\r"); + od_get_answer("\n\r"); + + od_clr_scr(); + od_printf("COLOR TEST:\n\r\n\r"); + for(n = 0; n < 256; ++n) + { + od_set_attrib(n); + od_printf("%x", n % 16); + if(n % 32 == 31) + { + od_set_attrib(0x07); + od_printf("\n\r"); + } + } + od_printf("\n\rIf ANSI or AVATAR modes are available, the\n\r"); + od_printf("above test pattern should print in color.\n\r"); + od_printf("\n\rPress [ENTER] to perform next test.\n\r"); + od_get_answer("\n\r"); + + od_clr_scr(); + od_printf("CURSOR POSITIONING TEST:\n\r"); + for(n = 15; n > 2; --n) + { + od_set_cursor(n, n); + od_printf("\\"); + } + for(n = 15; n > 2; --n) + { + od_set_cursor(n, 17 - n); + od_printf("/"); + } + + od_set_cursor(17, 1); + od_printf("If ANSI or AVATAR modes are available, a large X\n\r"); + od_printf("should appear on lines 3 to 15.\n\r"); + od_printf("\n\rPress [ENTER] to return.\n\r"); + od_get_answer("\n\r"); + break; + } + + od_clr_scr(); + } + + /* Return with success. */ + return(0); +} + + +char *BoolAsStr(int bValue) +{ + return(bValue ? "Yes (TRUE)" : "No (FALSE)"); +} + + +void ParseStandardCommandLine(int nArgCount, char *papszArguments[]) +{ + char *pszCurrentArg; + int nCurrentArg; + + for(nCurrentArg = 1; nCurrentArg < nArgCount; ++nCurrentArg) + { + pszCurrentArg = papszArguments[nCurrentArg]; + + switch(GetCommandLineParameter(pszCurrentArg)) + { + case kParamLocal: + od_control.od_force_local = TRUE; + break; + + case kParamBPS: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.baud = atol(papszArguments[nCurrentArg]); + break; + + case kParamPort: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.port = atoi(papszArguments[nCurrentArg]); + break; + + case kParamHelp: + printf("AVALIABLE COMMAND LINE PARAMETERS:\n"); + printf(" -L or -LOCAL - Causes door to operate in local mode, without requiring a\n"); + printf(" door information (drop) file.\n"); + printf(" -DROPFILE x - Door information file directory or directory+filename.\n"); + printf(" -N x or -NODE x - Sets the node number to use.\n"); + printf(" -B x or -BPS x - Sets the serial port <---> modem bps (baud) rate to use.\n"); + printf(" -P x or -PORT x - Sets the serial port to use, were 0=COM1, 1=COM2, etc.\n"); + printf(" -ADDRESS x - Sets serial port address in decimal NOT hexidecimal\n"); + printf(" (only has effect if FOSSIL driver is not being used).\n"); + printf(" -IRQ x - Sets the serial port IRQ line (only has effect if FOSSIL\n"); + printf(" driver is not being used).\n"); + printf(" -NOFOSSIL - Disables use of FOSSIL driver, even if available.\n"); + printf(" -NOFIFO - Disables use of 16550 FIFO buffers (only if FOSSIL driver\n"); + printf(" is not being used).\n"); + printf(" -PERSONALITY x - Sets the sysop status line / function key personality to\n"); + printf(" use - one of Standard, PCBoard, RemoteAccess or Wildcat.\n"); + printf(" -MAXTIME x - Sets the maximum number of minutes that any user will be\n"); + printf(" permitted to access the door.\n"); + printf(" -USERNAME x - Name of user who is currently online.\n"); + printf(" -TIMELEFT x - User's time remaining online.\n"); + printf(" -SECURITY x - User's security level.\n"); + printf(" -LOCATION x - Location from which user is calling.\n"); + printf(" -?, -H or -HELP - Displays command-line help and exits.\n"); + exit(1); + break; + + case kParamNode: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_node = atoi(papszArguments[nCurrentArg]); + break; + + case kParamPersonality: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + if(stricmp(papszArguments[nCurrentArg], "Standard") == 0) + { + od_control.od_default_personality = PER_OPENDOORS; + } + else if(stricmp(papszArguments[nCurrentArg], "PCBoard") == 0) + { + od_control.od_default_personality = PER_PCBOARD; + } + else if(stricmp(papszArguments[nCurrentArg], "RemoteAccess") == 0) + { + od_control.od_default_personality = PER_RA; + } + else if(stricmp(papszArguments[nCurrentArg], "Wildcat") == 0) + { + od_control.od_default_personality = PER_WILDCAT; + } + else + { + printf("Unknown personality: %s\n", papszArguments[nCurrentArg]); + exit(1); + } + break; + + case kParamMaxTime: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_maxtime = atoi(papszArguments[nCurrentArg]); + break; + + case kParamAddress: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_address = atoi(papszArguments[nCurrentArg]); + break; + + case kParamIRQ: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_irq = atoi(papszArguments[nCurrentArg]); + break; + + case kParamNoFOSSIL: + od_control.od_no_fossil = TRUE; + break; + + case kParamNoFIFO: + od_control.od_com_no_fifo = TRUE; + break; + + case kParamDropFile: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + strncpy(od_control.info_path, papszArguments[nCurrentArg], + sizeof(od_control.info_path) - 1); + od_control.info_path[sizeof(od_control.info_path) - 1] = '\0'; + break; + + case kParamUserName: + GetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_name, sizeof(od_control.user_name)); + break; + + case kParamTimeLeft: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_timelimit = atoi(papszArguments[nCurrentArg]); + break; + + case kParamSecurity: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_security = atoi(papszArguments[nCurrentArg]); + break; + + case kParamLocation: + GetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_location, sizeof(od_control.user_location)); + break; + + default: + printf("Unrecognized command line option: %s\n", pszCurrentArg); + exit(1); + break; + } + } +} + + +static void AdvanceToNextArg(int *pnCurrentArg, int nArgCount, char *pszOption) +{ + if(++*pnCurrentArg >= nArgCount) + { + printf("Missing parameter for option: %s\n", pszOption); + exit(1); + } +} + + +static void GetNextArgName(int *pnCurrentArg, int nArgCount, + char *papszArguments[], char *pszString, + int nStringSize) +{ + int bFirst = TRUE; + + if((*pnCurrentArg) + 1 >= nArgCount) + { + printf("Missing parameter for option: %s\n", + papszArguments[(*pnCurrentArg) - 1]); + exit(1); + } + + pszString[0] = '\0'; + + while(++*pnCurrentArg < nArgCount) + { + if(GetCommandLineParameter(papszArguments[*pnCurrentArg]) + != kParamUnknown) + { + --*pnCurrentArg; + break; + } + + if(strlen(pszString) >= nStringSize - 1) + { + break; + } + + if(!bFirst) + { + strcat(pszString, " "); + } + + strncat(pszString, papszArguments[*pnCurrentArg], + strlen(pszString) - nStringSize - 1); + pszString[nStringSize - 1] = '\0'; + + bFirst = FALSE; + } + +} + + +static tCommandLineParameter GetCommandLineParameter(char *pszArgument) +{ + if(*pszArgument == '-' || *pszArgument == '/') + { + ++pszArgument; + } + + if(stricmp(pszArgument, "L") == 0 + || stricmp(pszArgument, "LOCAL") == 0) + { + return(kParamLocal); + } + else if(stricmp(pszArgument, "B") == 0 + || stricmp(pszArgument, "BPS") == 0 + || stricmp(pszArgument, "BAUD") == 0) + { + return(kParamBPS); + } + else if(stricmp(pszArgument, "P") == 0 + || stricmp(pszArgument, "PORT") == 0) + { + return(kParamPort); + } + else if(stricmp(pszArgument, "N") == 0 + || stricmp(pszArgument, "NODE") == 0) + { + return(kParamNode); + } + else if(stricmp(pszArgument, "?") == 0 + || stricmp(pszArgument, "H") == 0 + || stricmp(pszArgument, "HELP") == 0) + { + return(kParamHelp); + } + else if(stricmp(pszArgument, "PERSONALITY") == 0) + { + return(kParamPersonality); + } + else if(stricmp(pszArgument, "MAXTIME") == 0) + { + return(kParamMaxTime); + } + else if(stricmp(pszArgument, "ADDRESS") == 0) + { + return(kParamAddress); + } + else if(stricmp(pszArgument, "IRQ") == 0) + { + return(kParamIRQ); + } + else if(stricmp(pszArgument, "NOFOSSIL") == 0) + { + return(kParamNoFOSSIL); + } + else if(stricmp(pszArgument, "NOFIFO") == 0) + { + return(kParamNoFIFO); + } + else if(stricmp(pszArgument, "DROPFILE") == 0) + { + return(kParamDropFile); + } + else if(stricmp(pszArgument, "USERNAME") == 0) + { + return(kParamUserName); + } + else if(stricmp(pszArgument, "TIMELEFT") == 0) + { + return(kParamTimeLeft); + } + else if(stricmp(pszArgument, "SECURITY") == 0) + { + return(kParamSecurity); + } + else if(stricmp(pszArgument, "LOCATION") == 0) + { + return(kParamLocation); + } + else + { + return(kParamUnknown); + } +} + + +void NoDoorFileHandler(void) +{ + /* Alter OpenDoors behaviour, so that we proceed with defaults if */ + /* no door information file is available, rather than exiting with */ + /* an error. Set od_no_file_func to point to this function. */ + if(strlen(od_control.user_name) == 0) + { + strcpy(od_control.user_name, "Unknown User"); + } + if(strlen(od_control.user_location) == 0) + { + strcpy(od_control.user_location, "Unknown Location"); + } + if(od_control.user_timelimit == 0) + { + od_control.user_timelimit = 30; + } + + od_control.od_info_type = CUSTOM; +} diff --git a/utils/magiedit/odoors/ex_hello.c b/utils/magiedit/odoors/ex_hello.c new file mode 100644 index 0000000..0144983 --- /dev/null +++ b/utils/magiedit/odoors/ex_hello.c @@ -0,0 +1,42 @@ +/* EX_HELLO.C - Example of a trivial OpenDoors program. Demonstrates */ +/* just how simple a fully functional door program can be. Also */ +/* shows all the basic elements required by any program using */ +/* OpenDoors. See manual for instructions on how to compile */ +/* this program. */ +/* */ +/* This program shows how to do the following: */ +/* */ +/* - #include the OpenDoors header file, opendoor.h. */ +/* - Create a mainline function that can be compiled under */ +/* both DOS and Windows versions of OpenDoors. */ +/* - How to display text on multiple lines. */ +/* - How to wait for a single key to be pressed. */ +/* - How to properly exit a program that uses OpenDoors. */ + + +/* The opendoor.h file must be included by any program using OpenDoors. */ +#include "OpenDoor.h" + + +/* The main() or WinMain() function: program execution begins here. */ +#ifdef ODPLAT_WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +#else +int main(int argc, char *argv[]) +#endif +{ + + /* Display a message. */ + od_printf("Hello world! This is a very simple OpenDoors program.\n\r"); + od_printf("Press any key to return to the BBS!\n\r"); + + + /* Wait for user to press a key. */ + od_get_key(TRUE); + + + /* Exit door program, returning to the BBS. */ + od_exit(0, FALSE); + return(0); +} diff --git a/utils/magiedit/odoors/ex_music.c b/utils/magiedit/odoors/ex_music.c new file mode 100644 index 0000000..4016181 --- /dev/null +++ b/utils/magiedit/odoors/ex_music.c @@ -0,0 +1,153 @@ +/* EX_MUSIC.C - Example program plays "Happy Birthday" to the remote user, */ +/* if possible. See the manual for instructions on how to */ +/* compile this program. */ +/* */ +/* This program shows how to do the following: */ +/* */ +/* - Demonstrates how to play sounds effects or music on a */ +/* remote terminal program that supports the so-called */ +/* "ANSI music" standard. */ +/* - Shows how to send text to the remote system without it */ +/* being displayed on the local screen. */ + + +/* The opendoor.h file must be included by any program using OpenDoors. */ +#include "OpenDoor.h" + +#include + +/* Functions for playing "ANSI music" and testing "ANSI music" capabilities. */ +void PlayANSISound(char *pszSounds); +char TestSound(void); + +/* Variable indicates whether or not sound is on */ +char bSoundEnabled = TRUE; + + +/* The main() or WinMain() function: program execution begins here. */ +#ifdef ODPLAT_WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +#else +int main(int argc, char *argv[]) +#endif +{ + /* Handle standard command-line options and perform other needed setup. */ +#ifdef ODPLAT_WIN32 + od_control.od_cmd_show = nCmdShow; + od_parse_cmd_line(lpszCmdLine); +#else + od_parse_cmd_line(argc, argv); +#endif + + /* Display introductory message. */ + od_printf("This is a simple door program that will play the song Happy Birthday\n\r"); + od_printf("tune on the remote system, if the user's terminal program supports ANSI\n\r"); + od_printf("music. Music is not played on the local speaker, as BBS system operators\n\r"); + od_printf("do not wish to have the BBS computer making sounds at any time of the day\n\r"); + od_printf("or night. However, the program can easily be modified to also echo sound to\n\r"); + od_printf("the local speaker.\n\r\n\r"); + + + /* Test whether user's terminal supports "ANSI music". */ + TestSound(); + + + /* Send birthday greetings to the remote user. */ + + /* Clear the screen. */ + od_clr_scr(); + + /* Display a message. */ + od_printf("\n\rHappy Birthday!\n\r"); + + /* If "ANSI music" is available, play "Happy Birthday". */ + PlayANSISound("MBT120L4MFMNO4C8C8DCFE2C8C8DCGF2C8C8O5CO4AFED2T90B-8B-8AFGF2"); + + /* Reset sound after finished playing. */ + PlayANSISound("00m"); + + + /* Wait for user to press a key before returning to the BBS. */ + od_printf("\n\rPress any key to return to BBS...\n\r"); + od_get_key(TRUE); + od_exit(0, FALSE); + return(0); +} + + +/* Function to test whether the user's terminal program supports ANSI music. */ +/* You can either do this every time the user uses your program, or only the */ +/* first time they use the program, saving the result in a data file. */ +char TestSound(void) +{ + /* Variable to store user's response to question. */ + char chResponse; + + /* Display description of test to user. */ + od_printf("We need to know whether or not your terminal program supports ANSI music.\n\r"); + od_printf("In order to test this, we will send a short ANSI music sequence. We will then\n\r"); + od_printf("ask whether or not you heard any sound.\n\r"); + od_printf("Press any key to begin this test... "); + + /* Wait for user to press a key to begin. */ + od_get_key(TRUE); + od_printf("\n\r\n\r"); + + /* Temporarily enable sound. */ + bSoundEnabled = TRUE; + + /* Send sound test sequence. */ + PlayANSISound("MBT120L4MFMNO4C8C8DC"); + + /* Reset sound after finished test. */ + PlayANSISound("00m"); + + /* Clear screen and ask whether user heard the sound. */ + od_clr_scr(); + od_printf("Did you just hear sound from your speaker? (Y/n)"); + chResponse = od_get_answer("YN"); + + /* Set ANSI music on/off according to user's response. */ + bSoundEnabled = (chResponse == 'Y'); + + return(bSoundEnabled); +} + + +/* Function to play "ANSI" music or sound effects. The play_sound() function + * can be called with a string of 0 to 250 characters. The caracters of the + * string define what sounds should be played on the remote speaker, as + * follows: + * + * A - G Musical Notes + * # or + Following A-G note means sharp + * - Following A-G note means flat + * < Move down one octave + * > Move up one octave + * . Period acts as dotted note (extend note duration by 3/2) + * MF Music Foreground (pause until finished playing music) + * MB Music Background (continue while music plays) + * MN Music note duration Normal (7/8 of interval between notes) + * MS Music note duration Staccato + * ML Music note duration Legato + * Ln Length of note (n=1-64, 1=whole note, 4=quarter note, etc) + * Pn Pause length (same n values as Ln above) + * Tn Tempo, n=notes/minute (n=32-255, default n=120) + * On Octave number (n=0-6, default n=4) + */ + +void PlayANSISound(char *pszSounds) +{ + /* Beginning of sound sequence. */ + char szStartSound[255] = {27, '[', '\0'}; + + /* Abort if sound is not enabled. */ + if(!bSoundEnabled) return; + + /* Send sequence to start playing sound to remote system only. */ + od_disp(szStartSound, strlen(szStartSound), FALSE); + + /* Send the sounds codes to the remote system only. */ + od_disp(pszSounds, strlen(pszSounds), FALSE); +} diff --git a/utils/magiedit/odoors/ex_ski.c b/utils/magiedit/odoors/ex_ski.c new file mode 100644 index 0000000..a2dd7c9 --- /dev/null +++ b/utils/magiedit/odoors/ex_ski.c @@ -0,0 +1,602 @@ +/* EX_SKI.C - EX_SKI is a simple but addictive door game that is written */ +/* using OpenDoors. In this action game, the player must control */ +/* a skier through a downhill slalom course. The user may turn */ +/* the skier left or right, and the game ends as soon as the */ +/* player skis outside the marked course. The game begins at */ +/* an easy level, but quickly becomes more and more difficult */ +/* as the course to be navigated becomes more and more narrow. */ +/* The game maintains a list of players with high scores, and */ +/* this list may be viewed from the main menu. */ +/* */ +/* This program shows how to do the following: */ +/* */ +/* - Maintain a high-score file in a game, in a multi-node */ +/* compatible manner. */ +/* - How to use your own terminal control sequences. */ +/* - How to perform reasonably percise timing under both DOS */ +/* and Windows. */ + + +/* Header file for the OpenDoors API */ +#include "OpenDoor.h" + +/* Other required C header files */ +#include +#include +#include +#include +#include + +#include "genwrap.h" + + +/* Hard-coded configurable constants - change these values to alter game */ +#define HIGH_SCORES 15 /* Number of high scores in list */ +#define INITIAL_COURSE_WIDTH 30 /* Initial width of ski course */ +#define MINIMUM_COURSE_WIDTH 4 /* Minimum width of course */ +#define DECREASE_WIDTH_AFTER 100 /* # of ticks before course narrows */ +#define CHANGE_DIRECTION 10 /* % of ticks course changes direction */ +#define MAX_NAME_SIZE 35 /* Maximum characters in player name */ +#define WAIT_FOR_FILE 10 /* Time to wait for access to file */ +#define SCORE_FILENAME "skigame.dat" /* Name of high score file */ + + +/* High-score file format structure */ +typedef struct +{ + char szPlayerName[MAX_NAME_SIZE + 1]; + DWORD lnHighScore; + time_t lnPlayDate; +} tHighScoreRecord; + +typedef struct +{ + tHighScoreRecord aRecord[HIGH_SCORES]; +} tHighScoreFile; + + +/* Prototypes for functions defined and used in this file */ +FILE *OpenAndReadHighScores(tHighScoreFile *pFileContents); +void CloseHighScores(FILE *pfHighScoreFile); +void WriteHighScores(FILE *pfHighScoreFile, tHighScoreFile *pFileContents); +FILE *OpenExclusiveFile(char *pszFileName, char *pszAccess, time_t Wait); +int FileExists(char *pszFileName); +void ShowHighScores(void); +void PlayGame(void); +void SpaceRight(int nColumns); +void MoveLeft(int nColumns); +int AddHighScore(tHighScoreFile *pHighScores, tHighScoreRecord *pScoreRecord); + + +/* The main() or WinMain() function: program execution begins here. */ +#ifdef ODPLAT_WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +#else +int main(int argc, char *argv[]) +#endif +{ + char chMenuChoice; + +#ifdef ODPLAT_WIN32 + /* In Windows, pass in nCmdShow value to OpenDoors. */ + od_control.od_cmd_show = nCmdShow; +#endif + + /* Set program's name for use by OpenDoors. */ + strcpy(od_control.od_prog_name, "Grand Slalom"); + strcpy(od_control.od_prog_version, "Version 6.00"); + strcpy(od_control.od_prog_copyright, "Copyright 1991-1996 by Brian Pirie"); + + /* Call the standard command-line parsing function. You will probably */ + /* want to do this in most programs that you write using OpenDoors, as it */ + /* automatically provides support for many standard command-line options */ + /* that will make the use and setup of your program easer. For details, */ + /* run the vote program with the /help command line option. */ +#ifdef ODPLAT_WIN32 + od_parse_cmd_line(lpszCmdLine); +#else + od_parse_cmd_line(argc, argv); +#endif + + /* Loop until the user chooses to exit the door */ + do + { + /* Clear the screen */ + od_clr_scr(); + + /* Display program title */ + od_printf("`bright white` Ûßß ÛßÜ ÛßÛ ÛÜ Û ÛßÜ Ûßß Û ÛßÛ Û ÛßÛ ÛßÛßÛ\n\r"); + od_printf("`bright red`ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ`bright white`ÛßÛ`bright red`Ä`bright white`ÛßÜ`bright red`Ä`bright white`ÛßÛ`bright red`Ä`bright white`Û`bright red`Ä`bright white`ßÛ`bright red`Ä`bright white`Û"); + od_printf("`bright red`Ä`bright white`Û`bright red`ÄÄÄ`bright white`ßßÛ`bright red`Ä`bright white`Û`bright red`ÄÄÄ`bright white`ÛßÛ`bright red`Ä`bright white`Û`bright red`ÄÄÄ`bright white`Û"); + od_printf("`bright red`Ä`bright white`Û`bright red`Ä`bright white`Û`bright red`Ä`bright white`Û`bright red`Ä`bright white`Û`bright red`ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n\r"); + od_printf("`bright white` ßßß ß ß ß ß ß ß ßß ßßß ßßß ß ß ßßß ßßß ß ß ß\n\r\n\r"); + + /* Display instructions */ + od_printf("`dark green`Prepare yourself for the challenge of Grand Slalom downhill skiing!\n\r\n\r"); + od_printf("When `flashing dark green`playing`dark green` the game, press:\n\r"); + od_printf("`dark green` [`bright green`Q`dark green`] key to ski left\n\r"); + od_printf(" [`bright green`W`dark green`] key to ski right\n\r\n\r"); + od_printf("All that you have to do is ski within the slalom course.\n\r"); + od_printf("It may sound easy - but be warned - it gets harder as you go!\n\r"); + od_printf("(Each time you hear the beep, the course becomes a bit narrower.)\n\r\n\r"); + + /* Get menu choice from user. */ + od_printf("`bright white`Now, press [ENTER] to begin game, [H] to view High Scores, [E] to Exit: "); + chMenuChoice = od_get_answer("HE\n\r"); + + /* Perform appropriate action based on user's choice */ + switch(chMenuChoice) + { + case '\n': + case '\r': + /* If user chooses to play the game */ + PlayGame(); + break; + + case 'H': + /* If user chose to view high scores */ + ShowHighScores(); + break; + + case 'E': + /* If user chose to return to BBS */ + od_printf("\n\rGoodbye from SKIGAME!\n\r"); + break; + } + } while(chMenuChoice != 'E'); + + /* Exit door at errorlevel 10, and do not hang up */ + od_exit(10, FALSE); + return(1); +} + + +/* OpenAndReadHighScores() - Opens high score file and reads contents. If */ +/* file does not exist, it is created. File is */ +/* locked to serialize access by other nodes on */ +/* this system. */ +FILE *OpenAndReadHighScores(tHighScoreFile *pFileContents) +{ + FILE *pfFile; + int iHighScore; + + /* If high score file does not exist */ + if(!FileExists(SCORE_FILENAME)) + { + /* Open and create it */ + pfFile = OpenExclusiveFile(SCORE_FILENAME, "wb", WAIT_FOR_FILE); + + /* If open was successful */ + if(pfFile != NULL) + { + /* Initialize new high score list */ + for(iHighScore = 0; iHighScore < HIGH_SCORES; ++iHighScore) + { + pFileContents->aRecord[iHighScore].lnHighScore = 0L; + } + + /* Write high score list to the file */ + WriteHighScores(pfFile, pFileContents); + } + } + + /* If high score file does exit */ + else + { + /* Open the existing file */ + pfFile = OpenExclusiveFile(SCORE_FILENAME, "r+b", + WAIT_FOR_FILE); + + /* Read the contents of the file */ + if(fread(pFileContents, sizeof(tHighScoreFile), 1, pfFile) != 1) + { + /* If unable to read file, then return with an error */ + fclose(pfFile); + pfFile = NULL; + } + } + + /* Return pointer to high score file, if avilable */ + return(pfFile); +} + + +/* FileExists() - Returns TRUE if file exists, otherwise returns FALSE */ +int FileExists(char *pszFileName) +{ + /* Attempt to open the specified file for reading. */ + FILE *pfFile = OpenExclusiveFile(pszFileName, "rb", WAIT_FOR_FILE); + + if(pfFile != NULL) + { + /* If we are able to open the file, then close it and return */ + /* indicating that it exists. */ + fclose(pfFile); + return(TRUE); + } + else + { + /* If we are unable to open the file, we proceed as if the file */ + /* doesn't exist (note that this may not always be a valid assumption) */ + return(FALSE); + } +} + + +/* OpenExclusiveFile() - Opens a file for exclusive access, waiting if the */ +/* file is not currently available. */ +FILE *OpenExclusiveFile(char *pszFileName, char *pszAccess, time_t Wait) +{ + FILE *pfFile; + time_t StartTime = time(NULL); + + for(;;) + { + /* Attempt to open file */ + pfFile = fopen(pszFileName, pszAccess); + + /* If file was opened successfuly, then exit */ + if(pfFile != NULL) break; + + /* If open failed, but not due to access failure, then exit */ + if(errno != EACCES) break; + + /* If maximum time has elapsed, then exit */ + if(StartTime + Wait < time(NULL)) break; + + /* Give the OpenDoors kernel a chance to execute before trying again */ + od_kernel(); + } + + /* Return pointer to file, if opened */ + return(pfFile); +} + + +/* CloseHighScores() - Closes the high score file, allowing other nodes on */ +/* system to access it. */ +void CloseHighScores(FILE *pfHighScoreFile) +{ + if(pfHighScoreFile != NULL) + { + fclose(pfHighScoreFile); + } +} + + +/* WriteHighScores() - Writes the information from pFileContents to the */ +/* high score file. */ +void WriteHighScores(FILE *pfHighScoreFile, tHighScoreFile *pFileContents) +{ + if(pfHighScoreFile != NULL) + { + fseek(pfHighScoreFile, 0L, SEEK_SET); + fwrite(pFileContents, sizeof(tHighScoreFile), 1, pfHighScoreFile); + } +} + + +/* ShowHighScores() - Called From DoDoor() to display list of high scores */ +void ShowHighScores(void) +{ + FILE *pfFile; + tHighScoreFile HighScores; + int iHighScore; + struct tm *pTimeBlock; + char szTimeString[34]; + + /* Clear the screen */ + od_clr_scr(); + + /* Attempt to read high scores from file */ + pfFile = OpenAndReadHighScores(&HighScores); + CloseHighScores(pfFile); + + if(pfFile == NULL) + { + /* If unable to open high score file, display an error message */ + od_printf("`bright red`Unable to access high score file!\n\r"); + } + else + { + /* Display header line */ + od_printf("`bright green`Player Score " + "Record Date`dark green`\n\r"); + od_printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n\r"); + + /* Display high scores */ + for(iHighScore = 0; iHighScore < HIGH_SCORES; ++iHighScore) + { + /* Exit loop when we have reached the end of the high scores */ + if(HighScores.aRecord[iHighScore].lnHighScore == 0L) break; + + /* Get local time when player set the high score */ + pTimeBlock = localtime(&HighScores.aRecord[iHighScore].lnPlayDate); + strftime(szTimeString, sizeof(szTimeString), + "%B %d, %Y at %I:%M%p", pTimeBlock); + + /* Display next high score */ + od_printf("%-32.32s %-8ld %s\n\r", + HighScores.aRecord[iHighScore].szPlayerName, + HighScores.aRecord[iHighScore].lnHighScore, + szTimeString); + } + } + + /* Display footer line */ + od_printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n\r\n\r"); + + /* Wait for user to press a key */ + od_printf("`bright white`Press [ENTER]/[RETURN] to continue: "); + od_get_answer("\n\r"); +} + + +/* PlayGame() - Called from DoDoor() when user chooses to play a game. */ +void PlayGame(void) +{ + int nLeftEdge = 1; + int nRightEdge = nLeftEdge + 1 + INITIAL_COURSE_WIDTH; + int nPlayerPos = nLeftEdge + 1 + (INITIAL_COURSE_WIDTH / 2); + long lnScore = 0; + int nDistanceSinceShrink = 0; + int bMovingRight = TRUE; + char cKeyPress; + tHighScoreRecord ScoreRecord; + FILE *pfFile; + tHighScoreFile HighScores; + int nBackup=0; + clock_t StartClock; + + /* Clear the Screen */ + od_set_color(L_WHITE, B_BLACK); + od_clr_scr(); + + /* Set current display colour to white */ + od_set_attrib(L_WHITE); + + /* Re-seed random number generator */ + srand((unsigned int)time(NULL)); + + /* Loop until game is over */ + for(;;) + { + StartClock = msclock(); + + /* Display current line */ + if(od_control.user_ansi || od_control.user_avatar) + { + SpaceRight(nLeftEdge - 1); + od_set_color(L_WHITE, D_RED); + od_putch((char)223); + od_repeat((unsigned char)219, + (unsigned char)(nPlayerPos - nLeftEdge - 1)); + od_putch((char)254); + od_repeat((unsigned char)219, + (unsigned char)(nRightEdge - nPlayerPos - 1)); + od_putch((char)223); + nBackup = nRightEdge - nPlayerPos + 1; + } + else + { + /* If neither ANSI nor AVATAR modes are active, then display */ + /* course using plain-ASCII. */ + SpaceRight(nLeftEdge - 1); + od_putch((char)(bMovingRight ? '\\' : '/')); + SpaceRight(nPlayerPos - nLeftEdge - 1); + od_putch('o'); + SpaceRight(nRightEdge - nPlayerPos - 1); + od_putch((char)(bMovingRight ? '\\' : '/')); + } + + /* Loop for each key pressed by user */ + while((cKeyPress = (char)od_get_key(FALSE)) != '\0') + { + if(cKeyPress == 'q' || cKeyPress == 'Q') + { + /* Move left */ + --nPlayerPos; + } + else if(cKeyPress == 'w' || cKeyPress == 'W') + { + /* Move right */ + ++nPlayerPos; + } + } + + /* Check whether course should turn */ + if((rand() % 100) < CHANGE_DIRECTION) + { + bMovingRight = !bMovingRight; + } + else + { + /* If no change in direction, then position moves */ + /* Adjust course position appropriately */ + if(bMovingRight) + { + ++nLeftEdge; + ++nRightEdge; + } + else + { + --nLeftEdge; + --nRightEdge; + } + } + + /* Check whether course size should shink */ + if(++nDistanceSinceShrink >= DECREASE_WIDTH_AFTER) + { + /* Reset distance */ + nDistanceSinceShrink = 0; + + /* Randomly choose a side to shrink */ + if((rand() % 100) < 50) + { + ++nLeftEdge; + } + else + { + --nRightEdge; + } + + /* Beep when we shrink the size. */ + od_printf("\a"); + } + + /* Change course direction if it collides with edge of screen */ + if(nLeftEdge < 1) + { + bMovingRight = TRUE; + ++nLeftEdge; + ++nRightEdge; + } + else if(nRightEdge > 79) + { + bMovingRight = FALSE; + --nLeftEdge; + --nRightEdge; + } + + /* Check that player is still within the course */ + if(nPlayerPos <= nLeftEdge || nPlayerPos >= nRightEdge) + { + /* Player has left course - game over! */ + od_set_color(D_GREY, D_BLACK); + od_clr_scr(); + od_printf("`bright red` !!! Game Over !!!\n\r\n\r"); + od_printf("`dark green`You have veered off the course!\n\r\n\r"); + od_printf("Your Score is: %ld\n\r", lnScore); + + /* Create a score record */ + ScoreRecord.lnHighScore = lnScore; + strncpy(ScoreRecord.szPlayerName, od_control.user_name, MAX_NAME_SIZE); + ScoreRecord.szPlayerName[MAX_NAME_SIZE] = '\0'; + ScoreRecord.lnPlayDate = time(NULL); + + /* Attempt to read high scores from file */ + pfFile = OpenAndReadHighScores(&HighScores); + + if(pfFile == NULL) + { + /* If unable to open high score file, display an error message */ + od_printf("`bright red`Unable to access high score file!\n\r"); + } + else + { + /* Check whether user made it to high score list */ + if(AddHighScore(&HighScores, &ScoreRecord)) + { + od_printf("Congratulations! You have made it to the high score list!\n\r"); + /* If so, write the new high score list */ + WriteHighScores(pfFile, &HighScores); + } + + /* Close and unlock file */ + CloseHighScores(pfFile); + } + + /* Wait for user to press enter */ + od_printf("`bright white`\n\rPress [ENTER]/[RETURN] to return to menu: "); + od_get_answer("\n\r"); + + return; + } + + /* Delay for about 1/10th of a second, to add a constant delay after */ + /* each line is displayed that does not depend on the connect speed. */ + while(msclock() < StartClock + (((clock_t)MSCLOCKS_PER_SEC) / 10)) + od_sleep(0); + + /* Increase score */ + ++lnScore; + + /* Replace skiier character with track character */ + if(od_control.user_ansi) + { + MoveLeft(nBackup); + od_set_color(L_WHITE, D_GREY); + od_putch((char)178); + od_set_color(L_WHITE, B_BLACK); + } + + /* Move to next line */ + od_printf("\r\n"); + } +} + + +/* SpaceRight() - Moves right the specified number of columns. In ANSI mode, */ +/* uses the move cursor right control sequence. Otherwise, */ +/* uses od_repeat(), which is optimized for ASCII and AVATAR */ +/* modes. */ +void SpaceRight(int nColumns) +{ + char szSequence[6]; + + /* If we don't have a positive column count, then return immediately */ + if(nColumns <= 0) return; + + /* If operating in ANSI mode */ + if(od_control.user_ansi) + { + /* Move cursor right using ESC[nC control sequence */ + sprintf(szSequence, "\x1b[%02dC", nColumns); + od_disp_emu(szSequence, TRUE); + } + + /* If not operating in ANSI mode */ + else + { + od_repeat(' ', (unsigned char)nColumns); + } +} + + +/* MoveLeft() - Moves the cursor right the specified number of columns. */ +/* Intended for use in ANSI mode only. */ +void MoveLeft(int nColumns) +{ + /* Move cursor left using ESC[nD control sequence */ + char szSequence[6]; + sprintf(szSequence, "\x1b[%02dD", nColumns); + od_disp_emu(szSequence, TRUE); +} + + +/* AddHighScore() - Adds a new score to the high score list, if it is high */ +/* enough. Returns TRUE if score is added, FALSE otherwise. */ +int AddHighScore(tHighScoreFile *pHighScores, tHighScoreRecord *pScoreRecord) +{ + int iHighScore; + int iExistingScore; + + /* Loop through each existing high score */ + for(iHighScore = 0; iHighScore < HIGH_SCORES; ++iHighScore) + { + /* If new score is greater than or equal to this one, then its */ + /* position has been found. */ + if(pHighScores->aRecord[iHighScore].lnHighScore <= + pScoreRecord->lnHighScore) + { + /* Move remaining scores down one in list */ + for(iExistingScore = HIGH_SCORES - 1; iExistingScore >= iHighScore + 1; + --iExistingScore) + { + pHighScores->aRecord[iExistingScore] = + pHighScores->aRecord[iExistingScore - 1]; + } + + /* Add new score to list */ + pHighScores->aRecord[iHighScore] = *pScoreRecord; + + /* Return with success */ + return(TRUE); + } + } + + /* Score did not make it to list */ + return(FALSE); +} diff --git a/utils/magiedit/odoors/ex_vote.c b/utils/magiedit/odoors/ex_vote.c new file mode 100644 index 0000000..5ee7581 --- /dev/null +++ b/utils/magiedit/odoors/ex_vote.c @@ -0,0 +1,1294 @@ +/* EX_VOTE.C - This program demonstrates an online voting program that is */ +/* written using OpenDoors. The Vote program allows users to */ +/* create questions or surveys for other users to respond to. */ +/* Users are also able to view the results of voting on each */ +/* topic. The program supports up to 200 questions, and can be */ +/* configured to either allow or disallow viewing of results */ +/* prior to voting. */ +/* */ +/* This program shows how to do the following: */ +/* */ +/* - How to display text using od_printf(), using imbedded */ +/* strings to change the display color. */ +/* - Add support for standard command-line options. */ +/* - Use the OpenDoors configuration file system, including */ +/* adding your own configuration file options. */ +/* - Activate the OpenDoors log file system and write */ +/* information to the log file. */ +/* - Display a menu from an external ASCI/ANSI/Avatar/RIP */ +/* file. */ +/* - How to setup a user file and general data file, and how */ +/* to access it in a multi-node compatible way (if */ +/* MULTINODE_AWARE is defined). */ +/* */ +/* To recompile this program, follow the instructions in the */ +/* OpenDoors manual. For a DOS compiler, be sure to set your */ +/* compiler to use the large memory model, and add the */ +/* ODOORL.LIB file to your project/makefile. */ + +/* Uncomment the following line for multi-node compatible file access. */ +/* #define MULTINODE_AWARE */ + +/* Include standard C header files required by Vote. */ +#include +#include +#include +#include +#include +#include + +/* Include the OpenDoors header file. This line must be done in any program */ +/* using OpenDoors. */ +#include "OpenDoor.h" + +#ifdef MULTINODE_AWARE +#include +#endif +#include "genwrap.h" + +/* Manifest constants used by Vote */ +#define NO_QUESTION -1 +#define NEW_ANSWER -1 + +#define QUESTIONS_VOTED_ON 0x0001 +#define QUESTIONS_NOT_VOTED_ON 0x0002 + +#define MAX_QUESTIONS 200 +#define MAX_USERS 30000 +#define MAX_ANSWERS 15 +#define QUESTION_STR_SIZE 71 +#define ANSWER_STR_SIZE 31 + +#define USER_FILENAME "vote.usr" +#define QUESTION_FILENAME "vote.qst" + +#define FILE_ACCESS_MAX_WAIT 20 + +#define QUESTION_PAGE_SIZE 17 + + +/* Structure of records stored in the VOTE.USR file */ +typedef struct +{ + char szUserName[36]; + BYTE bVotedOnQuestion[MAX_QUESTIONS]; +} tUserRecord; + +tUserRecord CurrentUserRecord; +int nCurrentUserNumber; + + +/* Structure of records stored in the VOTE.QST file */ +typedef struct +{ + char szQuestion[72]; + char aszAnswer[MAX_ANSWERS][32]; + INT32 nTotalAnswers; + DWORD auVotesForAnswer[MAX_ANSWERS]; + DWORD uTotalVotes; + DWORD bCanAddAnswers; + char szCreatorName[36]; + time_t lCreationTime; +} tQuestionRecord; + + +/* Global variables. */ +int nViewResultsFrom = QUESTIONS_VOTED_ON; +int nQuestionsVotedOn = 0; + + +/* Prototypes for functions that form EX_VOTE */ +void CustomConfigFunction(char *pszKeyword, char *pszOptions); +void BeforeExitFunction(void); +void VoteOnQuestion(void); +void ViewResults(void); +int GetQuestion(int nQuestion, tQuestionRecord *pQuestionRecord); +void AddQuestion(void); +int ChooseQuestion(int nFromWhichQuestions, char *pszTitle, int *nLocation); +void DisplayQuestionResult(tQuestionRecord *pQuestionRecord); +int ReadOrAddCurrentUser(void); +void WriteCurrentUser(void); +FILE *ExclusiveFileOpen(char *pszFileName, char *pszMode, int *phHandle); +void ExclusiveFileClose(FILE *pfFile, int hHandle); +void WaitForEnter(void); + + +/* main() or WinMain() function - Program execution begins here. */ +#ifdef ODPLAT_WIN32 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +#else +int main(int argc, char *argv[]) +#endif +{ + /* Variable to store user's choice from the menu */ + char chMenuChoice = '\0'; + char chYesOrNo; + +#ifdef ODPLAT_WIN32 + /* In Windows, pass in nCmdShow value to OpenDoors. */ + od_control.od_cmd_show = nCmdShow; + + /* Ignore unused parameters. */ + (void)hInstance; + (void)hPrevInstance; +#endif + + /* Set program's name for use by OpenDoors. */ + strcpy(od_control.od_prog_name, "Vote"); + strcpy(od_control.od_prog_version, "Version 6.00"); + strcpy(od_control.od_prog_copyright, "Copyright 1991-1996 by Brian Pirie"); + + /* Call the standard command-line parsing function. You will probably */ + /* want to do this in most programs that you write using OpenDoors, as it */ + /* automatically provides support for many standard command-line options */ + /* that will make the use and setup of your program easer. For details, */ + /* run the vote program with the /help command line option. */ +#ifdef ODPLAT_WIN32 + od_parse_cmd_line(lpszCmdLine); +#else + od_parse_cmd_line(argc, argv); +#endif + + /* Enable use of OpenDoors configuration file system. */ + od_control.od_config_file = INCLUDE_CONFIG_FILE; + + /* Set function to process custom configuration file lines. */ + od_control.od_config_function = CustomConfigFunction; + + /* Include the OpenDoors multiple personality system, which allows */ + /* the system operator to set the sysop statusline / function key set */ + /* to mimic the BBS software of their choice. */ + od_control.od_mps = INCLUDE_MPS; + + /* Include the OpenDoors log file system, which will record when the */ + /* door runs, and major activites that the user performs. */ + od_control.od_logfile = INCLUDE_LOGFILE; + + /* Set filename for log file. If not set, DOOR.LOG will be used by */ + /* default. */ + strcpy(od_control.od_logfile_name, "vote.log"); + + /* Set function to be called before program exits. */ + od_control.od_before_exit = BeforeExitFunction; + + /* Initialize OpenDoors. This function call is optional, and can be used */ + /* to force OpenDoors to read the door informtion file and begin door */ + /* operations. If a call to od_init() is not included in your program, */ + /* OpenDoors initialization will be performed at the time of your first */ + /* call to any OpenDoors function. */ + od_init(); + + /* Call the Vote function ReadOrAddCurrentUser() to read the current */ + /* user's record from the Vote user file, or to add the user to the */ + /* file if this is the first time that they have used Vote. */ + if(!ReadOrAddCurrentUser()) + { + /* If unable to obtain a user record for the current user, then exit */ + /* the door after displaying an error message. */ + od_printf("Unable to access user file. File may be locked or full.\n\r"); + WaitForEnter(); + od_exit(1, FALSE); + } + + /* Loop until the user choses to exit the door. For each iteration of */ + /* this loop, we display the main menu, get the user's choice from the */ + /* menu, and perform the appropriate action for their choice. */ + + while(chMenuChoice != 'E' && chMenuChoice != 'H') + { + /* Clear the screen */ + od_clr_scr(); + + /* Display main menu. */ + + /* First, attempt to display menu from an VOTE.ASC/ANS/AVT/RIP file. */ + if((chMenuChoice = od_hotkey_menu("VOTE", "VRADPEH", TRUE)) == 0) + { + /* If the VOTE file could not be displayed, display our own menu. */ + od_printf("`bright red` Vote - OpenDoors 6.00 example program\n\r");\ + od_printf("`dark red`"); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r\n\r\n\r`dark green`"); + od_printf(" [`bright green`V`dark green`] Vote on a question\n\r\n\r"); + od_printf(" [`bright green`R`dark green`] View the results of question\n\r\n\r"); + od_printf(" [`bright green`A`dark green`] Add a new question\n\r\n\r"); + od_printf(" [`bright green`P`dark green`] Page system operator for chat\n\r\n\r"); + od_printf(" [`bright green`E`dark green`] Exit door and return to the BBS\n\r\n\r"); + od_printf(" [`bright green`H`dark green`] End call (hangup)\n\r\n\r\n\r"); + od_printf("`bright white`Press the key corresponding to the option of your choice. (%d mins)\n\r`dark green`", + od_control.user_timelimit); + \ + /* Get the user's choice from the main menu. This choice may only be */ + /* V, R, A, D, P, E or H. */ + chMenuChoice = od_get_answer("VRADPEH"); + } + + /* Perform the appropriate action based on the user's choice */ + switch(chMenuChoice) + { + case 'V': + /* Call Vote's function to vote on question */ + VoteOnQuestion(); + break; + + case 'R': + /* Call Vote's function to view the results of voting */ + ViewResults(); + break; + + case 'A': + /* Call Vote's function to add a new question. */ + AddQuestion(); + break; + + case 'P': + /* If the user pressed P, allow them page the system operator. */ + od_page(); + break; + + case 'H': + /* If the user pressed H, ask whether they wish to hangup. */ + od_printf("\n\rAre you sure you wish to hangup? (Y/N) "); + + /* Get user's response */ + chYesOrNo = od_get_answer("YN"); + + if(chYesOrNo == 'N') + { + /* If user answered no, then reset menu choice, so that */ + /* program will not exit. */ + chMenuChoice = '\0'; + } + break; + } + } + + if(chMenuChoice == 'H') + { + /* If the user chooses to hangup, then hangup when exiting. */ + od_exit(0, TRUE); + } + else + { + /* Otherwise, exit normally (without hanging up). */ + od_printf("Returning to BBS, please wait...\n\r"); + od_exit(0, FALSE); + } + + return(0); +} + + +/* CustomConfigFunction() is called by OpenDoors to process custom */ +/* configuration file keywords that Vote uses. */ +void CustomConfigFunction(char *pszKeyword, char *pszOptions) +{ + if(stricmp(pszKeyword, "ViewUnanswered") == 0) + { + /* If keyword is ViewUnanswered, set local variable based on contents */ + /* of options string. */ + if(stricmp(pszOptions, "Yes") == 0) + { + nViewResultsFrom = QUESTIONS_VOTED_ON | QUESTIONS_NOT_VOTED_ON; + } + else if(stricmp(pszOptions, "No") == 0) + { + nViewResultsFrom = QUESTIONS_VOTED_ON; + } + } +} + + +/* Vote configures OpenDoors to call the BeforeExitFunction() before */ +/* the door exists for any reason. You can use this function to close any */ +/* files or perform any other operations that you wish to have peformed */ +/* before OpenDoors exists for any reason. The od_control.od_before_exit */ +/* variable sets the function to be called before program exit. */ +void BeforeExitFunction(void) +{ + char szLogMessage[80]; + + /* Write number of messages voted on to log file. */ + sprintf(szLogMessage, "User has voted on %d question(s)", + nQuestionsVotedOn); + od_log_write(szLogMessage); +} + + +/* Vote calls the VoteOnQuestion() function when the user chooses the */ +/* vote command from the main menu. This function displays a list of */ +/* available topics, asks for the user's answer to the topic they select, */ +/* and display's the results of voting on that topic. */ +void VoteOnQuestion(void) +{ + int nQuestion; + int nAnswer; + tQuestionRecord QuestionRecord; + char szNewAnswer[ANSWER_STR_SIZE]; + char szUserInput[3]; + FILE *fpFile; + int hFile; + int nPageLocation = 0; + + /* Loop until the user chooses to return to the main menu, or until */ + /* there are no more questions to vote on. */ + for(;;) + { + /* Allow the user to choose a question from the list of questions */ + /* that they have not voted on. */ + nQuestion = ChooseQuestion(QUESTIONS_NOT_VOTED_ON, + " Vote On A Question\n\r", + &nPageLocation); + + + /* If the user did not choose a question, return to main menu. */ + if(nQuestion == NO_QUESTION) + { + return; + } + + /* Read the question chosen by the user. */ + if(!GetQuestion(nQuestion, &QuestionRecord)) + { + /* If unable to access file, return to main menu. */ + return; + } + + /* Don't allow addition of new answers if maximum number of answers */ + /* have already been added. */ + if(QuestionRecord.nTotalAnswers >= MAX_ANSWERS) + { + QuestionRecord.bCanAddAnswers = FALSE; + } + + /* Loop until user makes a valid respose. */ + for(;;) + { + /* Display question to user. */ + + /* Clear the screen. */ + od_clr_scr(); + + /* Display question itself. */ + od_printf("`bright red`%s\n\r\n\r", QuestionRecord.szQuestion); + + /* Loop for each answer to the question. */ + for(nAnswer = 0; nAnswer < QuestionRecord.nTotalAnswers; ++nAnswer) + { + /* Display answer number and answer. */ + od_printf("`bright green`%d. `dark green`%s\n\r", + nAnswer + 1, + QuestionRecord.aszAnswer[nAnswer]); + } + + /* Display prompt to user. */ + od_printf("\n\r`bright white`Enter answer number, "); + if(QuestionRecord.bCanAddAnswers) + { + od_printf("[A] to add your own response, "); + } + od_printf("[Q] to quit: `dark green`"); + + /* Get response from user. */ + od_input_str(szUserInput, 2, ' ', 255); + /* Add a blank line. */ + od_printf("\n\r"); + + /* If user entered Q, return to main menu. */ + if(stricmp(szUserInput, "Q") == 0) + { + return; + } + + /* If user enetered A, and adding answers is premitted ... */ + else if (stricmp(szUserInput, "A") == 0 + && QuestionRecord.bCanAddAnswers) + { + /* ... Prompt for answer from user. */ + od_printf("`bright green`Please enter your new answer:\n\r"); + od_printf("`dark green`[------------------------------]\n\r "); + + /* Get string from user. */ + od_input_str(szNewAnswer, ANSWER_STR_SIZE - 1, ' ', 255); + + /* Record that user entered a new answer answer. */ + nAnswer = NEW_ANSWER; + + /* If user entered a valid answer, then exit loop. */ + if(strlen(szNewAnswer) > 0) + { + break; + } + } + + /* Otherwise, attempt to get answer number from user. */ + nAnswer = atoi(szUserInput) - 1; + + /* If user input is not a valid answer. */ + if(nAnswer < 0 || nAnswer >= QuestionRecord.nTotalAnswers) + { + /* Display message. */ + od_printf("That is not a valid response.\n\r"); + WaitForEnter(); + } + else + { + /* Otherwise, exit loop. */ + break; + } + } + + /* Add user's vote to question. */ + + /* Open question file for exclusive access by this node. */ + fpFile = ExclusiveFileOpen(QUESTION_FILENAME, "r+b", &hFile); + if(fpFile == NULL) + { + /* If unable to access file, display error and return. */ + od_printf("Unable to access the question file.\n\r"); + WaitForEnter(); + return; + } + + /* Read the answer record from disk, because it may have been changed. */ + /* by another node. */ + fseek(fpFile, (long)nQuestion * sizeof(tQuestionRecord), SEEK_SET); + if(fread(&QuestionRecord, sizeof(tQuestionRecord), 1, fpFile) != 1) + { + /* If unable to access file, display error and return. */ + ExclusiveFileClose(fpFile, hFile); + od_printf("Unable to read from question file.\n\r"); + WaitForEnter(); + return; + } + + /* If user entered their own answer, try to add it to the question. */ + if(nAnswer == NEW_ANSWER) + { + /* Check that there is still room for another answer. */ + if(QuestionRecord.nTotalAnswers >= MAX_ANSWERS) + { + ExclusiveFileClose(fpFile, hFile); + od_printf("Sorry, this question already has the maximum number of answers.\n\r"); + WaitForEnter(); + return; + } + + /* Set answer number to number of new answer. */ + nAnswer = QuestionRecord.nTotalAnswers; + + /* Add 1 to total number of answers. */ + ++QuestionRecord.nTotalAnswers; + + /* Initialize new answer string and count. */ + strcpy(QuestionRecord.aszAnswer[nAnswer], szNewAnswer); + QuestionRecord.auVotesForAnswer[nAnswer] = 0; + } + + /* Add user's vote to question. */ + ++QuestionRecord.auVotesForAnswer[nAnswer]; + ++QuestionRecord.uTotalVotes; + + /* Write the question record back to the file. */ + fseek(fpFile, (long)nQuestion * sizeof(tQuestionRecord), SEEK_SET); + if(fwrite(&QuestionRecord, sizeof(tQuestionRecord), 1, fpFile) != 1) + { + /* If unable to access file, display error and return. */ + ExclusiveFileClose(fpFile, hFile); + od_printf("Unable to write question to file.\n\r"); + WaitForEnter(); + return; + } + + /* Close the question file to allow access by other nodes. */ + ExclusiveFileClose(fpFile, hFile); + + /* Record that user has voted on this question. */ + CurrentUserRecord.bVotedOnQuestion[nQuestion] = TRUE; + + /* Open user file for exclusive access by this node. */ + fpFile = ExclusiveFileOpen(USER_FILENAME, "r+b", &hFile); + if(fpFile == NULL) + { + /* If unable to access file, display error and return. */ + od_printf("Unable to access the user file.\n\r"); + WaitForEnter(); + return; + } + + /* Update the user's record in the user file. */ + fseek(fpFile, nCurrentUserNumber * sizeof(tUserRecord), SEEK_SET); + if(fwrite(&CurrentUserRecord, sizeof(tUserRecord), 1, fpFile) != 1) + { + /* If unable to access file, display error and return. */ + ExclusiveFileClose(fpFile, hFile); + od_printf("Unable to write to user file.\n\r"); + WaitForEnter(); + return; + } + + /* Close the user file to allow access by other nodes. */ + ExclusiveFileClose(fpFile, hFile); + + /* Display the result of voting on this question to the user. */ + DisplayQuestionResult(&QuestionRecord); + + /* Add 1 to count of questions that the user has voted on. */ + nQuestionsVotedOn++; + } +} + + +/* The ViewResults function is called when the user chooses the "view */ +/* results" command from the main menu. This function alows the user to */ +/* choose a question from the list of questions, and then displays the */ +/* results of voting on that question. */ +void ViewResults(void) +{ + int nChoice; + tQuestionRecord QuestionRecord; + int nPageLocation = 0; + + /* Loop until user chooses to return to main menu. */ + for(;;) + { + /* Allow the user to choose a question from the list of questions that */ + /* they have already voted on. */ + nChoice = ChooseQuestion(nViewResultsFrom, + " View Results\n\r", &nPageLocation); + + /* If the user did not choose a question, return to main menu. */ + if(nChoice == NO_QUESTION) + { + return; + } + + /* Read the specified question number from the question file. */ + if(!GetQuestion(nChoice, &QuestionRecord)) + { + return; + } + + /* Display the results for the selected question. */ + DisplayQuestionResult(&QuestionRecord); + } +} + + +/* The GetQuestion function read the record for the specified question */ +/* number from the question file. */ +int GetQuestion(int nQuestion, tQuestionRecord *pQuestionRecord) +{ + FILE *fpQuestionFile; + int hQuestionFile; + + /* Open the question file for exculsive access by this node. */ + fpQuestionFile = ExclusiveFileOpen(QUESTION_FILENAME, "r+b", + &hQuestionFile); + if(fpQuestionFile == NULL) + { + /* If unable to access file, display error and return. */ + od_printf("Unable to access the question file.\n\r"); + WaitForEnter(); + return(FALSE); + } + + /* Move to location of question in file. */ + fseek(fpQuestionFile, (long)nQuestion * sizeof(tQuestionRecord), SEEK_SET); + + /* Read the question from the file. */ + if(fread(pQuestionRecord, sizeof(tQuestionRecord), 1, fpQuestionFile) != 1) + { + /* If unable to access file, display error and return. */ + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + od_printf("Unable to read from question file.\n\r"); + WaitForEnter(); + return(FALSE);; + } + + /* Close the question file to allow access by other nodes. */ + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + + /* Return with success. */ + return(TRUE); +} + + +/* The AddQuestion() function is called when the user chooses the "add */ +/* question" option from the main menu. This function allows the user */ +/* to enter a new question, possible responses, and save the question for */ +/* other users to vote on. */ +void AddQuestion(void) +{ + tQuestionRecord QuestionRecord; + FILE *fpQuestionFile; + int hQuestionFile; + char szLogMessage[100]; + + /* Clear the screen. */ + od_clr_scr(); + + /* Display screen header. */ + od_printf("`bright red` Add A Question\n\r"); + od_printf("`dark red`"); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r\n\r"); + + /* Obtain quesiton text from the user. */ + od_printf("`bright green`Enter Your Question (blank line cancels)\n\r"); + od_printf("`dark green`[----------------------------------------------------------------------]\n\r "); + od_input_str(QuestionRecord.szQuestion, QUESTION_STR_SIZE - 1, ' ', 255); + + /* If question was empty, then return to main menu. */ + if(strlen(QuestionRecord.szQuestion) == 0) + { + return; + } + + /* Display prompt for answers. */ + od_printf("\n\r`bright green`Enter Possible Answers (blank line when done)\n\r"); + od_printf("`dark green` [------------------------------]\n\r"); + + /* Loop, getting answers from user. */ + for(QuestionRecord.nTotalAnswers = 0; + QuestionRecord.nTotalAnswers < MAX_ANSWERS; + QuestionRecord.nTotalAnswers++) + { + /* Display prompt with answer number. */ + od_printf("`bright green`%2d: `dark green`", QuestionRecord.nTotalAnswers + 1); + + /* Get string from user. */ + od_input_str(QuestionRecord.aszAnswer[QuestionRecord.nTotalAnswers], + ANSWER_STR_SIZE - 1, ' ', 255); + + /* If string was empty, then exit loop. */ + if(strlen(QuestionRecord.aszAnswer[QuestionRecord.nTotalAnswers]) == 0) + { + break; + } + + /* Reset count of votes for this answer to zero. */ + QuestionRecord.auVotesForAnswer[QuestionRecord.nTotalAnswers] = 0; + } + + /* If no answers were supplied, then cancel, returning to main menu. */ + if(QuestionRecord.nTotalAnswers == 0) + { + return; + } + + /* Ask whether users should be able to add their own answers. */ + od_printf("\n\r`bright green`Should voters be able to add their own options? (Y/N) `dark green`"); + + /* Get answer from user. */ + if(od_get_answer("YN") == 'Y') + { + /* If user pressed the 'Y' key. */ + od_printf("Yes\n\r\n\r"); + + /* Record user's response. */ + QuestionRecord.bCanAddAnswers = TRUE; + } + else + { + /* If user pressed the 'N' key. */ + od_printf("No\n\r\n\r"); + + /* Record user's response. */ + QuestionRecord.bCanAddAnswers = FALSE; + } + + /* Confirm save of new question. */ + od_printf("`bright green`Do you wish to save this new question? (Y/N) `dark green`"); + + /* If user does not want to save the question, return to main menu now. */ + if(od_get_answer("YN") == 'N') + { + return; + } + + /* Set total number of votes for this question to 0. */ + QuestionRecord.uTotalVotes = 0; + + /* Set creator name and creation time for this question. */ + strcpy(QuestionRecord.szCreatorName, od_control.user_name); + QuestionRecord.lCreationTime = time(NULL); + + /* Open question file for exclusive access by this node. */ + fpQuestionFile = ExclusiveFileOpen(QUESTION_FILENAME, "a+b", + &hQuestionFile); + if(fpQuestionFile == NULL) + { + od_printf("Unable to access the question file.\n\r"); + WaitForEnter(); + return; + } + + /* Determine number of records in question file. */ + fseek(fpQuestionFile, 0, SEEK_END); + + /* If question file is full, display message and return to main menu */ + /* after closing file. */ + if(ftell(fpQuestionFile) / sizeof(tQuestionRecord) >= MAX_QUESTIONS) + { + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + od_printf("Cannot add another question, Vote is limited to %d questions.\n\r", MAX_QUESTIONS); + WaitForEnter(); + return; + } + + /* Add new question to file. */ + if(fwrite(&QuestionRecord, sizeof(QuestionRecord), 1, fpQuestionFile) != 1) + { + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + od_printf("Unable to write to question file.\n\r"); + WaitForEnter(); + return; + } + + /* Close question file, allowing other nodes to access file. */ + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + + /* Record in the logfile that user has added a new question. */ + sprintf(szLogMessage, "User adding questions: %s", + QuestionRecord.szQuestion); + od_log_write(szLogMessage); +} + + +/* The ChooseQuestion() function provides a list of questions and allows */ +/* the user to choose a particular question, cancel back to the main menu, */ +/* and page up and down in the list of questions. Depending upon the value */ +/* of the nFromWhichQuestions parameter, this function will present a list */ +/* of questions that the user has voted on, a list of questions that the */ +/* user has not voted on, or a list of all questions. */ +int ChooseQuestion(int nFromWhichQuestions, char *pszTitle, int *nLocation) +{ + int nCurrent; + int nFileQuestion = 0; + int nPagedToQuestion = *nLocation; + int nDisplayedQuestion = 0; + char bVotedOnQuestion; + char chCurrent; + tQuestionRecord QuestionRecord; + FILE *fpQuestionFile; + int hQuestionFile; + static char szQuestionName[MAX_QUESTIONS][QUESTION_STR_SIZE]; + static int nQuestionNumber[MAX_QUESTIONS]; + + /* Attempt to open question file. */ + fpQuestionFile = ExclusiveFileOpen(QUESTION_FILENAME, "r+b", + &hQuestionFile); + + /* If unable to open question file, assume that no questions have been */ + /* created. */ + if(fpQuestionFile == NULL) + { + /* Display "no questions yet" message. */ + od_printf("\n\rNo questions have been created so far.\n\r"); + + /* Wait for user to press enter. */ + WaitForEnter(); + + /* Indicate that no question has been chosen. */ + return(NO_QUESTION); + } + + /* Loop for every question record in the file. */ + while(fread(&QuestionRecord, sizeof(QuestionRecord), 1, fpQuestionFile) == 1) + { + /* Determine whether or not the user has voted on this question. */ + bVotedOnQuestion = CurrentUserRecord.bVotedOnQuestion[nFileQuestion]; + + /* If this is the kind of question that the user is choosing from */ + /* right now. */ + if((bVotedOnQuestion && (nFromWhichQuestions & QUESTIONS_VOTED_ON)) || + (!bVotedOnQuestion && (nFromWhichQuestions & QUESTIONS_NOT_VOTED_ON))) + { + /* Add this question to list to be displayed. */ + strcpy(szQuestionName[nDisplayedQuestion], + QuestionRecord.szQuestion); + nQuestionNumber[nDisplayedQuestion] = nFileQuestion; + + /* Add one to number of questions to be displayed in list. */ + nDisplayedQuestion++; + } + + /* Move to next question in file. */ + ++nFileQuestion; + } + + /* Close question file to allow other nodes to access the file. */ + ExclusiveFileClose(fpQuestionFile, hQuestionFile); + + /* If there are no questions for the user to choose, display an */ + /* appropriate message and return. */ + if(nDisplayedQuestion == 0) + { + /* If we were to list all questions. */ + if((nFromWhichQuestions & QUESTIONS_VOTED_ON) + && (nFromWhichQuestions & QUESTIONS_NOT_VOTED_ON)) + { + od_printf("\n\rThere are no questions.\n\r"); + } + /* If we were to list questions that the user has voted on. */ + else if(nFromWhichQuestions & QUESTIONS_VOTED_ON) + { + od_printf("\n\rThere are no questions that you have voted on.\n\r"); + } + /* Otherwise, we were to list questions that use has not voted on. */ + else + { + od_printf("\n\rYou have voted on all the questions.\n\r"); + } + + /* Wait for user to press enter key. */ + WaitForEnter(); + + /* Return, indicating that no question was chosen. */ + return(NO_QUESTION); + } + + /* Ensure that initial paged to location is within range. */ + while(nPagedToQuestion >= nDisplayedQuestion) + { + nPagedToQuestion -= QUESTION_PAGE_SIZE; + } + + /* Loop, displaying current page of questions, until the user makes a */ + /* choice. */ + for(;;) + { + /* Clear the screen. */ + od_clr_scr(); + + /* Display header. */ + od_printf("`bright red`"); + od_printf(pszTitle); + od_printf("`dark red`"); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r"); + + /* Display list of questions on this page. */ + for(nCurrent = 0; + nCurrent < QUESTION_PAGE_SIZE + && nCurrent < (nDisplayedQuestion - nPagedToQuestion); + ++nCurrent) + { + /* Determine character to display for current line. */ + if(nCurrent < 9) + { + chCurrent = (char)('1' + nCurrent); + } + else + { + chCurrent = (char)('A' + (nCurrent - 9)); + } + + /* Display this question's title. */ + od_printf("`bright green`%c.`dark green`", chCurrent); + od_printf(" %s\n\r", szQuestionName[nCurrent + nPagedToQuestion]); + } + + /* Display prompt for input. */ + od_printf("\n\r`bright white`[Page %d] Choose a question or", + (nPagedToQuestion / QUESTION_PAGE_SIZE) + 1); + if(nPagedToQuestion < nDisplayedQuestion - QUESTION_PAGE_SIZE) + { + od_printf(" [N]ext page,"); + } + if(nPagedToQuestion > 0) + { + od_printf(" [P]revious page,"); + } + od_printf(" [Q]uit.\n\r"); + + /* Loop until the user makes a valid choice. */ + for(;;) + { + /* Get input from user */ + chCurrent = (char)od_get_key(TRUE); + chCurrent = (char)toupper(chCurrent); + + /* Respond to user's input. */ + + /* If user pressed Q key. */ + if(chCurrent == 'Q') + { + /* Return without a choosing a question. */ + return(NO_QUESTION); + } + + /* If user pressed P key. */ + else if(chCurrent == 'P') + { + /* If we are not at the first page. */ + if(nPagedToQuestion > 0) + { + /* Move paged to location up one page. */ + nPagedToQuestion -= QUESTION_PAGE_SIZE; + + /* Exit user input loop to display next page. */ + break; + } + } + + /* If user pressed N key. */ + else if(chCurrent == 'N') + { + /* If there is more questions after this page. */ + if(nPagedToQuestion < nDisplayedQuestion - QUESTION_PAGE_SIZE) + { + /* Move paged.to location down one page. */ + nPagedToQuestion += QUESTION_PAGE_SIZE; + + /* Exit user input loop to display next page. */ + break; + } + } + + /* Otherwise, check whether the user chose a valid question. */ + else if ((chCurrent >= '1' && chCurrent <= '9') + || (chCurrent >= 'A' && chCurrent <= 'H')) + { + /* Get question number from key pressed. */ + if(chCurrent >= '1' && chCurrent <= '9') + { + nCurrent = chCurrent - '1'; + } + else + { + nCurrent = (chCurrent - 'A') + 9; + } + + /* Add current paged to position to user's choice. */ + nCurrent += nPagedToQuestion; + + /* If this is valid question number. */ + if(nCurrent < nDisplayedQuestion) + { + /* Set caller's current question number. */ + *nLocation = nPagedToQuestion; + + /* Return actual question number in file. */ + return(nQuestionNumber[nCurrent]); + } + } + } + } +} + + +/* The DisplayQuestionResult() function is called to display the results */ +/* of voting on a paricular question, and is passed the question record */ +/* of the question. This function is called when the user selects a */ +/* question using the "view results" option, and is also called after */ +/* the user has voted on a question, to display the results of voting on */ +/* that question. */ +void DisplayQuestionResult(tQuestionRecord *pQuestionRecord) +{ + int nAnswer; + int uPercent; + + /* Clear the screen. */ + od_clr_scr(); + + /* Check that there have been votes on this question. */ + if(pQuestionRecord->uTotalVotes == 0) + { + /* If there have been no votes for this question, display a message */ + /* and return. */ + od_printf("Nobody has voted on this question yet.\n\r"); + WaitForEnter(); + return; + } + + /* Display question itself. */ + od_printf("`bright red`%s\n\r", pQuestionRecord->szQuestion); + + /* Display author's name. */ + od_printf("`dark red`Question created by %s on %s\n\r", + pQuestionRecord->szCreatorName, + ctime(&pQuestionRecord->lCreationTime)); + + /* Display heading for responses. */ + od_printf("`bright green`Response Votes Percent Graph\n\r`dark green`"); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r"); + + /* Loop for each answer to the question. */ + for(nAnswer = 0; nAnswer < pQuestionRecord->nTotalAnswers; ++nAnswer) + { + /* Determine percent of users who voted for this answer. */ + uPercent = (pQuestionRecord->auVotesForAnswer[nAnswer] * 100) + / pQuestionRecord->uTotalVotes; + + /* Display answer, total votes and percentage of votes. */ + od_printf("`dark green`%-30.30s %-5u %3u%% `bright white`", + pQuestionRecord->aszAnswer[nAnswer], + pQuestionRecord->auVotesForAnswer[nAnswer], + uPercent); + + /* Display a bar graph corresponding to percent of users who voted */ + /* for this answer. */ + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)220, (unsigned char)((uPercent * 31) / 100)); + } + else + { + od_repeat('=', (unsigned char)((uPercent * 31) / 100)); + } + + /* Move to next line. */ + od_printf("\n\r"); + } + + /* Display footer. */ + od_printf("`dark green`"); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat((unsigned char)196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r"); + od_printf("`dark green` TOTAL: %u\n\r\n\r", + pQuestionRecord->uTotalVotes); + + /* Wait for user to press enter. */ + WaitForEnter(); +} + + +/* The ReadOrAddCurrentUser() function is used by Vote to search the */ +/* Vote user file for the record containing information on the user who */ +/* is currently using the door. If this is the first time that the user */ +/* has used this door, then their record will not exist in the user file. */ +/* In this case, this function will add a new record for the current */ +/* user. This function returns TRUE on success, or FALSE on failure. */ +int ReadOrAddCurrentUser(void) +{ + FILE *fpUserFile; + int hUserFile; + int bGotUser = FALSE; + int nQuestion; + + /* Attempt to open the user file for exclusize access by this node. */ + /* This function will wait up to the pre-set amount of time (as defined */ + /* near the beginning of this file) for access to the user file. */ + fpUserFile = ExclusiveFileOpen(USER_FILENAME, "a+b", &hUserFile); + + /* If unable to open user file, return with failure. */ + if(fpUserFile == NULL) + { + return(FALSE); + } + + /* Begin with the current user record number set to 0. */ + nCurrentUserNumber = 0; + + /* Loop for each record in the file */ + while(fread(&CurrentUserRecord, sizeof(tUserRecord), 1, fpUserFile) == 1) + { + /* If name in record matches the current user name ... */ + if(strcmp(CurrentUserRecord.szUserName, od_control.user_name) == 0) + { + /* ... then record that we have found the user's record, */ + bGotUser = TRUE; + + /* and exit the loop. */ + break; + } + + /* Move user record number to next user record. */ + nCurrentUserNumber++; + } + + /* If the user was not found in the file, attempt to add them as a */ + /* new user if the user file is not already full. */ + if(!bGotUser && nCurrentUserNumber < MAX_USERS) + { + /* Place the user's name in the current user record. */ + strcpy(CurrentUserRecord.szUserName, od_control.user_name); + + /* Record that user hasn't voted on any of the questions. */ + for(nQuestion = 0; nQuestion < MAX_QUESTIONS; ++nQuestion) + { + CurrentUserRecord.bVotedOnQuestion[nQuestion] = FALSE; + } + + /* Write the new record to the file. */ + if(fwrite(&CurrentUserRecord, sizeof(tUserRecord), 1, fpUserFile) == 1) + { + /* If write succeeded, record that we now have a valid user record. */ + bGotUser = TRUE; + } + } + + /* Close the user file to allow other nodes to access it. */ + ExclusiveFileClose(fpUserFile, hUserFile); + + /* Return, indciating whether or not a valid user record now exists for */ + /* the user that is currently online. */ + return(bGotUser); +} + + +/* The WriteCurrentUser() function is called to save the information on the */ +/* user who is currently using the door, to the VOTE.USR file. */ +void WriteCurrentUser(void) +{ + FILE *fpUserFile; + int hUserFile; + + /* Attempt to open the user file for exclusize access by this node. */ + /* This function will wait up to the pre-set amount of time (as defined */ + /* near the beginning of this file) for access to the user file. */ + fpUserFile = ExclusiveFileOpen(USER_FILENAME, "r+b", &hUserFile); + + /* If unable to access the user file, display an error message and */ + /* return. */ + if(fpUserFile == NULL) + { + od_printf("Unable to access the user file.\n\r"); + WaitForEnter(); + return; + } + + /* Move to appropriate location in user file for the current user's */ + /* record. */ + fseek(fpUserFile, (long)nCurrentUserNumber * sizeof(tUserRecord), SEEK_SET); + + /* Write the new record to the file. */ + if(fwrite(&CurrentUserRecord, sizeof(tUserRecord), 1, fpUserFile) == 1) + { + /* If unable to write the record, display an error message. */ + ExclusiveFileClose(fpUserFile, hUserFile); + od_printf("Unable to update your user record file.\n\r"); + WaitForEnter(); + return; + } + + /* Close the user file to allow other nodes to access it again. */ + ExclusiveFileClose(fpUserFile, hUserFile); +} + + +/* This function is used by Vote to open a file. If Vote has been compiled */ +/* with #define MULTINODE_AWARE uncommented (see the beginning of this */ +/* file), file access is performed in a multinode-aware way. This implies */ +/* that the file is opened of exclusive access, using share-aware open */ +/* functions that may not be available using all compilers. */ +FILE *ExclusiveFileOpen(char *pszFileName, char *pszMode, int *phHandle) +{ +#ifdef MULTINODE_AWARE + /* If Vote is being compiled for multinode-aware file access, then */ + /* attempt to use compiler-specific share-aware file open functions. */ + FILE *fpFile = NULL; + time_t StartTime = time(NULL); + int hFile; + + /* Attempt to open the file while there is still time remaining. */ + while((hFile = sopen(pszFileName, O_BINARY | O_RDWR, SH_DENYRW, + S_IREAD | S_IWRITE)) == -1) + { + /* If we have been unable to open the file for more than the */ + /* maximum wait time, or if open failed for a reason other */ + /* than file access, then attempt to create a new file and */ + /* exit the loop. */ + if(errno != EACCES || + difftime(time(NULL), StartTime) >= FILE_ACCESS_MAX_WAIT) + { + hFile = sopen(pszFileName, O_BINARY | O_CREAT, SH_DENYRW, + S_IREAD | S_IWRITE); + break; + } + + /* If we were unable to open the file, call od_kernel, so that */ + /* OpenDoors can continue to respond to sysop function keys, loss */ + /* of connection, etc. */ + od_kernel(); + } + + /* Attempt to obtain a FILE * corresponding to the handle. */ + if(hFile != -1) + { + fpFile = fdopen(hFile, pszMode); + if(fpFile == NULL) + { + close(hFile); + } + } + + /* Pass file handle back to the caller. */ + *phHandle = hFile; + + /* Return FILE pointer for opened file, if any. */ + return(fpFile); +#else + /* Ignore unused parameters. */ + (void)phHandle; + + /* If Vote is not being compiled for multinode-aware mode, then just */ + /* use fopen to access the file. */ + return(fopen(pszFileName, pszMode)); +#endif +} + + +/* The ExclusiveFileClose() function closes a file that was opened using */ +/* ExclusiveFileOpen(). */ +void ExclusiveFileClose(FILE *pfFile, int hHandle) +{ + fclose(pfFile); +#ifdef MULTINODE_AWARE + close(hHandle); +#else + /* Ignore unused parameters. */ + (void)hHandle; +#endif +} + + +/* The WaitForEnter() function is used by Vote to create its custom */ +/* "Press [ENTER] to continue." prompt. */ +void WaitForEnter(void) +{ + /* Display prompt. */ + od_printf("`bright white`Press [ENTER] to continue.\n\r"); + + /* Wait for a Carriage Return or Line Feed character from the user. */ + od_get_answer("\n\r"); +} diff --git a/utils/magiedit/odoors/hbuild.bat b/utils/magiedit/odoors/hbuild.bat new file mode 100644 index 0000000..8d76e20 --- /dev/null +++ b/utils/magiedit/odoors/hbuild.bat @@ -0,0 +1 @@ +make -fDOS.mak -DTARGET=h > out.txt diff --git a/utils/magiedit/odoors/historic/ODHIST.TXT b/utils/magiedit/odoors/historic/ODHIST.TXT new file mode 100644 index 0000000..e69cb79 --- /dev/null +++ b/utils/magiedit/odoors/historic/ODHIST.TXT @@ -0,0 +1,809 @@ + OpenDoors Door Programming Toolkit History + ------------------------------------------ + +This document describes the development history of the OpenDoors door +programming toolkit. This document is divided into two sections. The +first section provides a brief timeline of the OpenDoors releases since +version 1.00. The second section provides detailed information on the +changes and enhancements that were made for each version. + + +OPENDOORS TIME LINE +------------------- + +VERSION RELEASE DATE HIGHLIGHTS +------------------------------------------------------------------------------- +1.00 Fall, 1990 Initial beta version +1.10 Winter, 1991 First public release +1.20 Spring, 1991 Minor enhancments, including RA 1.00 support +1.30 Spring, 1991 A Few bug fixes +1.40 Spring, 1991 Message customizability +2.00 Summer, 1991 AVATAR support, improved ANSI support +2.10 Summer, 1991 Added od_printf() and a new registration key system +2.20 Summer, 1991 Further customizability, DesqView support +2.30 Summer, 1991 Minor bug fix +3.00 Fall, 1991 Beta release, with RA system file support +3.10 Fall, 1991 Public release with bug fixes from 3.00 +3.20 Winter, 1992 Support for enhanced FILES.BBS format +3.30 Winter, 1992 Further bug fiexes +3.40 May, 1992 Full locked-BPS rate support +4.00 July, 1992 New manual, inline colour setting with od_printf() +4.10 February, 1993 Configuration file and log file systems +5.00 September, 1994 Built-in serial I/O, multiple compiler support + + + +DETAILED HISTORY OF OPENDOORS EVOLUTION +--------------------------------------- + +VERSION 1.00 Initial beta test version of the OpenDoors doordriver. Proved to + be very bug-free. + + +VERSION 1.10 First public release. + + +VERSION 1.20 Made several changes: + + - Support for the new RemoteAccess 1.00 enhanced + exitinfo.bbs file, with many extra pieces of information. + + - Added a Alt-K function key to allow the sysop to + temporarily disable the user's keyboard + + - Added full support for turning on and off status line. + Status line has been changed slightly in format, and [F9] + help function key added. + + - Improved sysop chat mode (added multi-colour and wordwrap) + + - Fixed up shell-to-DOS to automatically shell to the + command processor specified in COMSPEC instead of always + using COMMAND.COM. OpenDoors now also returns to system to + the drive and directory it was in before DOS shell was + issued. + + - Added support for the new RemoteAccess "sysop next" key. + + +VERSION 1.30 A few quick changes to perfect all the features of this version + before beginning major development work on OpenDoors 2.00. Fixed + two problems: + + - The status line can no longer be turned back on by the + sysop using F1 - F9 keys when a door program has disable + the status line itself. + + - A rather major problem was fixed for use of OpenDoors in + conjunction with RA 1.00. We accidentally forgot to save + some of the data that is unused in previous versions, but + is now used in the new version. This bug caused some + unexpected problems, including damage to the USERSXI.BBS + file. + + +VERSION 1.40 Another maintenance release. This version should now function + perfectly when used in conjunction with older versions of Turbo + C. Other changes in this version include: + + - Better error recovery in the case that the door + information file has been damaged. + + - OpenDoors was made more customizable, including allowing + the programmer to alter the various OpenDoors messages, + and provisions for user defined function keys for the + sysop. (ie, it is now possible for the programmer to make + Alt-Y another hotkey for the sysop) + + +VERSION 2.00 Another release, adding a number of new features, such as: + + - Added support for AVATAR graphics. OpenDoors will + automatically detect the presence of AVATAR graphics mode + when running under Remote Access, and will allow your door + to toggle it when running under other BBS systems. + + - Improved ANSI routines. Added some new functions, and + changed existing functions to send more efficient ANSI + codes in some circumstances. + + - The "Sysop Next" key should now work correctly with RA + 1.00 and later. + + +VERSION 2.10 Changes in this version include: + + - Implementation of a registration key-code to allow + registered users to more easily upgrade to new versions. + + - Added an od_printf() function for ease of formatted output + from within OpenDoors. + + +VERSION 2.20 More improvements, including: + + - Fixing of some minor bugs, such as incorrect handling of + the path to DORINFO1.DEF/EXITINFO.BBS files. + + - Added support for more customization, such as hooks for + functions that will be called before and after Shell to + DOS and sysop chat. + + - OpenDoors is now DesqView aware. OpenDoors will + automatically detect the presence of DesqView, and uses + the DesqView `virtual screen buffer' for screen display if + present. + + - A QuickBBS 2.75 compatibility problem has also been fixed. + + +VERSION 2.30 Fixed a small bug in the registration system. + + +VERSION 3.00 A major upgrade, released as a beta-test version, including the + following additions/changes: + + - Eliminated many bugs. + + - Added support for door information files from: WWIV, PC- + Board, Spitfire, WildCat, GAP, TriTel and others. + + - Added .ASC/.ANS/.AVT file display support with automatic + interpretation of QBBS/SuperBBS/RA control characters. + + - Added ALT-D key to drop the user back to the BBS without + hanging up. + + - Added direct access to RA style configuration, file area, + message area, external protocols, event configuration, + caller history, users online, menu files, user base and + other system files. + + - Added complete set of message base manipulation routines, + with full support for the RA 1.01 message base locking + scheme. + + - The user manual has also been re-written in order to make + it easier to work with. + + +VERSION 3.10 The following bug fixes and changes have been made since the + release of the beta version, 3.00: + + - Time fields in messages are now correctly formatted + + - Corrected a bug in the od_set_attrib function where the + intensity setting would not correctly be transmitted to + the remote when using ANSI graphics. + + - Fixed a bug in the re-writing of the DORINFO1.DEF which + cause sysop and user's last names to be corrupted. + + - Registered users may now disable the display of copyright + and registration information when the door starts up. + + +VERSION 3.20 A few more changes and bug fixes were made since version 3.10, + including: + + - Fixed the FILES.BBS lister to correctly support FILES.BBS + files located in directories other than the default dir, + and added page pausing to the FILES.BBS lister. + + +VERSION 3.30 The following changes and bug fixes were made since version 3.20: + + - OpenDoors no longer re-writes the DORINFO1.DEF upon + exiting. No BBS's are known to actually make use of the + information changed in DORINFO1.DEF, and re-writing this + file was causing more troubles than it was worth. + + - The od_msg_read_hdr() function's NEXT_MESSAGE command now + works correctly. + + - Added an od_errno variable to assist in debugging of + programs written with the BBS file engine portion of + OpenDoors. + + +VERSION 3.40 A minor upgrade version, with the following changes: + + - Fixed a compatibility problem with some locked baud rates. + Now, if OpenDoors receives a baud rate the door + information file that is not supported in the FOSSIL + definitions, it will continue without setting the baud + rate. (Whereas before, OpenDoors would report an error and + exit.) + + - Made some changes to the manual, and included a utility to + remove the extended-ASCII characters from the manual to + ease printing on some printers. + + +VERSION 4.00 This version is a major overhaul of the entire OpenDoors package, + including a great many enhancements and additions. As of version + 4.00, OpenDoors is available as two separate packages - the door + programming toolkit (this package), and the BBS interface package + (which is available separately) Among the major changes to + version 4.00 of the OpenDoors door programming toolkit are: + + - A complete re-organization of the manual, including the + re-writing of a large portion of the manual. In order to + ease printing on some printers, the manual has been re- + formatted in order that it no longer contains extended + ASCII characters. More thorough documentation on the + OpenDoors functions and structures was written, along with + the addition of many more examples. Also added to the + manual are an index, glossary and other features intended + to make the reference manual an even more powerful and + flexible tool. + + - Full support for the changes to RemoteAccess 1.10/1.11 has + been added for version 4.00. These include the addition of + some new fields stored in the EXITINFO.BBS door + information file, and proper adjusting of the user's time + remaining online. Version 4.00 also now has full support + for the new QuickBBS-specific EXITINFO.BBS file. + + - All of the text displayed by OpenDoors is now fully + customizable using od_control structure variables. This + permits both greater door customization, and adds the + ability to write 100% non-English doors and programs. + + - The OpenDoors status lines have been changed. OpenDoors + now provides additional user information through multiple + RemoteAccess-style status lines, accessible through the + F2, F3, etc. keys. Also, the status line may now be turned + off by using the F10 key, allowing the sysop to view all + 25-lines of the information displayed by a door program. A + new function od_set_statusline(), permits program + selection of the current status line setting. + + - OpenDoors now allows colour codes to be embedded in + od_printf() functions, to eliminate the need for long + chains of alternating od_disp_str(), od_set_colour() / + od_set_attrib() function calls. + + - A new formatted input function, od_edit_str() has been + added for use in door programs running in ANSI or AVATAR + graphics mode. The od_edit_str() function features + advanced line editing capabilities which are normally + found only in non-door programs, such as inserting or + deleting text from the middle of a string, moving the + cursor with the arrow keys, and so on. The od_edit_str() + function also provides input formatting, allowing you to + force the user's input into any format you wish, from + phone number formats to date formats to username formats. + The od_edit_str() also provides special modes for + implementing features such as password input, field input + (where the user may move from one field to another using + arrow/tab keys), input field highlighting, editing + existing strings, auto-delete, and much more. The old + od_input_str() function still provides a subset of these + features which do not require ANSI or AVATAR graphics. + + - New functions have been added to the door driver module of + OpenDoors. Among these, are an od_putch() function for + displaying one character at a time, and an od_spawn() + function, for easily executing other programs from within + OpenDoors. The od_spawn() function automatically saves the + contents of the current door screen, system drive and + directory, and provides a separate screen on which the + spawned-to program can execute. The od_draw_box() function + allows you to easily display windows in door programs, + using ANSI or AVATAR graphics codes. Also added is are + od_carrier(), od_set_statusline() and od_edit_str() + functions, mentioned elsewhere. + + - More changes have been made in order to permit greater + customization and flexibility of OpenDoors. An + od_carrier() function has been added to detect the state + of the carrier detect signal in programs that disable + OpenDoor's internal carrier detection. Also, it is now + possible to shut down OpenDoors without exiting via the + od_exit() function. + + - OpenDoors now yeilds the processor to other executing + tasks in multitasking environments (ie. DesqView), when + the door is inactive or waiting for input. + + - The door driver function od_clr_scr() now only checks the + user's screen clearing setting if that information is + available from the door information file. If the + information is not available, the od_clr_scr() function + will always clear the screen. + + - Many other small changes were also made for version 4.00. + Among these, you now have access to the user's reason for + chat and you can switch the pause and stop keys on and off + during listing of available files or displaying a text + file. Also, previous versions of OpenDoors would read the + user's information from the first door information file + found. Instead, version 4.00 now reads the most recently + created door information file. A bug in the od_clr_line() + function has also been fixed. + + +VERSION 4.10 A great deal of work has been done between version 4.00 and 4.10 + of OpenDoors. This work falls into three major categories: bug + fixes, improved performance, and new features. In fact, enough + changes and improvements have been made that this version really + ought to be numbered 5.00. Below is a summary of the changes that + have occurred since version 4.00: + - Much of the door information file interfacing code has + been revamped, in order that OpenDoors now works correctly + with the newest versions of the BBS packages it supports. + OpenDoors now differentiates between three different + DOOR.SYS formats - the DoorWay format, the PC-Board / GAP + format, and the Wildcat format. Also, the SFDOORS.DAT code + has been fixed to correctly work with the newest version + of Spitfire. + + - OpenDoors will now attempt to swap itself and your entire + door program to expanded memory or disk when the sysop + shells to DOS, or when you call one of the od_spawn...() + functions. Memory swapping may be configured in a number + of ways, or even disabled. The OpenDoors swapping code + adds only 2K to the door's .EXE file size. + + - OpenDoors now includes a new od_spawnvpe() function. In + addition to the features of the "quick-spawn" od_spawn() + function, od_spawnvpe() also returns the errorlevel the + called program returned, allows you to alter the + environment passed to the child process, and uses the same + parameter format as the C spawnvpe() function. (see page + 117) + + - The od_page() function now checks the sysop paging hours, + set in the OpenDoors control structure. If the user + attempts to page the sysop outside of the defined paging + hours, he or she will be notified that the sysop is not + available. + + - OpenDoors now includes a configuration file sub-system + that you may choose to include in your OpenDoors programs. + This sub-system automatically parses the configuration + file you specify, responding to any of the built-in + configuration commands, and passing configuration options + specific to your program back to you. With only a single + line of code on your part, this sub-system will allow + people running your program to configure many options such + as sysop paging hours, system directories, maximum time + within the door, etc. It also allows the sysop to provide + information that may not be supplied by their particular + BBS software, such as modem settings, the system's name + and so on. In addition to all these built in commands, you + can add your own configuration options, such as display + colours, registration key numbers and other information + needed by your program - without the need to write your + own configuration file parsing routines. (See page 76) + + - OpenDoors now supports custom, sysop-defined door + information file (drop file) formats. By defining a custom + door information file format in the cofiguration file, + OpenDoors door programs can now be made to run directly + under BBS packages that use proprietary file formats that + are not directly supported by OpenDoors. (see page 78) + + - In order to make doors written with OpenDoors even more + foolproof for the sysop to setup, an intelligent door + information file (drop file) locator has been added. + OpenDoors will automatically search for a door information + file in the directory specified by the configuration file, + the directory specified by your door's source code, the + current directory, and the directory pointed to by the + environment variables used by any of a number of BBS + packages. + + - OpenDoors now includes a log file sub-system that you may + choose to include in your programs. The log file system + handles all access and formatting of the logfile, allowing + the programmer to make log file entries by simple function + calls such as od_write_log("User downloading file");. + Also, since the log file system is closely integrated with + the rest of OpenDoors, choosing to include the logfile + system in a program causes OpenDoors to automatically + output the most common logfile entries for events such as + the user paging sysop, the user hanging up, sysop chatting + with the user, user inactivity timeouts, and so on. (see + page 89) + + - OpenDoors 4.00 would not always correctly turn on and off + high intensity or flashing colour attributes in ANSI mode. + The ANSI colour handling code has been reworked for + version 4.10, to eliminate these problems. + + - An od_get_answer() function has been added, which can be + used to easily permit only certain keys to be pressed in + response to a prompt. For instance, to get a Yes/No + response from the user, use od_get_answer("YN"); (see page + 66) + + - A popular addition to OpenDoors 4.00 was the ability to + change the current display colour within od_printf() + format strings, using imbedded control characters. + However, the programmer was forced to use a rather cryptic + two-byte control sequence, where the second character of + the sequence contained an 8-bit colour attribute value. It + is now possible to change the display colour within + od_printf() by specifying the names of the desired + foreground and background colours, delimited by a set of + BACK-QUOTE (`) characters. For example: + + od_printf("`Red` THIS TEXT IS RED `Blue` THIS TEXT IS BLUE"); + od_printf("`Flashing bright green on dark green` AND THIS IS GREEN"); + + (see page 93) + + - Version 4.10 would not correctly "freeze" the user's time + during DOS shell and sysop page operations, when the door + was operating under RemoteAccess 1.11. This has been + fixed. + + - A new variable, od_spawn_freeze_time, has been added to + the OpenDoors control structure. When set to FALSE, the + user's time remaining continues to be deducted during the + execution of any of the od_spawn... functions. When set to + TRUE, the user's time remaining is frozen during the + execution of an od_spawn... function. + + - The current directory is now correctly restored to its + original setting after the sysop returns from a DOS shell, + and after calls to the od_spawn... functions. + + - A number of people were experiencing difficulty using the + od_edit_str() function in version 4.00. A number of + improvements to this function's logic have been made in an + attempt to make od_edit_str() more foolproof to use. Also, + a new flag setting, EDIT_FLAG_LEAVE_BLANK has been added. + However, there were a few reports of problems which we + were not able to reproduce. If you are still having + difficulty with this function, please carefully re-read + the section of the manual pertaining to it's use. In + particular, be sure that your difficulty is not resulting + from the flag settings you are using. If you still suspect + a bug in this function, please include with your bug + report the source code that is causing the problem. + + - Page pausing within the od_send_file() and od_list_files() + (FILES.BBS listing routine) functions can now be disabled + and re-enabled by the programmer. + + - The "Continue? [Y/n/=]" end of screen prompt and response + keys are now fully customizable. + + - The od_list_files() FILES.BBS listing function now works + correctly in all memory models. The function has also been + fixed to correctly handle cases where the trailing + backslash is not supplied in the path parameter. + + - The actual BBS line (node) number is now displayed on the + default status line, provided that this information is + supplied by the BBS software. + + - It is now possible to detect whether keystrokes originated + from the remote or local keyboard. This is a feature that + is useful in some special applications, such as split- + screen sysop chat programs. + + - Version 4.00 would not always correctly display the status + lines, if there was information missing from the + EXITINFO.BBS file. This has been fixed. In addition, the + "next event" information is now correctly displayed on the + status lines. Also, if the user's birthday is available, + their age will also be calculated and displayed on the + status line. + + - If you temporarily disable inactivity timeouts, OpenDoors + will no longer automatically trigger and inactivity + timeout as soon as you re-enable this feature. + + - A new function, od_hotkey_menu(), has been added to + facilitate displaying a menu with "hot keys". Like the + od_send_file() function, od_hotkey_menu() will display an + ASCII, ANSI or AVATAR file. However, od_hotkey_menu() also + allows you to pass a string listing possible hot keys. If + the user presses any of these keys while the menu is being + displayed, menu display will immediately cease, and the + function will return the key pressed by the user. (See + page 71) + + - The od_send_file() (the ASCII/ANSI/AVATAR file display + routine) no longer sends the EOF character if it happens + to exist at the end of a file. + + - In addition to the EZVote OpenDoors tutorial door, an + number of other example doors are now included in the + OpenDoors package. + + - A few errors have been corrected in the documentation, and + additional information has been added about the new + features in this version. + + + +VERSION 5.00 Version 5.00 represents several major steps forward for + OpenDoors. In addition to numerous bug fixes and minor + improvements, a number of major new features have been added to + this version. These include an optional multiple personality + system which allow the sysop to choose the status line and + function key style they prefer. This version also adds text-mode + support for RIP (Remote Imaging Protocol) graphics, and adds a + group of advanced ANSI/AVATAR/RIP functions for scrolling areas + of the screen, saving and restoring portions of the screen and + creating pop-up windows and menus. Also new in this version is + support for compilers other than Borland/Turbo C(++), such as + compilers from Microsoft. Version 5.00 also adds built-in + communications support, making the use of a FOSSIL driver + optional. Furthermore, direct support for additional BBS systems + has been added. The list below provides more detail of the + changes and new features in version 5.00: + + - The nonstop key ([=]) now works correctly during + FILES.BBS listing. + + - New door information file formats now supported include: + RA 2.00 EXITINFO.BBS. + + - If the TASK environment variable is set, OpenDoors will + now use its value to determine the current node number. + + - The od_control.od_spawn_freeze_time variable now works + correctly. Previously, the user's time would always be + frozen during od_spawn...() execution, regardless of the + value of this variable. + + - A new feature known as the "Multiple Personality System" + has been added to this version. If you choose to include + the Multiple Personality System in a door, the sysop will + be able to specify which of a number of "personalities" + should be used. Each personality defines the statusline + appearance and function keys seen by the sysop, and has + no effect on the door's operation from the user's + standpoint. OpenDoors 5.00 includes personality + definitions for WildCat, RemoteAccess, PC-Board, and it's + own simplified RA style status lines. You can also define + your own personalities by writing a personality + definition function. If your choose not to include the + Multiple Personality System in a door, you will still be + able to define which single personality you wish + OpenDoors to use. + + - This version of OpenDoors can be used with a larger + variety of compilers than where supported by the previous + version. OpenDoors 5.00 is known to work with all + versions of Turbo C, Turbo C++, Borland C++, Microsoft C, + Microsoft C++, Quick C and Visual C++. It should also + work with any other MS-DOS based ANSI C compiler that + supports the Microsoft/DOS .OBJect and .LIBrary file + formats. + + - A new diagnostics feature has been added to OpenDoors, + which allows you to determine the reason for the most + recent OpenDoors function failure. When any OpenDoors + function returns a failure condition, it also sets the + new od_control.od_error variable to indicate the reason + for the failure. + + - Added additional definitions to OPENDOOR.H, to map names + of OpenDoors functions and variables with the word + "colour" from the U.S. spelling "color". In other words, + both od_set_colour() and od_set_color() are now + recognized by OpenDoors. + + - The od_list_files() now supports more intelligent path + specifications. If the parameter to od_list_files() is + NULL or empty, it will search for a FILES.BBS file in the + current directory. If a directory path is specified, it + will look for a FILES.BBS in that directory. If a full + directory and filename are specified, the specified + filename will be used in place of FILES.BBS. + + - To save space, the compact memory model library is no + longer included in the normal OpenDoors package. The + compact memory model library is now available seperately. + + - A new function, od_set_dtr(), has been added to allow the + DTR line to the modem to be manually controlled. This can + be useful in writing programs where you wish to force the + modem to hangup, such as a call-back verification door. + + - Added additional support for various DOS multitasking + environments. OpenDoors is now specifically Microsoft + Windows aware. OpenDoors also now gives up time to other + waiting tasks when it is idle during chat mode. + + - The od_edit_str() "M" mode now capitializes a character + following a dash '-' character. + + - When transmitting more than one character at a time, + OpenDoors now uses the FOSSIL trasfer block function, + instead of multiple calls to the transfer character + function. This should help to improve performance over + high speed connections when running on slow PCs or under + multitasking environments. + + - OpenDoors 4.10 would not correctly change the display + colour from high-intensity back to low-intensity. This + problem has been fixed. + + - OpenDoors now recognizes DORINFO?.DEF filenames with + alphabetical identifiers (ie, DORINFOA.DEF thru + DORINFOZ.DEF) for nodes 10 thru 35. + + - Improvements have been made to the logfile system. An + exit at errorlevel zero no longer causes garbage to be + written to the logfile. The logfile functions have been + made more reliable when operating under low stack + availability conditions. In the past, if a large number + of local variables where allocated on the stack, the + logfile functions would fail, often writing garbage to + the logfile. When the user pages the sysop for chat, the + user's reason for wishing a chat is also written to the + logfile. + + - Support for text-mode RIP (Remote Imaging Protocol) + graphics has been added. Because this version of + OpenDoors always operates in DOS text-mode, none of the + graphics mode RIP features (such as drawing lines, + circles and displaying icons) will appear on the local + screen. Plans for a version of OpenDoors that will + operate in graphics mode and optionally display graphics + locally are currently under consideration. In this + version, RIP support includes a number of new features. + OpenDoors will now recognize the RIP setting passed in an + RA 2.00 EXITINFO.BBS file and WildCat DOOR.SYS file, and + also allows the RIP setting to be specified in a custom + door information file. The od_send_file() and + od_hotkey_menu() functions will now search for files with + .RIP, .AVT, .ANS and .ASC extensions. When displaying RIP + graphics to the remote user, a pop-up window appears on + the local screen, indicating to the sysop which file is + being displayed. + + - A set of new functions have been added to permit advanced + screen manipulations. These functions include + od_gettext() and od_puttext() to save and restore + portions of the screen, and od_save_screen() and + od_restore_screen() to save and restore the entire + screen. od_scroll() can be used to scroll any portion of + the screen upwards or downwards. od_save_screen() and + od_restore_screen() will operate in any mode, but the + other functions require ANSI/AVATAR/RIP mode to be + available. + + - Three additional functions, od_window_create(), + od_window_remove() and od_popup_menu(), have been added + to facilitate the creation of popup windows and menus. + When such a window or menu is removed from the screen, + the are of the screen "under" the window is returned to + it's original state. This allows you to create multiple + overlapping windows within a door program. The + od_popup_menu() function creates a popup window with a + menu from a simple menu definition string. The user can + select an option from this menu by pressing the key + associated with an option, or by moving a menu selection + bar using their arrow keys. These three functions require + an ANSI/AVATAR/RIP mode to be available. + + - A new function, od_chat() has been added, to allow you to + explicitly invoke the OpenDoors chat mode from within + your program. + + - A new setting variable, od_control.od_always_clear has + been added. When set to TRUE, od_clr_scr() will always + clear the screen, regardless of the user's screen + clearing setting. When set to FALE, od_clr_scr() will + only clear the screen if the user has screen clearing + enabled. + + - It is now possible to configure the errorlevels OpenDoors + exits with under various circumstances, such as when the + user runs out of time remaining online. See the + od_control.od_errorlevel variable + + - A new setting variable, od_control.od_force_local, can be + used to easily force OpenDoors to operate in local mode. + Using this variable you can easily add a command line + parameter such as "-local" to allow the sysop to force + your door to operate in local mode. When OpenDoors is + forced into local mode using this variable, it does not + look for a door information file, and uses default + settings for the user's name, etc. + + - OPENDOOR.H now sets structure packing to single byte + alignment for the od_control structure when Borland and + Microsoft compilers are being used. In the past, + programmers using OpenDoors have experienced difficulties + the od_control structure when the compiler has been set + to use word packing. + + - OpenDoors now closes the FOSSIL driver prior to + performing a spawn or sysop DOS shell. This allows doors + or other communications programs which use the FOSSIL + driver to be executed while the door's execution is + suspended. + + - When used with a FOSSIL driver, OpenDoors normally + changes the BPS rate to that passed from the BBS (if the + BBS passes a valid FOSSIL BPS rate). This BPS rate + setting may now be disabled by setting the + DIS_BPS_SETTING bit of the od_control.od_disable + variable. + + - A function hook has been added to allow you to install a + function to be called whenever od_kernel() executes + (od_control.od_ker_exec). Another function hook, + od_control.od_time_msg_func, can be installed to override + OpenDoor's time limit warning messages. + + - A new array, od_control.od_hot_function, allows the you + to define functions to be called when any of the + programmer-defined sysop hotkeys have been pressed. + + - A function hook, od_control.od_no_file_func, has been + added. This function will be called whenever OpenDoors is + unable to find or read a door information file. This + allows you to add your own door information file reader, + or to provide a local login prompt when no door + information file is present. + + - Previously, OpenDoors would stop correctly updating the + user's remaining time at midnight when running under + certain BIOSes. This problem has been fixed. + + - The current display colour attribute can now be accessed + through an control structure member, + od_control.od_cur_attrib. + + - od_send_file() and od_hotkey_menu() no longer pause with + a "Continue?" prompt prematurely in files that have line + lengths greater than 254 characters. + + - The local keyboard may now be disabled by setting the + DIS_LOCAL_INPUT bit of od_control.od_disable. This only + affects the sysop's input in circumstances that input is + also accepted from the remote user; this setting has no + effect on the sysop function keys. + + A new function hook: - + + void (*od_control.od_local_input)(int); + + has been added. If set, this function will be called + whenever the sysop presses a non-sysop-function key on + the local keyboard. + + - od_control.od_clear_on_exit now controls whether the + screen is cleared before shelling or executing + od_spawn...(), in addition to before OpenDoors shuts + down. + + - od_page() now restores the original display colour before + returning. + + - It is now possible to display an entire string of + characters with terminal emulation, using the new + function od_disp_emu(). + + - OpenDoors will now display a small popup window when + disconnecting the current connection. + + - A new variable, od_control.od_in_buf_size, can now be set + prior to calling any OpenDoors function to set the size + of OpenDoors combined local/remote keyboard input buffer. + By default, this buffer is 256 bytes in size. + + - Previously, there were a number of OpenDoors API + functions that would not correctly initialize OpenDoors + if they were the first function called in the program. + This has been fixed. + + - To facilitate setting of bps rates up to 115,200, + od_control.baud is now an unsigned long. + + - A new setting, od_control.od_no_ra_codes, has been added + to disable the use of RemoteAccess/QuickBBS control codes + by od_send_file()/od_hotkey_menu()/od_disp_emu(). The + RemoteAccess/QuickBBS ASCII 1 "pause for key" is also now + recognized. diff --git a/utils/magiedit/odoors/historic/ODN.FRM b/utils/magiedit/odoors/historic/ODN.FRM new file mode 100644 index 0000000..5ca5ff1 --- /dev/null +++ b/utils/magiedit/odoors/historic/ODN.FRM @@ -0,0 +1,70 @@ +Essentially, the OpenDoors Distribution Network is a list of "official" +OpenDoors distribution sites that will be distributed with future +versions of OpenDoors, and anyone is welcome to participate. The idea +behind the "OpenDoors distribution network" is simply to make it easier +for you, the OpenDoors programmer, to obtain OpenDoors updates. While +the newest version of OpenDoors is always available from the OpenDoors +Support BBS, and often from any system carrying the "Programmer's +Distribution Network", most OpenDoors programmers would find it useful +to know of a system closer to them where the newest version of OpenDoors +is always available. Although I would like to be able to send the newest +version of OpenDoors to any support site, the cost of doing so +unfortunately makes this impossible. However, it is likely that you +would pick up the newest version of OpenDoors when it is available +anyhow, so this shouldn't really make any difference. So, if you are +interested in becoming an official OpenDoors distribution site, simply +fill in the form below, and send it to me, either electronically or by +conventional mail at one of the addresses listed at the end of this +file. + +Brian Pirie + +OPENDOORS OFFICIAL DISTRIBUTION SITE APPLICATION FORM +----------------------------------------------------- + +YOUR NAME : ________________________________________ + (eg. Brian Pirie) + +LOCATION : ________________________________________ + (eg. Ottawa, Ontario, Canada) + +DATA NUMBER(S) : ________________________________________ + (eg. (613) 526-4466) + +NETWORK ADDRESSES: ________________________________________ + (eg. 1:243/8 in FidoNet) + +MODEM TYPE: ________________________________________ + (eg. 9600, V32bis, v42bis, HST) + +OTHER INFORMATION: ________________________________________ + + ________________________________________ + (eg. Hours of BBS operation, file request hours, + guest login and password, etc.) + + +I CAN BE INFORMED OF NEW RELEASES BY: + ____ + | | - ***ROUTED*** FIDONET NETMAIL + |____| + ____ + | | - OPENDOORS SUPPORT CONFERENCE + |____| + ____ + | | - INTERNET EMAIL + |____| + ____ + | | - OTHER: ________________________________ + |____| + + + FidoNet NetMail: 1:243/8 + InterNet EMail: brian@bpecomm.ocunix.on.ca + OpenDoors BBS: +1 613 526 4466 +Conventional mail: 1416 - 2201 Riverside Drive + Ottawa, Ontario + Canada + K1H 8K9 + + diff --git a/utils/magiedit/odoors/historic/ODN.NFO b/utils/magiedit/odoors/historic/ODN.NFO new file mode 100644 index 0000000..448b447 --- /dev/null +++ b/utils/magiedit/odoors/historic/ODN.NFO @@ -0,0 +1,170 @@ +Below is a list of sites from which the newest version of OpenDoors is +available, as of July 11, 1993, sorted by country. If you would like +to join the list of official OpenDoors distribution systems, please see +the following message. + +In addition to the sites listed below, the newest verion of OpenDoors +will likely be available from any system that carries "Programmer's +Distribution Network" files. Also, if you send a self-addressed +envelope, along with either a 3-1/2" or 5-1/4" (360K) diskette, and +$2.00 to cover postage, I would be happy to mail the newest version of +OpenDoors to you. My address is included in the list, below. + +Also, the newest version of this file is always available for download +or file request from my system, with the filename OD_SITES.ZIP. + +AUSTRALIA +--------- +Sydney, Australia - Rosalyn Anderson + Data Number : +61 2 552 3255 + Modem : 9600, v.32/PEP + Fidonet : 3:712/618 + Intlnet : 58:2100/146 + Comments : 24 hours - log on as "opendoors user" password "doors" + +Sydney, Australia - Chris Patten + Data Number : +61 2 977 6820 + Modem : 14400, v.32bis/v.42bis + Fidonet : 3:714/906 + Comments : 24 hours, file request for nodelisted sysops + + +CANADA +------ +Lancaster Park, Alberta, Canada - Thomas King + Data Number : +1 403 973 3856 + Modem : 16800, v.32bis/HST/v.42bis + Fidonet : 1:342/49 + IMEX : 89:701/513 + Worldnet : 62:3200/50 + Comments : Freq by Magic name ODOORS 23hrs/day + Guest Name "Visiting Sysop" PW is "PhoneBill" + +Saint John, New Brunswick, Canada - George Hannah + Data Number : +1 506 652 7292 + Modem : 14400, v.32bis/v.42bis + Fidonet : 1:255/7 + Comments : Freq ODOORS, except during ZMH + Login as OPENDOORS password GUEST + +Ottawa, Ontario, Canada - Brian Pirie + Data Number : +1 613 526 4466 + Modem : 9600, v.32/v.42bis + Fidonet : 1:243/8 + Internet : brian@bpecomm.ocunix.on.ca + Postal addr : Brian Pirie + 1416 - 2201 Riverside Drive + Ottawa, Ontario + Canada + K1H 8K9 + Comments : Freq and BBS available 24 hours / day to everyone + +Mascouche, Quebec, Canada - Robert La Ferte + Data Number : +1 514 968 1709 + Modem : 14400, v.32bis/v.42bis + Fidonet : 1:167/235 + Comments : BBS opened 24 hours a day, 7 days/week, + file request OPENDOORS for the latest version + + +ITALY +----- +Trieste, Italy - Pietro Budicin + Data Number : +39 40 3783111 + Modem : 14400, v.32bis/HST/v.42bis + Fidonet : 2:333/603 + Comments : Freq ODOORS and BBS 24hrs/day + + +NEW ZEALAND +----------- +Paraparaumu, New Zealand - Phill Mckenna + Data Number : +64 4 298 4194 + Modem : 14400, v.32bis/v.42bis + Fidonet : 3:771/180 + Comments : 24 hour system, magic name ODOORS for file reuquest + Guest User account (no password required) + + +UNITED KINGDOM +-------------- +Cambridge, United Kingdom - Marcel Cook + Data Number : +44 223 301487 + Modem : 14400, v.32bis/v.42bis + Fidonet : 2:440/34 + Comments : 24 hours for callers and F'REQs, instant registration. + Magic name OPENDOORS gets latest version. + +Ipswich, Suffolk, United Kingdom - Mark Clark + Data Number : +44 473 692882 + Modem : 14400, v.32bis/v.42bis + Fidonet : 2:440/107 + Comments : 24 Hours/Freqs Instant Registration + +Ipswich, Suffolk, United Kingdom - Mike Tatum + Data Number : +44 473 87450 + Modem : 14400, v.32bis/v.42bis + Fidonet : 2:440/112 + Comments : 23 hours a day, + Magic name of OPENDOORS to get latest version online. + +Mildenhall, Suffolk, United Kingdom - Dale Elrod + Data Number : +44 638 718623 + Modem : 16800, v.32bis/HST/v.42bis + Fidonet : 2:440/37 + Comments : 23 hours a day, + magic name of OPENDOORS to get latest version online. + + +UNITED STATES +------------- +San Jose, California, USA - Darryl Perry + Data Number : +1 408 265 4660 + Modem : 9600, v.32/v.42bis + Fidonet : 1:143/324 + Comments : Freq the full filename only. + +San Ramon, California, USA - Brent Johnson + Data Number : +1 510 830 4616 + Modem : 14400, v.32bis/HST + Fidonet : 1:161/610 + Comments : 23 hours, FREQ almost anytime if listed in nodelist. + +Fort Myers, Florida, USA - Jeff Cochran + Data Number : +1 813 939 3009 + Modem : 16800, v.32bis/HST/v.42bis + Fidonet : 1:371/26 + Comments : Downloads available first call + +Columbus, Georgia, USA - Scott Burkett + Data Number : +1 706 596 8126 + Modem : 9600, v.32 + Fidonet : 1:3613/12 + Comments : 24 Hour Operation and FREQ's + +Chicago, Illinois, USA - John Kristoff + Data Number : +1 312 587 8756 + Modem : 16800, v.32bis/HST + Fidonet : 1:115/743 + Comments : Freq avaiable, 24 hrs., GUEST account available + +Baltimore, Maryland, USA - Mike Gurski + Data Number : +1 410 256 1979 + Modem : 14400, v.32bis/v.42bis + Fidonet : 1:261/1062 + Echonet : 50:5410/1062 + Comments : 24 hour FREQs, unlisted systems welcome + +Minneapolis, Minnesota, USA - Bing Wu + Data Number : +1 612 378 7783 + Modem : 19200, v.32bis/ZYX/v.42bis + Fidonet : 1:282/1016 + Comments : 24 hours a day, F'req anytime except ZMH + +Muskogee, Oklahoma, USA - Vince Jacobs + Data Number : +1 918 687 1612 + Modem : 14400, v.32bis/v.42bis + Fidonet : 1:3813/309 + DoorNet : 75:7918/200 + Comments : 24 Hours, FREQ hours anytime but ZMH, + Guest Log In as The Inspector, password Gadget diff --git a/utils/magiedit/odoors/historic/ODTJ9304.TXT b/utils/magiedit/odoors/historic/ODTJ9304.TXT new file mode 100644 index 0000000..63c8145 --- /dev/null +++ b/utils/magiedit/odoors/historic/ODTJ9304.TXT @@ -0,0 +1,447 @@ +The +OPENDOORS TECH JOURNAL +Volume 93, Number 4 June 21st, 1993 + +"The Greatest Thing to happen to Journalism Since Real People" + +This Issue: A Word from the Editor - Scott Burkett + The Open Door - Brian Pirie + The OPENDOORS Echo + Where's the Source? - John Kristoff + Opendoors Tech Corner - Dropfile Location Logic + Review: BFE v1.30.2à + OpendDoors Snippets! + OpenDoors Roll Call + OpenDoors Distribution Network Sites + OpenDoors Tech Journal Information + +---------------------------------------------------------------------------- + A Word from the Editor: +---------------------------------------------------------------------------- + +Another day, another fifty cents. Welcome once again to that info-filled, +free-as-can-be periodical dedicated to the proposition that all C-based door +libraries are not equal! + +ODTJ is getting read worldwide. Yup. You know what that means? Aside from +the fact that it provides a wonderful forum for OD coders to share ideas and +information, it provides: + + FREE ADVERTISING! + +Man! With the distribution we are getting, ODTJ is the perfect place to +advertise that new door! I'll leave the rest up to you guys.... + +All in all this is a decent issue. It will probably be the last issue before +the 4.20 release of OpenDoors (it should be a doozy). On a side note, our +BBS (Under the Nile) is not running on a USR 14.4 Sportster. Too cool. + +That's it. No more words of wisdom this month. No more ranting and raving +on and on about how RIP is inevitably gonna die.... :-) + +Alles Klaar und spater! + +---------------------------------------------------------------------------- + THE OPEN DOOR - By Brian Pirie +---------------------------------------------------------------------------- + +** Editor's Note ** + +Has anyone seen this guy? Seriously, rumor has it that Brian is up to some- +thing *BIG*. Of course, once the rumors have been resolved, our readers will +be the first to know! Why? Because we have inquiring minds. Hrmpf! Look +for Brian next month....or the next month....or the.....ad infinitum. + +---------------------------------------------------------------------------- + OPENDOORS Echo! +---------------------------------------------------------------------------- + +OPENDOORS is an internationally distributed echo designed for discussion of +BBS door/utility programming, and in particular, Brian Pirie's OpenDoors C +Library! + +The OPENDOORS Echo was created by a group of dedicated BBS door and utility +programmers and designers, in order to promote discussions on BBS utility +programming techniques, tasks, standards, and trends. This echo is not just +for BBS door authors! Discussion of practically any aspect of BBS programming +is encouraged. Brian Pirie, the author of OpenDoors is available for tech +support, as are his beta-testers. + +The echo is not currently on the FidoNet backbone, but a feed is more than +likely available at your favorite ODN Support Site. Efforts are under way +to put OPENDOORS on the fido backbone...stay tuned! + +---------------------------------------------------------------------------- + Where's the Source? +---------------------------------------------------------------------------- + By: John Kristoff, The Crossroads BBS (1:115/743) + +There seems to be a problem with source code for BBS related utilities and +door programs being released. Why is this? I know we have BinkleyTerm, +Maximus and a handful of others, but how many door games do you see that come +with actual source code? I don't think I've seen any. In fact, the only +door program that I've seen the entire source for is Brian's RAVote. + +Not that I expect the source code for TradeWars (even if I wanted it), but I +find it surprising that so many door programmers are so greedy. I started +teaching myself C because I'm sick of relying on other authors. I wouldn't +be surprised if many other small time programmers have done the same. I've +always thought that the BBS community, and computer networks in general, are +one of the most free, open and chaotic cultures our planet has ever seen. +So I can't understand why people request $10, $25 or more for a files list +generator, a simple voting booth door or those other 'dime a dozen' programs. + +Don't get me wrong, I pay for quality software and I have at least a dozen +shareware programs registered. However, if I was to register every program +I've wanted to use for more than 30 days, I would be in the poor house. +There are just simply too many trivial programs in which I feel their price +isn't justified for lack of programmer committment, exhorborant price, or +just simply the value of the product. I'm not looking for a free ride, but +I am looking for quite a bit more respect from my fellow programmers. For +users, the hobby is relatively cheap, but for sysops, it's a different story. +Well, at least if you're honest. Us sysops have enough to worry about in +terms of phone bills, trouble users, hardware, updates and upgrades... and so +on. + +I'm including a text, simliar to this message with all programs I write to +encourage the programmers for sysops to write free or cheap software. I plan +on releasing all my BBS related utilities and door programs as freeware or +public domain (even if that is all they're worth). It's my way of giving +something back to the community that has given me so much. I encourage you +to do the same, or at the very least, with some of your less popular programs. + +John Kristoff +The Crossroads BBS +(312) 587-8756 +Chicago, IL +FidoNet: 1:115/743 +Internet: jkristof@mica.meddean.luc.edu + + +** Editor's response: + +While I am somewhat in agreeance with John on this subject, I must also play +devil's advocate, and come to the aid of door writers who produce solid +products, often without the availability of source. Source code availability +for shareware products is simply not available, for obvious reasons. The +author(s) of the product cannot make source available, as potential customers +could simply recompile the source, and effectively use the software without +properly registering it with the author(s). In my own case, I choose not +to distribute source code for this reason. For smaller, freeware titles, I +suppose I never considered the fact that other programmers would want to +peek at my code. As far as price goes, I have a set $10 registration fee for +all of my door packages, a price which I consider to be extremely low for the +quality of my products. + +Very interesting point, John...anyone out there have any feelings on this? + +---------------------------------------------------------------------------- + OpenDoors Tech Corner: Dropfile Location Logic +---------------------------------------------------------------------------- + +At this time, OpenDoors searches for the door information file (aka dropfile) +in the following order: + + 1.) First, if there was a custom door information file format + defined in the OpenDoors configuration file, OpenDoors will + begin by looking for this file. OpenDoors searches for the + custom information file in the following order: + A.) The path defined in the info_path variable + (which can be set by your door code and over- + ridden by the configuration file BBSDir setting) + B.) The directory which was the current default dir + at door startup time + C.) If any of the following environment variables + exist, OpenDoors will then search for the file + in the directories pointed to by these variables, + in the following order: + RA + QUICK + PCB + BBS + + 2.) If no custom door information file was found / defined, + OpenDoors will then search for door information files + corresponding to one of the built in formats. It will search + for these files in the same directories, and same order, as + it does for the custom door information file (A - C). Within + each directory, it will search for files with the following + filenames: + + CHAIN.TXT + SFDOORS.DAT + DOOR.SYS + CALLINFO.BBS + DORINFO1.DEF + DORINFOx.DEF, where x is the node number + set by your program, if + x != 1. + + As soon as it finds a directory containing one of these + filenames, OpenDoors will stop it's door information file + search phase. It then begins to decide what to do with what + it has found. If more than one of the above filenames was + found in the directory in question, OpenDoors will read the + file with the most recent date and time stamp. This is intended + to overcome abiguities that can arise when a door information + file conversion program is being used, and a number of + different door information files may still exist in the + directory. In such a case, it is assumed that the most recently + created file is the one that should be used. If more than one + file exist with an identical date and time, OpenDoors will use + the file that is closer to the beginning of the above list. (ie + they are listed in their order of priority) + + Once OpenDoors has decided which file it is going to use, it + may have still more decision-making to do. In the case of + door information file names that correspond to more than one + format (such as DOOR.SYS), OpenDoors will examine the file + to determine which format it actually is. If a dorinfo?.def + file is found, OpenDoors will then also search for an + EXITINFO.BBS file. (An EXITINFO.BBS file is always acompanyed + by a DORINFO?.DEF file, as it does not include all the + information needed by even the most basic of doors). Again, + if an EXITINFO.BBS file is found, OpenDoors must determine + which of the many EXITINFO.BBS formats it is actually dealing + with. + + This may all sound rather complicated, but it is a well thought- + out strategy that is intended to asure that the correct door + information file will be located and used in the vast majority + of cases. (and to think - it does all this in the blink of an + eye!) + +---------------------------------------------------------------------------- + REVIEW: BFE v1.30.2à +---------------------------------------------------------------------------- + +BFE v1.30.2à, the flexible BBS front end system from Cairo Research Labs is +now available! This is an alpha release of the upcoming 1.30 version of +BFE. + +BFE is a BBS front-end system that was designed to provide sysops with a +method of running more than one BBS from the same line. In addition, it has +a wealth of other options available to put in on the front-end of your BBS, +such as allowing file transfers, ANSI/ASCII file viewing, shelling to DOS +from remote, running external programs and batch files, and much more! + +BFE was designed to be called from a front-end mailer, such as Frontdoor or +Binkleyterm. Instead of spawning directly to the BBS system, it presents +a menu to the user, which details his immediate options. These options can +range from several different BBS systems, remote jobs, literally anything +you can think of! The BFE system can also be configured to be called +straight from your BBS software itself, in essence, running as a normal +door, using one of several popular BBS dropfile formats. Read onward.... + + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Features ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßß + + * Complete support for ANSI/ASCII/AVATAR users (Auto ANSI detect!) + * *TRUE* Multinode/Multiuser Compatibility! + * DESQview aware! + * Configurable for security concerns! + * Custom multi-level menus with item-level password protection! + * Complete carrier monitoring and timeout checking + * Use any of 11 standard dropfiles, or define custom ones! + * Run as a normal door or as a frontend! Dropfile not required! + * Complete BBS carousel - run multiple BBS systems + * ASCII/ANSI/AVATAR file support + * File transfer system with support for external protocols + * Run remote jobs, such as batch files, programs, other doors, etc. + * Remote OS shells! + * Built in chat mode + * Much more! + + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ What's New in This Release? ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ o New * Change ! Fix +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + + o *Major* code cleanup and internal re-documenting and optimizing. + This will be done every periodically in order for the product to + continue to grow. + + o New beta naming convention: MAJOR.MINOR.REV (Staging Level) + (i.e. this is 1.30.2à, v1.30, rev. 2, in alpha staging) + + o Custom user input using the new PROMPT keyword! Now, you can + utilize custom input as the value for SECONDARY data fields for + *any* menu type in BFE! + + o New keywords: NOPASSPARMS and PROCESS. These are used to directly + manipulate the way that BFE performs calls to external processes. + When used with the PROMPT keyword above, just about anything can + be called, in any order, with any arguments! + + o The COLOVERRIDE option has been added, to allow each individual + menu option to use its own unique color. This overrides the global + DESCRIPCOL keyword in each .CTL file. (Thanks to Chris Koziol) + + o Upload capability now in place! This involved changes to the + PROTOCOL.BFE file, and adding a new type "U" option. + + ! If BFE cannot locate ASCII/ANSI/AVATAR screens at display time, + it will log an error entry into the logfile, and will no longer + wait for a remote keystroke to continue. (Thanks to R. Guevarra) + + o Generic File Transfer System now in place! The new system allows + the use of configurable external protocols (no more hardcoded DSZ!) + + o WELCOMESCREEN option added, to provide a global intro screen to be + displayed upon entering the BFE system (shown once only). As with + all of the file display capabilities of BFE, the file can be in + ASCII, ANSI, or in AVATAR formats. BFE will display the one which + best fits the user's terminal settings. + + o The "time to next event" option has been put back into the system, + and is now passed via a new "-t" switch. (i.e. -t60, -t%3, etc). + This value is passed to external procedures (Type "R"). + + * The "O" type (Remote OS Shell) now utilizes the COMSPEC environment + variable to locate the command processor. The command processor + was formerly specified in the SECONDARY field. Previously, if + this value was keyed in wrong, it resulted in BFE locking up + the system. Using COMSPEC should make this a bit cleaner. + + o Still more documentation changes! + +FREQ: BFE from: Under the Nile! 14.4/v.32 1:3613/12 (706) 596-8126 + 93K + +Scott Burkett, +Cairo Research Labs + +---------------------------------------------------------------------------- + OPENDOORS SNIPPPPPPPPPETS!!!!!! +---------------------------------------------------------------------------- + +By: Mark Williamson, Software Solutions (1:214/54) + +Here's yet another way to center your favorite text string: + +void str_center(int line,char *string,char *color) +{ + int col = 40 - (strlen(string) / 2); + + /* This method uses the length of the string to center it. So, + you would get strange results if you embedded control codes + in your string. + */ + + if(od_control.user_ansi) { // This way allows you to specify + od_set_cursor(line,col); // the line to put the text on. + od_printf(color); // Use the `white on blue` code types + od_disp_str(string); + } + else { + od_repeat(' ',col); // This method uses the CURRENT + od_disp_str(string); // line the cursor happens to be on. + } + return; +} + +Mark Williamson +Software Solutions BBS +1:214/54 +Lemoore CA +(209)997-0224 +v32/v42bis +Open access to first time callers. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +By: Mark Williamson, Software Solutions (1:214/54) + +/****************************************************** +* fill_box() by Mark Williamson, Software Solutions BBS +* Fidonet 1:214/54, (209)997-0224 +* +* This code will paint a box in the +* specified color using the specified +* character using ansi/avatar graphics. +* Note that this does not make a border! +* Only 'fills' a block on the screen. +* Can be used to clear just parts of a screen. +* +* Call the function with the following parameters: +* +* int srow,scol: Starting row,col of the box +* int erow,ecol: Ending row,col of the box +* int attrib: od_set_attrib() style color code +* char fill_char: The character to use to paint the +* block. Use ' ' to clear a block. +* +* This code is placed in the public domain. +******************************************************/ + +#include +#include "opendoor.h" + +void fill_box(int srow, int scol, int erow, int ecol, + int attrib, char fill_char); + +void main(void) +{ + fill_box(3,10,13,40,0x1f,'°'); +} + +void fill_box(int srow, int scol, int erow, int ecol, + int attrib,char fill_char) +{ + int line_len,x; + if(srow<1) srow=1; + if(erow>24) erow=24; + if(scol<1) scol=1; + if(ecol>80) ecol=80; + line_len=ecol-scol; + od_clr_scr(); + od_set_attrib(attrib); + for(x=srow;x< End of The OpenDoors Tech Journal - Volume 93 Issue Number 4 ><- +---------------------------------------------------------------------------- + diff --git a/utils/magiedit/odoors/historic/ODTJ9305.TXT b/utils/magiedit/odoors/historic/ODTJ9305.TXT new file mode 100644 index 0000000..dc207cd --- /dev/null +++ b/utils/magiedit/odoors/historic/ODTJ9305.TXT @@ -0,0 +1,724 @@ +The +OPENDOORS TECH JOURNAL +Volume 93, Number 5 July 20th, 1993 + +"The Greatest Thing to happen to Journalism Since Real People" + +This Issue: A Word from the Editor - Scott Burkett + The Open Door - Brian Pirie (not!) + The Fidonet OPENDOORS Echo - Latest FAQ + Opendoors Tech Corner - ColorToString(); + In Search Of - The Art of Debugging + Review: VID v2.01 - The Virus Information Door + OpenDoors Snippets! + OpenDoors Tech Journal Information + +---------------------------------------------------------------------------- + A Word from the Editor: +---------------------------------------------------------------------------- + +Finally! After months of long-distance mail polling, the OPENDOORS echo is +now residing on the North American fidonet backbone! Yep. Sorry, Ma Bell. +More on this later, and now .... the rest of the story. Sorry Paul Harvey. + +Listen up children, today's editorial survey question is one which is sure to +draw quite a bit of flak from programmers around the globe. Which is the +better stimulant, Jolt Cola or Maxwell House? :-) + +DoorNet! That's right. Strange things are amiss at the Circle-K! Look for +an OPENDOORS conference (both mail and file based) to appear soon on the +DoorNet backbone listing. Thanks go out to Vince Jacobs for his work on +getting this implemented. This should make ODTJ and OD distribution a bit +easier on all of us. There has been mention of gating the current fidonet +OPENDOORS echo through to Doornet. I applaud this idea and welcome it with +much grandiose. Ahem. + +On another wavelength entirely, several hundred netmail messages were lost +from Under the Nile's mail machine a few weeks ago. Unfortunately, there +were a few requests for product announcements contained therein. If the +authors would be so kind as to send them back in, we will gladly publish +them in the next edition. Danke! + +On a serious note, my gerbil died. Peace, and a bottle of hair grease.... + +(Scott, it's time for your medication....yes, mother) + +---------------------------------------------------------------------------- + THE OPEN DOOR - By Brian Pirie +---------------------------------------------------------------------------- + +Unfortunately (I know, I know), Brian was unavailable for this issue. I +finally tracked him down in Tibet, busily polling the local populace for +new ideas for the 4.20 release. At any rate, look for him in ODTJ #6, along +with (hopefully) OpenDoors 4.20... :-) + +---------------------------------------------------------------------------- + OPENDOORS Echo FAQ - Frequently Asked Questions +---------------------------------------------------------------------------- +By: Brian Pirie +July 17th, 1993 + +ABOUT THIS FAQ +-------------- + +This document is a collection of frequently asked questions and answers. +If you have any questions about OpenDoors or the OPENDOORS echo, please +first refer to this FAQ. Not only will this help to reduce unnecessary +trafic in the echo, but it will also provide you with the answer to many +questions much more quickly than you would have otherwise. + +If you have any suggestions for additions or changes to this FAQ, please +direct them to the moderator, Brian Pirie (FidoNet: 1:243/8, Internet: +brian@bpecomm.ocunix.on.ca). + +Since the OPENDOORS echo and this FAQ are currently under a state of +change, this FAQ will be posted on a very regular basis for the time +being. In the future, the FAQ will probably be automatically posted on a +bi-weekly basis. + +CONTENTS +-------- + + 1.) What are the rules of the OPENDOORS echo? + 2.) What IS OpenDoors? + 3.) Where can I get a copy of OpenDoors? + 4.) What is the newest version of OpenDoors? + 5.) How much does OpenDoors cost? + 6.) Is the OpenDoors source code available? + 7.) Are there beta test versions of OpenDoors? + 8.) How can I contact the author of OpenDoors? + 9.) What IS the OpenDoors echo? +10.) What about the echo archives? +11.) How can I get help with OpenDoors or BBS door/utility programming? +12.) What guidelines are there for posting source code? + +1.) WHAT ARE THE RULES OF THE OPENDOORS ECHO? + ---------------------------------------- + +The rules of the OPENDOORS echo are few and far between. The most +important rules are those that are standard to all EchoMail conferences +that are distributed as a part of the FidoNet backbone distribution +system. The echo may not be used for illegal purposes, nor is profane +language accepted. Beyond this, your are trusted to use your own +judgement. While it is important to have as high a "signal to noise +ratio" as possible, it is also important to recognize the diverse group +of people you are communicating with though the OPENDOORS echo. There is +a wide range of technical knowledge, knowledge of network etiquette, and +personal background. If you can try to be as understanding and helpful +as possible, your doing so will help to keep friction and flaming to a +minimum. + +Since the participants in the OPENDOORS echo are generally all +programmers, it seems natural that they will want to tell the world +about the programs they have written. For this reason, announcements of +new programs - either written with OpenDoors or of interest to the +participants of this echo - is encourage. However, advertising of new +programs is not the primary purpose of the echo. For this reason, we +would ask that you refrain from posting the same advertisment message +more than once within a reasonable length of time (perhaps a month). + +If you are having any difficulty with the OPENDOORS echo - technical, +social, or otherwise - please feel more than free to contact the +moderator, Brian Pirie (1:243/8). + +2.) WHAT IS OPENDOORS? + ----------------- + +OpenDoors is a Turbo C(++) / Borland C++ door programming toolkit used +by well over 100 door programmers around the world. OpenDoors handles +all of the details of door programming, such as communicating with the +modem, interfacing with virtually any BBS package, maintaining status +lines, monitoring carrier detect and user timeouts, handling sysop +function keys such as DOS shell or chat, providing advanced ANSI/AVATAR +graphics support, and much more. + +OpenDoors is designed to allow you to write door programs just as you +would write any other C program, without requiring any additional effort +or knowledge. You can easily create fully functional door programs with +just a few lines of code. OpenDoors is so easy to use that many +OpenDoors programmers have begun using it with no programming +experience. + +OpenDoors directly interfaces with all of the most popular BBS packages +including RemoteAccess, QuickBBS, Telegard, Wildcat, PC-Board, Maximus, +Renegade, EzyCom, RBBS-PC, Spitfire, SuperBBS, RoboBoard, WWIV and many +others. In addition, OpenDoors allows the sysop to specify custom door +information file formats to permit your doors to run on virtually any +BBS system. + +Included with OpenDoors are a number of example doors that you can +compile, alter, or use as a basis for your own doors. Among these +example doors are a voting booth type door and an ANSI music +demonstration door, and dozens of sample doors within the door +programming tutorial manual. + +OpenDoors also provides a number of special features that you can +optionally include in your doors, such as transparent configuation file +support, logfile support, FILES.BBS listing, and many advanced +ANSI/AVATAR graphics routines. + +3.) WHERE CAN I GET A COPY OF OPENDOORS? + ----------------------------------- + +Below is a short table listing sites from which the newest version of +OpenDoors is available, as of April 19th, 1993. In addition to the sites +listed below, the newest verion of OpenDoors will likely be available +from any system that carries "Programmer's Distribution Network" files. +Also, if you send a self-addressed envelope, along with either a 3-1/2" +or 5-1/4" (360K) diskette, and $2.00 to cover postage, I would be happy +to mail the newest version of OpenDoors to you. My address is listed in +section 8. + +Also, the most recent list of OpenDoors distribution sites is always +available for download or file request from my system, in the file +OD_SITES.ZIP. If you are interested in becoming an official OpenDoors +distribution site, please see the file included in the OD_SITES.ZIP +archive. + +------------------------------------------------------------------------------- + FIDONET +LOCATION ADDRESS DATA NUMBER MODEM +------------------------------------------------------------------------------- +Sydney, Australia 3:712/618 +61 2 552 3255 (v.32/PEP) +Sydney, Australia 3:714/906 +61 2 977 6820 (v.32bis/HST) +Lancaster Park, Alberta, Canada 1:342/49 +1 403 973 3856 (v.32bis/HST) +Saint John, New Brunswick, Canada 1:255/7 +1 506 652 7292 (v.32bis) +Ottawa, Ontario, Canada 1:243/8 +1 613 526 4466 (v.32) +Mascouche, Quebec, Canada 1:167/235 +1 514 968 1709 (v.32bis) +Trieste, Italy 2:333/603 +39 40 3783111 (v.32bis/HST) +Paraparaumu, New Zealand 3:771/180 +64 4 298 4194 (v.32bis) +Cambridge, United Kingdom 2:440/34 +44 223 301487 (v.32bis) +Ipswich, Suffolk, United Kingdom 2:440/107 +44 473 692882 (v.32bis) +Ipswich, Suffolk, United Kingdom 2:440/112 +44 473 87450 (v.32bis) +Mildenhall, Suffolk, United Kingdom 2:440/37 +44 638 718623 (v.32bis/HST) +San Jose, California, USA 1:143/324 +1 408 265 4660 (v.32) +San Ramon, California, USA 1:161/610 +1 510 830 4616 (v.32bis/HST) +Fort Myers, Florida, USA 1:371/26 +1 813 939 3009 (v.32bis/HST) +Columbus, Georgia, USA 1:3613/12 +1 706 596 8126 (v.32) +Chicago, Illinois, USA 1:115/743 +1 312 587 8756 (v.32bis/HST) +Baltimore, Maryland, USA 1:261/1062 +1 410 256 1979 (v.32bis) +Minneapolis, Minnesota, USA 1:282/1016 +1 612 378 7783 (v.32bis) +Muskogee, Oklahoma, USA 1:3813/309 +1 918 687 1612 (v.32bis) +------------------------------------------------------------------------------- + +4.) WHAT IS THE NEWEST VERSION OF OPENDOORS? + --------------------------------------- + +Version 4.10 is the most recently released version of OpenDoors. There +is a more recent beta-test version of OpenDoors. For information on this +beta-test version, see section 7. + +5.) HOW MUCH DOES OPENDOORS COST? + ---------------------------- + +OpenDoors is distributed on a try-before-you-buy basis. You can pickup a +copy of OpenDoors from any of the OpenDoors distribution sites, listed +above, to have a closer look at the package. However, if you wish to +continue using OpenDoors after the three week trial period, you must +purchase an OpenDoors registration. Full details on registering +OpenDoors is included in the OpenDoors manual. However, a brief table +listing the prices within a number of countries is listed below: + + ----------------------------------------------- + REGISTRATION + REGISTRATION ONLY AND SOURCE CODE + ----------------------------------------------- + 34 Canadian Dollars 68 Canadian Dollars + 28 US Dollars 56 US Dollars + 18 British Pounds 36 British Pounds + 150 French Francs 300 French Francs + 44 German Marks 88 German Marks + 50 Netherland Gilders 100 Netherland Gilders + 39 Australian Dollars 78 Australian Dollars + ----------------------------------------------- + +6.) IS THE OPENDOORS SOURCE CODE AVAILABLE? + -------------------------------------- + +Yes, the OpenDoors source code is available, at a cost equal to the +registration, to registered users. Both the regisration and source code +may also be purchased at the same time, for a cost equal to twice the +normal registration fee. When you purchase the OpenDoors source code, +the most recent version of the source code is sent to directly. Also, +you will be entitled to free upgrades to all future versions of the +source code. Whenever you wish to pick up a new version of the source +code, you may download it from the OpenDoors support BBS, arrange to +pick it up via a FidoNet-compatible mailer (simply send me a message +asking me to place the source code package "on hold" for you to poll and +pick up), or by sending a diskette and self-addressed diskette mailer. + +7.) ARE THERE BETA TEST VERSIONS OF OPENDOORS? + ----------------------------------------- + +Yes. The beta test versions of OpenDoors are available to registered +OpenDoors users. However, keep in mind that the beta test version has +some new features that are still under development, and has not yet been +thoroughly tested. To save space, the documentation is not included with +the beta test version. As such, it is assumed that you also have the +most recent non-beta version of OpenDoors. The most recent beta version +may be file-requested from 1:243/8 as OD_BETA + +8.) HOW CAN I CONTACT THE AUTHOR OF OPENDOORS? + ----------------------------------------- + +If you wish to contact the author of OpenDoors, Brian Pirie, please feel +free to do so. I may be reached by any of the following means: + + FidoNet NetMail : 1:243/8 + + Internet EMail : brian@bpecomm.ocunix.on.ca + + Modem (BBS) : +1 613 526 4466 + + Conventional Mail : Brian Pirie + Apt. #1416 - 2201 Riverside Drive + Ottawa, Ontario + K1H 8K9 + Canada + +9.) WHAT IS THE OPENDOORS ECHO? + -------------------------- + +The OPENDOORS echomail conference is devoted to OpenDoors and BBS door / +utility programming in general. The OPENDOORS echo serves as a place +where people working with OpenDoors can share ideas, source code +examples, and other tricks and techniques. Through the OPENDOORS echo +you can receive help with OpenDoors and programming in general. Also +available through the OPENDOORS echo is information on future versions +of OpenDoors and recent developments of concern to BBS door and utility +programmers. The OPENDOORS echo is also place for suggestions for future +versions of OpenDoors, OpenDoors bug reports, a place to announce the +availablility of your programs, and much more information of interest to +OpenDoors programmers. There are participants in the OpenDoors echo from +throughout Canada and the U.S., as well as people in Europe and +Australia. + +10.) WHAT ABOUT THE ECHO ARCHIVES? + ---------------------------- + +Although we attempt to answer the most commonly asked questions in this +FAQ, there is so much discussed in the OPENDOORS echo that it is +impossible to address every possible question. As such, you may be +interested in referring to the OPENDOORS echo archives, in order to +learn more about OpenDoors and BBS door/utility programming in general. + +The OPENDOORS echo archives are prepared on a monthly basis, and +are available from the moderators system. Currently, the following +archives are available for request from 1:243/8 or download from the BBS +at +1 613 526 4466: + +ODJUL92.ZIP 42776 Discussion from the OpenDoors echo, July '92 +ODAUG92.ZIP 35432 Discussion from the OpenDoors echo, August '92 +ODSEP92.ZIP 36308 Discussion from the OpenDoors echo, September '92 +ODOCT92.ZIP 30922 Discussion from the OpenDoors echo, October '92 +ODNOV92.ZIP 34844 Discussion from the OpenDoors echo, November '92 +ODDEC92.ZIP 53647 Discussion from the OpenDoors echo, December '92 +ODJAN93.ZIP 24683 Discussion from the OpenDoors echo, January '93 +ODFEB93.ZIP 41562 Discussion from the OpenDoors echo, February '93 +ODMAR93.ZIP 24080 Discussion from the OpenDoors echo, March '93 +ODAPR93.ZIP 30027 Discussion from the OpenDoors echo, April '93 +ODMAY93.ZIP 39440 Discussion from the OpenDoors echo, May '93 +ODJUN93.ZIP 56615 Discussion from the OpenDoors echo, June '93 + +11.) HOW CAN I GET HELP WITH OPENDOORS OR BBS DOOR/UTILITY PROGRAMMING? + ----------------------------------------------------------------- + +If you have any problems with a program, please feel more than free to +post a message here, asking for help. Afterall, that is one of the +central purposes of this echo. However, try to keep the following points +in mind when asking a question. Doing so will help others to better +understand your problem, and as such will help them help you. + + A.) If you are having a problem with a program, try to + describe as much about the problem as possible. If you + can, precisely how to reproduce the problem. If you wish + to do so, posting source code can also be of great + advantage. For more information on posting source code in + the echo, please see section 12. + + B.) Explain what steps you have already taken in trying to + solve your problem. This will allow others to pick up from + where you have become "stuck", and not suggest solutions + that you have already tried yourself. + + + +12.) WHAT GUIDELINES ARE THERE FOR POSTING SOURCE CODE? + ------------------------------------------------- + +You are more than welcome to post source code in this echo. If you do +so, please keep the following guidelines in mind. + + A.) Unless you explicitly say otherwise, any source code + posted in this echo will be considered to be released to + the public domain. If you have some source code that you + do not wish others to copy, don't post it here! + + B.) For your source code to be useful to others, it has to be + understandable. Adding comments can be of great benifit to + someoone trying to understand your code. + + C.) If you are posting a program written with OpenDoors, + please be sure that you do NOT include your registration + key in the source code! + +---------------------------------------------------------------------------- + OpenDoors Tech Corner: ColorToString() +---------------------------------------------------------------------------- + + Authored by: Brian Pirie, OpenDoors author + +/* Function to convert an integer color attribute to an OpenDoors */ +/* style color description string, in the format: */ +/* */ +/* [Flashing] [Bright] [Foreground] on [Background] */ +/* */ +/* The function takes two parameters, an unsigned integer */ +/* representing the input color, and a pointer to a string where */ +/* the colour description should be output. Be sure that this */ +/* string is large enough to hold the largest possible color */ +/* description string. (If the code is not altered, the largest */ +/* possible string will be 35 characters, including the null */ +/* terminator */ + +void ColorToString(unsigned int color, char *outString) +{ + /* Array containing names of various colors */ + static char colorString[8][33]={"Black", + "Blue", + "Green", + "Cyan", + "Red", + "Magenta", + "Yellow", + "White"}; + + /* Initialize string */ + outString[0]='\0'; + + /* If flashing bit is set, output "Flashing" string + space */ + if(color & 0x80) { + strcat(outString, "Flashing "); + } + + /* If bright bit is set, output "Bright" string + space */ + if(color & 0x08) { + strcat(outString, "Bright "); + } + + /* Output foreground color */ + strcat(outString, colorString[color & 0x07]); + + /* Output the word "on" with a space before & after */ + strcat(outString, " on "); + + /* Output background color */ + strcat(outString, colorString[(color & 0x70) >> 4]); +} + +Editor's Note: Brian was kind enough to put this function together for us +upon request for a function to perform the reverse of the od_color_config() +function. I had to add a bracket or two that was left out (he did mention +that it was untested code!), but it works like a champ. + +---------------------------------------------------------------------------- + In Search Of - The Art of Debugging + By Mark Williamson +---------------------------------------------------------------------------- + +It happens. The inevitable. You have spent so many hours trying to +write the most optimized, cleanest code possible. But your best efforts +are laid to rest when some verocious little creature pops up, seemingly +at random, and wreaks havoc on all your efforts. + +What causes these bugs to appear? Can it be programming style? Or a +forgotten temporary variable? Where, or where, is that bug! + +If this has happened to you, don't feel bad. 50 percent of your time +programming will be devoted to the debugging cycle. Many books have +been written that are devoted to the art of programming style, debugging +and the development cycle. I will only touch on a couple of pointers to +get you started in the right direction in locating that invisible target +called so affectionately, the "bug." + +Case scenario: I was working on a program that would shell to DOS using +one of the OD_SPAWN... functions. OPENDOOR.DOC discusses in +good detail how to use either of these functions. But, being the eager +programmer that I am, I happily went about my way after I read what I +thought I needed to know. The program in question uses a temporary +directory to store files extracted from .ZIP/.ARJ/etc.. archive files. +As the program was running, it worked just great. Unpacked the files +using PKZIP. Repacked them using ARJ. + +Then I tried it again. That's when it all fell apart for me. +Unwillingly, I just started a four-day straight debugging session, +lasting until the wee hours of the night. + +Point one: Always read the docs...thoroughly! + +During this four day debugging frenzy I removed 20 or more variables I +didn't need, rewrote five functions to be more independent and portable +(ie modular programming) and greatly optimized the program overall. + +But I still couldn't find the bug. + +Here's a sample of the code: + + od_set_cursor(15,20); + od_printf("`bright cyan`Unpacking"); + error=run_it(progname,unpackcommand); // see the run_it function + // below. + if(error==0){ + od_set_cursor(15,33); + od_printf("`bright green`ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ `bright cyan` Ok "); + } + +The above code did not do as it appears it should. In fact, as soon as +the trace feature of Turbo C++ 3.0 hit the line that prints out the bar +and the word "Ok", what actually was printed out was something like +this: + + + Unpacking :\BBSFILES\BBSUPLOADS\CHKZIP.ZIP + +but not: + + Unpacking ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ Ok + +Now remember, I hadn't read the section on the od_swapping_path variable +yet. + +The OD_SPAWN.. functions will swap to either EMS memory or DISK. The +variable od_control.od_swapping_path is empty by default, which equates +to the CURRENT DIRECTORY!. Thus, when my utility unpacked/repacked the +files, it packed up the swap file also. Then, when I ran it the second +and future times on the same archive file, I was overwriting the swap +file! Effectively overwriting the program's data and code segments. + +Lesson learned: Read the docs..first. Don't use the old tried and +untrue "If all else fails, read the docs." Read them first. Read them +several times. + +How to debug: + +If your compiler has a trace feature, use it. + +Put all the variables in the watch window that could possibly have any +bearing on the function your are testing. Look for suspicious changes +in values when the variable has not been 'touched'. + +Minimize global variable useage. This makes portability difficult. If +you write functions that do not rely on any outside information except +that which is passed as an parameter, then it will be much easier to use +the same functions over and over, throughout many of your projects. + +Use descriptive variables. C gives you much luxury in the length of +your variable names. Use this to the max. How many times have you +scratched your head and wondered "what does this one do?" + +Use descriptive function names. See above + +Read other programmer's source for ideas. Many times you will probably +be reinventing the wheel. Read the C snippets for ideas. Check out +some other source code to see how it's done elsewhere. This may give +you much needed insight into the art of programming style. + +And last but not least.. Use comment lines! Don't be vague. Commenting +your source code will most likely help only one person. You. But, you +are the only one that matters anyway right? + +Good luck and press on! + +Mark Williamson +Software Solutions +Fido 1:214/54 + +Home of Labtest 2.00 - The Definitive Upload Processor +Written entirely in Turbo C++ 3.0 using Brian Pirie's Open Doors 4.1 + + +---------------------------------------------------------------------------- + REVIEW: VID v2.01 +---------------------------------------------------------------------------- + +VID v2.01, the BBS Virus Information Door from Cairo Research Labs, is now +available! + +The original VID was designed to provide a quick online virus reference for +BBS users, but has quickly evolved into quite a bit more! Thanks to a +tremendous response from Sysops around the world, VID has provided BBS users +with quick, accurate viral assessments while online on their favorite BBS +system. + +What's New in This Release? + + o Over 100 new viruses added, bringing the total up to 1,557 entries. + + o Cleaned up display in several of the search and list options, + including multi-column virus listings (Thanks to Chris Koziol). + + o Provided an option for online documentation for end-users. + + * Due to an internal problem in the original 2.00 release, you must + use v2.01+ to use any new enhancement modules. The database + structures have changed a bit. + + * The periodic VID integrity check has been enhanced. VID now + stores its integrity information in a file called SANITY.CHK. + Ensure that this file resides in the VID directory! + + * In the 2.00 release, the VIDDEF.TBL file had to reside in the + path. This was causing a message subsystem initialization error + if VID could not locate this file in the path! VID now looks in + the current directory first. (Thanks to Steve Pepin) + + ! In the Behavior search, although the default answer is "Ignore", + the prompt showed the default as "No". Fixed! (Steve Pepin). + + ! If VID was typed alone with no arguments, the old switches from + the 1.10 release were displayed! Fixed! (Steve Pepin, again!). + + ! VID now handles extraneous spaces in registration keys. This + occurred when clipping a key from a netmail message. Squashed! + (Thanks to Bart Holiman). + + ! In the 2.0 datafiles, the "Stealth" flag on several viruses was + not set properly. Squashed! + +FREQ: VID - This will get you the VID engine, documentation, Lite-level + database, and any release notes. 165K in size (VID201.ZIP). + + VIDPLUS - This will get you the VID+ modules. You must have the VID + engine (above) for this to be functional! This expands + to around 1.5MB or so. 323K in size (VP0793.ZIP). + + FROM - Under the Nile BBS, 1:3613/12, 14.4 USR + (706) 596-8126 + +--------------------------------------------------------------------------- + OPENDOORS SNIPPPPPPPPPETS!!!!!! +---------------------------------------------------------------------------- +By : Mark Williamson + +The previous post of this code had a little error. In the fill_box() +function, remove the od_clr_scr(). I had put that in for test purposes. Sorry +bout that! + +/********************************************************************/ + +I would like to submit this code for the next issue of ODTJ. Please +post my name and bbs info in the ODTJ with this code: + +/****************************************************** +* fill_box() by Mark Williamson, Software Solutions BBS +* Fidonet 1:214/54, (209)997-0224 +* +* This code will paint a box in the +* specified color using the specified +* character using ansi/avatar graphics. +* Note that this does not make a border! +* Only 'fills' a block on the screen. +* Can be used to clear just parts of a screen. +* +* Call the function with the following parameters: +* +* int srow,scol: Starting row,col of the box +* int erow,ecol: Ending row,col of the box +* int attrib: od_set_attrib() style color code +* char fill_char: The character to use to paint the +* block. Use ' ' to clear a block. +* +* This code is placed in the public domain. +******************************************************/ + +#include +#include "opendoor.h" + +void fill_box(int srow, int scol, int erow, int ecol, + int attrib, char fill_char); + +void main(void) +{ + fill_box(3,10,13,40,0x1f,'°'); +} + +void fill_box(int srow, int scol, int erow, int ecol, + int attrib,char fill_char) +{ + int line_len,x; + if(srow<1) srow=1; + if(erow>24) erow=24; + if(scol<1) scol=1; + if(ecol>80) ecol=80; + line_len=ecol-scol; +/* od_clr_scr(); OOPS! TAKE THIS LINE OUT */ + od_set_attrib(attrib); + for(x=srow;x< End of The OpenDoors Tech Journal - Volume 93 Issue Number 5 ><- +---------------------------------------------------------------------------- + diff --git a/utils/magiedit/odoors/historic/ODTJ9402.TXT b/utils/magiedit/odoors/historic/ODTJ9402.TXT new file mode 100644 index 0000000..8ba507c --- /dev/null +++ b/utils/magiedit/odoors/historic/ODTJ9402.TXT @@ -0,0 +1,2244 @@ +ÚÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¿ +³ Ü Ü Ü ³ Volume 94 Issue 2 ³ +³ÜÛÜ Û Ûßß ÜÜÜ ÛßÛ Ûßß ÛÛÜ ÜÜÛ ÜÜÜ ÜÜÜ ÜÜÜ Ûßß ³ September 23, 1994 ³ +³ Û ÛßÛ Ûß Û Û ÛÜÛ Ûß Û Þ Û Û Û Û Û Û Û ßßÛ ³ ³ +³ ÛÛ Û Û ÛÛÛ ÛÛÛ Û ÛÛÛ Û Þ ÛÛÛ ÛÛÛ ÛÛÛ Û ÛÛÛ ³ "The greatest thing ³ +³ Ü Ü Ü ³ to happen to ³ +³ÜÛÜ Ûßß ÜÜÜ Û Û ÜÜÜ Û Û ÜÜÜ ÛÛÜ ßßÛ Û ³ journalism since ³ +³ Û Ûß Û ÛßÛ Ý Û Û Û Û Û Û Û Þ ÛßÛ Û ³ Real People!" ³ +³ ÛÛ ÛÛÛ ÛÛÛ Û Û ÛÛÛ ÛÛÛ ÛÛÛ Û Û Þ ÛÛÛ ÛÛÛ ³ ³ +³ ³ Ed: Scott Burkett ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + +In this action-packed issue: + + - A Word from the Editor + - OpenDoors 5.0 Released! + - OpenDoors 5.0 Changes + - Bits 'n Bytes 'n Data types + - Adding InterBBS Capabilities to OpenDoors programs + - Opendoors Tech Corner - Inside OD 5.0's Internal Async Routines + - Opendoors Tech Corner - Adding Local Mode Functionality + - Opendoors Tech Corner - Finding physical cursor position in OD 5.0 + - Opendoors Tech Corner - Using UP/DOWN Arrow Keys in OD 5.0 + - Opendoors Tech Corner - Drawing bar graphs with OD! + - Opendoors Tech Corner - Obtaining Names/Passwords in ASCII Mode + - Opendoors Tech Corner - Files Transfers under OpenDoors + - Opendoors Tech Corner - Comparing file stamps + - Opendoors Tech Corner - Generating Fidonet *.MSG Messages + - Code Snippets! + - Opendoors Release Notice: BCHECKERS v1.2 + - Opendoors Release Notice: BFE 4.00.2r + - Opendoors Release Notice: GIF View Preview Door v1.0 + - Opendoors Release Notice: Operation: Office v.05 + - OpenDoors Tech Journal Information + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ A Word from the Editor ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßß + +By: Scott Burkett + +After many months of toiling, sweating, complaining, and otherwise +groveling - it is now official - OpenDoors v5.0 has arrived! Brian has +once again displayed his ability to provide his customers with simply +the best C-based door kit in existence. + +I've moved! Actually, I'm still moving. My wife and I just moved to +the Tampa Bay, Florida area and so far, so good! Actually, the author +of RemoteAccess, Andrew Milner lives in Clearwater now - supposedly owns +his own bar. I would go looking him up, but I'm afraid what might +happen if Andrew and I spent too much time together with his alcohol +supply. Such is life. + +If you haven't noticed by now, this issue is big - no, huge is more like +it. I've been saving bits and pieces here and there. Actually, I was +waiting on OD 5.0 to be released, and the pile just kept growing. I +am convinced that the only reason Brian finally released 5.0, was to +diminish my growing stack of code snippets.... :-) + +Just a reminder, but please be sure to send me any release notices for +your latest OpenDoors creations! Without being notified, chances are, +it won't appear in ODTJ. Free advertising is nice, isn't it.... :-) + +Alles Klaar und spater! (Until the next issue...) + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors 5.0 Released! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßß + +By: Brian Pirie + +This edition of the ODTJ marks the release of OpenDoors 5.00. Version 5.00 +embodies some major steps forward for OpenDoors, including built-in +asynchronous serial I/O capabilities, support for non-Borland C compilers +such as Microsoft C, and a set of new advanced screen, window and popup menu +functions. Many small enhancements have also been made, along with many +efficiency improvements. As the long "new features and enhancements" list for +version 5.00 will testify, this new release is one of the largest upgrades +ever made to the capabilities of OpenDoors. Version 5.00 has also been more +extensively tested than any previous version of OpenDoors, making it one of +the most stable and efficient foundations on which you could choose to build +your on-line software. + +Yet, even with all of the improvements that have been made for OpenDoors +5.00, work is already going ahead for version 5.10. The aim of version 5.10 +won't be so much to add new features, as to improve on already existing +features. More efficiency improvements and greater flexibility is the goal of +OpenDoors 5.10. + +What will come after OpenDoors 5.10? More than anything else, the future +directions of OpenDoors is guided by the programmers who work with it. Your +suggestions, ideas and even bug reports will determine what enhancements will +continue to be made to OpenDoors. Please don't hesitate to pass along any +changes that you would like to see in future versions of OpenDoors! I am also +interested to find out how much interest there would be in the following: + +- An OS/2-specific version of OpenDoors +- A Windows-specific version of OpenDoors +- Graphics-mode RIP support +- A programmer-configurable door installation/configuration utility + that would work in conjunction with the OpenDoors configuration file + system. +- A multi-node file system that would facilitate easy implementation + of multi-node doors with the ability to send messages between nodes + and control concurrent access to configuration and user files. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors 5.0 Released! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßß + +By: Brian Pirie + +Version 5.00 represents several major steps forward for OpenDoors. In +addition to numerous bug fixes and minor improvements, a number of major +new features have been added to this version. These include an optional +multiple personality system which allow the sysop to choose the status +line and function key style they prefer. This version also adds +text-mode support for RIP (Remote Imaging Protocol) graphics, and adds a +group of advanced ANSI/AVATAR/RIP functions for scrolling areas of the +screen, saving and restoring portions of the screen and creating pop-up +windows and menus. Also new in this version is support for compilers +other than Borland/Turbo C(++), such as compilers from Microsoft. +Version 5.00 also adds built-in communications support, making the use +of a FOSSIL driver optional. Furthermore, direct support for additional +BBS systems has been added. + +The list below provides more detail of the changes and new features in +version 5.00. For a summary of changes made for previous versions of +OpenDoors, refer to the OpenDoors History file that is available from my +system. + + - The nonstop key ([=]) now works correctly during FILES.BBS + listing. + + - New door information file formats now supported include: RA 2.00 + EXITINFO.BBS. + + - If the TASK environment variable is set, OpenDoors will now use + its value to determine the current node number. + + - The od_control.od_spawn_freeze_time variable now works correctly. + Previously, the user's time would always be frozen during + od_spawn...() execution, regardless of the value of this + variable. + + - A new feature known as the "Multiple Personality System" has been + added to this version. If you choose to include the Multiple + Personality System in a door, the sysop will be able to specify + which of a number of "personalities" should be used. Each + personality defines the statusline appearance and function keys + seen by the sysop, and has no effect on the door's operation from + the user's standpoint. OpenDoors 5.00 includes personality + definitions for WildCat, RemoteAccess, PC-Board, and it's own + simplified RA style status lines. You can also define your own + personalities by writing a personality definition function. If + your choose not to include the Multiple Personality System in a + door, you will still be able to define which single personality + you wish OpenDoors to use. + + - This version of OpenDoors can be used with a larger variety of + compilers than where supported by the previous version. OpenDoors + 5.00 is known to work with all versions of Turbo C, Turbo C++, + Borland C++, Microsoft C, Microsoft C++, Quick C and Visual C++. + It should also work with any other MS-DOS based ANSI C compiler + that supports the Microsoft/DOS .OBJect and .LIBrary file + formats. + + - A new diagnostics feature has been added to OpenDoors, which + allows you to determine the reason for the most recent OpenDoors + function failure. When any OpenDoors function returns a failure + condition, it also sets the new od_control.od_error variable to + indicate the reason for the failure. + + - Added additional definitions to OPENDOOR.H, to map names of + OpenDoors functions and variables with the word "colour" from the + U.S. spelling "color". In other words, both od_set_colour() and + od_set_color() are now recognized by OpenDoors. + + - The od_list_files() now supports more intelligent path + specifications. If the parameter to od_list_files() is NULL or + empty, it will search for a FILES.BBS file in the current + directory. If a directory path is specified, it will look for a + FILES.BBS in that directory. If a full directory and filename are + specified, the specified filename will be used in place of + FILES.BBS. + + - To save space, the compact memory model library is no longer + included in the normal OpenDoors package. The compact memory + model library is now available seperately. + + - A new function, od_set_dtr(), has been added to allow the DTR + line to the modem to be manually controlled. This can be useful + in writing programs where you wish to force the modem to hangup, + such as a call-back verification door. + + - Added additional support for various DOS multitasking + environments. OpenDoors is now specifically Microsoft Windows + aware. OpenDoors also now gives up time to other waiting tasks + when it is idle during chat mode. + + - The od_edit_str() "M" mode now capitializes a character following + a dash '-' character. + + - When transmitting more than one character at a time, OpenDoors + now uses the FOSSIL trasfer block function, instead of multiple + calls to the transfer character function. This should help to + improve performance over high speed connections when running on + slow PCs or under multitasking environments. + + - OpenDoors 4.10 would not correctly change the display colour from + high-intensity back to low-intensity. This problem has been + fixed. + + - OpenDoors now recognizes DORINFO?.DEF filenames with alphabetical + identifiers (ie, DORINFOA.DEF thru DORINFOZ.DEF) for nodes 10 + thru 35. + + - Improvements have been made to the logfile system. An exit at + errorlevel zero no longer causes garbage to be written to the + logfile. The logfile functions have been made more reliable when + operating under low stack availability conditions. In the past, + if a large number of local variables where allocated on the + stack, the logfile functions would fail, often writing garbage to + the logfile. When the user pages the sysop for chat, the user's + reason for wishing a chat is also written to the logfile. + + - Support for text-mode RIP (Remote Imaging Protocol) graphics has + been added. Because this version of OpenDoors always operates in + DOS text-mode, none of the graphics mode RIP features (such as + drawing lines, circles and displaying icons) will appear on the + local screen. Plans for a version of OpenDoors that will operate + in graphics mode and optionally display graphics locally are + currently under consideration. In this version, RIP support + includes a number of new features. OpenDoors will now recognize + the RIP setting passed in an RA 2.00 EXITINFO.BBS file and + WildCat DOOR.SYS file, and also allows the RIP setting to be + specified in a custom door information file. The od_send_file() + and od_hotkey_menu() functions will now search for files with + .RIP, .AVT, .ANS and .ASC extensions. When displaying RIP + graphics to the remote user, a pop-up window appears on the local + screen, indicating to the sysop which file is being displayed. + + - A set of new functions have been added to permit advanced screen + manipulations. These functions include od_gettext() and + od_puttext() to save and restore portions of the screen, and + od_save_screen() and od_restore_screen() to save and restore the + entire screen. od_scroll() can be used to scroll any portion of + the screen upwards or downwards. od_save_screen() and + od_restore_screen() will operate in any mode, but the other + functions require ANSI/AVATAR/RIP mode to be available. + + - Three additional functions, od_window_create(), + od_window_remove() and od_popup_menu(), have been added to + facilitate the creation of popup windows and menus. When such a + window or menu is removed from the screen, the are of the screen + "under" the window is returned to it's original state. This + allows you to create multiple overlapping windows within a door + program. The od_popup_menu() function creates a popup window with + a menu from a simple menu definition string. The user can select + an option from this menu by pressing the key associated with an + option, or by moving a menu selection bar using their arrow keys. + These three functions require an ANSI/AVATAR/RIP mode to be + available. + + - A new function, od_chat() has been added, to allow you to + explicitly invoke the OpenDoors chat mode from within your + program. + + - A new setting variable, od_control.od_always_clear has been + added. When set to TRUE, od_clr_scr() will always clear the + screen, regardless of the user's screen clearing setting. When + set to FALE, od_clr_scr() will only clear the screen if the user + has screen clearing enabled. + + - It is now possible to configure the errorlevels OpenDoors exits + with under various circumstances, such as when the user runs out + of time remaining online. See the od_control.od_errorlevel + variable + + - A new setting variable, od_control.od_force_local, can be used to + easily force OpenDoors to operate in local mode. Using this + variable you can easily add a command line parameter such as + "-local" to allow the sysop to force your door to operate in + local mode. When OpenDoors is forced into local mode using this + variable, it does not look for a door information file, and uses + default settings for the user's name, etc. + + - OPENDOOR.H now sets structure packing to single byte alignment + for the od_control structure when Borland and Microsoft compilers + are being used. In the past, programmers using OpenDoors have + experienced difficulties the od_control structure when the + compiler has been set to use word packing. + + - OpenDoors now closes the FOSSIL driver prior to performing a + spawn or sysop DOS shell. This allows doors or other + communications programs which use the FOSSIL driver to be + executed while the door's execution is suspended. + + - When used with a FOSSIL driver, OpenDoors normally changes the + BPS rate to that passed from the BBS (if the BBS passes a valid + FOSSIL BPS rate). This BPS rate setting may now be disabled by + setting the DIS_BPS_SETTING bit of the od_control.od_disable + variable. + + - A function hook has been added to allow you to install a function + to be called whenever od_kernel() executes + (od_control.od_ker_exec). Another function hook, + od_control.od_time_msg_func, can be installed to override + OpenDoor's time limit warning messages. + + - A new array, od_control.od_hot_function, allows the you to define + functions to be called when any of the programmer-defined sysop + hotkeys have been pressed. + + - A function hook, od_control.od_no_file_func, has been added. This + function will be called whenever OpenDoors is unable to find or + read a door information file. This allows you to add your own + door information file reader, or to provide a local login prompt + when no door information file is present. + + - Previously, OpenDoors would stop correctly updating the user's + remaining time at midnight when running under certain BIOSes. + This problem has been fixed. + + - The current display colour attribute can now be accessed through + an control structure member, od_control.od_cur_attrib. + + - od_send_file() and od_hotkey_menu() no longer pause with a + "Continue?" prompt prematurely in files that have line lengths + greater than 254 characters. + + - The local keyboard may now be disabled by setting the + DIS_LOCAL_INPUT bit of od_control.od_disable. This only affects + the sysop's input in circumstances that input is also accepted + from the remote user; this setting has no effect on the sysop + function keys. + + A new function hook: + + void (*od_control.od_local_input)(int); + + has been added. If set, this function will be called whenever the + sysop presses a non-sysop-function key on the local keyboard. + + - od_control.od_clear_on_exit now controls whether the screen is + cleared before shelling or executing od_spawn...(), in addition + to before OpenDoors shuts down. + + - od_page() now restores the original display colour before + returning. + + - It is now possible to display an entire string of characters with + terminal emulation, using the new function od_disp_emu(). + + - OpenDoors will now display a small popup window when + disconnecting the current connection. + + - A new variable, od_control.od_in_buf_size, can now be set prior + to calling any OpenDoors function to set the size of OpenDoors + combined local/remote keyboard input buffer. By default, this + buffer is 256 bytes in size. + + - Previously, there were a number of OpenDoors API functions that + would not correctly initialize OpenDoors if they were the first + function called in the program. This has been fixed. + + - To facilitate setting of bps rates up to 115,200, od_control.baud + is now an unsigned long. + + - A new setting, od_control.od_no_ra_codes, has been added to + disable the use of RemoteAccess/QuickBBS control codes by + od_send_file()/od_hotkey_menu()/od_disp_emu(). The + RemoteAccess/QuickBBS ASCII 1 "pause for key" is also now + recognized. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Bits and Bytes and Data Types ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ InterBBS Capabilities are Here! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +*** Editor's Note: The following is the press release for Brian's +InterBBS add-on library for OpenDoors. It can be obtained by FREQ'ing +IBBS from either his system or mine. Enjoy! + +BBS "door" programs have always allowed operators of online computer +services, such as electronic bulletin board systems, to easily expand the +services provided by their systems. Doors have greatly increased the +flexibility and usability of BBS systems. A recent trend in door development +has been to allow doors running on one BBS system to be linked to doors +running on other systems, often through existing mail networks. While these +networks have traditionally provided private and conference (echo) mail +services and file sharing capabilities, they can also be useful in providing +links between special applications that wish to share information with one +another. + +By taking advantage of existing mail network technology, BBS door developers +have been able to add a new dimension to the software they create. Among the +new ideas that have proven successful have been distributed BBS listing +services, distributed file listing services and games that share top-score +lists or even allow players to compete with people playing the game hundreds +or thousands of miles away. The possibilities are really limited only by the +imagination of the door software developer. + +This package is designed to assist in writing Inter-BBS door programs that +can communicate across FTSC-compatible mail networks, such as FidoNet. Using +this package, you can: + + - Send information messages through any FTSC-compatible mailer + that supports *.MSG format netmail, including FrontDoor, + InterMail, BinkleyTerm, D'Bridge, and others. + + - Send messages containing either textual or binary data. This + information is stored in the message body, to allow the message + to be sent either directly (CrashMail) or by routed netmail. + + - Easily send information to just one other system, or all + systems running the door. This allows you to implement both + centralized and de-centralized information distribution + schemes. + +This package includes the source code for an example skiing game door that +maintains a high score list across multiple BBSes. This game requires the +OpenDoors door programming toolkit to be compiled. However, the Inter-BBS +Toolkit itself can also be use in doors that are not written with OpenDoors. + +The Inter-BBS Toolkit is available free of charge, and the package includes +the complete C source code. This source code has been written for Borland C +and C++ compilers, but may easily be modified for use with other C compilers. +With the source code, you are able to customize or expand the capabilities of +the Inter-BBS Toolkit as you wish. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Tech Corner ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßß + +----------------------------------------------------------------------------- + Inside OD 5.0's Internal Async Routines + By: Brian Pirie/Scott Burkett +----------------------------------------------------------------------------- + + > Just a quick thought, but it would be nice if we could have + > access to the low level communication functions (both fossil and + > internal). The standard od...() functions work great for doors, + > but for critical timing matters such as protocols, etc, it + > doesn't fly. I am using my own fossil system for the timing + > essential portions of BFE, for example. + +I will consider adding these functions to the documented OpenDoors interface. In +the meantime, they are as follows: + +int _com_carrier(void); /* TRUE if DCD is high */ +void _com_clear_inbound(void); /* Clears outbound buffer */ +void _com_clear_outbound(void); /* Clears inbound buffer */ +void _com_close(void); /* Closes serial port */ +void _com_dtr(char high); /* TRUE raises DTR, FALSE lowers DTR */ +char _com_getchar(void); /* Returns next char from modem */ +void _com_ini(void); /* Opens serial port */ +char _com_inbound(void); /* FALSE if inbound buffer is empty */ +char _com_outbound(void); /* FALSE if outbound buffer is empty */ +void _com_sendchar(char ch); /* Sends character to modem */ + /* Sends multiple chars to modem */ +void _com_send_buf(char *buffer,int size); + +These functions assume that the door is not operating in local mode. Do not +call com_getchar() unless the _com_inbound() returns TRUE. + +----------------------------------------------------------------------------- + Adding Local Mode Functionality + By: Brian Pirie +----------------------------------------------------------------------------- + +OpenDoors 5.00 now permits you to easily force your door to operate in local +mode by setting the od_force_local variable. Normally OpenDoors will use a +default user name, but you can also use this feature to easily provide a +local login prompt for your door. The following example shows how you might +do this: + +(This code might look long, but keep in mind that most of it is comments!) + +#include "opendoor.h" + +int main(int argc, char *argv[]) + { + int counter; + char valid_login = TRUE; + + /* Check for /LOCAL command-line parameter */ + for(counter = 1; counter < argc; ++counter) + { + strupr(argv[counter]); /* Do this with care! */ + if(strcmp(argv[counter], "/LOCAL")==0) + { + /* We are operating in local mode */ + od_control.od_force_local = TRUE; + + /* Let user login */ + do { + /* Prompt for user name */ + printf("User Name : "); + + /* Get name from user. Note that it would be better */ + /* to use a console input routine that limits the */ + /* number of characters that can be inputted by the */ + /* user, to prevent od_user_name from being overrun. */ + /* I use gets() here for simplicity. */ + gets(od_control.od_user_name); + + /* At this point, if you have a user file for your door */ + /* you might want to check whether the user's name is */ + /* valid. If it is not valid, you can set valid_login */ + /* to false, to cause door to prompt for a new name. */ + /* (Keep in mind that you should provide some way for a */ + /* new user to log in locally!) */ + } while(!valid_login); + + /* Perform main door operations */ + doormain(); + + /* Exit program */ + return(0); + } + } + + /* If we get to this point, then there is no /LOCAL parameter. So, */ + /* we should operate normally */ + + /* Perform main door operations */ + doormain(); + + /* Exit program */ + return(0); + } + + +void doormain(void) + { + /* Initialize OpenDoors */ + od_init(); + + /* Door's main processing, common to remote and local modes, */ + /* here */ + } + +----------------------------------------------------------------------------- + Finding physical cursor position in OD 5.0 +----------------------------------------------------------------------------- + (Brian Pirie) + + > Quick question: Is there a method to determine the current + > location of the cursor, without keeping track of it manually? I + > vaguely recall a thread about this subject, but can't find it + > for the life of me... + +In 5.00, the following two variables: + + extern unsigned char phys_curx; + extern unsigned char phys_cury; + +store the current location of the cursor on the local screen. + +----------------------------------------------------------------------------- + Using UP/DOWN Arrow Keys in OpenDoors 5.0 +----------------------------------------------------------------------------- + (Taken from the OPENDOORS echo) + + > Any news on when the next beta will be out, and also do you plan + > on allowing support for use of the UP/DOWN arrow keys? + +This has been fixed in the 5.00/beta-8 package. The following program +demonstrates a door which displays a simple message when the up or down arrow +key is pressed. Since OpenDoors defaults to using the up and down arrow keys +for adjusting the user's time limit, such a program has to use different keys +for this purpose. This program reassigns the [Page Up] and [Page Down] keys +to be used for adjusting the user's remaining time. + +/* Simple program to demonstrate using arrow keys within an OpenDoors door */ +/* program. Since the arrow keys are normally used locally to adjust the */ +/* user's time up or down, you must choose different keys to adjust the */ +/* time limit. This program simply loops, displaying the word "up" if the */ +/* up arrow is pressed, "down" if the down arrow is pressed, and exiting */ +/* if the enter key is pressed. */ + +#include "opendoor.h" + +main() + { + int choice; + char pressed; + long timer; + + /* Notice call to od_init() here! */ + od_init(); + + /* Reassign PageUp and PageDown to increase/decrease time */ + /* Remember to do this after od_init() or your first call to any OpenDoors */ + /* function. */ + od_control.key_lesstime = 0x5100; /* Scan code for Page Down */ + od_control.key_moretime = 0x4900; /* Scan code for Page Up */ + + od_disp_str("Press up and down arrows keys. Press Enter when done\r\n"); + + for(;;) + { + pressed = od_get_key(TRUE); + + /* Check for ANSI arrow key sequences */ + if(pressed==27) + { + timer=(*(long far *)0x46cL)+2L; + while(timer>*(long far *)0x46cL && (pressed=od_get_key(FALSE))==0) + { + od_kernel(); + } + + if(pressed != '[') + { + continue; + } + else + { + timer=(*(long far *)0x46cL)+9L; + while(timer>*(long far *)0x46cL && (pressed=od_get_key(FALSE))==0) + { + od_kernel(); + } + if(pressed == 0) continue; + switch(pressed) + { + case 'A': + goto up_arrow; + + case 'B': + goto down_arrow; + } + } + } + + /* Check for doorway / local arrow key sequences */ + else if(pressed==0) + { + /* Get the next key from the keyboard */ + timer=(*(long far *)0x46cL)+9L; + while(timer>*(long far *)0x46cL && (pressed=od_get_key(FALSE))==0) + { + od_kernel(); + } + if(pressed == 0) continue; + + /* Respond appropriately */ + switch(pressed) + { + case 0x48: +up_arrow: + od_disp_str("Up Arrow.\r\n"); + break; + + case 0x50: +down_arrow: + od_disp_str("Down Arrow.\r\n"); + break; + } + } + /* exit program if user presses CR or LF */ + else if (pressed == '\n' || pressed == '\r') + { + break; + } + } + + + /* Note that od_exit() is now optional in OpenDoors 5.00/beta-8 */ + /* If you allow the program to return from the main() function without */ + /* first calling od_exit(), the od_exit() code will automatically be */ + /* performed. Note, however, that this does not allow OpenDoors to */ + /* determine the errorlevel being used, in order to report the */ + /* errorlevel in the logfile. */ + return(0); + } + + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Drawing Bar Graphs with OD! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß +By: Brian Pirie + +Many different types of programs can be enhanced by the use of graphical +information. Often, this graphical information can take the form of +horizontal bar graphs. + +An easy way to draw horizontal bars in door programs written with +OpenDoors, is to use the od_repeat() function. Not only does od_repeat() +allow you to easily form a bar by repeating a particular character the +specified number of times, but it is also a very efficient way to do so. +od_repeat() will take advantage of terminal emulation optimizations, +when available. For instance, a character can be repeated any number of +times with AVATAR by sending a short 3-byte sequence that specifies the +character and number of times to repeat. + +How do you calculate the number of character to use to form a bar in +your graph? The DrawHorizontalBar() function, which is provided below, +will do this calculation for you. Simply provide the value to be +represented by this bar, the minimum and maximum possible values, and +the maximum number of character to use to draw the bar. For example, if +you are graphing percentages (which could range from 0% to 100%), and +wanted the graph to fit in a space of 40 columns, you would use: + + DrawHorizontalBar(nPercent, 0, 100, 40); + +Below the listing for the DrawHorizontalBar() function is a complete program +which demonstrates the DrawHorizontalBar() function as called from another +function that will create complete horizontal bar graphs. This second function, +DrawGraphOfPercentages(), takes an array of titles, and array of values +corresponding to each title, and draws a complete bar graph from this +information. + + +/* Function to draw a horizontal bar, given a value, the minimum and maximum */ +/* possible values, and the number of characters the horizontal bar should */ +/* extended for the maximum value. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars) +{ + /* Determine lenght of bar */ + int nBarChars = ((nValue - nMinValue) * nMaxChars) / nMaxValue; + + if(od_control.user_ansi || od_control.user_avatar) + { + /* If ANSI or AVATAR graphics are available, assume that IBM extended */ + /* ASCII is also available. This function uses character 220 to form */ + /* bars that are 1/2 the height of the line. You might also want to */ + /* try character 119, which will form bars that are the entire height */ + /* of the line. */ + od_repeat(220, nBarChars); + } + else + { + /* In ASCII mode, the bar is formed by the '=' character. */ + od_repeat('=', nBarChars); + } +} + +----- ex_graph.c example program follows ------------------------------ + +/* Includes */ +#include "opendoor.h" + +/* Function prototypes. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars); +void DrawGraphOfPercentages(int nItems, int *panPercentages, + char **papszTitles, char bTitleColor, char bGraphColor, + int nTitleWidth, int nGraphWidth); + + +/* Main function - program execution begins here. */ +main() +{ + char *apszTitles[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + int anValues[7] = {50, 75, 100, 25, 83, 0, 43}; + + od_printf("`bright green`Test graph:\n\r"); + + DrawGraphOfPercentages(7, anValues, apszTitles, 0x02, 0x0f, 20, 50); + + od_get_key(TRUE); + + return(0); +} + +/* Function to draw horizontal graph of percentages with titles, to */ +/* demonstrate the use of the DrawHorizontalBar() function. */ +/* No titles should have more than nTitleWidth characters. */ +void DrawGraphOfPercentages(int nItems, int *panPercentages, + char **papszTitles, char bTitleColor, char bGraphColor, + int nTitleWidth, int nGraphWidth) +{ + int nCurrentItem; + + /* Loop for each item (line) in the graph. */ + for(nCurrentItem = 0; nCurrentItem < nItems; ++nCurrentItem) + { + /* Set display color for title text. */ + od_set_attrib(bTitleColor); + + /* Add spaces to right-align all titles. */ + od_repeat(' ', nTitleWidth - strlen(papszTitles[nCurrentItem])); + + /* Display the title. */ + od_disp_str(papszTitles[nCurrentItem]); + + /* Add space between title and graph. */ + od_printf(" "); + + /* Set display color for graph. */ + od_set_attrib(bGraphColor); + + /* Draw bar graph for this line. */ + DrawHorizontalBar(panPercentages[nCurrentItem], 0, 100, nGraphWidth); + + /* Move to the next line. */ + od_printf("\n\r"); + } +} + + +/* Function to draw a horizontal bar, given a value, the minimum and maximum */ +/* possible values, and the number of characters the horizontal bar should */ +/* extended for the maximum value. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars) +{ + /* Determine lenght of bar */ + int nBarChars = ((nValue - nMinValue) * nMaxChars) / nMaxValue; + + if(od_control.user_ansi || od_control.user_avatar) + { + /* If ANSI or AVATAR graphics are available, assume that IBM extended */ + /* ASCII is also available. This function uses character 220 to form */ + /* bars that are 1/2 the height of the line. You might also want to */ + /* try character 119, which will form bars that are the entire height */ + /* of the line. */ + od_repeat(220, nBarChars); + } + else + { + /* In ASCII mode, the bar is formed by the '=' character. */ + od_repeat('=', nBarChars); + } +} + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Obtaining Names/Passwords in ASCII Mode ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +By: Brett Barnes, THE TOWER BBS 071 636 3957, England + +#include +#include +#include "opendoor.h" + +void Get_Password(char *string, int length); +void Get_Full_Name(char *string, int length); + +void Get_Password(char *string, int length) +{ +int key; +int count = 0; + + od_clear_keybuffer(); + while((key = od_get_key(TRUE)) != 13) + { + if(key == 0) + od_get_key(TRUE); + + if(key >= 32 && key <= 127 && count < length) + { + string[count++] = key; + od_putch('*'); + } + if(key == '\b' && count > 0) + { + od_putch('\b'); + od_putch(' '); + od_putch('\b'); + count--; + string[count] = '\0'; + } + } + strupr(string);/*make string uppercase*/ +} + +void Get_Full_Name(char *string, int length) +{ +int key; +int count = 0; + + od_clear_keybuffer(); + while((key = od_get_key(TRUE)) != 13)/* Drops out when Enter key*/ + { + if(key == 0) + od_get_key(TRUE);/*cancels prob with DEL key*/ + /*If key = valid ascii code */ + if(key >= 32 && key <= 127 && count < length) + { + /*if uppercase */ if(key >= 65 && key <= 90) + key = key+32;/*convert to lowercase*/ + if(count == 0 && key >= 97 && key <= 122) + key = key-32;/*convert to uppercase*/ + else + if(string[count-1] == ' ' && key >= 97 && key <= 122) + key = key-32;/*convert to uppercase*/ + /*Stop spaces being put in first*/ + if(key != 32) + { + string[count++] = key; + od_putch(key); + } + else if(count > 0) + { + string[count++] = key; + od_putch(key); + } + } + if(key == '\b' && count > 0)/*If Backspace*/ + { + od_putch('\b'); + od_putch(' '); + od_putch('\b'); + count--; + string[count] = '\0'; + } + } +} + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ File Transfers Under OpenDoors ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß +By: Brian Pirie, taken from the OPENDOORS echomail conference: + +Often, it can be useful or necessary to send and receive files between +a program using OpenDoors, and the remote user's system. To allow file +uploading and downloadeding, you can either implement the common file +transfer protocols as part of your program, or you can call an external +file transfer program, such as DSZ. This tip demonstrates how you can +call DSZ using OpenDoors. + +In order to see this program in action, you should run a terminal +program on one machine, and connect to second machine that will run this +example program. (You could also do this in two different windows on one +machine.) The demonstration program will ask whether you want to upload +or download files, and will then prompt you for the file transfer protocol +to use and the filename to transfer. Once this is done, DSZ is invoked +to perform the file transfer. As such, DSZ will need to be installed on +the machine that will run the example program. + +The tip2.c program provides a function that you can use to perform file +transfers. This function is defined as follows: + + int TransferFile(char *pszFilename, eProtocol Protocol, char bReceive) + +The first parameter should contain the name of the file or files to be +transfered. The second parameter should specify the file transfer +protocol to use, and should be one of the following enumerated +constants: + + XModem + XModemCRC + XModem1K + YModem + YModemG + ZModem + +The third parameter specifies whether the file is being send (FALSE) or +received (TRUE). From the user's perspective, sending the file means +downloading, and receiving the file means uploading. + +The TransferFile() function returns TRUE if the file transfer was +completed, and FALSE if it was not. + +If the DSZ program is not present in the system's PATH or the current +directory, then the global variable szDSZFilename must be set to the +full path and filename of the DSZ program. This could be done by adding +a custom OpenDoors configuration file line with a keyword such as +"DSZPath". + +The first part of the tip2.c program discussed in the previous message +follows: + +/* tip2.c - Example program to demonstrate how to send or receive files */ +/* using DSZ, from within an OpenDoors program. */ + +/* Include required header files. */ +#include +#include +#include "opendoor.h" + +/* File transfer protocol enumeration. */ +typedef enum +{ + XModem, + XModemCRC, + XModem1K, + YModem, + YModemG, + ZModem +} eProtocol; + +/* Function prototypes. */ +int TransferFile( + char *pszFilename, + eProtocol Protocol, + char bReceive); +eProtocol ChooseProtocol(void); +void AddParameter( + char **papszArguments, + int *pnCount, + char *pszNewArgument); + +/* Manifest constants. */ +#define ARGS_ARRAY_SIZE 10 + +/* Global variable with DSZ filename. */ +char szDSZFilename[80] = "DSZ"; + + +/* Program's execution begins here. */ +main() +{ + char chAnswer; + char bReceive; + eProtocol Protocol; + char szFilename[73]; + int bSuccess; + + od_printf("OpenDoors file transfer demo.\n\r\n\r"); + + /* Get file transfer direction from user. */ + od_printf("Do you wish to [U]pload or [D]ownload? "); + chAnswer = od_get_answer("UD"); + if(chAnswer == 'U') + { + od_printf("Upload\n\r\n\r"); + bReceive = TRUE; + } + else + { + od_printf("Download\n\r\n\r"); + bReceive = FALSE; + } + + /* Get file transfer protocol from user. */ + Protocol = ChooseProtocol(); + + /* Get filename. */ + od_printf("\n\rEnter filename(s) : "); + od_input_str(szFilename, 72, ' ', 255); + od_printf("\n\r"); + + /* Perform file transfer. */ + bSuccess = TransferFile(szFilename, Protocol, bReceive); + + /* Display result of file transfer to user. */ + od_clr_scr(); + if(bSuccess) + { + od_printf("File transfer successful.\n\r"); + } + else + { + od_printf("File transfer not completed.\n\r"); + } + + /* Prompt user to exit program. */ + od_printf("Press [Enter] to return to BBS.\n\r"); + od_get_answer("\n\r"); + + /* Return control to calling BBS software. */ + od_exit(0, FALSE); + + return(0); +} + + +/* Function to allow user to choose a file transfer protocol. */ +eProtocol ChooseProtocol(void) +{ + eProtocol Protocol; + char chAnswer; + + od_printf("Available file transfer protocols:\n\r"); + od_printf(" [X] XModem\n\r"); + od_printf(" [C] XModem/CRC\n\r"); + od_printf(" [1] XModem/1K\n\r"); + od_printf(" [Y] YModem\n\r"); + od_printf(" [G] YModem-G\n\r"); + od_printf(" [Z] ZModem\n\r\n\r"); + od_printf("Please select a protocol: "); + + chAnswer = od_get_answer("XC1YGZ"); + + switch(chAnswer) + { + case 'X': + od_printf("XModem\n\r"); + Protocol = XModem; + break; + case 'C': + od_printf("XModem/CRC\n\r"); + Protocol = XModemCRC; + break; + case '1': + od_printf("XModem/1K\n\r"); + Protocol = XModem1K; + break; + case 'Y': + od_printf("YModem\n\r"); + Protocol = YModem; + break; + case 'G': + od_printf("YModem-G\n\r"); + Protocol = YModemG; + break; + case 'Z': + default: + od_printf("ZModem\n\r"); + Protocol = ZModem; + break; + } + + return(Protocol); +} + +/* Function to send or receive a file to/from remote system. */ +int TransferFile( + char *pszFilename, + eProtocol Protocol, + char bReceive) +{ + char szPort[7]; + char *apszArguments[ARGS_ARRAY_SIZE]; + int nArgCount = 0; + + /* Filename cannot be NULL. */ + assert(pszFilename != NULL); + + /* Ensure that we are not operating in local mode. */ + if(od_control.baud == 0) + { + od_printf("Operating in local mode;" + " file transfer not possible.\n\r"); + return(FALSE); + } + + /* Generate DSZ command line */ + + /* Begin with executable filename. */ + AddParameter(apszArguments, &nArgCount, szDSZFilename); + + /* Add port parameter. */ + AddParameter(apszArguments, &nArgCount, "port"); + sprintf(szPort, "%d", od_control.port + 1); + AddParameter(apszArguments, &nArgCount, szPort); + + /* Restrict inbound files to current drive and directory. */ + AddParameter(apszArguments, &nArgCount, "restrict"); + + /* Generate DSZ protocol parameters from specified protocol. */ + if(bReceive) + { + switch(Protocol) + { + case XModem: + case XModem1K: + AddParameter(apszArguments, &nArgCount, "rx"); + break; + case XModemCRC: + AddParameter(apszArguments, &nArgCount, "rc"); + break; + case YModem: + AddParameter(apszArguments, &nArgCount, "rb"); + break; + case YModemG: + AddParameter(apszArguments, &nArgCount, "rb"); + AddParameter(apszArguments, &nArgCount, "-g"); + break; + case ZModem: + AddParameter(apszArguments, &nArgCount, "rz"); + break; + default: + assert(FALSE); + } + } + else + { + switch(Protocol) + { + case XModem: + case XModemCRC: + AddParameter(apszArguments, &nArgCount, "sx"); + break; + case XModem1K: + AddParameter(apszArguments, &nArgCount, "sx"); + AddParameter(apszArguments, &nArgCount, "-k"); + break; + case YModem: + case YModemG: + AddParameter(apszArguments, &nArgCount, "sb"); + break; + case ZModem: + AddParameter(apszArguments, &nArgCount, "sz"); + break; + default: + assert(FALSE); + } + } + + /* Add filename parameter to command line. */ + AddParameter(apszArguments, &nArgCount, pszFilename); + + /* Display prompt to user providing */ + od_printf("Begin your transfer now," + " or press [Ctrl]-[X] several times to abort.\n\r"); + + /* Execute command using the OpenDoors od_spawn() function. */ + return(od_spawnvpe(P_WAIT, apszArguments[0], apszArguments, + NULL) == 0); +} + + +/* Function to add next parameter to array of parameters to pass to */ +/* od_spawnvpe(). */ +void AddParameter( + char **papszArguments, + int *pnCount, + char *pszNewArgument) +{ + assert(*pnCount < ARGS_ARRAY_SIZE - 1); + assert(papszArguments != NULL); + assert(pnCount != NULL); + assert(pszNewArgument != NULL); + + /* Add next argument to array. */ + papszArguments[(*pnCount)++] = pszNewArgument; + + /* Ensure that the array is always NULL-terminated. */ + papszArguments[*pnCount] = NULL; +} + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Comparing File Stamps ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßß + +By: Brian Pirie, taken from the OPENDOORS echomail conference: + + > I am trying to find a way to basically look at a files date and + > then determine if it is older than say 10 days old? + > I looked thru all of my manuals, and sample programs and could + > find no examples, so I thought I would turn to the experts here. + > If anyone can give me help I would greatly appreciate it! + +For others who were wondering about this problem, the program below will +display the names of all files in the current directory that are more than +10 days old. + +If you ran the program at 10:35:20 on Friday, August 5th, a file dated +10:35:20 on Tuesday, July 26th (or later) would not be displayed, but a file +dated 10:35:18 on Tuesday, July 26th (or earlier) would be displayed. +(DOS's file time is only accurate to the nearest 2 seconds.) + +**** Editor's Note: To further explain Brian's information, here is a +brief explanation of why DOS file time stamps are only accurate to the +nearest two seconds. The file's time field is set when you create the file, +and updated thereafter whenever you close the file, but *only* if +information has been written to the file. This field is not updated if +the file is merely read, copied, or renamed. When the time field gets +updated, though, the new time is retrieved from the system clock. The +following is a breakdown of the meaning of each bit in the time field: + + FEDCAB98 76543210 + + xxxxx = Hours + xxx xxx = Minutes + xxxxx = Two second increments + +The hour is contained in five bits (on a 24 hour clock), and the minutes +in six bits. Because this only leaves 5 bits in which to store the +seconds, DOS divides the actual value by two (2). A little known fact +about the file time field, is that if all bits in both bytes are set to +zero (0), the DIR command will not show any time. Ok, back to Brian's +snippet (sorry!). + +Included in this file is a function named DIRToCTime(), which converts the +DOS file time format to the C time_t format. + +/* This example program will display the names of all files that are */ +/* more than ten days old. */ + +#include +#include +#include +#include + +time_t DIRToCTime(unsigned uDate, unsigned uTime); + +#define SECONDS_PER_DAY (60 * 60 * 24) + +main() +{ + struct ffblk DirEntry; + time_t CurrentTime = time(NULL); + time_t FileTime; + double dElapsedSeconds; + double dElapsedDays; + + if(!findfirst("*.*", &DirEntry, FA_ARCH)) + { + do + { + /* This loop repeats for every found file ... */ + + /* Convert the file's time as returned by findfirst() to a time_t. */ + FileTime = DIRToCTime(DirEntry.ff_fdate, DirEntry.ff_ftime); + + /* Determine the number of seconds that have elapsed between the */ + /* two times. */ + dElapsedSeconds = difftime(CurrentTime, FileTime); + + /* Determine the number of days that have elapsed. */ + dElapsedDays = dElapsedSeconds / SECONDS_PER_DAY; + + /* If more than ten 24-hour periods have elapsed, display filename. */ + if(dElapsedDays > 10) + { + printf("%s is more than ten days old.\n", DirEntry.ff_name); + } + } while(!findnext(&DirEntry)); + } + + return(0); +} + + +time_t DIRToCTime(unsigned uDate, unsigned uTime) +{ + struct tm TimeStruct; + + TimeStruct.tm_sec = (uTime & 0x001f) * 2; + TimeStruct.tm_min = (uTime & 0x07e0) >> 5; + TimeStruct.tm_hour = (uTime & 0xf800) >> 11; + TimeStruct.tm_mday = uDate & 0x001f; + TimeStruct.tm_mon = ((uDate & 0x01e0) >> 5) - 1; + TimeStruct.tm_year = 80 + ((uDate & 0xfe00) >> 9); + + return(mktime(&TimeStruct)); +} + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Generating Fidonet *.MSG Messages ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß +By: Mark Williamson, taken from the OPENDOORS echomail conference: + +/* NETMAIL.C : This little jewel will write send a netmail message to + the names and addresses listed in NAMES.LST. This file + has the format of: + + First Lastname + Zone Node Net Point (point is optional) + + example: + + Mark Williamson + 1 202 750 <0> + + When the program loads, it will load the editor EDIT.EXE. + Just change the line system("EDIT.EXE") to load your editor. + This program expects to find a file NET.MSG. + + This program is public domain . + The attribute used in this program is CRASH KILL SENT. + + Look in the Fidonet Technical Specifications for the full + structures and meaning of each field. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static char msghdr[50],year[5],msgfile[80],firstname[30]; +char *msgtext,select; +void writefido(void); + +char *strrep(char *str, char *oldstr, char *newstr) +{ + int OldLen, NewLen; + char *p, *q; + + if(NULL == (p = strstr(str, oldstr))) + return p; + OldLen = strlen(oldstr); + NewLen = strlen(newstr); + memmove(q = p+NewLen, p+OldLen, strlen(p+OldLen)+1); + memcpy(p, newstr, NewLen); + return q; +} + +/* *.MSG format: */ +struct { + char from[36], + to[36], + subject[72], + datetime[20]; + int timesread, + destnode, + orignode, + cost, + orignet, + destnet, + destzone, + origzone, + destpoint, + origpoint, + replyto, + attribute, + nextreply; + } Msg; + + +char buffer[89]; +void main(void) +{ + + FILE *fp,*fp2; + struct tm *time_now; + time_t secs_now; + char zone[10],node[10],net[10],point[10]; + + /* load your editor to create/change the message. */ + + system("EDIT C:\\NET.MSG"); + if(access("C:\\NET.MSG",0)!=0) return; + + /* open the name list */ + + fp=fopen("C:\\NAMES.LST","rt"); + if(fp==NULL) return; + time(&secs_now); + Msg.timesread=0; + Msg.cost=0; + + + strcpy(Msg.from,"Mark Williamson"); + strcpy(Msg.subject,"Labtest Beta Message"); /* remember, the subject */ + /* for a file attach message */ + /* is the full path and file */ + /* name of the file(s) to send +*/ + /* be sure to set the correct +*/ + /* message attribute to send */ + /* or request files. */ + + + Msg.attribute=0x0183; + + /* change this to your fido address */ + Msg.orignode=750; + Msg.orignet=202; + Msg.origzone=1; + Msg.origpoint=0; + Msg.replyto=0; + Msg.nextreply=0; + time_now=localtime(&secs_now); + strftime(Msg.datetime,20,"%a %d %b %y %X",time_now); + while(!feof(fp)) + { + Msg.destnode=Msg.destpoint=Msg.destnet=0; + Msg.destzone=1; + + if(fgets(buffer,88,fp)==NULL) break; + buffer[strlen(buffer)-1]=0; + strcpy(Msg.to,buffer); + if(fgets(buffer,88,fp)==NULL) break; + buffer[strlen(buffer)-1]=0; + zone[0]=point[0]=node[0]=net[0]=0; + sscanf(buffer,"%s %s %s %s",zone,net,node,point); + Msg.destnode=atoi(node); + Msg.destpoint=atoi(point); + Msg.destzone=atoi(zone); + Msg.destnet=atoi(net); + + ultoa(bp(Msg.to,199309),registerkey,10); + fp2=fopen("C:\\NET.MSG","rb"); + msgtext=(char *)malloc(filelength(fp)+1000); + memset(msgtext,0,filelength(fp)+1000); + fread(msgtext,filelength(fp),1,fp2); + fclose(fp2); + sscanf(Msg.to,"%s",firstname); + + + /* here are some macros to make auto replacement easier. */ + /* this is great for form letters, kinda personnalizes the */ + /* message.*/ + + strrep(msgtext,"@FIRST@",firstname); + printf("\nWriting message to: %s, %s:%s/%s%s%s", + Msg.to, + zone,net, + node,Msg. + destpoint!=0?".":"", + Msg.destpoint!=0?point:""); + writefido(); + free(msgtext); + } + fclose(fp); +} + +void writefido(void) +{ + int count=250; /* this controls the starting point. */ + /* this function will count down until */ + /* finds a *.MSG. It will then increment */ + /* by one and write the message. There */ + /* is probably a better way, but you know. */ + /* set this number higher if you have lots */ + /* of netmail messages. */ + + char firstname[20]; + FILE *fp; + tzset(); + + /* Fido *.msgs use a MSGID line which is preceded by */ + /* a CONTROL-A. Then your fido address, a carriage */ + /* return, CONTROL-A and the name of the program that */ + /* created the message and version number, then another */ + /* carriage return. */ + strcpy(msghdr,"\x01MSGID: 1:202/750\r\x01PID: MM 1.0\r"); + + /* this begins our loop to find the last written */ + /* netmail message in your netmail directory */ + sprintf(msgfile,"C:\\RA\\MAIL\\%d.MSG",count); + while(access(msgfile,0)) + sprintf(msgfile,"C:\\RA\\MAIL\\%d.MSG",--count); + + /* got this far, we have a number! */ + /* increment it by one to get the next available slot */ + sprintf(msgfile,"C:\\RA\\MAIL\\%d.MSG",++count); + fp=fopen(msgfile,"wb"); + if(fp==NULL) puts("\nError opening file..."); + else + { + fwrite(&Msg,sizeof(Msg),1,fp); + fwrite(&msghdr,strlen(msghdr),1,fp); + fwrite(msgtext,strlen(msgtext),1,fp); + fwrite("\0x00",1,1,fp); + fclose(fp); + } +} + +That's it! This is a simple program I wrote to send form letters to numerous +people who needed to have the same information. This could be done in +Frontdoor with the ALT-L forward command, but then it was much more fun +creating something and knowing watching it work! + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ Code Snippets! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßß + +Sample code to validate credit card numbers +Posted in the OPENDOORS echo by Robert La Ferte, +Original by Andrue Carr + +/* +** Testcard.c 1.0 Copyright (C) 1993 by DruId Software. +*/ + +#include +#include +#include +#include + +int formula(char card[23],int len); + +// actual formula for creditcard! +// this can be used to build the last CRC digit by changing the len by 1 +// it is mainly used to make sure the card is a correct card by verifying +// the last CRC digit against the rest of the card. +// the formula will run all the numbers in the card but the last one +// which is the CRC digit. if the number the formula kicks out is the +// same as the last digit of the card then it is a valid credit card +// if not then its not correct. this is what a ZON machine uses to +// determine if it is a good number or not. If you need more help +// let me know and i can explain this better: +// Andrue Carr: fido: 1:331/201, SL_net: 250:502/1294, ISG 91:5/201 +// Acmenet: 400:508/201 +// box 473, West Tisbury, mass 02575 (Over Board BBS (508)693-5344) + +int formula(char card[23], int len) +{ + int x, + xcard = 0, + y; + + for(x = 0; x <= len; x++) + { + if(len % 2) + { + if(x % 2) + y = (card[x] - 48) * 2; + else + y = (card[x] - 48); + } + else + { + if(x % 2) + y = (card[x] - 48); + else + y = (card[x] - 48) * 2; + } + if(y >= 10) + y = (y - 10) + 1; + + xcard += y; + } + + x = (10 - (xcard % 10)); + + if(x == 10) + x = 0; + + return(x); // send back the computed check digit! +} + +void main(int argc, char *argv[]) +{ + int i = 0, + size = 0; + + if(argc < 2) + { + // testcard.exe [cardnumber] if no card# then error + cputs("\007No credit card entered"); + exit(1); + } + + size = strlen(argv[1]); + + i = formula(argv[1], (size - 2)); + + // check for all but crc digit + // if the number returned from formula() isnt the last digit + // of the actual card number then it isnt valid! + + if(i != (argv[1][size - 1] - 48)) + cputs("\007 -> Invalid Card!"); + else + cputs(" -> Valid Card"); + + exit(0); +} + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Release Notice: BCHECKERS 1.2! ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +BCHECKERS -- Version 1.2 -- is released! +======================================== + +** NOW SUPPORTS RA 2.00+! ** + +As a sysop of a FidoNet BBS, I was disappointed in the lack of a good, +non-interactive checkers door. Sure, there were some that allowed inter- +node play and the like, but these were expensive and few offered any +decent ANSI graphics and the simple ability to have callers make moves +on alternate logons. I also wanted to try my hand at programming in C, +having learned a number of other programming languages. BCheckers is the +result of this effort; and at only $10 is a bargain in shareware. + +BCheckers offers the following sysop features (and more I've probably +overlooked in these docs): + +- As you would expect, BCheckers monitors carrier detect functions, to + automatically recover when a user drops carrier. + +- Includes a fully-adjustable inactivity timeout monitor. A warning is + sent 5 seconds before the caller is ejected. + +- Share-aware file i/o for use in multi-node BBS systems. You must have + DOS's SHARE.EXE loaded for multi-node use. + +- Supports most popular BBS door information files, such as DORINFO1.DEF, + EXITINFO.BBS, CHAIN.TXT, DOOR.SYS, etc. + +- Displays and updates a QuickBBS-style status line, with information + available to the sysop such as user name, location, baud rate, time left, + function keys, ANSI and AVATAR settings, and so on. + +- Keeps track of a user "wants-chat" indicator, just like the one in + RemoteAccess, QuickBBS and other BBS systems. Allows for sysop page from + the door, and integrated chat mode. + +- Provides the sysop with all the standard function keys for adjusting user + time, hanging up on or even locking out the user -- and sysop shell to DOS. + +- Full support for locked baud-rates of up to 38,400 baud, using the FOSSIL + driver for maximum compatibility with any system. If a FOSSIL is not + available, BCheckers will use its own communications routines. Auto-detect + of local operation. + +- BCheckers is also DesqView and Windows aware. + +New features: + +- Minor bug fix to the Hall of Fame generation and key recognition code. + +- Minor cosmetic improvements. + +- Altered prompts slightly to alleviate problems with some modems when + using XON/XOFF handshaking. + +BCHECKERS is coming soon to a DOORNET or DDSDOORS distribution site in your +area, or you can freq the latest version directly from the author at FidoNet +node 1:231/710 using the "magic name" of BCHECK. Alternatively, the door can +be downloaded from the H.O.M.E. BBS at (317)539-6579. The next release will +have a "play against the computer" mode! Upgrades will be free, but a new +registration will increase by $5. Register now, while it's still cheap! + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Release Notice: BFE v4.00.2r ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +BFE v4.00.2r, the flexible telecommunications front end system from +Southeastern DataLINK, is now available! + +BFE is a BBS front-end system that was designed to provide sysops with a +fast, efficient method of "connecting" things at the front end of their +site. + +BFE features include: + + * Custom multi-level menus, with RIP graphics support + * Item and/or menu level password protection with daily scheduling + * Hotkey items or SlashCommand(tm) mode + * Attractive internal menuing scheme to ease your work load + * Support for custom user menus (for aspiring sysops and artists) + * Support for popup lightbar menus + * Design and employ interactive full-screen data entry forms + * Full Multinode/Multiuser Compatibility + * Internal DOS-to-UNIX gateway! Give your users the power of UNIX. + * The gateway services can also be used to gate calls to a packet radio + * Client/server approach to the UNIX gateway. Provide interactive access + * Provide *REAL* UUCP sessions from your UNIX server to your DOS callers + * Intuitive menu-driven setup and customization facility (BFE/Setup) + * Feature packed "C" like Script system + * Run automated scripts, even offline in a maintenance role. + * WFC (Wait-For-Caller) module to handle non-mailer sites (reg. only) + * DESQview *and* MS-Windows aware + * Configurable for security concerns + * Complete carrier monitoring and timeout checking + * Use any of 11 standard dropfiles, or define custom ones + * Run as a normal door or as a frontend (Dropfile not required!) + * Complete support for ANSI/ASCII/AVATAR/RIP users + * Configurable automatic ANSI and RIP detection schemes + * File transfer system with support for external protocols + * Run remote jobs, such as batch files, programs, other doors, etc. + * Internal remote shells to the operating system + * Built in chat/paging system with hourly/daily time restrictions + * Split screen chat mode, along with line chat mode for TTY users + * *Total* configurability + +What's changed since the last release? + + o New mailing address and contact information for Southeastern + DataLINK: + Address: 13500 Feather Sound Circle West + Suite 1313 + Clearwater, FL 34622 + Data: (813) 572-6817 + Voice: (813) 573-5078 + Internet: scottb@sedl.com - Scott Burkett + sales@sedl.com - Sales Q/A + support@sedl.com - Technical support + Fidonet: 1:3603/500 + + o BFE now supports "Before" and "After" scripts for each menu option + in your control files. The BEFORE scripts are called + immedicately after the user presses the key corresponding to + the menu option, but before the menu option's actions are + carried out. The AFTER scripts are executed upon completion + of the menu item selected, and before returning to the BFE + menu system. These scripts should be located in the SCRIPTS + directory (configured in BFE/Setup), and should be named as + per the following naming convention: + + BEFORE scripts: .B + AFTER scripts: .A + + For example, if in your MAIN control file, you have a menu + option which uses the "1" key as the hotkey, the BEFORE and + AFTER scripts would be named "MAIN.B1" and "MAIN.A1". + + o NEW SCRIPT COMMANDS: + + CompareStr() - Compares a string with the contents of the + internal script buffer. + + o NEW SAMPLE SCRIPTS: + + GETPASS.SCR - Demonstrates the use of the CompareStr() + function call. + + o BFE's menu handler now sports a rudimentary line noise "filter". + + o All of the text used during user system logins is now + configurable in the language file. + + * BFE's internal comm routines now supports all IRQ lines from + 1 to 15. In addition, full support for 16550A FIFO buffers is + in place as well. + + * The RA "personality" now accurately mimics the latest version + of the RA status line. + + * Quite a bit of code cleanup in this release. + + * Several additional checks are now in place for the BFE setup + sanity check, which verifies the BFE path setup. + + * When opening a .CTL file under BFE/Setup, it now defaults to open + an "existing" .CTL file, instead of creating a new one. (Thanks + to George Bynum for this suggestion). + + * Quite a few changes and additions in the BFE user manual (including + WFC, BFE/Gateway, and BFE/Setup). + + * The "p" identifier has been removed from the end of the normal + archive naming convention, as it was confusing OS/2 users. It + has been replaced by an "r", which means "public (r)elease". + + * The fossil buffers are now flushed before every gateway session + is initiated. This was inserted in order to make BFE's internal + serial gateway more "friendly" towards packet radio systems. + (Thanks to Mark Stanchin). + + * A popup "dialog" box will appear whenever BFE is dropping + carrier, informing you of such. + + * The WFC module for registered users will now place both the + COM port number *and* the fossil port number into the + DOBBSx.BAT files. + + ! The displayfile() script function should no longer give erroneous + password prompts if a password was used to get into the script + to begin with. (Thanks to Mark Stanchin). + + o A new dot command has been added to BFE/Formgen. The ".type" + keyword will direct Formgen to output information in either + "delimited" format (default), or "linear". Thanks to Dana + Meli-Wischman. + + ! In certain situations, BFE would force the caller to hit a key + twice before the keystroke was registered. Squashed. + + ! BFE/Gateway sessions should now properly monitor the caller's + carrier signal. + + ! ANSI detection would fail under certain situations. Squashed. + + o The BFE registration system has been revamped completely. If you + are a previously registered user of BFE, please contact us for your + new key file. + + o Marketing strategy has been updated, and now includes three very + distinct levels of BFE registration. + + o New Module: BFE/Node Monitor for DESQview systems. BFEMON is a + compact monitoring system designed for sites running BFE in a + multinode environment. This module is made available free of charge + to registered users of BFE. (+) + + o New Module: BFE/WFC - The Wait For Caller module is designed to + provide a flexible method of handling inbound calls on non-mailer + nodes. It's features include: + + - DESQview/Win31/OS2 Aware + - Intuitive menu-driven setup and windowed environment + - Internal screen blanker + - Full support for 50 line VGA mode + - Designed with multinode systems in mind + - Custom connect strings for FAX, UUCP, etc. + - FOSSIL driven, for maximum compatibility + - Full internal event system + + The WFC module is made available free of charge to registered users + of BFE. (+) + + o New subsystem: BFE/FormGen - a powerful full screen data entry form + designer is now included as part of the base BFE package. + + o BFE/Setup now includes an internal user file editor. :-) + + o BFE now supports non-fossil sites by providing an internal serial + communications system. This adds three new command line switches: + + -i = No fossil! Use internal routines + -u = COMx Base Address (i.e. -u03F8) + -v = COMx IRQ Line (i.e. -v4) + + o The time adjustment sysop keys (formerly cursor up/down) have been + remapped to pageup and pagedown. + + o Multiline descriptions with embedded colors are now available. In + BFE/Setup, the description field is now two lines long. Also, BFE + now supports embedded color tokens in the description field, thus + allowing you to highlight certain portions of the description of + each menu item. ** NOTE: BFE will not automatically align the + two lines of text if the first one wraps around! This will be + taken care of in a future release, but for now, you will have to + space them out accordingly. + + o When using BFE's internal files system for providing downloads, + the file "FILES.BBS" is no longer assumed. :-) Now, you must + provide the full path *AND* filename of the file to be used as the + list file. This allows you to keep your list files in one shared + directory. In addition, the full path is no longer needed in the + list files. If the path is not given, BFE will look for each file + in the directory the list file resides in. + + o New Language File Keywords (Thanks to Michael Stumpp) + + PASSWORD - "Enter password" prompt - Default is "Password:" + Y_CONTINUE - Key used to continue in "more" prompting + N_CONTINUE - Key used to stop in "more" prompting + S_CONTINUE - Key used to go nonstop in "more" prompting + + o BFE's internal user system now has an additional mode of operation. + This "Exclusive" mode is identical to the full user system, but + will not allow new users at all. This may come in handy if you + wish to allow only "registered" users on certain nodes, or if you + run a "member's only" BBS. (Thanks to Dana Meli-Wischman). + + o NEW SCRIPT COMMANDS: + + FormGen() - Processes a BFE/FormGen Entry Form + + SaveScreen() - Saves contents of current screen + + RestoreScreen() - Restores contents of saved screens + + PopupMenu() - Creates a configurable popup menu + + RemoveFile() - Removes the passed filename (deletes it) + + MakeCustomSem() - Creates a CUSTOM.nnn semaphore in the + IPC directory. + + RemCustomSem() - Removes CUSTOM.nnn semaphore from IPC dir. + + NoConsoleLogging() - Temporarily disables console logging + while in a BFE gateway session. (+) + + ConsoleLogging() - Re-enables console logging in BFE gateway + sessions. (+) + + DisableServerStr() - Temporarily disables BFE's remote server + strings. (+) + + EnableServerStr() - Re-enables remote server strings. (+) + + SetAccess() - Adjusts the caller's security level + + UpdateUserRecord() - Update's user's record in user file + + o RIP support updated - when BFE is displaying a RIP file to user, + the appropriate ANSI or ASCII version will be displayed locally + on the sysop's console. Note that this doesn't include the + default BFE internal menus, although it will in the future. + + o A new utility called COLORUPD.EXE has been provided. This program + will read the default color configuration stored in the GLOBALS.CFG + file, and will update the color maps of all .CTL files in the + current directory. This program is distributed in the \UTILS + subdirectory in the distribution archive. The source (COLORUDP.C) + is located in the \DEVKIT subdirectory. Thanks to Keith Ross for + this suggestion. + + o If using the BFE User System, BFE will now export the user's name + and password to two environment variables in the DOS master + environment upon exiting on an errorlevel (USERNAME and PASSWORD + are the new environment variables) This should make automatic + logins through BFE a bit easier, as you can now pass the name and + password on the command line to your BBS packages. + + o Now, a special "log text" field is attached to each menu item. + This field serves two purposes: + + - It is used in the log file for the task to describe each + event. + + - It is used in the menu item selector screen in BFE/Setup, + in place of the description field. + + If no log text is supplied, the normal description will be used. + + o The macro system has been completely revamped, and the following + new macros are available: + + %U = User's name + %W = User's password + %H = User's handle + + o BFE will now periodically perform an Integrity check, to ensure + that pertinent system files have not been altered by viruses or + intruders. + + o Some sample .CTL files are now included under (\SAMPLES\CTL). + These will be updated further as more features are added to the + product. + + o New networking semaphore files implemented (nnn = node number): + + SHELL.nnn - User/sysop in DOS shell + XFER.nnn - User transferring a file + CHAT.nnn - User either paging or in a chat session + FORMGEN.nnn - User in a BFE/FormGen Entry Form + CUSTOM.nnn - Custom user-defined semaphores + + o New fields in BFE/Setup: + + Default .CTL file Path (for BFE control files) + Default .FRM file Path (for BFE/Formgen files) + Default .SCR file Path (for BFE/Script files) + Default .ANS file Path (for ANS/ASC/AVT/RIP files) + + o New script hook: This script will be executed automatically + if it exists when a new user has logged into the system. + + * The graphics detection routines have been replaced, and should + perform much smoother now. + + * Three new fields have been added to the user file. They are + handle, home phone, and work phone. + + * The documentation has been completely reorganized. + + * BFE will no longer automatically put a divider line in between + normal and global commands when using the internal menus. If you + want a divider line, you can just add it to the top of your + global menu. :-) + + * When displaying standard ASCII files, BFE will now default to light + gray on black. In previous releases, the color of the text would + appear in the color of the user input. + + * When running external processes (other doors, in particular), BFE + will now de-initialize the fossil driver, and re-initialize it upon + re-entry. This was due to the fact that some doors left the fossil + driver in quite a shabby state after exiting, so bad, in fact, that + BFE would function normally, but not be seen on the remote end! + + * Gateway sessions will now flow much smoother. So smooth, in fact, + that we actually ran a SCO/UNIX UUCP session through it. :-) (+) + + * BFE now tries to avoid the use of high bit ascii characters when + running with ASCII callers. If any of you have seen ANSI emulation + under UNIX terminal packages, you know why... :-) + + * Password protection now covers an entire file list when downloading + from protected areas. In previous releases, the user had to enter + the password for each file. Sounds stupid, doesn't it? It was. + + * Rewrote the import message file routines when using external + editors. You should no longer lose characters under certain + word wrapping conditions. + +FREQ: BFE from: Southeastern DataLINK Zoom 28.8 1:3603/500 (813) 572-6817 + 345K in size + + FTP: ftp.csn.org:~/crlhq/bfe4002r.zip + +Previously registered users of BFE should contact us through the normal +support channels (email, netmail, dialup) to request your new serialization +keys. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Release Notice: GIF View Preview Door v1.0 ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +Greetings All, from Lone Wolf Software! + +**************************************************************** +* GIF View Preview Door * +* FileName: VUGIF10.ZIP FileSize: 590k * +**************************************************************** + +FEATURES............ + +o Tag up to 50 GIFs for download. +o Users can convert GIF files to JPG files for fast file transfers. +o Internal file base engine for super quick file handling. +o RIPterm users can view the JPG files while ON LINE! +o Converts large GIF files to small (often less than 10k) JPG files + that transfer fast. RIPterm users can tag, convert and view GIFs + while on line in under 30 seconds at 14,400 baud. +o Non RIPterm users (ANSI callers) can use many popular graphic + file viewers like CShow or The Graphics Work Shop to view JPG + preview files to see if they want to download the actual GIF. +o State of the art sysop management tools, file base editor, and + built in GIF graphic file viewer. +o Others may say "On Line GIF Viewing", but they require you to log + off to view the graphic file, that's not on line viewing. This + door actually lets RIPterm users view the JPG / GIF while still + on line. +o Extensive use of RIP through out, both to the user and the sysop. +o Option to disable RIP on either local or remote end. + +FREQ the file VUGIF10.ZIP from 1:3813/309 or call the board at +1-918-687-1612 at speeds up to 19,200. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Release Notice: Operation: Office v0.5 ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + + Operation: Office v0.5 + ---------------------- + An OmniWare Product + ------------------- + by Mike Aleksiuk + +Get your latest copy from... + +Name: C.R.I.S.I.S. HQ +Number: 686-0449 +Node Number: 1:134/31 +Magic Name: OPOFF +File Name: OPOFFV05.ZIP +Place: Calgary, AB, Canada + + In this exciting new game, we have you set in the unexciting +role of an "office worker". But last night you overheard your boss +talking to someone... and for no apparent reason, you decide to kill +him! The challenge is about to begin... + + Supports all major dropfiles (DOOR.SYS, DORINFO?.DEF, etc). +Configure specific game settings. Usable player editor for registered +users. Unregistered users may only delete/look at the player information. + + Features + -------- + + - chat with other players in a "one-liner" fashion + - use the phone + - listen to the radio + - many different enemies to fight, many different things to buy + - work to make money + + Beta Gamma Wanna-Be + ------------------- + + Version 0.5 is the "Beta Gamma Wanna-Be" version of Operation: +Office. In other words, it is a gamma/wide beta, for all to test. It +is fully functioning, but still needs to be refined. + + A Few Future Features + --------------------- + + - personal player phone numbers! + - much more detailed fight method! + - more enemies! + + Please send all comments/bug reports via FidoNet netmail to +1:134/21.10, or conventional mail at the address stated within the +SysOp documentation. Unfortunately, I don't have the time/money to +return all of your messages... Sorry! + +Mike Aleksiuk, Author of "O:O" + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +ܳ OpenDoors Tech Journal Information ³ +ÛÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß + +Editors: Scott Burkett + Southeastern DataLINK BBS + 1:3603/500@fidonet.org + scottb@sedl.com (Internet EMail) + root@sedl.com (Internet EMail) + (813) 572-6817 28.8 Zoom! + 13500 Feather Sound Circle West + Suite #1313 + Clearwater, FL 34622 + + Brian Pirie + BP ECOMM Systems + 1:243/8@fidonet.org + brian@bpecomm.ocunix.on.ca (Internet EMail) + 75122,2303 (Compuserve) + (613) 526-4466 14.4 + 1416 - 2201 Riverside Drive + Ottawa, Ontario + Canada + K1H 8K9 + +Published by and for programmers and users of the OpenDoors Door +Programming Toolkit. It is a compilation of tips, reviews, and tidbits +pertaining to BBS programming and general usage. The opinions expressed +in this publication do not necessarily represent those of its editors, +the OpenDoors author, or other contributors. + +OBTAINING COPIES: The latest copy of the OpenDoors Tech Journal will always +be available under the magic name of ODTJ. + +SUBMISSIONS: You are encouraged to submit articles for publication in the +journal. Please send all items to one of the afore-mentioned systems via BBS +upload or mailer file/attach. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ->< End of The OpenDoors Tech Journal - Volume 94 Issue Number 2 ><- +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + diff --git a/utils/magiedit/odoors/historic/ROLLCALL.TXT b/utils/magiedit/odoors/historic/ROLLCALL.TXT new file mode 100644 index 0000000..b60fdac --- /dev/null +++ b/utils/magiedit/odoors/historic/ROLLCALL.TXT @@ -0,0 +1,173 @@ +---------------------------------------------------------------------------- + The OpenDoors Rollcall! +---------------------------------------------------------------------------- + +The OpenDoors Roll Call is a compilation of BBS utilities and doors that were +authored using Brian Pirie's OpenDoors package. If you would like to see +your products listed in this section, send the following information to either +Brian Pirie or myself (via netmail, echomail, or snailmail): + + Product Name + Author Name + Description + Price + FREQ Address/BBS Number + FREQ Name + Latest Version + +---------------------------------------------------------------------------- + +Auto-Message +------------ +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Message to next caller door. +Price: + +BFE (BBS Front End System) +-------------------------- +Author(s): Scott Burkett - Cairo Research Labs +version: 1.30.2à +Requestable from: 1:3613/12 +Freq name: BFE +Description: Complete BBS carousel, front end menu builder, remote jobs, etc +Price: $10 + +BID (BBS Information Door) +-------------------------- +Author(s): Brian Pirie - Pirie Enterprises +version: 2.00 +Requestable from: 1:243/8 +Freq name: BID +Description: A door to introduce new BBS users to the world of BBSing +Price: Freeware + +CALL-BACK +--------- +Author(s): Don Laverdure +version: 4.02 +Requestable from: 1:249/124 +Freq name: CB-402.ARJ +Description: Callback verifier door for RA/SBBS/QBBS systems +Price: unknown/Shareware + +EZVote +------ +Author(s): Brian Pirie - Pirie Enterprises +version: 4.10 +Requestable from: 1:243/8 +Freq name: EZVOTE +Description: A user voting door for use with most BBS systems +Price: Freeware + +Flame-Thrower +------------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Users leave next caller a flaming one-liner. +Price: + +Node-Door +--------- +Author(s): Don Laverdure +Version: 2.11 +Requestable from: 1:249/124 +Freq name: ND-211.ARJ +Description: Nodelist browser door for raw nodelists. +Price: unknown/Shareware + + +RegPRO +------ +Author(s): Scott Burkett - Cairo Research Labs +Version: 2.60 +Requestable from: 3613/12 +Freq name: REGPRO +Description: Online BBS Fullscreen Entry Form/User Questionnaire System +Price: $10/Shareware + +ROBO TAPE +--------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: 2.00 +Requestable from: 1:3813/309, 62:9600/0, 75:400/0 Anytime But ZMH. +Freq name: ROBOT200.ARJ +Description: BBS Tape Access Door +Price: $10/Shareware + +TBM (Turbo Bulletin Manager) +---------------------------- +Author(s): Scott Burkett - Cairo Research Labs +Version: 2.50 +Requestable from: 3613/12 +Freq name: TBM +Description: BBS Bulletin Manager/Tons of features/Most BBS Systems +Price: $10/Shareware + +Tic-Tac-Toe +----------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Plays just like the real thing. +Price: + +Triple Dare +----------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Try and outdraw the dealer! Great graphics. +Price: + +Turbo Poll +---------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Very graphical voting booth door +Price: + +Turbo Quotes +------------ +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Randomly displays quotes to users +Price: + +Users-Info +---------- +Author(s): Vince Jacobs - Lone Wolf Software +Version: +Requestable from: +Freq name: +Description: Displays Exteneded Info about users and prints it out. +Price: + +VID (Virus Information Door) +---------------------------- +Author(s): Scott Burkett - Cairo Research Labs +Version: 2.00 +Requestable from: 3613/12 +Freq name: VID and VIDPLUS (Enhancement Module) +Description: Online Virus Reference Database for most BBS types +Price: $10/Shareware + +VKill +----- +Author(s): Scott Burkett - Cairo Research Labs +Version: 3.00a +Requestable from: 1:3613/12 +Freq name: VKILL +Description: Upload Integrity Door for Maximus CBCS +Price: $10/Shareware + diff --git a/utils/magiedit/odoors/historic/odtips3/BPFIND.H b/utils/magiedit/odoors/historic/odtips3/BPFIND.H new file mode 100644 index 0000000..5dac67b --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/BPFIND.H @@ -0,0 +1,25 @@ +/* MSC / BC compatible findfirst()/findnext() definitions. */ + +#ifdef __TURBOC__ +#include +#include +#else +#include +struct ffblk +{ + char ff_reserved[21]; + char ff_attrib; + unsigned ff_ftime; + unsigned ff_fdate; + long ff_fsize; + char ff_name[13]; +} +#define findfirst(p, f, a) _dos_findfirst(p, (struct _find_t *)f, a) +#define findnext(f) _dos_findnext((struct _find_t *)f) +#define FA_RDONLY _A_RDONLY +#define FA_HIDDEN _A_HIDDEN +#define FA_SYSTEM _A_SYSTEM +#define FA_LABEL _A_VOLID +#define FA_DIREC _A_SUBDIR +#define FA_ARCH _A_ARCH +#endif diff --git a/utils/magiedit/odoors/historic/odtips3/CMDLINE.C b/utils/magiedit/odoors/historic/odtips3/CMDLINE.C new file mode 100644 index 0000000..f38ad5b --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/CMDLINE.C @@ -0,0 +1,342 @@ +#include +#include +#include + +#include "opendoor.h" +#include "cmdline.h" + + +#ifndef BOOL +typedef int BOOL; +#endif + +typedef enum +{ + kParamLocal, + kParamBPS, + kParamPort, + kParamNode, + kParamHelp, + kParamPersonality, + kParamMaxTime, + kParamAddress, + kParamIRQ, + kParamNoFOSSIL, + kParamNoFIFO, + kParamDropFile, + kParamUserName, + kParamTimeLeft, + kParamSecurity, + kParamLocation, + kParamUnknown +} tCommandLineParameter; + + +static void AdvanceToNextArg(int *pnCurrentArg, int nArgCount, + char *pszOption); +static void GetNextArgName(int *pnCurrentArg, int nArgCount, + char *papszArguments[], char *pszString, + int nStringSize); +static tCommandLineParameter GetCommandLineParameter(char *pszArgument); + + +void ParseStandardCommandLine(int nArgCount, char *papszArguments[]) +{ + char *pszCurrentArg; + int nCurrentArg; + + for(nCurrentArg = 1; nCurrentArg < nArgCount; ++nCurrentArg) + { + pszCurrentArg = papszArguments[nCurrentArg]; + + switch(GetCommandLineParameter(pszCurrentArg)) + { + case kParamLocal: + od_control.od_force_local = TRUE; + break; + + case kParamBPS: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.baud = atol(papszArguments[nCurrentArg]); + break; + + case kParamPort: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.port = atoi(papszArguments[nCurrentArg]); + break; + + case kParamHelp: + printf("AVALIABLE COMMAND LINE PARAMETERS:\n"); + printf(" -L or -LOCAL - Causes door to operate in local mode, without requiring a\n"); + printf(" door information (drop) file.\n"); + printf(" -DROPFILE x - Door information file directory or directory+filename.\n"); + printf(" -N x or -NODE x - Sets the node number to use.\n"); + printf(" -B x or -BPS x - Sets the serial port <---> modem bps (baud) rate to use.\n"); + printf(" -P x or -PORT x - Sets the serial port to use, were 0=COM1, 1=COM2, etc.\n"); + printf(" -ADDRESS x - Sets serial port address in decimal NOT hexidecimal\n"); + printf(" (only has effect if FOSSIL driver is not being used).\n"); + printf(" -IRQ x - Sets the serial port IRQ line (only has effect if FOSSIL\n"); + printf(" driver is not being used).\n"); + printf(" -NOFOSSIL - Disables use of FOSSIL driver, even if available.\n"); + printf(" -NOFIFO - Disables use of 16550 FIFO buffers (only if FOSSIL driver\n"); + printf(" is not being used).\n"); + printf(" -PERSONALITY x - Sets the sysop status line / function key personality to\n"); + printf(" use - one of Standard, PCBoard, RemoteAccess or Wildcat.\n"); + printf(" -MAXTIME x - Sets the maximum number of minutes that any user will be\n"); + printf(" permitted to access the door.\n"); + printf(" -USERNAME x - Name of user who is currently online.\n"); + printf(" -TIMELEFT x - User's time remaining online.\n"); + printf(" -SECURITY x - User's security level.\n"); + printf(" -LOCATION x - Location from which user is calling.\n"); + printf(" -?, -H or -HELP - Displays command-line help and exits.\n"); + exit(1); + break; + + case kParamNode: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_node = atoi(papszArguments[nCurrentArg]); + break; + + case kParamPersonality: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + if(stricmp(papszArguments[nCurrentArg], "Standard") == 0) + { + od_control.od_default_personality = PER_OPENDOORS; + } + else if(stricmp(papszArguments[nCurrentArg], "PCBoard") == 0) + { + od_control.od_default_personality = PER_PCBOARD; + } + else if(stricmp(papszArguments[nCurrentArg], "RemoteAccess") == 0) + { + od_control.od_default_personality = PER_RA; + } + else if(stricmp(papszArguments[nCurrentArg], "Wildcat") == 0) + { + od_control.od_default_personality = PER_WILDCAT; + } + else + { + printf("Unknown personality: %s\n", papszArguments[nCurrentArg]); + exit(1); + } + break; + + case kParamMaxTime: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_maxtime = atoi(papszArguments[nCurrentArg]); + break; + + case kParamAddress: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_address = atoi(papszArguments[nCurrentArg]); + break; + + case kParamIRQ: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.od_com_irq = atoi(papszArguments[nCurrentArg]); + break; + + case kParamNoFOSSIL: + od_control.od_no_fossil = TRUE; + break; + + case kParamNoFIFO: + od_control.od_com_no_fifo = TRUE; + break; + + case kParamDropFile: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + strncpy(od_control.info_path, papszArguments[nCurrentArg], + sizeof(od_control.info_path) - 1); + od_control.info_path[sizeof(od_control.info_path) - 1] = '\0'; + break; + + case kParamUserName: + GetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_name, sizeof(od_control.user_name)); + break; + + case kParamTimeLeft: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_timelimit = atoi(papszArguments[nCurrentArg]); + break; + + case kParamSecurity: + AdvanceToNextArg(&nCurrentArg, nArgCount, pszCurrentArg); + od_control.user_security = atoi(papszArguments[nCurrentArg]); + break; + + case kParamLocation: + GetNextArgName(&nCurrentArg, nArgCount, papszArguments, + od_control.user_location, sizeof(od_control.user_location)); + break; + + default: + printf("Unrecognized command line option: %s\n", pszCurrentArg); + exit(1); + break; + } + } +} + + +static void AdvanceToNextArg(int *pnCurrentArg, int nArgCount, char *pszOption) +{ + if(++*pnCurrentArg >= nArgCount) + { + printf("Missing parameter for option: %s\n", pszOption); + exit(1); + } +} + + +static void GetNextArgName(int *pnCurrentArg, int nArgCount, + char *papszArguments[], char *pszString, + int nStringSize) +{ + BOOL bFirst = TRUE; + + if((*pnCurrentArg) + 1 >= nArgCount) + { + printf("Missing parameter for option: %s\n", + papszArguments[(*pnCurrentArg) - 1]); + exit(1); + } + + pszString[0] = '\0'; + + while(++*pnCurrentArg < nArgCount) + { + if(GetCommandLineParameter(papszArguments[*pnCurrentArg]) + != kParamUnknown) + { + --*pnCurrentArg; + break; + } + + if(strlen(pszString) >= nStringSize - 1) + { + break; + } + + if(!bFirst) + { + strcat(pszString, " "); + } + + strncat(pszString, papszArguments[*pnCurrentArg], + strlen(pszString) - nStringSize - 1); + pszString[nStringSize - 1] = '\0'; + + bFirst = FALSE; + } + +} + + +static tCommandLineParameter GetCommandLineParameter(char *pszArgument) +{ + if(*pszArgument == '-' || *pszArgument == '/') + { + ++pszArgument; + } + + if(stricmp(pszArgument, "L") == 0 + || stricmp(pszArgument, "LOCAL") == 0) + { + return(kParamLocal); + } + else if(stricmp(pszArgument, "B") == 0 + || stricmp(pszArgument, "BPS") == 0 + || stricmp(pszArgument, "BAUD") == 0) + { + return(kParamBPS); + } + else if(stricmp(pszArgument, "P") == 0 + || stricmp(pszArgument, "PORT") == 0) + { + return(kParamPort); + } + else if(stricmp(pszArgument, "N") == 0 + || stricmp(pszArgument, "NODE") == 0) + { + return(kParamNode); + } + else if(stricmp(pszArgument, "?") == 0 + || stricmp(pszArgument, "H") == 0 + || stricmp(pszArgument, "HELP") == 0) + { + return(kParamHelp); + } + else if(stricmp(pszArgument, "PERSONALITY") == 0) + { + return(kParamPersonality); + } + else if(stricmp(pszArgument, "MAXTIME") == 0) + { + return(kParamMaxTime); + } + else if(stricmp(pszArgument, "ADDRESS") == 0) + { + return(kParamAddress); + } + else if(stricmp(pszArgument, "IRQ") == 0) + { + return(kParamIRQ); + } + else if(stricmp(pszArgument, "NOFOSSIL") == 0) + { + return(kParamNoFOSSIL); + } + else if(stricmp(pszArgument, "NOFIFO") == 0) + { + return(kParamNoFIFO); + } + else if(stricmp(pszArgument, "DROPFILE") == 0) + { + return(kParamDropFile); + } + else if(stricmp(pszArgument, "USERNAME") == 0) + { + return(kParamUserName); + } + else if(stricmp(pszArgument, "TIMELEFT") == 0) + { + return(kParamTimeLeft); + } + else if(stricmp(pszArgument, "SECURITY") == 0) + { + return(kParamSecurity); + } + else if(stricmp(pszArgument, "LOCATION") == 0) + { + return(kParamLocation); + } + else + { + return(kParamUnknown); + } +} + + +void NoDoorFileHandler(void) +{ + /* Alter OpenDoors behaviour, so that we proceed with defaults if */ + /* no door information file is available, rather than exiting with */ + /* an error. Set od_no_file_func to point to this function. */ + if(strlen(od_control.user_name) == 0) + { + strcpy(od_control.user_name, "Unknown User"); + } + if(strlen(od_control.user_location) == 0) + { + strcpy(od_control.user_location, "Unknown Location"); + } + if(od_control.user_timelimit == 0) + { + od_control.user_timelimit = 30; + } + + od_control.od_info_type = CUSTOM; +} diff --git a/utils/magiedit/odoors/historic/odtips3/CMDLINE.H b/utils/magiedit/odoors/historic/odtips3/CMDLINE.H new file mode 100644 index 0000000..f1a23b4 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/CMDLINE.H @@ -0,0 +1,5 @@ +#ifndef INC_CMDLINE +#define INC_CMDLINE +void ParseStandardCommandLine(int nArgCount, char *papszArguments[]); +void NoDoorFileHandler(void); +#endif diff --git a/utils/magiedit/odoors/historic/odtips3/FILEVIEW.C b/utils/magiedit/odoors/historic/odtips3/FILEVIEW.C new file mode 100644 index 0000000..cc7bb4a --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/FILEVIEW.C @@ -0,0 +1,352 @@ +/* fileview.c - File viewing door that demonstrates the use of the */ +/* PagedViewer() function. This door can be setup to */ +/* to display a single text file, or any file from an */ +/* entire directory of text files. The program accepts */ +/* a single command-line argument, which if present, */ +/* specifies the filename or wildcard of the files to */ +/* display. If this argument is not present, all files */ +/* in the current directory will be available for */ +/* viewing. If there is more than one possible file to */ +/* be displayed, this program will display a list of */ +/* files that the user can choose from to display. If */ +/* there is only one possible file, that file is */ +/* is displayed. This program uses PagedViewer() for two */ +/* seperate uses - the list of available files, and for */ +/* viewing the file itself. */ + +#include +#include +#include +#include "bpfind.h" +#include "opendoor.h" +#include "pageview.h" + + +/* Configurable constants. */ +#define FILENAME_SIZE 75 +#define PATH_CHARS (FILENAME_SIZE - 13) +#define LINE_SIZE 80 +#define ARRAY_GROW_SIZE 20 + + +/* Global variables. */ +int nTotalFiles = 0; +int nFileArraySize = 0; +char *paszFileArray = NULL; + +FILE *pfCurrentFile; +int nTotalLines = 0; +int nLineArraySize = 0; +long *palLineOffset = NULL; + + +/* Function prototypes. */ +void AddFilesMatching(char *pszFileSpec); +char *GetFilename(int nIndex); +int AddFilename(char *pszFilename); +void GetDirOnly(char *pszOutDirName, const char *pszInPathName); +int DirExists(const char *pszDirName); +void BuildPath(char *pszOut, char *pszPath, char *pszFilename); +void FreeFileList(void); +void DisplayFileName(int nLine, void *pCallbackData); +void DisplayFile(char *pszFilename); +void DisplayFileLine(int nLine, void *pCallbackData); +int AddOffsetToArray(long lOffset); +void FreeLineArray(void); + + +/* Program execution begins here. */ +int main(int nArgCount, char *papszArgument[]) +{ + int nArg; + int nChoice; + + od_init(); + + /* Get file specifiction from command-line, if any. */ + if(nArgCount >= 2) + { + for(nArg = 1; nArg < nArgCount; ++nArg) + { + AddFilesMatching(papszArgument[nArg]); + } + } + + /* If there are no command-line parameters, use *.* */ + else + { + AddFilesMatching("*.*"); + } + + /* If there are no matching files, display error. */ + if(nTotalFiles == 0) + { + od_printf("No files were found.\n\r\n\r"); + od_printf("Press [Enter] to continue.\n\r"); + od_get_answer("\n\r"); + return(0); + } + + /* If only one file was found, then display it. */ + else if(nTotalFiles == 1) + { + DisplayFile(GetFilename(0)); + } + + /* If more than one file was found, allow user to choose file */ + /* to display. */ + else + { + /* Loop until user chooses to quit. */ + nChoice = 0; + for(;;) + { + /* Get user's selection. */ + nChoice = PagedViewer(nChoice, nTotalFiles, DisplayFileName, + NULL, TRUE, "Choose A File To Display", 19); + + /* If user chose to quit, then exit door. */ + if(nChoice == NO_LINE) break; + + /* Otherwise, display the file that the user chose. */ + DisplayFile(GetFilename(nChoice)); + } + } + + FreeFileList(); + + return(0); +} + + +void AddFilesMatching(char *pszFileSpec) +{ + struct ffblk DirEntry; + int bNoMoreFiles; + char szDirName[PATH_CHARS + 1]; + char szFileName[FILENAME_SIZE]; + + /* Check that file specification is not too long. */ + if(strlen(pszFileSpec) > PATH_CHARS) + { + return; + } + + /* Get directory name from path. */ + GetDirOnly(szDirName, pszFileSpec); + + bNoMoreFiles = findfirst(pszFileSpec, &DirEntry, FA_RDONLY); + while(!bNoMoreFiles) + { + BuildPath(szFileName, szDirName, DirEntry.ff_name); + + AddFilename(szFileName); + + bNoMoreFiles = findnext(&DirEntry); + } +} + + +void GetDirOnly(char *pszOutDirName, const char *pszInPathName) +{ + char *pchBackslashChar; + + /* Default dir name is entire path. */ + strcpy(pszOutDirName, pszInPathName); + + /* If there is a backslash in the string. */ + pchBackslashChar = strrchr(pszOutDirName, '\\'); + if(pchBackslashChar != NULL) + { + /* Remove all character beginning at last backslash from path. */ + *pchBackslashChar = '\0'; + } + else + { + /* If there is no backslash in the filename, then the dir name */ + /* is empty. */ + pszOutDirName[0] = '\0'; + } +} + + +void BuildPath(char *pszOut, char *pszPath, char *pszFilename) +{ + /* Copy path to output filename. */ + strcpy(pszOut, pszPath); + + /* Ensure there is a trailing backslash. */ + if(strlen(pszOut) > 0 && pszOut[strlen(pszOut) - 1] != '\\') + { + strcat(pszOut, "\\"); + } + + /* Append base filename. */ + strcat(pszOut, pszFilename); +} + + +char *GetFilename(int nIndex) +{ + return(paszFileArray + (nIndex * FILENAME_SIZE)); +} + + +int AddFilename(char *pszFilename) +{ + int nNewArraySize; + char *paszNewArray; + char *pszNewString; + + /* If array is full, then try to grow it. */ + if(nTotalFiles == nFileArraySize) + { + nNewArraySize = nFileArraySize + ARRAY_GROW_SIZE; + if((paszNewArray = + realloc(paszFileArray, nNewArraySize * FILENAME_SIZE)) == NULL) + { + return(FALSE); + } + nFileArraySize = nNewArraySize; + paszFileArray = paszNewArray; + } + + /* Get address to place new string at, while incrementing total number */ + /* of filenames. */ + pszNewString = GetFilename(nTotalFiles++); + + /* Copy up to the maximum number of filename characters to the string. */ + strncpy(pszNewString, pszFilename, FILENAME_SIZE - 1); + pszNewString[FILENAME_SIZE - 1] = '\0'; + + return(TRUE); +} + + +void FreeFileList(void) +{ + if(nFileArraySize > 0) + { + free(paszFileArray); + nFileArraySize = 0; + nTotalFiles = 0; + paszFileArray = NULL; + } +} + + +void DisplayFileName(int nLine, void *pCallbackData) +{ + (void)pCallbackData; + + od_printf(GetFilename(nLine)); +} + + +void DisplayFile(char *pszFilename) +{ + char szLine[LINE_SIZE]; + long lnOffset; + + /* Clear the screen. */ + od_clr_scr(); + + /* Attempt to open the file. */ + pfCurrentFile = fopen(pszFilename, "r"); + if(pfCurrentFile == NULL) + { + od_printf("Unable to open file.\n\r\n\r"); + od_printf("Press [Enter] to continue.\n\r"); + od_get_answer("\n\r"); + return; + } + + /* Get file offsets of each line and total line count from file. */ + for(;;) + { + lnOffset = fTell(pfCurrentFile); + + if(fgets(szLine, LINE_SIZE, pfCurrentFile) == NULL) break; + + AddOffsetToArray(lnOffset); + } + + /* Use PagedViewer() to view the file. */ + PagedViewer(0, nTotalLines, DisplayFileLine, NULL, FALSE, NULL, 21); + + /* Deallocate array of line offsets. */ + FreeLineArray(); + + /* Close the file. */ + fclose(pfCurrentFile); +} + + +void DisplayFileLine(int nLine, void *pCallbackData) +{ + char szLine[LINE_SIZE]; + long lnTargetOffset = palLineOffset[nLine]; + int nLineLen; + + (void)pCallbackData; + + /* Move to proper offset in file. */ + if(lnTargetOffset != ftell(pfCurrentFile)) + { + fseek(pfCurrentFile, lnTargetOffset, SEEK_SET); + } + + /* Get line from line. */ + if(fgets(szLine, LINE_SIZE, pfCurrentFile) != NULL) + { + /* Remote any trailing CR/LF sequence from line. */ + nLineLen = strlen(szLine); + while(nLineLen > 0 + && (szLine[nLineLen - 1] == '\r' || szLine[nLineLen - 1] == '\n')) + { + szLine[--nLineLen] = '\0'; + } + + /* Display the line on the screen. */ + od_disp_str(szLine); + } +} + + +int AddOffsetToArray(long lOffset) +{ + long *palNewArray; + int nNewArraySize; + + /* If array is full, then grow it. */ + if(nTotalLines == nLineArraySize) + { + nNewArraySize = nLineArraySize + ARRAY_GROW_SIZE; + + if((palNewArray = + realloc(palLineOffset, nNewArraySize * sizeof(long))) == NULL) + { + return(FALSE); + } + + nLineArraySize = nNewArraySize; + palLineOffset = palNewArray; + } + + palLineOffset[nTotalLines++] = lOffset; + + return(TRUE); +} + + +void FreeLineArray(void) +{ + if(nLineArraySize > 0) + { + nTotalLines = 0; + nLineArraySize = 0; + free(palLineOffset); + palLineOffset = NULL; + } +} + \ No newline at end of file diff --git a/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.C b/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.C new file mode 100644 index 0000000..3f8676b --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.C @@ -0,0 +1,177 @@ +/* pageview.c - Implementation of the PagedViewer() system. */ + +#include + +#include "opendoor.h" +#include "pageview.h" + +char bTitleColor = 0x0c; +char bTitleLineColor = 0x04; +char bNumberColor = 0x0a; +char bTextColor = 0x02; +char bPromptColor = 0x0f; + +int PagedViewer( + int nInitialLine, /* Zero-based initial line number. */ + int nTotalLines, /* Total line count. */ + void (*pDisplayCallback)(int nLine, void *pData), + void *pCallbackData, /* Data to pass to callback func. */ + BOOL bAllowSelection, /* TRUE if selection is permitted. */ + char *pszTitle, /* Title string, or NULL. */ + int nPageSize) /* # of lines to display per page. */ +{ + int nCurrentPage = 0; + int nScreenLine; + int nAbsoluteLine; + char chPressed; + char bCanPageDown; + char bCanPageUp; + + /* Determine current page from initial line number, if specified. */ + if(nInitialLine != NO_LINE) + { + nCurrentPage = nInitialLine / nPageSize; + } + + /* Loop until user makes a selection, or chooses to quit. */ + for(;;) + { + /* Display the current page. */ + + /* Clear the screen */ + od_printf("\n\r"); + od_clr_scr(); + + /* If a title has been specified, then display it. */ + if(pszTitle != NULL) + { + od_set_attrib(bTitleColor); + od_repeat(' ', (80 - strlen(pszTitle)) / 2); + od_disp_str(pszTitle); + od_printf("\n\r"); + od_set_attrib(bTitleLineColor); + if(od_control.user_ansi || od_control.user_avatar) + { + od_repeat(196, 79); + } + else + { + od_repeat('-', 79); + } + od_printf("\n\r"); + } + + /* Display the lines on this page. */ + nAbsoluteLine = nCurrentPage * nPageSize; + nScreenLine = 0; + while(nScreenLine < nPageSize && nAbsoluteLine < nTotalLines) + { + /* If selection is permitted, display an identifier for each line. */ + if(bAllowSelection) + { + od_set_attrib(bNumberColor); + if(nScreenLine < 9) + { + od_printf("%d. ", nScreenLine + 1); + } + else + { + od_printf("%c. ", 'A' + (nScreenLine - 9)); + } + } + + /* Display the line itself. */ + od_set_attrib(bTextColor); + (*pDisplayCallback)(nAbsoluteLine, pCallbackData); + od_printf("\n\r"); + + /* Move to next line. */ + nScreenLine++; + nAbsoluteLine++; + } + + /* Determine whether user can page up or down from this page. */ + bCanPageDown = nCurrentPage < (nTotalLines - 1) / nPageSize; + bCanPageUp = nCurrentPage > 0; + + /* Display prompt at bottom of screen. */ + od_set_attrib(bPromptColor); + od_printf("\n\r[Page %d of %d] ", nCurrentPage + 1, + ((nTotalLines - 1) / nPageSize) + 1); + if(bAllowSelection) + { + od_printf("Choose an option or"); + } + else + { + od_printf("Available options:"); + } + if(bCanPageDown) + { + od_printf(" [N]ext page,"); + } + if(bCanPageUp) + { + od_printf(" [P]revious page,"); + } + od_printf(" [Q]uit."); + + /* Loop until the user makes a valid choice. */ + for(;;) + { + /* Get key from user */ + chPressed = toupper(od_get_key(TRUE)); + + if(chPressed == 'Q') + { + /* If user chooses to quit, then return without a selection. */ + od_printf("\n\r"); + return(NO_LINE); + } + + else if(chPressed == 'P' && bCanPageUp) + { + /* Move to previous page and redraw screen. */ + --nCurrentPage; + break; + } + + else if(chPressed == 'N' && bCanPageDown) + { + /* Move to next page and redraw screen. */ + ++nCurrentPage; + break; + } + + else if(bAllowSelection + && ( + (chPressed >= '1' && chPressed <= '9') + || (chPressed >= 'A' && chPressed <= 'M') + ) + ) + { + /* If user pressed a possible line key, and selection is */ + /* enabled, try translating character to a line number. */ + if(chPressed >= '1' && chPressed <= '9') + { + nScreenLine = chPressed - '1'; + } + else + { + nScreenLine = 9 + (chPressed - 'A'); + } + + /* Calculate absolute line number. */ + nAbsoluteLine = nScreenLine + (nCurrentPage * nPageSize); + + /* If selected line is within range, then return selected line */ + /* number. */ + if(nScreenLine < nPageSize && nAbsoluteLine < nTotalLines) + { + od_printf("\n\r"); + return(nAbsoluteLine); + } + } + } + } +} diff --git a/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.H b/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.H new file mode 100644 index 0000000..4171848 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/PAGEVIEW.H @@ -0,0 +1,19 @@ +/* pageview.h - Include file for PagedViewer() function. */ + +/* Manifest constant. */ +#define NO_LINE -1 + +/* Boolean definitions. */ +#ifndef BOOL +typedef int BOOL; +#endif + +/* Prototype for the function. */ +int PagedViewer( + int nInitialLine, + int nTotalLines, + void (*pDisplayCallback)(int nLine, void *pCallbackData), + void *pCallbackData, + BOOL bAllowSelection, + char *pszTitle, + int nPageSize); diff --git a/utils/magiedit/odoors/historic/odtips3/SUMMARY.TXT b/utils/magiedit/odoors/historic/odtips3/SUMMARY.TXT new file mode 100644 index 0000000..6db22ce --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/SUMMARY.TXT @@ -0,0 +1,46 @@ + OpenDoors tips package #3 + + --- + + (C) Copyright 1994, Brian Pirie. All Rights Reserved. + + +This package includes a collection of tips and utility functions to help +those using the OpenDoors door programming toolkit. You are free to use +these tips and included source code as you wish, without any fee or +royalty. + + +This package includes the following tip files: + +Tip #1. Drawing horizontal bar graphs using od_repeat(). + Files: tip1.txt, tip1.c + +Tip #2. Transferring files using DSZ. + Files: tip2.txt, tip2.c + +Tip #3. A generic paged viewing / selection routine, and text file + viewing door that uses the paged viewing routine. + Files: tip3.txt, pageview.c, pageview.h, fileview.c, bpfind.h + +Tip #4. Command-line processing for many standard door-related command + line options. + Files: tip4.txt,tip4.c, cmdline.c, cmdline.h + + +How to contact the author +------------------------- + +I can be reached by any of the following means: + + Internet email : brianp@bpecomm.ocunix.on.ca + +Fidonet Crashmail : 1:243/8 (you must poll for a response) + +Modem (24hrs/day) : +1 613 526 4466 + +Conventional mail : Brian Pirie + #1416 - 2201 Riverside Drive + Ottawa, Ontario + K1H 8K9 + Canada diff --git a/utils/magiedit/odoors/historic/odtips3/TIP1.C b/utils/magiedit/odoors/historic/odtips3/TIP1.C new file mode 100644 index 0000000..66d9e2f --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP1.C @@ -0,0 +1,88 @@ +/* Includes */ +#include "opendoor.h" + +/* Function prototypes. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars); +void DrawGraphOfPercentages(int nItems, int *panPercentages, + char **papszTitles, char bTitleColor, char bGraphColor, + int nTitleWidth, int nGraphWidth); + + +/* Main function - program execution begins here. */ +main() +{ + char *apszTitles[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + int anValues[7] = {50, 75, 100, 25, 83, 0, 43}; + + od_printf("`bright green`Test graph:\n\r"); + + DrawGraphOfPercentages(7, anValues, apszTitles, 0x02, 0x0f, 20, 50); + + od_get_key(TRUE); + + return(0); +} + + +/* Function to draw horizontal graph of percentages with titles, to */ +/* demonstrate the use of the DrawHorizontalBar() function. */ +/* No titles should have more than nTitleWidth characters. */ +void DrawGraphOfPercentages(int nItems, int *panPercentages, + char **papszTitles, char bTitleColor, char bGraphColor, + int nTitleWidth, int nGraphWidth) +{ + int nCurrentItem; + + /* Loop for each item (line) in the graph. */ + for(nCurrentItem = 0; nCurrentItem < nItems; ++nCurrentItem) + { + /* Set display color for title text. */ + od_set_attrib(bTitleColor); + + /* Add spaces to right-align all titles. */ + od_repeat(' ', nTitleWidth - strlen(papszTitles[nCurrentItem])); + + /* Display the title. */ + od_disp_str(papszTitles[nCurrentItem]); + + /* Add space between title and graph. */ + od_printf(" "); + + /* Set display color for graph. */ + od_set_attrib(bGraphColor); + + /* Draw bar graph for this line. */ + DrawHorizontalBar(panPercentages[nCurrentItem], 0, 100, nGraphWidth); + + /* Move to the next line. */ + od_printf("\n\r"); + } +} + + +/* Function to draw a horizontal bar, given a value, the minimum and maximum */ +/* possible values, and the number of characters the horizontal bar should */ +/* extended for the maximum value. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars) +{ + /* Determine lenght of bar */ + int nBarChars = ((nValue - nMinValue) * nMaxChars) / nMaxValue; + + if(od_control.user_ansi || od_control.user_avatar) + { + /* If ANSI or AVATAR graphics are available, assume that IBM extended */ + /* ASCII is also available. This function uses character 220 to form */ + /* bars that are 1/2 the height of the line. You might also want to */ + /* try character 119, which will form bars that are the entire height */ + /* of the line. */ + od_repeat(220, nBarChars); + } + else + { + /* In ASCII mode, the bar is formed by the '=' character. */ + od_repeat('=', nBarChars); + } +} diff --git a/utils/magiedit/odoors/historic/odtips3/TIP1.TXT b/utils/magiedit/odoors/historic/odtips3/TIP1.TXT new file mode 100644 index 0000000..aca07d3 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP1.TXT @@ -0,0 +1,55 @@ +Many different types of programs can be enhanced by the use of graphical +information. Often, this graphical information can take the form of +horizontal bar graphs. + +An easy way to draw horizontal bars in door programs written with +OpenDoors, is to use the od_repeat() function. Not only does od_repeat() +allow you to easily form a bar by repeating a particular character the +specified number of times, but it is also a very efficient way to do so. +od_repeat() will take advantage of terminal emulation optimizations, +when available. For instance, a character can be repeated any number of +times with AVATAR by sending a short 3-byte sequence that specifies the +character and number of times to repeat. + +How do you calculate the number of character to use to form a bar in +your graph? The DrawHorizontalBar() function, which is provided below, +will do this calculation for you. Simply provide the value to be +represented by this bar, the minimum and maximum possible values, and +the maximum number of character to use to draw the bar. For example, if +you are graphing percentages (which could range from 0% to 100%), and +wanted the graph to fit in a space of 40 columns, you would use: + + DrawHorizontalBar(nPercent, 0, 100, 40); + +The included tip1.c is a complete program which demonstrates the +DrawHorizontalBar() function as called from another function that will +create complete horizontal bar graphs. This second function, +DrawGraphOfPercentages(), takes an array of titles, and array of values +corresponding to each title, and draws a complete bar graph from this +information. + + +/* Function to draw a horizontal bar, given a value, the minimum and maximum */ +/* possible values, and the number of characters the horizontal bar should */ +/* extended for the maximum value. */ +void DrawHorizontalBar(int nValue, int nMinValue, int nMaxValue, + int nMaxChars) +{ + /* Determine lenght of bar */ + int nBarChars = ((nValue - nMinValue) * nMaxChars) / nMaxValue; + + if(od_control.user_ansi || od_control.user_avatar) + { + /* If ANSI or AVATAR graphics are available, assume that IBM extended */ + /* ASCII is also available. This function uses character 220 to form */ + /* bars that are 1/2 the height of the line. You might also want to */ + /* try character 119, which will form bars that are the entire height */ + /* of the line. */ + od_repeat(220, nBarChars); + } + else + { + /* In ASCII mode, the bar is formed by the '=' character. */ + od_repeat('=', nBarChars); + } +} diff --git a/utils/magiedit/odoors/historic/odtips3/TIP2.C b/utils/magiedit/odoors/historic/odtips3/TIP2.C new file mode 100644 index 0000000..6dcd1c1 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP2.C @@ -0,0 +1,245 @@ +/* tip2.c - Example program to demonstrate how to send or receive files */ +/* using DSZ, from within an OpenDoors program. */ + +/* Include required header files. */ +#include +#include +#include "opendoor.h" + +/* File transfer protocol enumeration. */ +typedef enum +{ + XModem, + XModemCRC, + XModem1K, + YModem, + YModemG, + ZModem +} eProtocol; + +/* Function prototypes. */ +int TransferFile(char *pszFilename, eProtocol Protocol, char bReceive); +eProtocol ChooseProtocol(void); +void AddParameter(char **papszArguments, int *pnCount, char *pszNewArgument); + +/* Manifest constants. */ +#define ARGS_ARRAY_SIZE 10 + +/* Global variable with DSZ filename. */ +char szDSZFilename[80] = "DSZ"; + + +/* Program's execution begins here. */ +main() +{ + char chAnswer; + char bReceive; + eProtocol Protocol; + char szFilename[73]; + int bSuccess; + + od_printf("OpenDoors file transfer demo.\n\r\n\r"); + + /* Get file transfer direction from user. */ + od_printf("Do you wish to [U]pload or [D]ownload? "); + chAnswer = od_get_answer("UD"); + if(chAnswer == 'U') + { + od_printf("Upload\n\r\n\r"); + bReceive = TRUE; + } + else + { + od_printf("Download\n\r\n\r"); + bReceive = FALSE; + } + + /* Get file transfer protocol from user. */ + Protocol = ChooseProtocol(); + + /* Get filename. */ + od_printf("\n\rEnter filename(s) : "); + od_input_str(szFilename, 72, ' ', 255); + od_printf("\n\r"); + + /* Perform file transfer. */ + bSuccess = TransferFile(szFilename, Protocol, bReceive); + + /* Display result of file transfer to user. */ + od_clr_scr(); + if(bSuccess) + { + od_printf("File transfer successful.\n\r"); + } + else + { + od_printf("File transfer not completed.\n\r"); + } + + /* Prompt user to exit program. */ + od_printf("Press [Enter] to return to BBS.\n\r"); + od_get_answer("\n\r"); + + /* Return control to calling BBS software. */ + od_exit(0, FALSE); + + return(0); +} + + +/* Function to allow user to choose a file transfer protocol. */ +eProtocol ChooseProtocol(void) +{ + eProtocol Protocol; + char chAnswer; + + od_printf("Available file transfer protocols:\n\r"); + od_printf(" [X] XModem\n\r"); + od_printf(" [C] XModem/CRC\n\r"); + od_printf(" [1] XModem/1K\n\r"); + od_printf(" [Y] YModem\n\r"); + od_printf(" [G] YModem-G\n\r"); + od_printf(" [Z] ZModem\n\r\n\r"); + od_printf("Please select a protocol: "); + + chAnswer = od_get_answer("XC1YGZ"); + + switch(chAnswer) + { + case 'X': + od_printf("XModem\n\r"); + Protocol = XModem; + break; + case 'C': + od_printf("XModem/CRC\n\r"); + Protocol = XModemCRC; + break; + case '1': + od_printf("XModem/1K\n\r"); + Protocol = XModem1K; + break; + case 'Y': + od_printf("YModem\n\r"); + Protocol = YModem; + break; + case 'G': + od_printf("YModem-G\n\r"); + Protocol = YModemG; + break; + case 'Z': + default: + od_printf("ZModem\n\r"); + Protocol = ZModem; + break; + } + + return(Protocol); +} + + +/* Function to send or receive a file to/from remote system. */ +int TransferFile(char *pszFilename, eProtocol Protocol, char bReceive) +{ + char szPort[7]; + char *apszArguments[ARGS_ARRAY_SIZE]; + int nArgCount = 0; + + /* Filename cannot be NULL. */ + assert(pszFilename != NULL); + + /* Ensure that we are not operating in local mode. */ + if(od_control.baud == 0) + { + od_printf("Operating in local mode; file transfer not possible.\n\r"); + return(FALSE); + } + + /* Generate DSZ command line */ + + /* Begin with executable filename. */ + AddParameter(apszArguments, &nArgCount, szDSZFilename); + + /* Add port parameter. */ + AddParameter(apszArguments, &nArgCount, "port"); + sprintf(szPort, "%d", od_control.port + 1); + AddParameter(apszArguments, &nArgCount, szPort); + + /* Restrict inbound files to current drive and directory. */ + AddParameter(apszArguments, &nArgCount, "restrict"); + + /* Generate DSZ protocol parameters from specified protocol and direction. */ + if(bReceive) + { + switch(Protocol) + { + case XModem: + case XModem1K: + AddParameter(apszArguments, &nArgCount, "rx"); + break; + case XModemCRC: + AddParameter(apszArguments, &nArgCount, "rc"); + break; + case YModem: + AddParameter(apszArguments, &nArgCount, "rb"); + break; + case YModemG: + AddParameter(apszArguments, &nArgCount, "rb"); + AddParameter(apszArguments, &nArgCount, "-g"); + break; + case ZModem: + AddParameter(apszArguments, &nArgCount, "rz"); + break; + default: + assert(FALSE); + } + } + else + { + switch(Protocol) + { + case XModem: + case XModemCRC: + AddParameter(apszArguments, &nArgCount, "sx"); + break; + case XModem1K: + AddParameter(apszArguments, &nArgCount, "sx"); + AddParameter(apszArguments, &nArgCount, "-k"); + break; + case YModem: + case YModemG: + AddParameter(apszArguments, &nArgCount, "sb"); + break; + case ZModem: + AddParameter(apszArguments, &nArgCount, "sz"); + break; + default: + assert(FALSE); + } + } + + /* Add filename parameter to command line. */ + AddParameter(apszArguments, &nArgCount, pszFilename); + + /* Display prompt to user providing */ + od_printf("Begin your transfer now, or press [Ctrl]-[X] several times to abort.\n\r"); + + /* Execute command using the OpenDoors od_spawn() function. */ + return(od_spawnvpe(P_WAIT, apszArguments[0], apszArguments, NULL) == 0); +} + + +/* Function to add next parameter to array of parameters to pass to */ +/* od_spawnvpe(). */ +void AddParameter(char **papszArguments, int *pnCount, char *pszNewArgument) +{ + assert(*pnCount < ARGS_ARRAY_SIZE - 1); + assert(papszArguments != NULL); + assert(pnCount != NULL); + assert(pszNewArgument != NULL); + + /* Add next argument to array. */ + papszArguments[(*pnCount)++] = pszNewArgument; + + /* Ensure that the array is always NULL-terminated. */ + papszArguments[*pnCount] = NULL; +} diff --git a/utils/magiedit/odoors/historic/odtips3/TIP2.TXT b/utils/magiedit/odoors/historic/odtips3/TIP2.TXT new file mode 100644 index 0000000..7e4a91e --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP2.TXT @@ -0,0 +1,45 @@ +Often, it can be useful or necessary to send and receive files between +a program using OpenDoors, and the remote user's system. To allow file +uploading and downloadeding, you can either implement the common file +transfer protocols as part of your program, or you can call an external +file transfer program, such as DSZ. This tip demonstrates how you can +call DSZ using OpenDoors. + +In order to see this program in action, you should run a terminal +program on one machine, and connect to second machine that will run this +example program. (You could also do this in two different windows on one +machine.) The demonstration program will ask whether you want to upload +or download files, and will then prompt you for the file transfer protocol +to use and the filename to transfer. Once this is done, DSZ is invoked +to perform the file transfer. As such, DSZ will need to be installed on +the machine that will run the example program. + +The tip2.c source file provides a function that you can use to perform +file transfers. This function is defined as follows: + + int TransferFile(char *pszFilename, eProtocol Protocol, char bReceive) + +The first parameter should contain the name of the file or files to be +transfered. The second parameter should specify the file transfer +protocol to use, and should be one of the following enumerated +constants: + + XModem + XModemCRC + XModem1K + YModem + YModemG + ZModem + +The third parameter specifies whether the file is being send (FALSE) or +received (TRUE). From the user's perspective, sending the file means +downloading, and receiving the file means uploading. + +The TransferFile() function returns TRUE if the file transfer was +completed, and FALSE if it was not. + +If the DSZ program is not present in the system's PATH or the current +directory, then the global variable szDSZFilename must be set to the +full path and filename of the DSZ program. This could be done by adding +a custom OpenDoors configuration file line with a keyword such as +"DSZPath". diff --git a/utils/magiedit/odoors/historic/odtips3/TIP3.TXT b/utils/magiedit/odoors/historic/odtips3/TIP3.TXT new file mode 100644 index 0000000..f8a5bef --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP3.TXT @@ -0,0 +1,82 @@ +Many people have admired the paged question selection facility in the +OpenDoors 5.00 EZVote example door. EZVote allows the user to choose +questions from a list of up to 200 questions, by displaying one page +of questions at a time. The user is able to page up or down in the list +of quesitons, select a question from the list, or return to the main +menu. A prompt at the bottom of the screen shows the current page +number, and a list of options that are currently available. For +instance, when displaying the first of two pages, this prompt indicates +that the user can move to the next page, but not the previous page. + +This OpenDoors Tip shows a generic function that provides the same sorts +of capabilities that are seen in the EZVote example door, in a form that +can be re-used in many different programs. This function, named +PagedViewer(), can be used for displaying multi-paged messages, text +files, or for permitting selection from a potentially very long list of +items. To use the PagedViewer() in a program, you should add the +pageview.c file to your project file / makefile, and #include the +pageview.h file in any source file that calls PagedViewer(). + +The prototype for the PagedViewer() function is as follows: + + int PagedViewer( + int nInitialLine, + int nTotalLines, + void (*pDisplayCallback)(int nLine, void *pCallbackData), + void *pCallbackData, + BOOL bAllowSelection, + char *pszTitle, + int nPageSize); + +The nInitialLine parameter specifies the line to begin viewing at. +Normally this would be 0, but you may wish to pass a different value to +this function to force the viewer to begin on a page other than the +first. Using this parameter, you can have the user return to +the page they were previously viewing, rather than returning to the +first page and having to again find their original location. + +The nTotalLines parameter specifies the total number of lines that can +be viewed, and can be any value greater than or equal to 0. + +The pDisplayCallback parameter must be a pointer to a function that the +PagedViewer will call to display a particular line of the file at the +current location. When PagedViewer() calls your function, it will pass +the line number to be displayed, along with the value originally passed +to PagedViewer() in pCallbackData. The provided function should simply +display the text for the specified line number, without a trailing CR/LF +sequence, and then return. + +The pCallbackData can point to any data that you wish PagedViewer() to +pass to your callback function, or may be NULL if you do not wish to use +this feature. + +The bAllowSelection parameter should be TRUE if the user should be able +to make a selection from the list, and FALSE if they should not. If +bAllowSelection is TRUE, PagedViewer() will display a letter beside each +line, and allow the user to select a line by pressing the corresponding +letter. If you are using PagedViewer() to display a text file or +message, you will want to set bAllowSelection to FALSE. If you are using +PagedViewer() to display a list of items from which the user can select, +you will want to set bAllowSelection to TRUE. + +The pszTitle parameter can point to a title to be displayed at the top +of each page, and could be something like ("Select a message"). If you +do not wish to have a title displayed, set this parameter to NULL. + +The nPageSize parameter specifies the number of lines that should be +displayed on each page. If you do not wish to have the local screen +(with a two line status line) to be scrolled while displaying the list, +the maximum page size you should use is 21 if no title is being +displayed, and 19 if a title is being displayed. + +The included fileview.c text file viewing program demonstrates the use +of PagedViewer(). The fileview.c door can be setup to allow the user to +view one or more files. If setup to view multiple files, the program +first displays a list of files that the user can select to view. +The fileview.c program uses PagedViewer() in two places - for providing +the list of files and for displaying the file itself. As such, the user +can page up or down in the list of files, select a file to view, and +then page up or down in the file. When the user selects quit while +viewing the file, they are returned to the list of files to possibly +select another file. When the user selects quit from the list of files, +the door returns control to the calling BBS software. diff --git a/utils/magiedit/odoors/historic/odtips3/TIP4.C b/utils/magiedit/odoors/historic/odtips3/TIP4.C new file mode 100644 index 0000000..1ad0176 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP4.C @@ -0,0 +1,19 @@ +#include "opendoor.h" +#include "cmdline.h" + +int main(int argc, char *argv[]) +{ + /* Set function to be called if no door information file is found. */ + od_control.od_no_file_func = NoDoorFileHandler; + + /* Call command-line processing function before first call to any */ + /* OpenDoors function! */ + ParseStandardCommandLine(argc, argv); + + /* Proceed with door normally. */ + od_printf("Hello World!\n\r\n\r"); + od_printf("Press [Enter] to return to BBS.\n\r"); + od_get_answer("\n\r"); + + return(0); +} diff --git a/utils/magiedit/odoors/historic/odtips3/TIP4.TXT b/utils/magiedit/odoors/historic/odtips3/TIP4.TXT new file mode 100644 index 0000000..a974d11 --- /dev/null +++ b/utils/magiedit/odoors/historic/odtips3/TIP4.TXT @@ -0,0 +1,50 @@ +It is common for BBS door programs to accept command line parameters +that permit various door-related settings, such as the serial port, baud +rate, and node number. This tip demonstrates how you can do this when +working with OpenDoors. This tip is presented in the following files: + + cmdline.h - Header file for command line processing function. + cmdline.c - Implementation of command line processing function. + tip4.c - Example of a program that uses the command line + processing function. + +The cmdline.c module implements the ParseStandardCommandLine() function, +which takes as its parameters the same argc and argv parameters that are +passed to the main() function of any C program. The +ParseStandardCommandLine() function then sets the appropriate OpenDoors +settings based on the following optional command-line parameters: + + -L or -LOCAL - Causes door to operate in local mode, without + requiring a door information (drop) file. + -B x or -BPS x - Sets the bps (baud) rate to use. + -P x or -PORT x - Sets the serial port to use, were 0=COM1, 1=COM2, + etc. + -N x or -NODE x - Sets the node number to use. + -?, -H or -HELP - Displays command-line help and exits + -PERSONALITY x - Sets the sysop status line / function key + personality to use. + -MAXTIME x - Sets the maximum number of minutes that any + user will be permitted to access the door. + -ADDRESS x - Sets serial port address, to be used if FOSSIL + driver is not being used. + -IRQ x - Sets the serial port IRQ line, to be used if + FOSSIL driver is not being used. + -NOFOSSIL - Disables use of FOSSIL driver, even if it is + present. + -NOFIFO - Disables use of 16550 FIFO buffers (only if + FOSSIL driver is not being used). + -DROPFILE x - Door information file directory or + directory+filename. + -USERNAME x - Name of user who is currently online. + -TIMELEFT x - User's time remaining online. + -SECURITY x - User's security level. + -LOCATION x - Location from which user is calling. + +Note that any information that is available from the door information +file overrides information provided on the command-line. If sufficient +parameters are provided on the command-line, the door can be operated +without a door information file. In order to do this, cmdline.c provides +a callback function that you can hook into od_control.od_no_file_func, +as demonstrated in tip4.c. + +Case is not sensitive in the names of command line arguments. diff --git a/utils/magiedit/odoors/lbuild.bat b/utils/magiedit/odoors/lbuild.bat new file mode 100644 index 0000000..7249ff8 --- /dev/null +++ b/utils/magiedit/odoors/lbuild.bat @@ -0,0 +1 @@ +make -fDOS.mak -DTARGET=l > out.txt diff --git a/utils/magiedit/odoors/license.txt b/utils/magiedit/odoors/license.txt new file mode 100644 index 0000000..5615459 --- /dev/null +++ b/utils/magiedit/odoors/license.txt @@ -0,0 +1,459 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + diff --git a/utils/magiedit/odoors/out.txt b/utils/magiedit/odoors/out.txt new file mode 100644 index 0000000..e69de29 diff --git a/utils/magiedit/odoors/sbuild.bat b/utils/magiedit/odoors/sbuild.bat new file mode 100644 index 0000000..da4e6d9 --- /dev/null +++ b/utils/magiedit/odoors/sbuild.bat @@ -0,0 +1 @@ +make -fDOS.mak -DTARGET=s > out.txt diff --git a/utils/magiedit/odoors/wbuild.bat b/utils/magiedit/odoors/wbuild.bat new file mode 100644 index 0000000..63c7d6d --- /dev/null +++ b/utils/magiedit/odoors/wbuild.bat @@ -0,0 +1 @@ +nmake -fWin32.mak > out.txt diff --git a/utils/magiedit/odoors/win32.mak b/utils/magiedit/odoors/win32.mak new file mode 100644 index 0000000..9b5563f --- /dev/null +++ b/utils/magiedit/odoors/win32.mak @@ -0,0 +1,372 @@ +# OpenDoors 6.20 +# (C) Copyright 1991 - 1997 by Brian Pirie. All Rights Reserved. +# +# Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net) +# +# +# File: Win32.mak +# +# Description: Makefile used to build the Win32 OpenDoors libraries from +# the sources. Usage is described below. +# +# Revisions: Date Ver Who Change +# --------------------------------------------------------------- +# Oct 13, 1994 6.00 BP New file header format. +# Oct 13, 1994 6.00 BP Made directories configurable. +# Oct 13, 1994 6.00 BP Erase tlib-created backup file. +# Oct 14, 1994 6.00 BP Added ODGen.h dependencies. +# Oct 14, 1994 6.00 BP Added ODPlat.c module. +# Oct 31, 1994 6.00 BP Added headers dependency constant. +# Nov 01, 1994 6.00 BP Added ODUtil.c module. +# Dec 31, 1994 6.00 BP Added -B option for Borland Cs. +# Jan 01, 1995 6.00 BP Added ODKrnl.c, ODKrnl.h. +# Jan 29, 1995 6.00 BP Added ODCmdLn.c. +# Nov 16, 1995 6.00 BP Added ODInQue.c, and new headers. +# Nov 21, 1995 6.00 BP Created ODInit1.c, ODInit2.c. +# Dec 02, 1995 6.00 BP Added ODRes.h +# Dec 02, 1995 6.00 BP Added ODFrame.c, ODFrame.h. +# Dec 02, 1995 6.00 BP Added ODStat.h, ODSwap.h. +# Dec 04, 1995 6.00 BP Changes for building Win32 version. +# Dec 05, 1995 6.00 BP Split into makefiles for each platform +# Dec 07, 1995 6.00 BP Added ODEdit.c. +# Dec 21, 1995 6.00 BP Changes for building as DLL. +# Jan 04, 1996 6.00 BP Added ODGetIn.c. +# Feb 09, 1996 6.00 BP Renamed ODInit?.* to ODInEx?.* +# Feb 19, 1996 6.00 BP Turned off OD_DEBUG +# Feb 19, 1996 6.00 BP Changed version number to 6.00. +# Mar 03, 1996 6.10 BP Begin version 6.10. +# Oct 19, 2001 6.20 RS Added door32.sys and socket support. +# +############################################################################### +# +# USAGE INFORMATION +# +############################################################################### +# +# Command Line: make -fWin32.mak +# or +# nmake /f Win32.mak +# +############################################################################### +# +# CONFIGURATION +# +# Customize this section of the makefile to provide the relevant information +# for your compiler, assembler (if any) and build environment. +# +############################################################################### +# Compiler executable file name. Use: +# +# tcc - For Borland Turbo C and Turbo C++ +# bcc - For Borland C++ +# cl - For Microsoft compilers +# +CC=cl +# +#------------------------------------------------------------------------------ +# +# Linker executable file name. Use: +# +# tlink - For Borland compilers +# link - For Microsoft compilers +# +LINK=link +# +#------------------------------------------------------------------------------ +# +# Resource compiler exectuable file name. +# +RC=rc +# +#------------------------------------------------------------------------------ +# +# Win32 compiler command-line flags. Use: +# +# /c /W3 /D "WIN32" /D "_WINDOWS" - For Microsoft compilers +# +CFLAGS=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "_WINDOWS" /c +# /MTd /Zi - for debug +# +#------------------------------------------------------------------------------ +# +# Link flags. +# +LINKFLAGS=kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib wsock32.lib\ + uuid.lib comctl32.lib /NOLOGO /DLL /INCREMENTAL:no\ + /MAP\ +# /DEBUG\ + /MACHINE:I386\ + /DEF:$(SOURCEDIR)"OpenDoor.def" /OUT:$(LIBDIR)"ODoors62.dll"\ + /IMPLIB:$(LIBDIR)"ODoorW.lib" /SUBSYSTEM:windows,4.0 +# +#------------------------------------------------------------------------------ +# +# Output directories. customize for your own preferences. Note that trailing +# backslash (\) characters are required. +# +SOURCEDIR=.\ # Comments required +ODHEADERDIR=.\ # in order to +OBJDIR=.\ # was ..\obj # avoid line +LIBDIR=.\ # was ..\lib # concatentation +# +############################################################################### +# +# DEPENDENCIES +# +# You won't normally have to change anything after this point in this makefile. +# +############################################################################### +# +# Define primary target. +# +TARGET=w +all: $(LIBDIR)ODoors62.dll +# +#------------------------------------------------------------------------------ +# +# Name of all headers. +# +HEADERS= $(HEADERDIR)ODCom.h\ + $(HEADERDIR)ODCore.h\ + $(HEADERDIR)ODFrame.h\ + $(HEADERDIR)ODGen.h\ + $(HEADERDIR)ODInEx.h\ + $(HEADERDIR)ODInQue.h\ + $(HEADERDIR)ODKrnl.h\ + $(HEADERDIR)ODPlat.h\ + $(HEADERDIR)ODRes.h\ + $(HEADERDIR)ODScrn.h\ + $(HEADERDIR)ODStat.h\ + $(HEADERDIR)ODSwap.h\ + $(HEADERDIR)ODTypes.h\ + $(HEADERDIR)ODUtil.h\ + $(HEADERDIR)OpenDoor.h +# +#------------------------------------------------------------------------------ +# +# +DEF_FILE=$(SOURCEDIR)OpenDoor.def +# +#------------------------------------------------------------------------------ +# +# Build from C sources. +# +$(OBJDIR)odauto$(TARGET).obj : $(SOURCEDIR)odauto.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odauto.c + command /c erase $(OBJDIR)odauto$(TARGET).obj + move odauto.obj $(OBJDIR)odauto$(TARGET).obj + +$(OBJDIR)odblock$(TARGET).obj : $(SOURCEDIR)odblock.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odblock.c + command /c erase $(OBJDIR)odblock$(TARGET).obj + move odblock.obj $(OBJDIR)odblock$(TARGET).obj + +$(OBJDIR)odcfile$(TARGET).obj : $(SOURCEDIR)odcfile.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odcfile.c + command /c erase $(OBJDIR)odcfile$(TARGET).obj + move odcfile.obj $(OBJDIR)odcfile$(TARGET).obj + +$(OBJDIR)odcmdln$(TARGET).obj : $(SOURCEDIR)odcmdln.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odcmdln.c + command /c erase $(OBJDIR)odcmdln$(TARGET).obj + move odcmdln.obj $(OBJDIR)odcmdln$(TARGET).obj + +$(OBJDIR)odcom$(TARGET).obj : $(SOURCEDIR)odcom.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odcom.c + command /c erase $(OBJDIR)odcom$(TARGET).obj + move odcom.obj $(OBJDIR)odcom$(TARGET).obj + +$(OBJDIR)odcore$(TARGET).obj : $(SOURCEDIR)odcore.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odcore.c + command /c erase $(OBJDIR)odcore$(TARGET).obj + move odcore.obj $(OBJDIR)odcore$(TARGET).obj + +$(OBJDIR)oddrbox$(TARGET).obj : $(SOURCEDIR)oddrbox.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)oddrbox.c + command /c erase $(OBJDIR)oddrbox$(TARGET).obj + move oddrbox.obj $(OBJDIR)oddrbox$(TARGET).obj + +$(OBJDIR)odedit$(TARGET).obj : $(SOURCEDIR)odedit.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odedit.c + command /c erase $(OBJDIR)odedit$(TARGET).obj + move odedit.obj $(OBJDIR)odedit$(TARGET).obj + +$(OBJDIR)odedstr$(TARGET).obj : $(SOURCEDIR)odedstr.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odedstr.c + command /c erase $(OBJDIR)odedstr$(TARGET).obj + move odedstr.obj $(OBJDIR)odedstr$(TARGET).obj + +$(OBJDIR)odemu$(TARGET).obj : $(SOURCEDIR)odemu.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odemu.c + command /c erase $(OBJDIR)odemu$(TARGET).obj + move odemu.obj $(OBJDIR)odemu$(TARGET).obj + +$(OBJDIR)odframe$(TARGET).obj : $(SOURCEDIR)odframe.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odframe.c + command /c erase $(OBJDIR)odframe$(TARGET).obj + move odframe.obj $(OBJDIR)odframe$(TARGET).obj + +$(OBJDIR)odgetin$(TARGET).obj : $(SOURCEDIR)odgetin.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odgetin.c + command /c erase $(OBJDIR)odgetin$(TARGET).obj + move odgetin.obj $(OBJDIR)odgetin$(TARGET).obj + +$(OBJDIR)odgraph$(TARGET).obj : $(SOURCEDIR)odgraph.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odgraph.c + command /c erase $(OBJDIR)odgraph$(TARGET).obj + move odgraph.obj $(OBJDIR)odgraph$(TARGET).obj + +$(OBJDIR)odinex1$(TARGET).obj : $(SOURCEDIR)odinex1.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odinex1.c + command /c erase $(OBJDIR)odinex1$(TARGET).obj + move odinex1.obj $(OBJDIR)odinex1$(TARGET).obj + +$(OBJDIR)odinex2$(TARGET).obj : $(SOURCEDIR)odinex2.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odinex2.c + command /c erase $(OBJDIR)odinex2$(TARGET).obj + move odinex2.obj $(OBJDIR)odinex2$(TARGET).obj + +$(OBJDIR)odinque$(TARGET).obj : $(SOURCEDIR)odinque.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odinque.c + command /c erase $(OBJDIR)odinque$(TARGET).obj + move odinque.obj $(OBJDIR)odinque$(TARGET).obj + +$(OBJDIR)odkrnl$(TARGET).obj : $(SOURCEDIR)odkrnl.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odkrnl.c + command /c erase $(OBJDIR)odkrnl$(TARGET).obj + move odkrnl.obj $(OBJDIR)odkrnl$(TARGET).obj + +$(OBJDIR)odlist$(TARGET).obj : $(SOURCEDIR)odlist.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odlist.c + command /c erase $(OBJDIR)odlist$(TARGET).obj + move odlist.obj $(OBJDIR)odlist$(TARGET).obj + +$(OBJDIR)odlog$(TARGET).obj : $(SOURCEDIR)odlog.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odlog.c + command /c erase $(OBJDIR)odlog$(TARGET).obj + move odlog.obj $(OBJDIR)odlog$(TARGET).obj + +$(OBJDIR)odmulti$(TARGET).obj : $(SOURCEDIR)odmulti.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odmulti.c + command /c erase $(OBJDIR)odmulti$(TARGET).obj + move odmulti.obj $(OBJDIR)odmulti$(TARGET).obj + +$(OBJDIR)odplat$(TARGET).obj : $(SOURCEDIR)odplat.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odplat.c + command /c erase $(OBJDIR)odplat$(TARGET).obj + move odplat.obj $(OBJDIR)odplat$(TARGET).obj + +$(OBJDIR)odpcb$(TARGET).obj : $(SOURCEDIR)odpcb.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odpcb.c + command /c erase $(OBJDIR)odpcb$(TARGET).obj + move odpcb.obj $(OBJDIR)odpcb$(TARGET).obj + +$(OBJDIR)odpopup$(TARGET).obj : $(SOURCEDIR)odpopup.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odpopup.c + command /c erase $(OBJDIR)odpopup$(TARGET).obj + move odpopup.obj $(OBJDIR)odpopup$(TARGET).obj + +$(OBJDIR)odprntf$(TARGET).obj : $(SOURCEDIR)odprntf.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odprntf.c + command /c erase $(OBJDIR)odprntf$(TARGET).obj + move odprntf.obj $(OBJDIR)odprntf$(TARGET).obj + +$(OBJDIR)odra$(TARGET).obj : $(SOURCEDIR)odra.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odra.c + command /c erase $(OBJDIR)odra$(TARGET).obj + move odra.obj $(OBJDIR)odra$(TARGET).obj + +$(OBJDIR)odscrn$(TARGET).obj : $(SOURCEDIR)odscrn.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odscrn.c + command /c erase $(OBJDIR)odscrn$(TARGET).obj + move odscrn.obj $(OBJDIR)odscrn$(TARGET).obj + +$(OBJDIR)odspawn$(TARGET).obj : $(SOURCEDIR)odspawn.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odspawn.c + command /c erase $(OBJDIR)odspawn$(TARGET).obj + move odspawn.obj $(OBJDIR)odspawn$(TARGET).obj + +$(OBJDIR)odstand$(TARGET).obj : $(SOURCEDIR)odstand.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odstand.c + command /c erase $(OBJDIR)odstand$(TARGET).obj + move odstand.obj $(OBJDIR)odstand$(TARGET).obj + +$(OBJDIR)odstat$(TARGET).obj : $(SOURCEDIR)odstat.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odstat.c + command /c erase $(OBJDIR)odstat$(TARGET).obj + move odstat.obj $(OBJDIR)odstat$(TARGET).obj + +# This file (odsys.c) wasn't included in 6.1.1 source +#$(OBJDIR)odsys$(TARGET).obj : $(SOURCEDIR)odsys.c $(HEADERS) +# $(CC) $(CFLAGS) $(SOURCEDIR)odsys.c +# command /c erase $(OBJDIR)odsys$(TARGET).obj +# move odsys.obj $(OBJDIR)odsys$(TARGET).obj + +$(OBJDIR)odutil$(TARGET).obj : $(SOURCEDIR)odutil.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odutil.c + command /c erase $(OBJDIR)odutil$(TARGET).obj + move odutil.obj $(OBJDIR)odutil$(TARGET).obj + +$(OBJDIR)odwcat$(TARGET).obj : $(SOURCEDIR)odwcat.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odwcat.c + command /c erase $(OBJDIR)odwcat$(TARGET).obj + move odwcat.obj $(OBJDIR)odwcat$(TARGET).obj + +$(OBJDIR)odwin$(TARGET).obj : $(SOURCEDIR)odwin.c $(HEADERS) + $(CC) $(CFLAGS) $(SOURCEDIR)odwin.c + command /c erase $(OBJDIR)odwin$(TARGET).obj + move odwin.obj $(OBJDIR)odwin$(TARGET).obj +# +#------------------------------------------------------------------------------ +# +# Build from resource script. +# +$(OBJDIR)ODoor$(TARGET).res: $(SOURCEDIR)ODRes.rc + $(RC) $(SOURCEDIR)ODRes.rc + command /c erase $(LIBDIR)ODoor$(TARGET).res + move $(SOURCEDIR)ODRes.res $(OBJDIR)ODoor$(TARGET).res +# +#------------------------------------------------------------------------------ +# +# Build DLL from objects. +# +OBJECTS= $(OBJDIR)odauto$(TARGET).obj\ + $(OBJDIR)odblock$(TARGET).obj\ + $(OBJDIR)odcfile$(TARGET).obj\ + $(OBJDIR)odcmdln$(TARGET).obj\ + $(OBJDIR)odcom$(TARGET).obj\ + $(OBJDIR)odcore$(TARGET).obj\ + $(OBJDIR)oddrbox$(TARGET).obj\ + $(OBJDIR)odedit$(TARGET).obj\ + $(OBJDIR)odedstr$(TARGET).obj\ + $(OBJDIR)odemu$(TARGET).obj\ + $(OBJDIR)odframe$(TARGET).obj\ + $(OBJDIR)odgetin$(TARGET).obj\ + $(OBJDIR)odgraph$(TARGET).obj\ + $(OBJDIR)odinex1$(TARGET).obj\ + $(OBJDIR)odinex2$(TARGET).obj\ + $(OBJDIR)odinque$(TARGET).obj\ + $(OBJDIR)odkrnl$(TARGET).obj\ + $(OBJDIR)odlist$(TARGET).obj\ + $(OBJDIR)odlog$(TARGET).obj\ + $(OBJDIR)odmulti$(TARGET).obj\ + $(OBJDIR)odplat$(TARGET).obj\ + $(OBJDIR)odpcb$(TARGET).obj\ + $(OBJDIR)odpopup$(TARGET).obj\ + $(OBJDIR)odprntf$(TARGET).obj\ + $(OBJDIR)odra$(TARGET).obj\ + $(OBJDIR)odscrn$(TARGET).obj\ + $(OBJDIR)odspawn$(TARGET).obj\ + $(OBJDIR)odstand$(TARGET).obj\ + $(OBJDIR)odstat$(TARGET).obj\ +# $(OBJDIR)odsys$(TARGET).obj\ this file is missing + $(OBJDIR)odutil$(TARGET).obj\ + $(OBJDIR)odwcat$(TARGET).obj\ + $(OBJDIR)odwin$(TARGET).obj\ + $(OBJDIR)ODoor$(TARGET).res +$(LIBDIR)ODoors62.dll : $(DEF_FILE) $(OBJECTS) + $(LINK) @<< + $(LINKFLAGS) $(OBJECTS) +<< +# +#------------------------------------------------------------------------------