1435 lines
56 KiB
C
1435 lines
56 KiB
C
/* OpenDoors Online Software Programming Toolkit
|
|
* (C) Copyright 1991 - 1999 by Brian Pirie.
|
|
*
|
|
* Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*
|
|
* File: 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
|
|
#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;btCount<pExitInfoRecord->bbs.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 */
|