ODInEx2.c 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. *
  21. * File: ODInEx2.c
  22. *
  23. * Description: Performs OpenDoors initialization and shutdown operations
  24. * (od_init() and od_exit()), including drop file I/O. This
  25. * module is broken into two files, ODInEx1.c and ODInEx2.c.
  26. *
  27. * Revisions: Date Ver Who Change
  28. * ---------------------------------------------------------------
  29. * Oct 13, 1994 6.00 BP New file header format.
  30. * Oct 21, 1994 6.00 BP Further isolated com routines.
  31. * Oct 29, 1994 6.00 BP New EXITINFO.BBS timelimit writing.
  32. * Nov 01, 1994 6.00 BP New directory access functions.
  33. * Dec 09, 1994 6.00 BP Standardized coding style.
  34. * Dec 13, 1994 6.00 BP Remove include of dir.h.
  35. * Dec 31, 1994 6.00 BP Add DIR_ATTRIB_ARCH in file search.
  36. * Dec 31, 1994 6.00 BP Move _mt_init to new func in odplat.c
  37. * Jan 01, 1995 6.00 BP _waitdrain() -> ODWaitDrain().
  38. * Aug 19, 1995 6.00 BP 32-bit portability.
  39. * Nov 11, 1995 6.00 BP Removed register keyword.
  40. * Nov 14, 1995 6.00 BP Added include of odscrn.h.
  41. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  42. * Nov 17, 1995 6.00 BP Use new input queue mechanism.
  43. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  44. * Jan 01, 1996 6.00 BP Added od_disable_dtr, DIS_DTR_DISABLE.
  45. * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent.
  46. * Jan 19, 1996 6.00 BP Don't use atexit() under Win32.
  47. * Jan 21, 1996 6.00 BP Try DTR disable sequence twice.
  48. * Jan 21, 1996 6.00 BP Use ODScrnShowMessage().
  49. * Jan 23, 1996 6.00 BP Added od_exiting.
  50. * Jan 23, 1996 6.00 BP Use ODProcessExit() instead of exit().
  51. * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
  52. * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout.
  53. * Jan 31, 1996 6.00 BP Support new SFDOORS.DAT format.
  54. * Feb 02, 1996 6.00 BP Added RA 2.50 EXITINFO.BBS support.
  55. * Feb 09, 1996 6.00 BP Correctly translate RA 2.x sex field.
  56. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  57. * Feb 23, 1996 6.00 BP Make DTR disable code shared.
  58. * Mar 03, 1996 6.10 BP Begin version 6.10.
  59. * Mar 06, 1996 6.10 BP Added TRIBBS.SYS support.
  60. * Mar 27, 1996 6.10 BP Added WCNODEID to
  61. * Jan 13, 1997 6.10 BP Fixes for Door32 support.
  62. * Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support.
  63. * Aug 10, 2003 6.23 SH *nix support
  64. */
  65. #define BUILDING_OPENDOORS
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <stdarg.h>
  69. #include <string.h>
  70. #include <ctype.h>
  71. #include <time.h>
  72. #include "OpenDoor.h"
  73. #include "ODStr.h"
  74. #include "ODCore.h"
  75. #include "ODGen.h"
  76. #include "ODCom.h"
  77. #include "ODPlat.h"
  78. #include "ODTypes.h"
  79. #include "ODScrn.h"
  80. #include "ODInQue.h"
  81. #include "ODKrnl.h"
  82. #include "ODInEx.h"
  83. #include "ODUtil.h"
  84. /* Time difference leeway for door information files to be considered to */
  85. /* have been written during the same exit (door execution session). */
  86. #define DROPFILE_TIME_LEEWAY 10
  87. /* Maximum length of modem response string. */
  88. #define MAX_RESPONSE_LEN 40
  89. /* Maximum time to wait for modem response string, in milliseconds. */
  90. #define RESPONSE_TIMEOUT 2000
  91. /* Environment variables that specify directories where drop files may be */
  92. /* found. */
  93. static char *apszEnvVarNames[] =
  94. {
  95. "RA",
  96. "QUICK",
  97. "PCB",
  98. "BBS",
  99. "WCNODEID",
  100. "SBBSNODE",
  101. };
  102. #define NUM_DIR_ENV_VARS DIM(apszEnvVarNames)
  103. /* Local helper functions. */
  104. static INT ODSearchInDir(char **papszFileNames, INT nNumFileNames,
  105. char *pszFound, char *pszDirectory);
  106. /* Currently, the following functions are only used in the Win32 version. */
  107. #ifdef ODPLAT_WIN32
  108. static BOOL ODSendModemCommand(char *pszCommand, int nRetries);
  109. static BOOL ODSendModemCommandOnce(char *pszCommand);
  110. static BOOL ODWaitForString(char *pszResponse, tODMilliSec ResponseTimeout);
  111. #endif /* ODPLAT_WIN32 */
  112. #ifdef OD_DIAGNOSTICS
  113. static char szDebugWorkString[500] = "";
  114. #endif /* OD_DIAGNOSTICS */
  115. /* ----------------------------------------------------------------------------
  116. * od_exit()
  117. *
  118. * Shuts down OpenDoors operations. Normally, the program is exited as soon
  119. * as OpenDoors is shutdown.
  120. *
  121. * Parameters: nErrorLevel - Result code to exit program with.
  122. *
  123. * bTermCall - TRUE to disconnect the user before exiting,
  124. * FALSE to leave the user connected.
  125. *
  126. * Return: void
  127. */
  128. ODAPIDEF void ODCALL od_exit(INT nErrorLevel, BOOL bTermCall)
  129. {
  130. BYTE btCount;
  131. FILE *pfDropFile;
  132. time_t nMaxTime;
  133. time_t nDoorEndTime;
  134. void *pWindow = NULL;
  135. DWORD dwActiveMinutes;
  136. static BOOL bExiting = FALSE;
  137. /* Log function entry if running in trace mode */
  138. TRACE(TRACE_API, "od_exit()");
  139. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  140. if(od_control.od_internal_debug)
  141. {
  142. MessageBox(NULL, "Starting up od_exit()", "OpenDoors Diagnostics",
  143. MB_OK);
  144. }
  145. #endif
  146. /* If this is a recursive od_exit() call, then ignore it. */
  147. if(bExiting)
  148. {
  149. return;
  150. }
  151. bExiting = TRUE;
  152. /* If user called od_exit() before doing anything else, then we first */
  153. /* initialize OpenDoors in order to shutdown and exit. */
  154. if(!bODInitialized) od_init();
  155. /* Update remaining time. */
  156. od_control.user_timelimit += od_control.od_maxtime_deduction;
  157. /* Calculate deducted time */
  158. time(&nDoorEndTime);
  159. ODDWordDivide(&dwActiveMinutes, NULL, nDoorEndTime - nStartupUnixTime, 60L);
  160. od_control.user_time_used += ((nInitialRemaining
  161. - od_control.user_timelimit) - (int)dwActiveMinutes);
  162. /* Reset to original bps rate that was stored in drop file */
  163. od_control.baud = dwFileBPS;
  164. /* If function hook is defined. */
  165. if(od_control.od_before_exit != NULL)
  166. {
  167. /* Then call it. */
  168. (*od_control.od_before_exit)();
  169. }
  170. if(bTermCall && od_control.od_hanging_up != NULL)
  171. {
  172. pWindow = ODScrnShowMessage(od_control.od_hanging_up, 0);
  173. }
  174. else if(!bTermCall)
  175. {
  176. pWindow = ODScrnShowMessage(od_control.od_exiting, 0);
  177. }
  178. if(szOriginalDir != NULL)
  179. {
  180. ODDirChangeCurrent(szOriginalDir);
  181. free(szOriginalDir);
  182. szOriginalDir=NULL;
  183. }
  184. if(od_control.od_extended_info) /* Update EXITINFO.BBS, if applicable */
  185. {
  186. ODMakeFilename(szExitinfoBBSPath, szExitinfoBBSPath, "EXITINFO.BBS",
  187. sizeof(szExitinfoBBSPath));
  188. if((pfDropFile = fopen(szExitinfoBBSPath, "r+b")) != NULL)
  189. {
  190. switch(od_control.od_info_type)
  191. {
  192. case RA2EXITINFO:
  193. pRA2ExitInfoRecord->baud = (unsigned int)od_control.baud;
  194. pRA2ExitInfoRecord->num_calls = od_control.system_calls;
  195. ODStringCToPascal(pRA2ExitInfoRecord->last_caller,35,od_control.system_last_caller);
  196. ODStringCToPascal(pRA2ExitInfoRecord->sLastHandle,35,od_control.system_last_handle);
  197. ODStringCToPascal(pRA2ExitInfoRecord->start_date,8,od_control.timelog_start_date);
  198. memcpy(&pRA2ExitInfoRecord->busyperhour,&od_control.timelog_busyperhour,62);
  199. ODStringCToPascal(pRA2ExitInfoRecord->name,35,od_control.user_name);
  200. ODStringCToPascal(pRA2ExitInfoRecord->location,25,od_control.user_location);
  201. ODStringCToPascal(pRA2ExitInfoRecord->organisation,50,od_control.user_org);
  202. for(btCount=0;btCount<3;++btCount)
  203. ODStringCToPascal(pRA2ExitInfoRecord->address[btCount],50,od_control.user_address[btCount]);
  204. ODStringCToPascal(pRA2ExitInfoRecord->handle,35,od_control.user_handle);
  205. ODStringCToPascal(pRA2ExitInfoRecord->comment,80,od_control.user_comment);
  206. pRA2ExitInfoRecord->password_crc=od_control.user_pwd_crc;
  207. ODStringCToPascal(pRA2ExitInfoRecord->dataphone,15,od_control.user_dataphone);
  208. ODStringCToPascal(pRA2ExitInfoRecord->homephone,15,od_control.user_homephone);
  209. ODStringCToPascal(pRA2ExitInfoRecord->lasttime,5,od_control.user_lasttime);
  210. ODStringCToPascal(pRA2ExitInfoRecord->lastdate,8,od_control.user_lastdate);
  211. pRA2ExitInfoRecord->attrib=od_control.user_attribute;
  212. pRA2ExitInfoRecord->attrib2=od_control.user_attrib2;
  213. memcpy(&pRA2ExitInfoRecord->flags,&od_control.user_flags,14);
  214. pRA2ExitInfoRecord->sec=od_control.user_security;
  215. pRA2ExitInfoRecord->lastread=od_control.user_lastread;
  216. memcpy(&pRA2ExitInfoRecord->nocalls,&od_control.user_numcalls,29);
  217. pRA2ExitInfoRecord->group=od_control.user_group;
  218. memcpy(&pRA2ExitInfoRecord->combinedrecord,&od_control.user_combinedrecord,200);
  219. ODStringCToPascal(pRA2ExitInfoRecord->firstcall,8,od_control.user_firstcall);
  220. ODStringCToPascal(pRA2ExitInfoRecord->birthday,8,od_control.user_birthday);
  221. ODStringCToPascal(pRA2ExitInfoRecord->subdate,8,od_control.user_subdate);
  222. pRA2ExitInfoRecord->screenwidth=od_control.user_screenwidth;
  223. pRA2ExitInfoRecord->language=od_control.user_language;
  224. pRA2ExitInfoRecord->dateformat=od_control.user_date_format;
  225. ODStringCToPascal(pRA2ExitInfoRecord->forwardto,35,od_control.user_forward_to);
  226. memcpy(&pRA2ExitInfoRecord->msgarea,&od_control.user_msg_area,15);
  227. pRA2ExitInfoRecord->sex = (od_control.user_sex == 'M') ? 1 : 2;
  228. pRA2ExitInfoRecord->btAttribute3=od_control.user_attrib3;
  229. ODStringCToPascal(pRA2ExitInfoRecord->sPassword,15,od_control.user_password);
  230. pRA2ExitInfoRecord->status=od_control.event_status;
  231. ODStringCToPascal(pRA2ExitInfoRecord->starttime,5,od_control.event_starttime);
  232. memcpy(&pRA2ExitInfoRecord->errorlevel,&od_control.event_errorlevel,3);
  233. ODStringCToPascal(pRA2ExitInfoRecord->lasttimerun,8,od_control.event_last_run);
  234. memcpy(&pRA2ExitInfoRecord->netmailentered,&od_control.user_netmailentered,2);
  235. ODStringCToPascal(pRA2ExitInfoRecord->logintime,5,od_control.user_logintime);
  236. ODStringCToPascal(pRA2ExitInfoRecord->logindate,8,od_control.user_logindate);
  237. memcpy(&pRA2ExitInfoRecord->timelimit,&od_control.user_timelimit,6);
  238. memcpy(&pRA2ExitInfoRecord->userrecord,&od_control.user_num,8);
  239. ODStringCToPascal(pRA2ExitInfoRecord->timeofcreation,5,od_control.user_timeofcreation);
  240. pRA2ExitInfoRecord->logonpasswordcrc=od_control.user_logon_pwd_crc;
  241. pRA2ExitInfoRecord->wantchat=od_control.user_wantchat;
  242. pRA2ExitInfoRecord->deducted_time=od_control.user_deducted_time;
  243. for(btCount=0;btCount<50;++btCount)
  244. ODStringCToPascal(pRA2ExitInfoRecord->menustack[btCount],8,od_control.user_menustack[btCount]);
  245. pRA2ExitInfoRecord->menustackpointer=od_control.user_menustackpointer;
  246. memcpy(&pRA2ExitInfoRecord->error_free,&od_control.user_error_free,3);
  247. ODStringCToPascal(pRA2ExitInfoRecord->emsi_crtdef,40,od_control.user_emsi_crtdef);
  248. ODStringCToPascal(pRA2ExitInfoRecord->emsi_protocols,40,od_control.user_emsi_protocols);
  249. ODStringCToPascal(pRA2ExitInfoRecord->emsi_capabilities,40,od_control.user_emsi_capabilities);
  250. ODStringCToPascal(pRA2ExitInfoRecord->emsi_requests,40,od_control.user_emsi_requests);
  251. ODStringCToPascal(pRA2ExitInfoRecord->emsi_software,40,od_control.user_emsi_software);
  252. memcpy(&pRA2ExitInfoRecord->hold_attr1,&od_control.user_hold_attr1,3);
  253. ODStringCToPascal(pRA2ExitInfoRecord->page_reason,77,od_control.user_reasonforchat);
  254. if(bRAStatus)
  255. {
  256. pRA2ExitInfoRecord->status_line = btCurrentStatusLine + 1;
  257. }
  258. ODStringCToPascal(pRA2ExitInfoRecord->last_cost_menu,9,od_control.user_last_cost_menu);
  259. pRA2ExitInfoRecord->menu_cost_per_min=od_control.user_menu_cost;
  260. pRA2ExitInfoRecord->has_rip=od_control.user_rip;
  261. pRA2ExitInfoRecord->btRIPVersion=od_control.user_rip_ver;
  262. fwrite(pRA2ExitInfoRecord,1,sizeof(tRA2ExitInfoRecord),pfDropFile);
  263. free(pRA2ExitInfoRecord);
  264. break;
  265. case EXITINFO:
  266. ODStringCToPascal(pExitInfoRecord->bbs.ra.timeofcreation,5,od_control.user_timeofcreation);
  267. ODStringCToPascal(pExitInfoRecord->bbs.ra.logonpassword,15,od_control.user_logonpassword);
  268. pExitInfoRecord->bbs.ra.wantchat=od_control.user_wantchat;
  269. ODWriteExitInfoPrimitive(pfDropFile,476);
  270. break;
  271. case RA1EXITINFO:
  272. pExtendedExitInfo->deducted_time=od_control.user_deducted_time;
  273. for(btCount=0;btCount<50;++btCount)
  274. {
  275. ODStringCToPascal(pExtendedExitInfo->menustack[btCount],8,od_control.user_menustack[btCount]);
  276. }
  277. pExtendedExitInfo->menustackpointer=od_control.user_menustackpointer;
  278. ODStringCToPascal(pExtendedExitInfo->userhandle,35,od_control.user_handle);
  279. ODStringCToPascal(pExtendedExitInfo->comment,80,od_control.user_comment);
  280. ODStringCToPascal(pExtendedExitInfo->firstcall,8,od_control.user_firstcall);
  281. memcpy(pExtendedExitInfo->combinedrecord,od_control.user_combinedrecord,25);
  282. ODStringCToPascal(pExtendedExitInfo->birthday,8,od_control.user_birthday);
  283. ODStringCToPascal(pExtendedExitInfo->subdate,8,od_control.user_subdate);
  284. pExtendedExitInfo->screenwidth=od_control.user_screenwidth;
  285. pExtendedExitInfo->msgarea = (BYTE)od_control.user_msg_area;
  286. pExtendedExitInfo->filearea = (BYTE)od_control.user_file_area;
  287. pExtendedExitInfo->language=od_control.user_language;
  288. pExtendedExitInfo->dateformat=od_control.user_date_format;
  289. ODStringCToPascal(pExtendedExitInfo->forwardto,35,od_control.user_forward_to);
  290. memcpy(&pExtendedExitInfo->error_free,&od_control.user_error_free,3);
  291. ODStringCToPascal(pExtendedExitInfo->emsi_crtdef,40,od_control.user_emsi_crtdef);
  292. ODStringCToPascal(pExtendedExitInfo->emsi_protocols,40,od_control.user_emsi_protocols);
  293. ODStringCToPascal(pExtendedExitInfo->emsi_capabilities,40,od_control.user_emsi_capabilities);
  294. ODStringCToPascal(pExtendedExitInfo->emsi_requests,40,od_control.user_emsi_requests);
  295. ODStringCToPascal(pExtendedExitInfo->emsi_software,40,od_control.user_emsi_software);
  296. memcpy(&pExtendedExitInfo->hold_attr1,&od_control.user_hold_attr1,3);
  297. ODStringCToPascal(pExitInfoRecord->bbs.ra.timeofcreation,5,od_control.user_timeofcreation);
  298. ODStringCToPascal(pExitInfoRecord->bbs.ra.logonpassword,15,od_control.user_logonpassword);
  299. pExitInfoRecord->bbs.ra.wantchat=od_control.user_wantchat;
  300. ODWriteExitInfoPrimitive(pfDropFile,476);
  301. fwrite(pExtendedExitInfo,1,1017,pfDropFile);
  302. free(pExtendedExitInfo);
  303. break;
  304. case QBBS275EXITINFO:
  305. pExitInfoRecord->elapsed=nInitialElapsed;
  306. pExitInfoRecord->bbs.qbbs.qwantchat=od_control.user_wantchat;
  307. pExitInfoRecord->bbs.qbbs.gosublevel=od_control.user_menustackpointer;
  308. for(btCount=0;btCount<pExitInfoRecord->bbs.qbbs.gosublevel;++btCount)
  309. {
  310. ODStringCToPascal(pExitInfoRecord->bbs.qbbs.menustack[btCount],8,od_control.user_menustack[btCount]);
  311. }
  312. ODStringCToPascal(pExitInfoRecord->bbs.qbbs.menu,8,od_control.user_menustack[od_control.user_menustackpointer]);
  313. pExitInfoRecord->bbs.qbbs.externlogoff = bTermCall ? 1 : 0;
  314. pExitInfoRecord->bbs.qbbs.ripactive = od_control.user_rip ? 1 : 0;
  315. ODWriteExitInfoPrimitive(pfDropFile,644);
  316. }
  317. fclose(pfDropFile);
  318. }
  319. }
  320. switch(od_control.od_info_type)
  321. {
  322. case DOORSYS_GAP:
  323. case DOORSYS_WILDCAT:
  324. pfDropFile=fopen(szDropFilePath,"w");
  325. if(od_control.baud==0L)
  326. {
  327. fprintf(pfDropFile,"COM0:\n");
  328. }
  329. else
  330. {
  331. fprintf(pfDropFile,"COM%d:\n",od_control.port+1);
  332. }
  333. fprintf(pfDropFile,"%s",apszDropFileInfo[0]);
  334. fprintf(pfDropFile,"%s",apszDropFileInfo[1]);
  335. fprintf(pfDropFile,"%u\n",od_control.od_node);
  336. switch(btDoorSYSLock)
  337. {
  338. case 0:
  339. fprintf(pfDropFile,"%lu\n",od_control.baud);
  340. break;
  341. case 1:
  342. fprintf(pfDropFile,"N\n");
  343. break;
  344. case 2:
  345. fprintf(pfDropFile,"Y\n");
  346. }
  347. fprintf(pfDropFile,"%s",apszDropFileInfo[3]);
  348. fprintf(pfDropFile,"%s",apszDropFileInfo[4]);
  349. fprintf(pfDropFile,"%s",apszDropFileInfo[5]);
  350. fprintf(pfDropFile,"%s",apszDropFileInfo[22]);
  351. strupr(od_control.user_name);
  352. fprintf(pfDropFile,"%s\n",od_control.user_name);
  353. fprintf(pfDropFile,"%s\n",od_control.user_location);
  354. fprintf(pfDropFile,"%s\n",od_control.user_homephone);
  355. fprintf(pfDropFile,"%s\n",od_control.user_dataphone);
  356. fprintf(pfDropFile,"%s\n",od_control.user_password);
  357. fprintf(pfDropFile,"%u\n",od_control.user_security);
  358. fprintf(pfDropFile,"%d\n",od_control.user_numcalls);
  359. fprintf(pfDropFile,"%s\n",od_control.user_lastdate);
  360. fprintf(pfDropFile,"%u\n",(signed int)od_control.user_timelimit*60);
  361. fprintf(pfDropFile,"%d\n",od_control.user_timelimit);
  362. if(od_control.user_rip)
  363. {
  364. fprintf(pfDropFile,"RIP\n");
  365. }
  366. else if(od_control.user_ansi)
  367. {
  368. fprintf(pfDropFile,"GR\n");
  369. }
  370. else
  371. {
  372. fprintf(pfDropFile,"NG\n");
  373. }
  374. fprintf(pfDropFile,"%d\n",od_control.user_screen_length);
  375. fprintf(pfDropFile,"%s",apszDropFileInfo[8]);
  376. fprintf(pfDropFile,"%s",apszDropFileInfo[9]);
  377. fprintf(pfDropFile,"%s",apszDropFileInfo[10]);
  378. fprintf(pfDropFile,"%s\n",od_control.user_subdate);
  379. fprintf(pfDropFile,"%u\n",od_control.user_num);
  380. fprintf(pfDropFile,"%s",apszDropFileInfo[6]);
  381. fprintf(pfDropFile,"%u\n",od_control.user_uploads);
  382. fprintf(pfDropFile,"%u\n",od_control.user_downloads);
  383. fprintf(pfDropFile,"%u\n",od_control.user_todayk);
  384. fprintf(pfDropFile,"%s",apszDropFileInfo[21]);
  385. if(od_control.od_info_type==DOORSYS_WILDCAT)
  386. {
  387. fprintf(pfDropFile,"%s\n",od_control.user_birthday);
  388. fprintf(pfDropFile,"%s",apszDropFileInfo[11]);
  389. fprintf(pfDropFile,"%s",apszDropFileInfo[12]);
  390. fprintf(pfDropFile,"%s\n",od_control.sysop_name);
  391. strupr(od_control.user_handle);
  392. fprintf(pfDropFile,"%s\n",od_control.user_handle);
  393. fprintf(pfDropFile,"%s\n",od_control.event_starttime);
  394. if(od_control.user_error_free)
  395. fprintf(pfDropFile,"Y\n");
  396. else
  397. fprintf(pfDropFile,"N\n");
  398. fprintf(pfDropFile,"%s",apszDropFileInfo[7]);
  399. fprintf(pfDropFile,"%s",apszDropFileInfo[13]);
  400. fprintf(pfDropFile,"%s",apszDropFileInfo[14]);
  401. fprintf(pfDropFile,"%s",apszDropFileInfo[15]);
  402. fprintf(pfDropFile,"%s",apszDropFileInfo[16]);
  403. fprintf(pfDropFile,"%s\n",od_control.user_logintime);
  404. fprintf(pfDropFile,"%s\n",od_control.user_lasttime);
  405. fprintf(pfDropFile,"%s",apszDropFileInfo[18]);
  406. fprintf(pfDropFile,"%s",apszDropFileInfo[19]);
  407. fprintf(pfDropFile,"%u\n",od_control.user_upk);
  408. fprintf(pfDropFile,"%u\n",od_control.user_downk);
  409. fprintf(pfDropFile,"%s\n",od_control.user_comment);
  410. fprintf(pfDropFile,"%s",apszDropFileInfo[20]);
  411. fprintf(pfDropFile,"%u\n",od_control.user_messages);
  412. }
  413. fclose(pfDropFile);
  414. break;
  415. case DOORSYS_DRWY:
  416. pfDropFile=fopen(szDropFilePath,"w");
  417. fprintf(pfDropFile,"%s\n",od_control.user_name);
  418. if(od_control.baud==0L)
  419. {
  420. fprintf(pfDropFile,"-1\n");
  421. }
  422. else
  423. {
  424. fprintf(pfDropFile,"%d\n",od_control.port+1);
  425. }
  426. fprintf(pfDropFile,"%lu\n",od_control.baud);
  427. fprintf(pfDropFile,"%d\n",od_control.user_timelimit);
  428. if(od_control.user_ansi)
  429. {
  430. fprintf(pfDropFile,"G\n");
  431. }
  432. else
  433. {
  434. fprintf(pfDropFile,"M\n");
  435. }
  436. fclose(pfDropFile);
  437. break;
  438. case SFDOORSDAT:
  439. pfDropFile=fopen(szDropFilePath,"w");
  440. fprintf(pfDropFile,"%u\n",od_control.user_num);
  441. fprintf(pfDropFile,"%s\n",od_control.user_name);
  442. fprintf(pfDropFile,"%s\n",od_control.user_password);
  443. fprintf(pfDropFile,"%s",apszDropFileInfo[0]);
  444. fprintf(pfDropFile,"%lu\n",od_control.baud);
  445. fprintf(pfDropFile,"%d\n",od_control.port+1);
  446. fprintf(pfDropFile,"%d\n",od_control.user_timelimit);
  447. fprintf(pfDropFile,"%s",apszDropFileInfo[13]);
  448. fprintf(pfDropFile,"%s",apszDropFileInfo[14]);
  449. if(od_control.user_ansi)
  450. {
  451. fprintf(pfDropFile,"TRUE\n");
  452. }
  453. else
  454. {
  455. fprintf(pfDropFile,"FALSE\n");
  456. }
  457. fprintf(pfDropFile,"%u\n",od_control.user_security);
  458. fprintf(pfDropFile,"%u\n",od_control.user_uploads);
  459. fprintf(pfDropFile,"%u\n",od_control.user_downloads);
  460. fprintf(pfDropFile,"%s",apszDropFileInfo[1]);
  461. fprintf(pfDropFile,"%s",apszDropFileInfo[2]);
  462. fprintf(pfDropFile,"%s",apszDropFileInfo[3]);
  463. if(od_control.sysop_next)
  464. {
  465. fprintf(pfDropFile,"TRUE\n");
  466. }
  467. else
  468. {
  469. fprintf(pfDropFile,"FALSE\n");
  470. }
  471. fprintf(pfDropFile,"%s",apszDropFileInfo[4]);
  472. fprintf(pfDropFile,"%s",apszDropFileInfo[5]);
  473. fprintf(pfDropFile,"%s",apszDropFileInfo[6]);
  474. if(od_control.user_error_free)
  475. {
  476. fprintf(pfDropFile,"TRUE\n");
  477. }
  478. else
  479. {
  480. fprintf(pfDropFile,"FALSE\n");
  481. }
  482. fprintf(pfDropFile,"%u\n",od_control.user_msg_area);
  483. fprintf(pfDropFile,"%u\n",od_control.user_file_area);
  484. fprintf(pfDropFile,"%u\n",od_control.od_node);
  485. fprintf(pfDropFile,"%s",apszDropFileInfo[10]);
  486. fprintf(pfDropFile,"%s",apszDropFileInfo[11]);
  487. fprintf(pfDropFile,"%s",apszDropFileInfo[12]);
  488. fprintf(pfDropFile,"%u\n",od_control.user_todayk);
  489. fprintf(pfDropFile,"%u\n",od_control.user_upk);
  490. fprintf(pfDropFile,"%u\n",od_control.user_downk);
  491. fprintf(pfDropFile,"%s\n",od_control.user_homephone);
  492. fprintf(pfDropFile,"%s\n",od_control.user_location);
  493. if(apszDropFileInfo[15][0]!='\0')
  494. {
  495. fprintf(pfDropFile, "%s", apszDropFileInfo[15]);
  496. fprintf(pfDropFile, od_control.user_rip ? "TRUE\n" : "FALSE\n");
  497. fprintf(pfDropFile, od_control.user_wantchat ? "TRUE\n"
  498. : "FALSE\n");
  499. fprintf(pfDropFile, "%s", apszDropFileInfo[17]);
  500. fprintf(pfDropFile, "%d\n", od_control.od_com_irq);
  501. fprintf(pfDropFile, "%d\n", od_control.od_com_address);
  502. fprintf(pfDropFile, "%s", apszDropFileInfo[18]);
  503. }
  504. fclose(pfDropFile);
  505. break;
  506. case CHAINTXT:
  507. pfDropFile=fopen(szDropFilePath,"w");
  508. fprintf(pfDropFile,"%d\n",od_control.user_num);
  509. fprintf(pfDropFile,"%s\n",od_control.user_handle);
  510. fprintf(pfDropFile,"%s\n",od_control.user_name);
  511. fprintf(pfDropFile,"%s\n",od_control.user_callsign);
  512. fprintf(pfDropFile,"%s",apszDropFileInfo[0]);
  513. fprintf(pfDropFile,"%c\n",od_control.user_sex);
  514. fprintf(pfDropFile,"%s",apszDropFileInfo[1]);
  515. fprintf(pfDropFile,"%s\n",od_control.user_lastdate);
  516. fprintf(pfDropFile,"%d\n",od_control.user_screenwidth);
  517. fprintf(pfDropFile,"%d\n",od_control.user_screen_length);
  518. fprintf(pfDropFile,"%d\n",od_control.user_security);
  519. fprintf(pfDropFile,"%d\n",bIsSysop);
  520. fprintf(pfDropFile,"%d\n",bIsCoSysop);
  521. fprintf(pfDropFile,"%d\n",od_control.user_ansi);
  522. if(od_control.baud==0L)
  523. {
  524. fprintf(pfDropFile,"0\n");
  525. }
  526. else
  527. {
  528. fprintf(pfDropFile,"1\n");
  529. }
  530. fprintf(pfDropFile," %d.00\n",od_control.user_timelimit*60);
  531. fprintf(pfDropFile,"%s",apszDropFileInfo[3]);
  532. fprintf(pfDropFile,"%s",apszDropFileInfo[4]);
  533. fprintf(pfDropFile,"%s",apszDropFileInfo[5]);
  534. if(od_control.baud==0L)
  535. {
  536. fprintf(pfDropFile,"KB\n");
  537. }
  538. else
  539. {
  540. fprintf(pfDropFile,"%lu\n",od_control.baud);
  541. }
  542. fprintf(pfDropFile,"%d\n",od_control.port+1);
  543. fprintf(pfDropFile,"%s",apszDropFileInfo[6]);
  544. fprintf(pfDropFile,"%s\n",od_control.user_password);
  545. fprintf(pfDropFile,"%s",apszDropFileInfo[2]);
  546. fprintf(pfDropFile,"%s",apszDropFileInfo[7]);
  547. fprintf(pfDropFile,"%s",apszDropFileInfo[8]);
  548. fprintf(pfDropFile,"%s",apszDropFileInfo[9]);
  549. fprintf(pfDropFile,"%s",apszDropFileInfo[10]);
  550. fprintf(pfDropFile,"%s",apszDropFileInfo[11]);
  551. fprintf(pfDropFile,"%s",apszDropFileInfo[12]);
  552. fclose(pfDropFile);
  553. break;
  554. case TRIBBSSYS:
  555. pfDropFile = fopen(szDropFilePath, "w");
  556. fprintf(pfDropFile, "%u\n", od_control.user_num);
  557. fprintf(pfDropFile, "%s\n", od_control.user_name);
  558. fprintf(pfDropFile, "%s\n", od_control.user_password);
  559. fprintf(pfDropFile, "%u\n", od_control.user_security);
  560. fprintf(pfDropFile, "%c\n", od_control.user_expert ? 'Y' : 'N');
  561. fprintf(pfDropFile, "%c\n", od_control.user_ansi ? 'Y' : 'N');
  562. fprintf(pfDropFile, "%d\n", od_control.user_timelimit);
  563. fprintf(pfDropFile, "%s\n", od_control.user_homephone);
  564. fprintf(pfDropFile, "%s\n", od_control.user_location);
  565. od_control.user_birthday[2] = '/';
  566. od_control.user_birthday[5] = '/';
  567. fprintf(pfDropFile, "%s\n", od_control.user_birthday);
  568. fprintf(pfDropFile, "%d\n", od_control.od_node);
  569. fprintf(pfDropFile, "%d\n", od_control.port + 1);
  570. fprintf(pfDropFile, "%lu\n", od_control.od_connect_speed);
  571. fprintf(pfDropFile, "%lu\n", od_control.baud);
  572. fprintf(pfDropFile, "%c\n", (od_control.od_com_flow_control
  573. == COM_RTSCTS_FLOW) ? 'Y' : 'N');
  574. fprintf(pfDropFile, "%c\n", od_control.user_error_free ? 'Y' : 'N');
  575. fprintf(pfDropFile, "%s\n", od_control.system_name);
  576. fprintf(pfDropFile, "%s\n", od_control.sysop_name);
  577. fprintf(pfDropFile, "%s\n", od_control.user_handle);
  578. fprintf(pfDropFile, "%c\n", od_control.user_rip ? 'Y' : 'N');
  579. fclose(pfDropFile);
  580. break;
  581. }
  582. /* Deallocate temorary strings. */
  583. for(btCount=0;btCount<25;++btCount)
  584. {
  585. free(apszDropFileInfo[btCount]);
  586. }
  587. /* If logfile system is active. */
  588. if(pfLogClose != NULL)
  589. {
  590. /* Then close the logfile. */
  591. (*pfLogClose)(nErrorLevel);
  592. }
  593. /* Disconnect the remote user if required. */
  594. if(od_control.baud && bTermCall)
  595. {
  596. BOOL bCarrier;
  597. /* Wait up to ten seconds for bufffer to drain. */
  598. ODWaitDrain(10000);
  599. /* Wait up to five seconds for no carrier */
  600. ODComSetDTR(hSerialPort, FALSE);
  601. nMaxTime = time(NULL) + 5L;
  602. do
  603. {
  604. ODComCarrier(hSerialPort, &bCarrier);
  605. } while(bCarrier && time(NULL) <= nMaxTime);
  606. /* Raise DTR signal again. */
  607. ODComSetDTR(hSerialPort, TRUE);
  608. }
  609. /* In Win32 version, disable DTR before closing serial port, if */
  610. /* required. */
  611. #ifdef ODPLAT_WIN32
  612. /* If we are operating in remote mode, and we should not hangup on the */
  613. /* caller ... */
  614. if(!bTermCall && od_control.baud)
  615. {
  616. ODInExDisableDTR();
  617. }
  618. #endif /* ODPLAT_WIN32 */
  619. /* Remove the message that indicates we are in the process of exiting */
  620. /* or hanging up. */
  621. ODScrnRemoveMessage(pWindow);
  622. #ifndef ODPLAT_WIN32
  623. /* Reset output area boundary to the entire screen. */
  624. ODScrnSetBoundary(1,1,80,25);
  625. /* Reset text color. */
  626. ODScrnSetAttribute(0x07);
  627. /* Clear screen if neccesary. */
  628. if(od_control.od_clear_on_exit)
  629. {
  630. ODScrnClear();
  631. }
  632. else
  633. {
  634. ODScrnSetCursorPos(1, 1);
  635. }
  636. #endif /* !ODPLAT_WIN32 */
  637. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  638. if(od_control.od_internal_debug)
  639. {
  640. MessageBox(NULL, "Terminating kernel threads", "OpenDoors Diagnostics",
  641. MB_OK);
  642. }
  643. #endif
  644. /* Shutdown the OpenDoors kernel. */
  645. ODKrnlShutdown();
  646. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  647. if(od_control.od_internal_debug)
  648. {
  649. MessageBox(NULL, "Shutting down local screen", "OpenDoors Diagnostics",
  650. MB_OK);
  651. }
  652. #endif
  653. /* Shutdown OpenDoors local screen module. */
  654. ODScrnShutdown();
  655. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  656. if(od_control.od_internal_debug)
  657. {
  658. MessageBox(NULL, "Performing any final serial port deallocation",
  659. "OpenDoors Diagnostics", MB_OK);
  660. }
  661. #endif
  662. /* If not operating in local mode, then deallocate serial port resources. */
  663. if(od_control.baud != 0)
  664. {
  665. /* Close serial port. */
  666. ODComClose(hSerialPort);
  667. /* Deallocate serial port object. */
  668. ODComFree(hSerialPort);
  669. }
  670. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  671. if(od_control.od_internal_debug)
  672. {
  673. MessageBox(NULL, "Deallocating common queue", "OpenDoors Diagnostics",
  674. MB_OK);
  675. }
  676. #endif
  677. /* Deallocate input buffer. */
  678. ODInQueueFree(hODInputQueue);
  679. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  680. if(od_control.od_internal_debug)
  681. {
  682. MessageBox(NULL, "Going to inactive mode", "OpenDoors Diagnostics",
  683. MB_OK);
  684. }
  685. #endif
  686. /* OpenDoors is no longer active. */
  687. bODInitialized = FALSE;
  688. /* od_exit() is no longer active. */
  689. bExiting = FALSE;
  690. /* If the client does not want a call to od_exit() to shutdown the */
  691. /* application, but just to shutdown OpenDoors, then return now. */
  692. if(od_control.od_noexit) return;
  693. /* If exit() has already been called, then do not call it again. */
  694. if(bPreOrExit) return;
  695. #if defined(OD_DIAGNOSTICS) && defined(ODPLAT_WIN32)
  696. if(od_control.od_internal_debug)
  697. {
  698. MessageBox(NULL, "Terminating process", "OpenDoors Diagnostics", MB_OK);
  699. }
  700. #endif
  701. /* Exit with appropriate errorlevel. */
  702. ODProcessExit(nErrorLevel);
  703. }
  704. /* ----------------------------------------------------------------------------
  705. * ODSearchForDropFile()
  706. *
  707. * Searches for a door information (drop) file, given a list of possible drop
  708. * file names. Searches for the drop file first in the directory specified
  709. * by od_control.info_path. If a directory was specified in the configuration
  710. * file, this is where that directory name would be stored. This function will
  711. * then proceed to search the current directory and any directories specified
  712. * by recognized environment variables, until either a drop file is found, or
  713. * until all possibilities are exhaused.
  714. *
  715. * If a directory contains more than one supported dropfile, the choice of
  716. * drop files is narrowed to the most recently written file, and any files
  717. * written in the ten seconds before that file was written. Of these files,
  718. * the file with the highest priority (based on its position in the list of
  719. * possible drop file names) is selected. This heuristic attempts to ignore
  720. * any "old" drop files that may still be hanging around from another
  721. * program or another login session, while still choosing the file with the
  722. * most information.
  723. *
  724. * Parameters: papszFileNames - Array of possible drop file names.
  725. *
  726. * nNumFilesNames - The number of names in papszFileNames.
  727. *
  728. * pszFound - If a drop file was found, this string
  729. * will be changed to point to the filename
  730. * of the file that was found.
  731. *
  732. * pszDirectory - If a drop file was found, this string
  733. * will be changed to contain the name of
  734. * the directory in which the file was found.
  735. *
  736. * Return: Index in the array of the file that was found, or -1 if no
  737. * potential drop file was found.
  738. */
  739. INT ODSearchForDropFile(char **papszFileNames, INT nNumFileNames,
  740. char *pszFound, char *pszDirectory)
  741. {
  742. BYTE btCount;
  743. char *pszEnvVarSetting;
  744. INT nResult;
  745. ASSERT(papszFileNames != NULL);
  746. ASSERT(nNumFileNames > 0);
  747. ASSERT(pszFound != NULL);
  748. /* First, look for the drop file(s) in the directory specified by */
  749. /* od_control.info_path. */
  750. if(strlen(od_control.info_path) != 0)
  751. {
  752. if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound,
  753. od_control.info_path)) != -1)
  754. {
  755. if(pszDirectory != NULL) strcpy(pszDirectory, od_control.info_path);
  756. return(nResult);
  757. }
  758. }
  759. /* Next, look for the drop file(s) in the current directory. */
  760. if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound,
  761. "."DIRSEP_STR)) != -1)
  762. {
  763. if(pszDirectory != NULL) strcpy(pszDirectory, "."DIRSEP_STR);
  764. return(nResult);
  765. }
  766. /* Look through array of environment variables, checking whether any of */
  767. /* them specify the name of a directory in which a drop file can be */
  768. /* found. */
  769. ASSERT(DIM(apszEnvVarNames) == NUM_DIR_ENV_VARS);
  770. for(btCount = 0; btCount < NUM_DIR_ENV_VARS; ++btCount)
  771. {
  772. if((pszEnvVarSetting = (char *)getenv(apszEnvVarNames[btCount])) != NULL)
  773. {
  774. if((nResult = ODSearchInDir(papszFileNames, nNumFileNames, pszFound,
  775. pszEnvVarSetting)) != -1)
  776. {
  777. if(pszDirectory != NULL) strcpy(pszDirectory,pszEnvVarSetting);
  778. return(nResult);
  779. }
  780. }
  781. }
  782. return(-1);
  783. }
  784. /* ----------------------------------------------------------------------------
  785. * ODSearchInDir() *** PRIVATE FUNCTION ***
  786. *
  787. * Private helper function used by ODSearchForDropFile(). Searches for a drop
  788. * file in a single specified directory. The heuristic for selecting a drop
  789. * file, if more than one exists, is described in the header for the
  790. * ODSearchForDropFile() function.
  791. *
  792. * Parameters: papszFileNames - Array of possible drop file names.
  793. *
  794. * nNumFilesNames - The number of names in papszFileNames.
  795. *
  796. * pszFound - If a drop file was found, this string
  797. * will be changed to point to the filename
  798. * of the file that was found.
  799. *
  800. * pszDirectory - Name of the directory to search in.
  801. *
  802. * Return: Index in the array of the file that was found, or -1 if no
  803. * potential drop file was found.
  804. */
  805. static INT ODSearchInDir(char **papszFileNames, INT nNumFileNames,
  806. char *pszFound, char *pszDirectory)
  807. {
  808. BYTE btCount;
  809. char szFullName[80];
  810. INT nFound = -1;
  811. tODDirHandle hDir;
  812. tODDirEntry DirEntry;
  813. time_t LatestTime = 0;
  814. ASSERT(papszFileNames != NULL);
  815. ASSERT(nNumFileNames > 0);
  816. ASSERT(pszFound != NULL);
  817. ASSERT(pszDirectory != NULL);
  818. for(btCount=0; btCount < nNumFileNames; ++btCount)
  819. {
  820. /* Do not consider DORINFO1.DEF if a DORINFOx.DEF for this node has */
  821. /* been found. */
  822. if(btCount == 2 && nFound == 1)
  823. {
  824. continue;
  825. }
  826. ASSERT(papszFileNames[btCount] != NULL);
  827. ODMakeFilename(szFullName, pszDirectory, (char *)papszFileNames[btCount],
  828. sizeof(szFullName));
  829. /* Attempt to open directory. */
  830. if(ODDirOpen(szFullName, DIR_ATTRIB_NORMAL | DIR_ATTRIB_ARCH, &hDir)
  831. == kODRCSuccess)
  832. {
  833. /* Read the first matching entry in the directory. */
  834. ODDirRead(hDir, &DirEntry);
  835. if(nFound == -1
  836. || DirEntry.LastWriteTime > LatestTime + DROPFILE_TIME_LEEWAY)
  837. {
  838. if(!ODFileAccessMode(szFullName, 4))
  839. {
  840. nFound=btCount;
  841. LatestTime = DirEntry.LastWriteTime;
  842. }
  843. }
  844. /* Close the open directory. */
  845. ODDirClose(hDir);
  846. }
  847. }
  848. if(nFound != -1)
  849. {
  850. ODMakeFilename(pszFound, pszDirectory, (char *)papszFileNames[nFound],
  851. 160);
  852. }
  853. return(nFound);
  854. }
  855. /* ----------------------------------------------------------------------------
  856. * ODReadExitInfoPrimitive()
  857. *
  858. * Reads the core a of pre-RA2 style EXITINFO.BBS file.
  859. *
  860. * Parameters: pfDropFile - Pointer to already open EXITINFO.BBS file.
  861. *
  862. * nCount - Specifies the number of bytes to read.
  863. *
  864. * Return: TRUE on success, or FALSE on failure.
  865. */
  866. BOOL ODReadExitInfoPrimitive(FILE *pfDropFile, INT nCount)
  867. {
  868. if((pExitInfoRecord=malloc(sizeof(tExitInfoRecord)))==NULL) return(FALSE);
  869. if(fread(pExitInfoRecord,1,nCount,pfDropFile)!=(size_t)nCount)
  870. {
  871. return(FALSE);
  872. }
  873. /* now we read all the data from the */
  874. /* EXITINFO structure to the OpenDoors */
  875. /* control structure. This may look */
  876. /* a bit messy, but it gets the job */
  877. /* done, and allows the programmer */
  878. /* to access all the strings in C */
  879. /* format instead of Pascal */
  880. od_control.baud=pExitInfoRecord->baud;
  881. od_control.system_calls=pExitInfoRecord->num_calls;
  882. ODStringPascalToC(od_control.system_last_caller,pExitInfoRecord->last_caller,35);
  883. ODStringPascalToC(od_control.timelog_start_date,pExitInfoRecord->start_date,8);
  884. memcpy(&od_control.timelog_busyperhour,&pExitInfoRecord->busyperhour,62);
  885. ODStringPascalToC(od_control.user_name,pExitInfoRecord->uname,35);
  886. ODStringPascalToC(od_control.user_location,pExitInfoRecord->uloc,25);
  887. ODStringPascalToC(od_control.user_password,pExitInfoRecord->password,15);
  888. ODStringPascalToC(od_control.user_dataphone,pExitInfoRecord->dataphone,12);
  889. ODStringPascalToC(od_control.user_homephone,pExitInfoRecord->homephone,12);
  890. ODStringPascalToC(od_control.user_lasttime,pExitInfoRecord->lasttime,5);
  891. ODStringPascalToC(od_control.user_lastdate,pExitInfoRecord->lastdate,8);
  892. memcpy(&od_control.user_attribute,&pExitInfoRecord->attrib,5);
  893. od_control.user_net_credit=pExitInfoRecord->credit;
  894. od_control.user_pending=pExitInfoRecord->pending;
  895. od_control.user_messages=pExitInfoRecord->posted;
  896. od_control.user_lastread=pExitInfoRecord->lastread;
  897. od_control.user_security=pExitInfoRecord->sec;
  898. od_control.user_numcalls=pExitInfoRecord->nocalls;
  899. od_control.user_uploads=pExitInfoRecord->ups;
  900. od_control.user_downloads=pExitInfoRecord->downs;
  901. od_control.user_upk=pExitInfoRecord->upk;
  902. od_control.user_downk=pExitInfoRecord->downk;
  903. od_control.user_todayk=pExitInfoRecord->todayk;
  904. memcpy(&od_control.user_time_used,&pExitInfoRecord->elapsed,6);
  905. od_control.user_group=pExitInfoRecord->group;
  906. od_control.user_xi_record=pExitInfoRecord->xirecord;
  907. od_control.event_status=pExitInfoRecord->status;
  908. ODStringPascalToC(od_control.event_starttime,pExitInfoRecord->starttime,5);
  909. memcpy(&od_control.event_errorlevel,&pExitInfoRecord->errorlevel,3);
  910. ODStringPascalToC(od_control.event_last_run,pExitInfoRecord->lasttimerun,8);
  911. memcpy(&od_control.user_netmailentered,&pExitInfoRecord->netmailentered,2);
  912. ODStringPascalToC(od_control.user_logintime,pExitInfoRecord->logintime,5);
  913. ODStringPascalToC(od_control.user_logindate,pExitInfoRecord->logindate,8);
  914. /* Note that the timelimit field is skipped here. This value has already */
  915. /* been read from the DORINFOx.DEF file, and is not consistently written */
  916. /* to the EXITINFO.BBS file by various BBS packages. */
  917. memcpy(&od_control.user_loginsec,&pExitInfoRecord->loginsec,16);
  918. od_control.user_ansi=od_control.user_attribute&8;
  919. od_control.user_avatar=od_control.user_attrib2&2;
  920. return(TRUE);
  921. }
  922. /* ----------------------------------------------------------------------------
  923. * ODWriteExitInfoPrimitive()
  924. *
  925. * Writes the core a of pre-RA2 style EXITINFO.BBS file.
  926. *
  927. * Parameters: pfDropFile - Pointer to already open EXITINFO.BBS file.
  928. *
  929. * nCount - Number of bytes to be written.
  930. *
  931. * Return: Number of bytes actually written.
  932. */
  933. INT ODWriteExitInfoPrimitive(FILE *pfDropFile, INT nCount)
  934. {
  935. INT nToReturn;
  936. DWORD dwActiveMinutes;
  937. INT nUserTimeLost;
  938. INT nTimeSubtractedBySysop;
  939. time_t nCurrentUnixTime;
  940. pExitInfoRecord->num_calls=od_control.system_calls;
  941. ODStringCToPascal(pExitInfoRecord->last_caller,35,od_control.system_last_caller);
  942. ODStringCToPascal(pExitInfoRecord->start_date,8,od_control.timelog_start_date);
  943. memcpy(&pExitInfoRecord->busyperhour,&od_control.timelog_busyperhour,31);
  944. ODStringCToPascal(pExitInfoRecord->uname,35,od_control.user_name);
  945. ODStringCToPascal(pExitInfoRecord->uloc,25,od_control.user_location);
  946. ODStringCToPascal(pExitInfoRecord->password,15,od_control.user_password);
  947. ODStringCToPascal(pExitInfoRecord->dataphone,12,od_control.user_dataphone);
  948. ODStringCToPascal(pExitInfoRecord->homephone,12,od_control.user_homephone);
  949. ODStringCToPascal(pExitInfoRecord->lasttime,5,od_control.user_lasttime);
  950. ODStringCToPascal(pExitInfoRecord->lastdate,8,od_control.user_lastdate);
  951. memcpy(&pExitInfoRecord->attrib,&od_control.user_attribute,5);
  952. pExitInfoRecord->credit=(WORD)od_control.user_net_credit;
  953. pExitInfoRecord->pending=(WORD)od_control.user_pending;
  954. pExitInfoRecord->posted=(WORD)od_control.user_messages;
  955. pExitInfoRecord->lastread=(WORD)od_control.user_lastread;
  956. pExitInfoRecord->sec=(WORD)od_control.user_security;
  957. pExitInfoRecord->nocalls=(WORD)od_control.user_numcalls;
  958. pExitInfoRecord->ups=(WORD)od_control.user_uploads;
  959. pExitInfoRecord->downs=(WORD)od_control.user_downloads;
  960. pExitInfoRecord->upk=(WORD)od_control.user_upk;
  961. pExitInfoRecord->downk=(WORD)od_control.user_downk;
  962. pExitInfoRecord->todayk=(WORD)od_control.user_todayk;
  963. memcpy(&pExitInfoRecord->elapsed,&od_control.user_time_used,6);
  964. pExitInfoRecord->group = (BYTE)od_control.user_group;
  965. pExitInfoRecord->xirecord=(WORD)od_control.user_xi_record;
  966. pExitInfoRecord->status=od_control.event_status;
  967. pExitInfoRecord->status=od_control.event_status;
  968. ODStringCToPascal(pExitInfoRecord->starttime,5,od_control.event_starttime);
  969. memcpy(&pExitInfoRecord->errorlevel,&od_control.event_errorlevel,3);
  970. ODStringCToPascal(pExitInfoRecord->lasttimerun,8,od_control.event_last_run);
  971. memcpy(&pExitInfoRecord->netmailentered,&od_control.user_netmailentered,2);
  972. ODStringCToPascal(pExitInfoRecord->logintime,5,od_control.user_logintime);
  973. ODStringCToPascal(pExitInfoRecord->logindate,8,od_control.user_logindate);
  974. /* Calculate new time limit based on how time was adjusted during door's */
  975. /* execution. */
  976. time(&nCurrentUnixTime);
  977. ODDWordDivide(&dwActiveMinutes, NULL, nCurrentUnixTime-nStartupUnixTime, 60L);
  978. nUserTimeLost = (nInitialRemaining - od_control.user_timelimit);
  979. nTimeSubtractedBySysop = nUserTimeLost - (int)dwActiveMinutes;
  980. pExitInfoRecord->timelimit -= nTimeSubtractedBySysop;
  981. memcpy(&pExitInfoRecord->loginsec,&od_control.user_loginsec,16);
  982. nToReturn=(fwrite(pExitInfoRecord,1,nCount,pfDropFile) == (size_t)nCount);
  983. free(pExitInfoRecord);
  984. return(nToReturn);
  985. }
  986. /* ----------------------------------------------------------------------------
  987. * ODAtExitCallback()
  988. *
  989. * OpenDoors sets up the C library to call back this function when the program
  990. * is about to exit. OpenDoors uses this function to attempt to trap the
  991. * condition where the programmer exits the program without explicitly calling
  992. * od_exit(). If the program is about to exit, and OpenDoors is still active,
  993. * then od_exit() is called.
  994. *
  995. * It is not recommended that the programmer using OpenDoors rely on this
  996. * mechanism, because:
  997. *
  998. * 1. It doesn't seem to be supported by all compilers.
  999. *
  1000. * 2. It doesn't permit OpenDoors to determine the actual error level
  1001. * that the program is exiting with in order to report this information
  1002. * in the log file (if enabled).
  1003. *
  1004. * Parameters: none
  1005. *
  1006. * Return: void
  1007. */
  1008. #ifndef ODPLAT_WIN32
  1009. void ODAtExitCallback(void)
  1010. {
  1011. if(bODInitialized)
  1012. {
  1013. bPreOrExit = TRUE;
  1014. if(od_control.od_errorlevel[0])
  1015. {
  1016. od_exit(od_control.od_errorlevel[7],FALSE);
  1017. }
  1018. else
  1019. {
  1020. od_exit(6,FALSE);
  1021. }
  1022. }
  1023. }
  1024. #endif /* !ODPLAT_WIN32 */
  1025. /* Currently, these functions are only used in the Win32 version. */
  1026. #ifdef ODPLAT_WIN32
  1027. /* ----------------------------------------------------------------------------
  1028. * ODSendModemCommand() *** PRIVATE FUNCTION ***
  1029. *
  1030. * Sends a sequence of commands to the modem, waiting for the specified
  1031. * response between each command. The command sequence is retried the specified
  1032. * number of times.
  1033. *
  1034. * Parameters: pszCommand - Command string to send to the modem, along with
  1035. * response strings. Each of these are separated by
  1036. * a space character. A pipe character ('|') denotes a
  1037. * CR, and a tilde character ('~') denotes a one
  1038. * second pause.
  1039. *
  1040. * nRetries - Number of times to retry command sequence.
  1041. *
  1042. * Return: TRUE on success, or FALSE if some expected response string was
  1043. * not received from the modem after modem response timeout period.
  1044. */
  1045. static BOOL ODSendModemCommand(char *pszCommand, int nRetries)
  1046. {
  1047. ASSERT(pszCommand != NULL);
  1048. ASSERT(nRetries >= 1);
  1049. while(nRetries--)
  1050. {
  1051. if(ODSendModemCommandOnce(pszCommand))
  1052. {
  1053. return(TRUE);
  1054. }
  1055. }
  1056. return(FALSE);
  1057. }
  1058. /* ----------------------------------------------------------------------------
  1059. * ODSendModemCommandOnce() *** PRIVATE FUNCTION ***
  1060. *
  1061. * Sends a series of commands to the modem, waiting for the specified response
  1062. * between each command.
  1063. *
  1064. * Parameters: pszCommand - Command string to send to the modem, along with
  1065. * response strings. Each of these are separated by
  1066. * a space character. A pipe character ('|') denotes a
  1067. * CR, and a tilde character ('~') denotes a one
  1068. * second pause.
  1069. *
  1070. * Return: TRUE on success, or FALSE if some expected response string was
  1071. * not received from the modem after modem response timeout period.
  1072. */
  1073. static BOOL ODSendModemCommandOnce(char *pszCommand)
  1074. {
  1075. char *pchCurrent;
  1076. char szResponse[MAX_RESPONSE_LEN + 1];
  1077. int nResponsePos;
  1078. BOOL bSendingCommand = TRUE;
  1079. ASSERT(pszCommand != NULL);
  1080. /* We must be operating in remote mode. */
  1081. ASSERT(od_control.baud != 0);
  1082. /* Loop through each character in the string. */
  1083. for(pchCurrent = pszCommand; *pchCurrent != '\0'; ++pchCurrent)
  1084. {
  1085. /* What we do with this character depends upon whether we are */
  1086. /* currently sending a command, or waiting for a response. */
  1087. if(bSendingCommand)
  1088. {
  1089. switch(*pchCurrent)
  1090. {
  1091. case ' ':
  1092. /* A space character denotes that we should toggle between */
  1093. /* sending a command and receiving a response. */
  1094. bSendingCommand = FALSE;
  1095. /* Start at the beginning of the empty response string. */
  1096. nResponsePos = 0;
  1097. szResponse[0] = '\0';
  1098. break;
  1099. case '|':
  1100. /* A pipe character denotes that a carriage return should be */
  1101. /* send to the modem. */
  1102. ODComSendByte(hSerialPort, '\r');
  1103. #ifdef OD_DIAGNOSTICS
  1104. strcat(szDebugWorkString, "\n");
  1105. #endif /* OD_DIAGNOSTICS */
  1106. break;
  1107. case '~':
  1108. /* A tilde character denotes a 1 second pause. */
  1109. od_sleep(1000);
  1110. break;
  1111. default:
  1112. /* Otherwise, send this character as is. */
  1113. ODComSendByte(hSerialPort, *pchCurrent);
  1114. #ifdef OD_DIAGNOSTICS
  1115. {
  1116. char szAppend[2];
  1117. szAppend[0] = *pchCurrent;
  1118. szAppend[1] = 0;
  1119. strcat(szDebugWorkString, szAppend);
  1120. }
  1121. #endif /* OD_DIAGNOSTICS */
  1122. }
  1123. od_sleep(200);
  1124. }
  1125. else
  1126. {
  1127. /* We are currently building a string that we should wait for. */
  1128. switch(*pchCurrent)
  1129. {
  1130. case ' ':
  1131. /* A space character denotes that we should toggle between */
  1132. /* sending a command and receiving a response. */
  1133. /* Wait until the response string we have built is received. */
  1134. if(!ODWaitForString(szResponse, RESPONSE_TIMEOUT))
  1135. {
  1136. /* If string was not received, then return now. */
  1137. return(FALSE);
  1138. }
  1139. /* Switch to sending command mode. */
  1140. bSendingCommand = TRUE;
  1141. break;
  1142. case '~':
  1143. /* Pauses are ignored in response strings. */
  1144. break;
  1145. default:
  1146. /* Otherwise, add this character to the response string. */
  1147. if(nResponsePos < MAX_RESPONSE_LEN)
  1148. {
  1149. szResponse[nResponsePos] = *pchCurrent;
  1150. ++nResponsePos;
  1151. szResponse[nResponsePos] = '\0';
  1152. }
  1153. }
  1154. }
  1155. }
  1156. /* Return with success. */
  1157. return(TRUE);
  1158. }
  1159. /* ----------------------------------------------------------------------------
  1160. * ODWaitForString() *** PRIVATE FUNCTION ***
  1161. *
  1162. * Waits for the specified string to be received from the modem, for up to
  1163. * the specified length of time.
  1164. *
  1165. * Parameters: pszResponse - Pointer to the string to wait for.
  1166. *
  1167. * ResponseTimeout - The maximum time, in milliseconds, to wait.
  1168. *
  1169. * Return: TRUE on success, or FALSE if some expected response string was
  1170. * not received from the modem after modem response timeout period.
  1171. */
  1172. static BOOL ODWaitForString(char *pszResponse, tODMilliSec ResponseTimeout)
  1173. {
  1174. tODTimer Timer;
  1175. char szReceived[MAX_RESPONSE_LEN + 1] = "\0";
  1176. tODInputEvent InputEvent;
  1177. ASSERT(pszResponse != NULL);
  1178. ASSERT(ResponseTimeout > 0);
  1179. /* We must be operating in remote mode. */
  1180. ASSERT(od_control.baud != 0);
  1181. /* If response string is empty, then we don't wait for anything. */
  1182. if(strlen(pszResponse) == 0) return(TRUE);
  1183. #ifdef OD_DIAGNOSTICS
  1184. strcat(szDebugWorkString, "[");
  1185. #endif /* OD_DIAGNOSTICS */
  1186. ODTimerStart(&Timer, ResponseTimeout);
  1187. while(!ODTimerElapsed(&Timer))
  1188. {
  1189. if(ODInQueueGetNextEvent(hODInputQueue, &InputEvent,
  1190. ODTimerLeft(&Timer)) == kODRCSuccess)
  1191. {
  1192. if(InputEvent.bFromRemote && InputEvent.EventType == EVENT_CHARACTER)
  1193. {
  1194. #ifdef OD_DIAGNOSTICS
  1195. {
  1196. char szAppend[2];
  1197. szAppend[0] = InputEvent.chKeyPress;
  1198. szAppend[1] = 0;
  1199. strcat(szDebugWorkString, szAppend);
  1200. }
  1201. #endif /* OD_DIAGNOSTICS */
  1202. /* Add the received character to the received string. */
  1203. if(strlen(szReceived) == MAX_RESPONSE_LEN)
  1204. {
  1205. memmove(szReceived, szReceived + 1, MAX_RESPONSE_LEN);
  1206. }
  1207. szReceived[strlen(szReceived) + 1] = '\0';
  1208. szReceived[strlen(szReceived)] = InputEvent.chKeyPress;
  1209. /* If the sequence has been received, then return with success. */
  1210. if(strstr(szReceived, pszResponse) != NULL)
  1211. {
  1212. #ifdef OD_DIAGNOSTICS
  1213. strcat(szDebugWorkString, "]");
  1214. #endif /* OD_DIAGNOSTICS */
  1215. return(TRUE);
  1216. }
  1217. }
  1218. }
  1219. else
  1220. {
  1221. /* When no characters are waiting, allow other processes to run. */
  1222. od_sleep(0);
  1223. }
  1224. }
  1225. #ifdef OD_DIAGNOSTICS
  1226. strcat(szDebugWorkString, "]");
  1227. #endif OD_DIAGNOSTICS
  1228. /* Indicate that string was not received in the time alotted. */
  1229. return(FALSE);
  1230. }
  1231. /* ----------------------------------------------------------------------------
  1232. * ODInExDisableDTR()
  1233. *
  1234. * Disables DTR response by the modem, if required.
  1235. *
  1236. * Parameters: None
  1237. *
  1238. * Return: void
  1239. */
  1240. void ODInExDisableDTR(void)
  1241. {
  1242. BOOL bCarrier;
  1243. /* If we are using the Door32 interface, then do not disable DTR. */
  1244. if(od_control.od_com_method == COM_DOOR32 || od_control.od_com_method == COM_SOCKET)
  1245. {
  1246. return;
  1247. }
  1248. /* Check that carrier detect signal is still present. */
  1249. ODComCarrier(hSerialPort, &bCarrier);
  1250. if(bCarrier)
  1251. {
  1252. /* Only disable DTR response if OpenDoors opened the serial port, */
  1253. /* and DTR disabling has not been explicitly turned off. */
  1254. if(od_control.od_open_handle == 0
  1255. && !(od_control.od_disable & DIS_DTR_DISABLE))
  1256. {
  1257. if(!ODSendModemCommand(od_control.od_disable_dtr, 2))
  1258. {
  1259. #ifdef OD_DIAGNOSTICS
  1260. if(od_control.od_internal_debug)
  1261. {
  1262. MessageBox(NULL, szDebugWorkString, "DTR Disable FAILED!",
  1263. MB_OK);
  1264. szDebugWorkString[0] = '\0';
  1265. }
  1266. #endif /* OD_DIAGNOSTICS */
  1267. }
  1268. else
  1269. {
  1270. #ifdef OD_DIAGNOSTICS
  1271. if(od_control.od_internal_debug)
  1272. {
  1273. MessageBox(NULL, szDebugWorkString, "DTR Disable Succeeded!",
  1274. MB_OK);
  1275. szDebugWorkString[0] = '\0';
  1276. }
  1277. #endif /* OD_DIAGNOSTICS */
  1278. }
  1279. }
  1280. }
  1281. }
  1282. #endif /* ODPLAT_WIN32 */