ODCore.c 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620
  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: ODCore.c
  22. *
  23. * Description: Implements the core of OpenDoors, including chat mode
  24. * and standard input/output functions that are
  25. * used throughout OpenDoors.
  26. *
  27. * Revisions: Date Ver Who Change
  28. * ---------------------------------------------------------------
  29. * Oct 13, 1994 6.00 BP New file header format.
  30. * Oct 19, 1994 6.00 BP Changed paging hours logic.
  31. * Oct 21, 1994 6.00 BP Further isolated com routines.
  32. * Oct 22, 1994 6.00 BP Name case conversion /w punct.
  33. * Dec 08, 1994 6.00 BP Allow custom chat mode deactivation.
  34. * Dec 09, 1994 6.00 BP Remove global dir entry structure.
  35. * Dec 13, 1994 6.00 BP Remove include of dir.h.
  36. * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
  37. * Dec 31, 1994 6.00 BP Remove old multitasker definitions.
  38. * Jan 01, 1995 6.00 BP Don't use ODComInbound().
  39. * Jan 01, 1995 6.00 BP _waitdrain() -> ODWaitDrain().
  40. * Jan 01, 1995 6.00 BP Use new millisecond timer functions.
  41. * Jan 01, 1995 6.00 BP Remove od_init() from _remotechar()
  42. * Jan 01, 1995 6.00 BP Split off odkrnl.c from odcore.c
  43. * Aug 19, 1995 6.00 BP 32-bit portability.
  44. * Nov 11, 1995 6.00 BP Moved first_word() to odlist.c
  45. * Nov 11, 1995 6.00 BP Removed register keyword.
  46. * Nov 14, 1995 6.00 BP Added include of odscrn.h.
  47. * Nov 16, 1995 6.00 BP Create odcore.h.
  48. * Nov 17, 1995 6.00 BP Use new input queue mechanism.
  49. * Dec 12, 1995 6.00 BP Added od_set_color().
  50. * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
  51. * Dec 13, 1995 6.00 BP Moved chat mode code to ODKrnl.h.
  52. * Dec 19, 1995 6.00 BP Request reason for chat outside hours.
  53. * Dec 23, 1995 6.00 BP Allow space to continue at page pause.
  54. * Dec 24, 1995 6.00 BP Added abtGreyBlock.
  55. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  56. * Jan 03, 1996 6.00 BP Use OD_API_VAR_DEFN for od_control.
  57. * Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent.
  58. * Jan 23, 1996 6.00 BP No od_set_statusline() under Win32.
  59. * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
  60. * Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout.
  61. * Jan 09, 1996 6.00 BP ODComOutbound() returns actual size.
  62. * Jan 09, 1996 6.00 BP Reduce kernel calls from od_disp...().
  63. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  64. * Mar 03, 1996 6.10 BP Begin version 6.10.
  65. * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
  66. * Mar 21, 1996 6.10 BP Added od_control_get().
  67. * Sep 01, 1996 6.10 BP Update output area on od_set_per...().
  68. * Oct 19, 2001 6.20 RS od_get_key now ignores linefeeds.
  69. * Mar 14, 2002 6.22 RS Fixed od_get_key(bWait=FALSE)
  70. * Aug 10, 2003 6.23 SH *nix support
  71. */
  72. #define BUILDING_OPENDOORS
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include <ctype.h>
  77. #include <time.h>
  78. #include <errno.h>
  79. #include "OpenDoor.h"
  80. #include "ODStr.h"
  81. #include "ODGen.h"
  82. #include "ODPlat.h"
  83. #include "ODCom.h"
  84. #include "ODKrnl.h"
  85. #include "ODScrn.h"
  86. #include "ODCore.h"
  87. #include "ODInQue.h"
  88. #ifdef ODPLAT_WIN32
  89. #include "ODFrame.h"
  90. #endif /* ODPLAT_WIN32 */
  91. /* GLOBAL VARIABLES SHARED THROUGHOUT OPENDOORS. */
  92. /* Global declaration of the OpenDoors control structure. */
  93. OD_API_VAR_DEFN tODControl
  94. #ifndef _WIN32 /* warning C4229: anachronism used : modifiers on data are ignored */
  95. OD_GLOBAL_CONV
  96. #endif
  97. od_control;
  98. /* OpenDoors global initialized flag. */
  99. BOOL bODInitialized = FALSE;
  100. /* Global serial port object handle. */
  101. tPortHandle hSerialPort;
  102. /* Global input queue object handle. */
  103. tODInQueueHandle hODInputQueue;
  104. /* Reentrancy control. */
  105. BOOL bIsCallbackActive = FALSE;
  106. BOOL bShellChatActive = FALSE;
  107. /* Global working space. */
  108. char szODWorkString[OD_GLOBAL_WORK_STRING_SIZE];
  109. /* Global instance of the text information structure for general use. */
  110. tODScrnTextInfo ODTextInfo;
  111. /* Logfile function hooks. */
  112. BOOL (*pfLogWrite)(INT) = NULL;
  113. void (*pfLogClose)(INT) = NULL;
  114. /* od_color_config() support for od_printf(). */
  115. char chColorCheck = 0;
  116. char *pchColorEndPos;
  117. /* Status line information. */
  118. BYTE btCurrentStatusLine = STATUS_NONE;
  119. OD_PERSONALITY_CALLBACK *pfCurrentPersonality = NULL;
  120. char szDesiredPersonality[33] = "";
  121. SET_PERSONALITY_FUNC *pfSetPersonality = NULL;
  122. /* Commonly used character sequences. */
  123. char abtBlackBlock[2] = {' ', 0x07};
  124. char abtGreyBlock[2] = {' ', 0x70};
  125. char szBackspaceWithDelete[4] = {8, ' ', 8, 0};
  126. /* Current output area on screen. */
  127. BYTE btOutputTop = 1;
  128. BYTE btOutputBottom = 23;
  129. /* PRIVATE VARIABLES. */
  130. /* Display color varaibles. */
  131. char bAnyColorChangeYet;
  132. /* Static character sequences. */
  133. static char szClearScreen[2] = {12, 0};
  134. /* Lookup table to map colors from PC values to ANSI color values. */
  135. static BYTE abtPCToANSIColorTable[8] = {30, 34, 32, 36, 31, 35, 33, 37};
  136. /* LOCAL HELPER FUNCTIONS. */
  137. static void ODAddANSIParameter(char *szControlSequence, int nParameterValue);
  138. /* ----------------------------------------------------------------------------
  139. * ODWaitDrain()
  140. *
  141. * Waits for up to the specified number of milliseconds for the output serial
  142. * buffer to drain.
  143. *
  144. * Parameters: MaxWait - Specifies the maximum number of milliseconds to wait
  145. * before timing out.
  146. *
  147. * Return: void
  148. */
  149. void ODWaitDrain(tODMilliSec MaxWait)
  150. {
  151. int nOutboundSize;
  152. tODTimer Timer;
  153. /* If we are operating in local mode, then don't do anything. */
  154. if(od_control.baud == 0) return;
  155. /* Otherwise, start a timer that is set to elapse after the maximum */
  156. /* wait period. */
  157. ODTimerStart(&Timer, MaxWait);
  158. /* Loop until either the outbound buffer is empty, or the */
  159. /* timer has elapsed. */
  160. for(;;)
  161. {
  162. /* Check whether any data is in the outbound serial queue. */
  163. ODComOutbound(hSerialPort, &nOutboundSize);
  164. /* If the queue is empty or the timer has elapsed, then stop */
  165. /* waiting. */
  166. if(nOutboundSize == 0 || ODTimerElapsed(&Timer)) break;
  167. /* Otherwise, give other tasks a chance to run. */
  168. od_sleep(0);
  169. /* Give od_kernel() activities a chance to run. */
  170. CALL_KERNEL_IF_NEEDED();
  171. }
  172. }
  173. /* ----------------------------------------------------------------------------
  174. * od_clr_scr()
  175. *
  176. * Clears the contents of the local and remote screens, if screen clearing is
  177. * enabled.
  178. *
  179. * Parameters: none
  180. *
  181. * Return: void
  182. */
  183. ODAPIDEF void ODCALL od_clr_scr(void)
  184. {
  185. INT16 nOriginalAttrib;
  186. /* Log function entry if running in trace mode */
  187. TRACE(TRACE_API, "od_clr_scr()");
  188. if(!bODInitialized) od_init();
  189. OD_API_ENTRY();
  190. /* Don't clear screen if disabled. */
  191. if(!od_control.od_always_clear && !(od_control.user_attribute & 2)
  192. && (od_control.od_extended_info || od_control.od_info_type == CUSTOM))
  193. {
  194. OD_API_EXIT();
  195. return;
  196. }
  197. if(od_control.user_rip)
  198. {
  199. od_disp("!|*", 3, FALSE);
  200. if(!od_control.od_default_rip_win)
  201. {
  202. od_disp("!|w0000270M12", 13, FALSE);
  203. }
  204. }
  205. if(od_control.user_ansi)
  206. {
  207. od_disp("\x1b[2J\x1b[1;1H", 10, FALSE);
  208. }
  209. else {
  210. /* Send ascii 12 to modem, no local echo. */
  211. od_disp(szClearScreen, 1, FALSE);
  212. }
  213. /* Clear local window. */
  214. ODScrnClear();
  215. /* Get color set prior to screen clear. */
  216. nOriginalAttrib = od_control.od_cur_attrib;
  217. /* Current color state is unknown. */
  218. od_control.od_cur_attrib = -1;
  219. /* Set color to original value. This gurantees that local and */
  220. /* remote systems both have the same current color set. */
  221. od_set_attrib(nOriginalAttrib);
  222. OD_API_EXIT();
  223. }
  224. /* ----------------------------------------------------------------------------
  225. * od_input_str()
  226. *
  227. * Allows the user to input a string up to the specified length, using
  228. * characters in the specified range. This string input function is designed
  229. * to be compatible with all terminal types.
  230. *
  231. * Parameters: pszInput - Pointer to string to store input in.
  232. *
  233. * nMaxLength - Maximum number of characters to permit the user
  234. * to input.
  235. *
  236. * chMin - The minimum character value to permit. This must
  237. * be at least ASCII 32.
  238. *
  239. * chMax - The maximum character value to permit.
  240. *
  241. * Return: void
  242. */
  243. ODAPIDEF void ODCALL od_input_str(char *pszInput,
  244. INT nMaxLength,
  245. unsigned char chMin,
  246. unsigned char chMax)
  247. {
  248. char chKeyPressed;
  249. INT nPosition;
  250. /* Log function entry if running in trace mode. */
  251. TRACE(TRACE_API, "od_input_str()");
  252. /* Initialize OpenDoors if it hasn't already been done. */
  253. if(!bODInitialized) od_init();
  254. OD_API_ENTRY();
  255. /* Start at the beginning of the string. */
  256. nPosition = 0;
  257. /* Check that input parameters are valid. */
  258. if(pszInput == NULL || nMaxLength < 1 || chMin > chMax)
  259. {
  260. od_control.od_error = ERR_PARAMETER;
  261. OD_API_EXIT();
  262. return;
  263. }
  264. for(;;)
  265. {
  266. chKeyPressed = od_get_key(TRUE);
  267. /* If user pressed enter. */
  268. if(chKeyPressed == '\r' || chKeyPressed == '\n')
  269. {
  270. /* Terminate the string. */
  271. pszInput[nPosition] = '\0';
  272. /* Display CR-LF sequence. */
  273. od_disp_str("\n\r");
  274. /* Exit the function. */
  275. OD_API_EXIT();
  276. return;
  277. }
  278. /* If the user pressed backspace. */
  279. else if(chKeyPressed == 8)
  280. {
  281. /* If we are not currently at the beginning of the string. */
  282. if(nPosition > 0)
  283. {
  284. /* Send backspace sequence. */
  285. od_disp_str(szBackspaceWithDelete);
  286. /* Move current position back by one position in the string. */
  287. --nPosition;
  288. }
  289. }
  290. /* If this is a valid character to place in the string and we have */
  291. /* not reached the maximum size of the string yet. */
  292. else if(chKeyPressed >= chMin && chKeyPressed <= chMax
  293. && nPosition < nMaxLength)
  294. {
  295. /* Display key that was pressed. */
  296. od_putch(chKeyPressed);
  297. /* Add the entered character to the string and increment our */
  298. /* current position in the string. */
  299. pszInput[nPosition++] = chKeyPressed;
  300. }
  301. }
  302. }
  303. /* ----------------------------------------------------------------------------
  304. * od_clear_keybuffer()
  305. *
  306. * Clears any keystrokes from the inbound buffers. Both input from local and
  307. * remote systems is discarded, by clearing both OpenDoors' common input
  308. * event queue, and the serial port inbound buffer. This function is called
  309. * to cause any input by the user prior to the time the function was called
  310. * to be ignored.
  311. *
  312. * Parameters: none
  313. *
  314. * Return: void
  315. */
  316. ODAPIDEF void ODCALL od_clear_keybuffer(void)
  317. {
  318. /* Log function entry if running in trace mode. */
  319. TRACE(TRACE_API, "od_clear_keybuffer()");
  320. /* Initialize OpenDoors if it hasn't already been done. */
  321. if(!bODInitialized) od_init();
  322. OD_API_ENTRY();
  323. /* Empty any events in the common input event queue. */
  324. ODInQueueEmpty(hODInputQueue);
  325. /* If we are not operating in local mode ... */
  326. if(od_control.baud != 0)
  327. {
  328. /* ... then remove any items in the serial port inbound buffer. */
  329. ODComClearInbound(hSerialPort);
  330. }
  331. /* Call the OpenDoors kernel function. */
  332. CALL_KERNEL_IF_NEEDED();
  333. OD_API_EXIT();
  334. }
  335. /* ----------------------------------------------------------------------------
  336. * od_key_pending()
  337. *
  338. * Returns TRUE if there's a key pending, FALSE otherwise.
  339. *
  340. * Parameters: none
  341. *
  342. * Return: TRUE if character is waiting, FALSE if no character is waiting.
  343. */
  344. ODAPIDEF BOOL ODCALL od_key_pending(void)
  345. {
  346. /* Initialize OpenDoors if it hasn't already been done. */
  347. if(!bODInitialized) od_init();
  348. /* Log function entry if running in trace mode. */
  349. TRACE(TRACE_API, "od_get_key()");
  350. OD_API_ENTRY();
  351. /* Call the OpenDoors kernel. */
  352. CALL_KERNEL_IF_NEEDED();
  353. if(!ODInQueueWaiting(hODInputQueue))
  354. {
  355. OD_API_EXIT();
  356. return(FALSE);
  357. }
  358. OD_API_EXIT();
  359. return(TRUE);
  360. }
  361. /* ----------------------------------------------------------------------------
  362. * od_get_key()
  363. *
  364. * Inputs a single character, optionally waiting for the next character if no
  365. * character has been received yet. This function returns data received from
  366. * either the local or remote system, in the order in which it was received.
  367. *
  368. * Parameters: bWait - FALSE if od_get_key() should return right away with
  369. * a value of 0 if no characters have been received, or
  370. * TRUE if od_get_key() should wait for the next received
  371. * character.
  372. *
  373. * Return: Character that was received, or 0 if no character is waiting.
  374. */
  375. ODAPIDEF char ODCALL od_get_key(BOOL bWait)
  376. {
  377. tODInputEvent InputEvent;
  378. /* Initialize OpenDoors if it hasn't already been done. */
  379. if(!bODInitialized) od_init();
  380. /* Log function entry if running in trace mode. */
  381. TRACE(TRACE_API, "od_get_key()");
  382. OD_API_ENTRY();
  383. /* Call the OpenDoors kernel. */
  384. CALL_KERNEL_IF_NEEDED();
  385. do {
  386. /* If we aren't supposed to wait for input, then check whether any */
  387. /* input is waiting in the input queue, and if not return right away */
  388. /* without any data. */
  389. if(!bWait)
  390. {
  391. if(!ODInQueueWaiting(hODInputQueue))
  392. {
  393. OD_API_EXIT();
  394. return(0);
  395. }
  396. }
  397. /* Obtain the next character from the input queue. If we get to this */
  398. /* point and there is no data waiting in the input queue, then the */
  399. /* ODInQueueGetNextEvent() function will block until a character */
  400. /* is available in the input queue. */
  401. ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT);
  402. /* Only keyboard input events are currently supported by od_get_key(). */
  403. ASSERT(InputEvent.EventType == EVENT_CHARACTER);
  404. /* Update OpenDoors control structure member that records whether the */
  405. /* last input came from the local or remote user. */
  406. od_control.od_last_input = InputEvent.bFromRemote ? 0 : 1;
  407. } while(InputEvent.chKeyPress == '\n'); /* Ignore line-feed char */
  408. /* Return the character that was pressed by the user. */
  409. OD_API_EXIT();
  410. return(InputEvent.chKeyPress);
  411. }
  412. /* ----------------------------------------------------------------------------
  413. * od_carrier()
  414. *
  415. * Allows programs to determine the current state of the carrier detect
  416. * signal when OpenDoors' automatic carrier detection has been disabled.
  417. *
  418. * Parameters: none
  419. *
  420. * Return: TRUE if the carrier detct signal is present, FALSE if it
  421. * isn't. When operating in local mode, this function always
  422. * returns FALSE.
  423. */
  424. ODAPIDEF BOOL ODCALL od_carrier(void)
  425. {
  426. BOOL bIsCarrier;
  427. /* Initialize OpenDoors if it hasn't already been done. */
  428. if(!bODInitialized) od_init();
  429. OD_API_ENTRY();
  430. /* Log function entry if running in trace mode */
  431. TRACE(TRACE_API, "od_carrier()");
  432. /* If we are operating in local mode, then return FALSE. */
  433. if(od_control.baud == 0)
  434. {
  435. od_control.od_error = ERR_NOREMOTE;
  436. OD_API_EXIT();
  437. return(FALSE);
  438. }
  439. /* In remote mode, obtain the current state of the carrier detect signal. */
  440. ODComCarrier(hSerialPort, &bIsCarrier);
  441. /* Return the current state of the carrier detect signal. */
  442. OD_API_EXIT();
  443. return(bIsCarrier);
  444. }
  445. /* ----------------------------------------------------------------------------
  446. * od_repeat()
  447. *
  448. * This function displays the same character the specified number of times on
  449. * the local and remote screens, using any available optimal control sequences
  450. * under the current display mode.
  451. *
  452. * Parameters: chValue - Character to repeat.
  453. *
  454. * btTimes - Number of times to repeat the character.
  455. *
  456. * Return: void
  457. */
  458. ODAPIDEF void ODCALL od_repeat(char chValue, BYTE btTimes)
  459. {
  460. char *pchCurStringPos;
  461. BYTE btLeft;
  462. char szBuffer[3];
  463. /* Log function entry if running in trace mode. */
  464. TRACE(TRACE_API, "od_repeat()");
  465. /* Ensure that OpenDoors has been initialized. */
  466. if(!bODInitialized) od_init();
  467. OD_API_ENTRY();
  468. /* If the caller asked to repeat the character 0 times, then we can */
  469. /* safely return right away without doing anything. */
  470. if(btTimes == 0)
  471. {
  472. OD_API_EXIT();
  473. return;
  474. }
  475. /* Generate string of repeat characters. */
  476. pchCurStringPos = szODWorkString;
  477. for(btLeft = btTimes; btLeft--;)
  478. {
  479. *pchCurStringPos++ = chValue;
  480. }
  481. *pchCurStringPos = '\0';
  482. /* Display repeated string on local screen. */
  483. ODScrnDisplayString(szODWorkString);
  484. /* If we are operating in AVATAR mode. */
  485. if(od_control.user_avatar)
  486. {
  487. /* Generate the AVATAR control sequence to repeat this character */
  488. /* the specified number of times. */
  489. szBuffer[0] = 25;
  490. szBuffer[1] = chValue;
  491. szBuffer[2] = btTimes;
  492. od_disp(szBuffer, 3, FALSE);
  493. }
  494. /* If AVATAR mode is not available. */
  495. else
  496. {
  497. /* Send the entire repeated string to the remote system. */
  498. od_disp(szODWorkString, btTimes, FALSE);
  499. }
  500. OD_API_EXIT();
  501. }
  502. /* ----------------------------------------------------------------------------
  503. * od_page()
  504. *
  505. * This function is called when the user wished to page the system operator.
  506. *
  507. * Parameters: none
  508. *
  509. * Return: void
  510. */
  511. ODAPIDEF void ODCALL od_page(void)
  512. {
  513. INT16 nCount;
  514. tODTimer Timer;
  515. time_t nUnixTime;
  516. struct tm *TimeBlock;
  517. INT16 nMinute;
  518. BOOL bFailed = FALSE;
  519. INT16 nOriginalAttrib;
  520. /* Log function entry if running in trace mode. */
  521. TRACE(TRACE_API, "od_page()");
  522. /* Initialize OpenDoors if it hasn't already been done. */
  523. if(!bODInitialized) od_init();
  524. OD_API_ENTRY();
  525. /* Save current display color attribute. */
  526. nOriginalAttrib = od_control.od_cur_attrib;
  527. /* Clear the screen. */
  528. od_clr_scr();
  529. od_set_attrib(od_control.od_chat_color1);
  530. /* Ask reason for chat. */
  531. od_disp_str(od_control.od_chat_reason);
  532. od_set_attrib(od_control.od_chat_color2);
  533. od_putch('[');
  534. /* Use extended ASCII characters if operating in ANSI or AVATAR mode. */
  535. if(od_control.user_ansi || od_control.user_avatar)
  536. {
  537. od_repeat('Ä',77);
  538. }
  539. else
  540. {
  541. od_repeat('-',77);
  542. }
  543. od_disp_str("]\n\r ");
  544. od_input_str(od_control.user_reasonforchat,77,32,255);
  545. /* If the user did not abort sysop paging by entering a blank reason */
  546. /* for chat. */
  547. if(strlen(od_control.user_reasonforchat) != 0)
  548. {
  549. /* Indicate that the user wants to chat. */
  550. od_control.user_wantchat = TRUE;
  551. #ifdef ODPLAT_WIN32
  552. ODFrameUpdateWantChat();
  553. #endif /* ODPLAT_WIN32 */
  554. /* Determine whether or not sysop paging should be permitted at */
  555. /* the current time. */
  556. nUnixTime = time(NULL);
  557. TimeBlock = localtime(&nUnixTime);
  558. nMinute = (60 * TimeBlock->tm_hour) + TimeBlock->tm_min;
  559. if(od_control.od_pagestartmin < od_control.od_pageendmin)
  560. {
  561. if(nMinute < od_control.od_pagestartmin
  562. || nMinute >= od_control.od_pageendmin)
  563. {
  564. bFailed = TRUE;
  565. }
  566. }
  567. else if(od_control.od_pagestartmin > od_control.od_pageendmin)
  568. {
  569. if(nMinute < od_control.od_pagestartmin
  570. && nMinute >= od_control.od_pageendmin)
  571. {
  572. bFailed = TRUE;
  573. }
  574. }
  575. else
  576. {
  577. bFailed = FALSE;
  578. }
  579. /* If paging is set to PAGE_ENABLE, meaning that sysop paging should */
  580. /* be permitted regardless of the time of day, then allow paging. */
  581. if(od_control.od_okaytopage == PAGE_ENABLE)
  582. {
  583. bFailed = FALSE;
  584. }
  585. /* If paging is explicitly disable by PAGE_DISABLE, or the current */
  586. /* time of the day is not normally permitted for paging. */
  587. if(od_control.od_okaytopage == PAGE_DISABLE || bFailed)
  588. {
  589. /* Indicate this to user. */
  590. od_disp_str("\n\r");
  591. od_disp_str(od_control.od_no_sysop);
  592. od_disp_str(od_control.od_press_key);
  593. od_get_answer("\x0d\x0a");
  594. /* Return from this function. */
  595. goto cleanup;
  596. }
  597. /* Update status line right away. */
  598. bForceStatusUpdate = TRUE;
  599. CALL_KERNEL_IF_NEEDED();
  600. /* Write sysop page information to the logfile, if the log file */
  601. /* system is hooked up. */
  602. if(pfLogWrite != NULL)
  603. {
  604. (*pfLogWrite)(8);
  605. }
  606. /* Tell the user that we are now paging the system operator. */
  607. od_set_attrib(od_control.od_chat_color1);
  608. od_disp_str(od_control.od_paging);
  609. #ifdef OD_TEXTMODE
  610. /* Display sysop page status line if it exists and the sysop status */
  611. /* line is currently active. */
  612. if(od_control.od_page_statusline != -1 && btCurrentStatusLine != 8)
  613. {
  614. od_set_statusline(od_control.od_page_statusline);
  615. }
  616. #endif /* OD_TEXTMODE */
  617. /* Increment the total number of times that the user has paged */
  618. /* the sysop. */
  619. ++od_control.user_numpages;
  620. /* Sysop hasn't responded yet. */
  621. bChatted=FALSE;
  622. /* Loop for length of sysop page. */
  623. for(nCount = 0; nCount < od_control.od_page_len; ++nCount)
  624. {
  625. /* Start a timer that is set to elapse in exactly one second. */
  626. ODTimerStart(&Timer, 1000);
  627. /* Display another period character. */
  628. od_putch('.');
  629. /* Abort page if system operator answered */
  630. if(bChatted) goto cleanup;
  631. /* Send beep to local and remote systems. */
  632. od_putch('\a');
  633. /* Check whether system operator has answered after playing beep. */
  634. if (bChatted) goto cleanup;
  635. /* Wait for the timer to elapse, calling od_kernel() so that */
  636. /* chat mode will start as soon as the sysop presses the */
  637. /* chat key. */
  638. while(!ODTimerElapsed(&Timer))
  639. {
  640. CALL_KERNEL_IF_NEEDED();
  641. }
  642. }
  643. /* If sysop page time has elapsed without a response from the */
  644. /* sysop, then notify the user. */
  645. od_disp_str(od_control.od_no_response);
  646. od_disp_str(od_control.od_press_key);
  647. od_get_answer("\x0d\x0a");
  648. od_disp_str("\n\r\n\r");
  649. }
  650. cleanup:
  651. /* Restore original display color attribute. */
  652. od_set_attrib(nOriginalAttrib);
  653. OD_API_EXIT();
  654. }
  655. /* ----------------------------------------------------------------------------
  656. * od_disp()
  657. *
  658. * Function to send one or more character to the remote system, optionally
  659. * also echoing the same characters to the local screen.
  660. *
  661. * Parameters: pachBuffer - Pointer to buffer of characters to send.
  662. *
  663. * nSize - Number of characters to send from the buffer.
  664. *
  665. * bLocalEcho - TRUE to also echo the characters to the local
  666. * screen, FALSE to just send the characters to the
  667. * remote system.
  668. *
  669. * Return: void
  670. */
  671. ODAPIDEF void ODCALL od_disp(const char *pachBuffer, INT nSize, BOOL bLocalEcho)
  672. {
  673. /* Log function entry if running in trace mode. */
  674. TRACE(TRACE_API, "od_disp()");
  675. /* Initialize OpenDoors if it hasn't already been done. */
  676. if(!bODInitialized) od_init();
  677. OD_API_ENTRY();
  678. /* Call the OpenDoors kernel, if needed. */
  679. #ifndef OD_MULTITHREADED
  680. if(ODTimerElapsed(&RunKernelTimer))
  681. {
  682. CALL_KERNEL_IF_NEEDED();
  683. }
  684. #endif /* !OD_MULTITHREADED */
  685. /* If we are operating in remote mode, then send the buffer to the */
  686. /* remote system. */
  687. if(od_control.baud != 0)
  688. {
  689. ODComSendBuffer(hSerialPort, (BYTE *)pachBuffer, nSize);
  690. }
  691. /* If we are also to display the character on the local screen, then */
  692. /* display the buffer on the local screen. */
  693. if(bLocalEcho)
  694. {
  695. ODScrnDisplayBuffer(pachBuffer, nSize);
  696. }
  697. OD_API_EXIT();
  698. }
  699. /* ----------------------------------------------------------------------------
  700. * od_disp_str()
  701. *
  702. * Displays a string on both the local and remote systems.
  703. *
  704. * Parameters: pszToDisplay - Pointer to the string to be displayed.
  705. *
  706. * Return: void
  707. */
  708. ODAPIDEF void ODCALL od_disp_str(const char *pszToDisplay)
  709. {
  710. /* Log function entry if running in trace mode */
  711. TRACE(TRACE_API, "od_disp_str()");
  712. /* Initialize OpenDoors if it hasn't already been done. */
  713. if(!bODInitialized) od_init();
  714. OD_API_ENTRY();
  715. /* Call the OpenDoors kernel, if needed. */
  716. #ifndef OD_MULTITHREADED
  717. if(ODTimerElapsed(&RunKernelTimer))
  718. {
  719. CALL_KERNEL_IF_NEEDED();
  720. }
  721. #endif /* !OD_MULTITHREADED */
  722. /* Send the string to the remote system, if we are running in remote mode. */
  723. if(od_control.baud != 0)
  724. {
  725. ODComSendBuffer(hSerialPort, (BYTE *)pszToDisplay, strlen(pszToDisplay));
  726. }
  727. /* Display the screen on the local screen. */
  728. ODScrnDisplayString(pszToDisplay);
  729. OD_API_EXIT();
  730. }
  731. /* ----------------------------------------------------------------------------
  732. * od_set_statusline()
  733. *
  734. * Switches to one of the available status lines provided by the current
  735. * personality, or turns off the status line altogether.
  736. *
  737. * Parameters: nSetting - Indicates which status line (if any) should be
  738. * activated.
  739. *
  740. * Return: void
  741. */
  742. ODAPIDEF void ODCALL od_set_statusline(INT nSetting)
  743. {
  744. #ifdef OD_TEXTMODE
  745. INT nDistance;
  746. BYTE btCount
  747. #endif /* OD_TEXTMODE */
  748. /* Log function entry if running in trace mode. */
  749. TRACE(TRACE_API, "od_set_statusline()");
  750. /* Initialize OpenDoors if it hasn't already been done. */
  751. if(!bODInitialized) od_init();
  752. OD_API_ENTRY()
  753. #ifdef OD_TEXTMODE
  754. /* If status line is disabled, then don't do anything. */
  755. if(!od_control.od_status_on)
  756. {
  757. OD_API_EXIT();
  758. return;
  759. }
  760. /* Ensure that the parameter is within the valid range. */
  761. if(nSetting < 0 || nSetting > 8)
  762. {
  763. nSetting = 0;
  764. }
  765. /* If the specified status line is already active, and status line */
  766. /* update isn't being forced, then return without doing anything. */
  767. if(!od_control.od_update_status_now && nSetting == btCurrentStatusLine)
  768. {
  769. OD_API_EXIT();
  770. return;
  771. }
  772. /* Save the current cursor settings. */
  773. ODStoreTextInfo();
  774. /* Reset screen boundary to allow access to the entire screen. */
  775. ODScrnSetBoundary(1,1,80,25);
  776. /* If status line is being turned off. */
  777. if(btCurrentStatusLine == STATUS_NONE)
  778. {
  779. if((nDistance = (INT)ODTextInfo.cury - ( 1 + (INT)btOutputBottom
  780. - (INT)btOutputTop)) > 0)
  781. {
  782. ODScrnCopyText(1, (BYTE)((INT)btOutputTop + nDistance), 80,
  783. (BYTE)((INT)btOutputBottom + nDistance), (BYTE)btOutputTop, 1);
  784. ODTextInfo.cury = 1 + btOutputBottom - btOutputTop;
  785. }
  786. else if(ODTextInfo.cury < btOutputTop)
  787. {
  788. ODTextInfo.cury = btOutputTop;
  789. ODScrnCopyText(1, (BYTE)(btOutputTop + 24 - btOutputBottom), 80, 25,
  790. btOutputTop, 1);
  791. }
  792. }
  793. od_control.od_current_statusline = btCurrentStatusLine = nSetting;
  794. if(nSetting == 8)
  795. {
  796. ODScrnSetAttribute(0x07);
  797. for(btCount = 1; btCount <= 25; ++btCount)
  798. {
  799. if(btCount < btOutputTop || btCount > btOutputBottom)
  800. {
  801. if(btCount == 25)
  802. {
  803. ODScrnPutText(80, 25, 80, 25, abtBlackBlock);
  804. ODScrnSetCursorPos(1, 25);
  805. ODScrnDisplayString(" ");
  806. }
  807. else
  808. {
  809. ODScrnSetCursorPos(1, 24);
  810. ODScrnDisplayString(" ");
  811. }
  812. }
  813. }
  814. ODScrnSetAttribute(ODTextInfo.attribute);
  815. ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
  816. }
  817. else
  818. {
  819. ODScrnEnableCaret(FALSE);
  820. ODScrnEnableScrolling(FALSE);
  821. (*pfCurrentPersonality)((BYTE)nSetting);
  822. ODScrnEnableCaret(TRUE);
  823. ODScrnEnableScrolling(TRUE);
  824. ODScrnSetBoundary(1, btOutputTop, 80, btOutputBottom);
  825. ODScrnSetAttribute(ODTextInfo.attribute);
  826. ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
  827. }
  828. #else /* !OD_TEXTMODE */
  829. od_control.od_error = ERR_UNSUPPORTED;
  830. #endif /* !OD_TEXTMODE */
  831. OD_API_EXIT();
  832. }
  833. /* ----------------------------------------------------------------------------
  834. * ODStoreTextInfo()
  835. *
  836. * Stores the current text settings into the OpenDoors global text information
  837. * structure.
  838. *
  839. * Parameters: none
  840. *
  841. * Return: void
  842. */
  843. void ODStoreTextInfo(void)
  844. {
  845. ODScrnGetTextInfo(&ODTextInfo);
  846. }
  847. /* ----------------------------------------------------------------------------
  848. * ODRestoreTextInfo()
  849. *
  850. * Restores display settings previously stored by ODStoreTextInfo()
  851. *
  852. * Parameters: none
  853. *
  854. * Return: void
  855. */
  856. void ODRestoreTextInfo(void)
  857. {
  858. ODScrnSetBoundary(ODTextInfo.winleft, ODTextInfo.wintop,
  859. ODTextInfo.winright, ODTextInfo.winbottom);
  860. ODScrnSetAttribute(ODTextInfo.attribute);
  861. ODScrnSetCursorPos(ODTextInfo.curx, ODTextInfo.cury);
  862. }
  863. /* ----------------------------------------------------------------------------
  864. * ODStringToName()
  865. *
  866. * Reformats a string so that it has the correct capitalization for a name,
  867. * and removes any trailing line break character.
  868. *
  869. * Parameters: pszToConvert - Pointer to the string to reformat.
  870. *
  871. * Return: void
  872. */
  873. void ODStringToName(char *pszToConvert)
  874. {
  875. /* Begin by changing the entire string to lower case. */
  876. strlwr(pszToConvert);
  877. /* Trim any newline character that may be at the end of the string. */
  878. if(pszToConvert[strlen(pszToConvert) - 1] == '\n')
  879. {
  880. pszToConvert[strlen(pszToConvert) - 1] = '\0';
  881. }
  882. /* Trim any CR character that may be at the end of the string. */
  883. if(pszToConvert[strlen(pszToConvert) - 1] == '\r')
  884. {
  885. pszToConvert[strlen(pszToConvert) - 1] = '\0';
  886. }
  887. /* Change the first character to lower case. */
  888. *pszToConvert = toupper(*pszToConvert);
  889. /* Loop through the rest of the string, capitalizing any other words */
  890. /* in the string. */
  891. while(*pszToConvert)
  892. {
  893. switch(*pszToConvert++)
  894. {
  895. case ' ':
  896. case '\t':
  897. case ',':
  898. case '.':
  899. case '-':
  900. *pszToConvert = toupper(*pszToConvert);
  901. break;
  902. }
  903. }
  904. }
  905. /* ----------------------------------------------------------------------------
  906. * od_set_color()
  907. *
  908. * Sets the current display color for both local and remote output.
  909. *
  910. * Parameters: nForeground - New foreground (text) color.
  911. *
  912. * nBackground - New background color.
  913. *
  914. * Return: void
  915. */
  916. ODAPIDEF void ODCALL od_set_color(INT nForeground, INT nBackground)
  917. {
  918. /* Use od_set_attrib() to perform the actual color setting. */
  919. /* Here, we rely on od_set_attrib() to look after initialization, */
  920. /* API_ENTRY() and API_EXIT() calls, etc. This allows od_set_color() */
  921. /* (which was previously just a macro) to be implemented with as */
  922. /* little overhead as possible. */
  923. od_set_attrib(nForeground | (nBackground << 4));
  924. }
  925. /* ----------------------------------------------------------------------------
  926. * od_set_attrib()
  927. *
  928. * Sets the current display color for both local and remote output.
  929. *
  930. * Parameters: nColor - New Display color to set, or -1 for no change.
  931. *
  932. * Return: void
  933. */
  934. ODAPIDEF void ODCALL od_set_attrib(INT nColor)
  935. {
  936. char szControlSequence[40];
  937. /* Log function entry if running in trace mode */
  938. TRACE(TRACE_API, "od_set_attrib()");
  939. /* Ensure that OpenDoors has been initialized. */
  940. if(!bODInitialized) od_init();
  941. OD_API_ENTRY();
  942. /* If color value is -1, then make no change. */
  943. if(nColor == -1)
  944. {
  945. OD_API_EXIT();
  946. return;
  947. }
  948. /* If we are operating in AVATAR mode. */
  949. if(od_control.user_avatar)
  950. {
  951. if(od_control.od_cur_attrib != nColor || od_control.od_full_color)
  952. {
  953. /* Change local text color. */
  954. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib = nColor));
  955. /* Generate AVATAR control sequence. */
  956. szControlSequence[0] = 22;
  957. szControlSequence[1] = 1;
  958. szControlSequence[2] = nColor;
  959. /* Send AVATAR control sequence. */
  960. od_disp(szControlSequence, 3, FALSE);
  961. }
  962. }
  963. /* If we are operating in ANSI mode. */
  964. else if(od_control.user_ansi)
  965. {
  966. bAnyColorChangeYet = FALSE;
  967. if(od_control.od_cur_attrib == -1 || od_control.od_full_color)
  968. {
  969. ansi_reset:
  970. /* Reset ANSI terminal status. */
  971. ODAddANSIParameter(szControlSequence, 0);
  972. /* If blink attribute is set. */
  973. if(nColor & 0x80)
  974. {
  975. /* Add it to the ANSI color sequence. */
  976. ODAddANSIParameter(szControlSequence, 5);
  977. }
  978. /* If high intensity attribute is set. */
  979. if(nColor & 0x08)
  980. {
  981. /* Add it to the ANSI color sequence. */
  982. ODAddANSIParameter(szControlSequence, 1);
  983. }
  984. }
  985. /* If current color is known. */
  986. else
  987. {
  988. /* If have to reset flashing or bright. */
  989. if(((od_control.od_cur_attrib&0x80) &&
  990. !(nColor & 0x80)) || ((od_control.od_cur_attrib & 0x08)
  991. && !(nColor & 0x08)))
  992. {
  993. /* Must reset entire colour settings. */
  994. od_control.od_cur_attrib = -1;
  995. goto ansi_reset;
  996. }
  997. /* If flashing has to be turned on. */
  998. if((nColor & 0x80) != (od_control.od_cur_attrib & 0x80))
  999. {
  1000. /* Add it to the ANSI color sequence. */
  1001. ODAddANSIParameter(szControlSequence, 5);
  1002. }
  1003. /* If bright has to be turned on. */
  1004. if((nColor & 0x08) != (od_control.od_cur_attrib & 0x08)
  1005. || od_control.od_cur_attrib == -1)
  1006. {
  1007. /* Add it to the ANSI color sequence. */
  1008. ODAddANSIParameter(szControlSequence, 1);
  1009. }
  1010. }
  1011. /* If foreground color has changed. */
  1012. if((nColor & 0x07) != (od_control.od_cur_attrib & 0x07)
  1013. || od_control.od_cur_attrib == -1 || od_control.od_full_color)
  1014. {
  1015. /* Add translated color to sequence. */
  1016. ODAddANSIParameter(szControlSequence,
  1017. abtPCToANSIColorTable[nColor&0x07]);
  1018. }
  1019. /* If background color has changed. */
  1020. if((nColor & 0x70) != (od_control.od_cur_attrib & 0x70)
  1021. || od_control.od_cur_attrib == -1 || od_control.od_full_color)
  1022. {
  1023. /* Add translated color to sequence. */
  1024. ODAddANSIParameter(szControlSequence,
  1025. abtPCToANSIColorTable[(nColor & 0x70) >> 4] + 10);
  1026. }
  1027. /* If any change in color. */
  1028. if(bAnyColorChangeYet)
  1029. {
  1030. /* Append change-attribute command. */
  1031. strcat(szControlSequence, "m");
  1032. /* Send ANSI sequence to the modem. */
  1033. od_disp(szControlSequence, strlen(szControlSequence), FALSE);
  1034. }
  1035. /* Change local text color. */
  1036. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib = nColor));
  1037. }
  1038. else
  1039. {
  1040. od_control.od_error = ERR_NOGRAPHICS;
  1041. }
  1042. OD_API_EXIT();
  1043. }
  1044. /* ----------------------------------------------------------------------------
  1045. * ODAddANSIParameter() *** PRIVATE FUNCTION ***
  1046. *
  1047. * Adds a parameter to an ANSI color sequence.
  1048. *
  1049. * Parameters: szControlSequence - The contents of the control sequence string
  1050. * generated so far.
  1051. *
  1052. * nParameterValue - Value of the parameter to add.
  1053. *
  1054. * Return: void
  1055. */
  1056. static void ODAddANSIParameter(char *szControlSequence, int nParameterValue)
  1057. {
  1058. char szTemp[5];
  1059. if(bAnyColorChangeYet)
  1060. {
  1061. sprintf(szTemp, ";%d", nParameterValue);
  1062. strcat(szControlSequence, szTemp);
  1063. }
  1064. else
  1065. {
  1066. bAnyColorChangeYet = TRUE;
  1067. sprintf(szControlSequence, "x[%d", nParameterValue);
  1068. szControlSequence[0] = 27;
  1069. }
  1070. }
  1071. /* ----------------------------------------------------------------------------
  1072. * od_putch()
  1073. *
  1074. * Displays a character on the local and remote screens.
  1075. *
  1076. * Parameters: chToDisplay - The character to display.
  1077. *
  1078. * Return: void
  1079. */
  1080. ODAPIDEF void ODCALL od_putch(char chToDisplay)
  1081. {
  1082. /* Log function entry if running in trace mode. */
  1083. TRACE(TRACE_API, "od_putch()");
  1084. /* Initialize OpenDoors if it hasn't been done already. */
  1085. if(!bODInitialized) od_init();
  1086. OD_API_ENTRY();
  1087. /* Display the character on the local screen. */
  1088. ODScrnDisplayChar(chToDisplay);
  1089. /* If not operating in local mode, then send the character to the */
  1090. /* serial port. */
  1091. if(od_control.baud)
  1092. {
  1093. ODComSendByte(hSerialPort, chToDisplay);
  1094. }
  1095. /* If it is time to call the kernel, then do so. */
  1096. if(ODTimerElapsed(&RunKernelTimer))
  1097. {
  1098. CALL_KERNEL_IF_NEEDED();
  1099. }
  1100. OD_API_EXIT();
  1101. }
  1102. /* ----------------------------------------------------------------------------
  1103. * od_set_dtr()
  1104. *
  1105. * Changes the state of the DTR line to the modem, if not running in local
  1106. * mode.
  1107. *
  1108. * Parameters: bHigh - TRUE to raise DTR, FALSE to lower it.
  1109. *
  1110. * Return: void
  1111. */
  1112. ODAPIDEF void ODCALL od_set_dtr(BOOL bHigh)
  1113. {
  1114. /* Log function entry if running in trace mode. */
  1115. TRACE(TRACE_API, "od_set_dtr()");
  1116. /* Initialize OpenDoors if it hasn't already been done. */
  1117. if(!bODInitialized) od_init();
  1118. OD_API_ENTRY();
  1119. /* If we are running in local mode, then return with an error. */
  1120. if(!od_control.baud)
  1121. {
  1122. od_control.od_error = ERR_NOREMOTE;
  1123. OD_API_EXIT();
  1124. return;
  1125. }
  1126. /* Otherwise, change the state of the DTR line. */
  1127. ODComSetDTR(hSerialPort, bHigh);
  1128. OD_API_EXIT();
  1129. }
  1130. /* ----------------------------------------------------------------------------
  1131. * od_get_answer()
  1132. *
  1133. * Waits for the user to press one of the keys listed in pszOptions. Case is
  1134. * not sensitive, although the pressed key is returned in the same case as it
  1135. * is specified in pszOptions.
  1136. *
  1137. * Parameters: pszOptions - String listing characters to accept.
  1138. *
  1139. * Return: void
  1140. */
  1141. ODAPIDEF char ODCALL od_get_answer(const char *pszOptions)
  1142. {
  1143. char *pchPossibleOption;
  1144. char chPressed;
  1145. /* Log function entry if running in trace mode. */
  1146. TRACE(TRACE_API, "od_get_answer()");
  1147. /* Initialize OpenDoors if it hasn't already been done. */
  1148. if(!bODInitialized) od_init();
  1149. OD_API_ENTRY();
  1150. for(;;)
  1151. {
  1152. /* Wait for the next key press by the user. */
  1153. chPressed = od_get_key(TRUE);
  1154. chPressed = tolower(chPressed);
  1155. /* Loop through list of possible options. */
  1156. pchPossibleOption = (char *)pszOptions;
  1157. while(*pchPossibleOption)
  1158. {
  1159. /* If the key pressed matches this possible option. */
  1160. if(tolower(*pchPossibleOption) == chPressed)
  1161. {
  1162. /* Then return the character in the case originally specified */
  1163. /* by the caller. */
  1164. OD_API_EXIT();
  1165. return(*pchPossibleOption);
  1166. }
  1167. /* Move on to the next possible option. */
  1168. ++pchPossibleOption;
  1169. }
  1170. /* If the key pressed did not match a possible option, then we */
  1171. /* just loop again, getting the next key. */
  1172. }
  1173. }
  1174. /* ----------------------------------------------------------------------------
  1175. * od_color_config()
  1176. *
  1177. * Determines the color attribute that is described by the provided string.
  1178. * This string is in the same format that is used for specifying colors in the
  1179. * OpenDoors configuration file.
  1180. *
  1181. * Parameters: pszColorDesc - Color description string.
  1182. *
  1183. * Return: The PC-style color attribute corresponding to the color
  1184. * description string.
  1185. */
  1186. ODAPIDEF BYTE ODCALL od_color_config(char *pszColorDesc)
  1187. {
  1188. BYTE btColor = 0x07;
  1189. char szToken[40];
  1190. char *pszStart=(char *)pszColorDesc;
  1191. char *pszEnd;
  1192. BYTE btLength;
  1193. BYTE btIdentifier;
  1194. BOOL bForeground = TRUE;
  1195. /* Log function entry if running in trace mode. */
  1196. TRACE(TRACE_API, "od_color_config()");
  1197. /* Initialize OpenDoros if it hasn't already been done. */
  1198. if(!bODInitialized) od_init();
  1199. OD_API_ENTRY();
  1200. while(*pszStart && *pszStart!=chColorCheck)
  1201. {
  1202. if(*pszStart == ' ' || *pszStart== '\t')
  1203. {
  1204. ++pszStart;
  1205. }
  1206. else
  1207. {
  1208. btLength = 0;
  1209. pszEnd = (char *)pszStart;
  1210. while(*pszEnd && *pszEnd != chColorCheck && *pszEnd != ' '
  1211. && *pszEnd != '\t')
  1212. {
  1213. ++btLength;
  1214. ++pszEnd;
  1215. }
  1216. if(btLength > 39) btLength = 39;
  1217. strncpy(szToken, pszStart, btLength);
  1218. szToken[btLength] = '\0';
  1219. strupr(szToken);
  1220. for(btIdentifier = 0; btIdentifier < 12; ++btIdentifier)
  1221. if(strcmp(od_config_colours[btIdentifier], szToken) == 0)
  1222. {
  1223. if(btIdentifier <= 9)
  1224. {
  1225. if(btIdentifier >= 8) btIdentifier -= 2;
  1226. if(bForeground)
  1227. {
  1228. bForeground=FALSE;
  1229. btColor &=~ 0x07;
  1230. btColor |= btIdentifier;
  1231. }
  1232. else
  1233. {
  1234. btColor &=~ 0x70;
  1235. btColor |= (btIdentifier << 4);
  1236. }
  1237. }
  1238. else if(btIdentifier == 10)
  1239. {
  1240. btColor |= 0x08;
  1241. }
  1242. else if(btIdentifier == 11)
  1243. {
  1244. btColor |= 0x80;
  1245. }
  1246. break;
  1247. }
  1248. pszStart = (char *)pszEnd;
  1249. }
  1250. }
  1251. pchColorEndPos = (char *)pszStart;
  1252. OD_API_EXIT();
  1253. return(btColor);
  1254. }
  1255. /* ----------------------------------------------------------------------------
  1256. * ODPagePrompt()
  1257. *
  1258. * Called to display the page prompt at the end of a screen of text. This page
  1259. * prompt allows the user to stop further display, to display the next page,
  1260. * or to display in continuous (non-stop) mode with page pausing disabled.
  1261. *
  1262. * Parameters: pbPausing - Pointer to current page pausing enabled flag.
  1263. *
  1264. * Return: FALSE if display should be continued, or TRUE to abort display.
  1265. */
  1266. BOOL ODPagePrompt(BOOL *pbPausing)
  1267. {
  1268. INT nPromptLength = strlen(od_control.od_continue);
  1269. tODScrnTextInfo TextInfo;
  1270. BOOL bToReturn = FALSE;
  1271. char chKeyPressed;
  1272. BYTE btCount;
  1273. /* Return right away if page pausing is disabled. */
  1274. if(!*pbPausing) return(FALSE);
  1275. /* Get current text color. */
  1276. ODScrnGetTextInfo(&TextInfo);
  1277. /* Set to prompt color. */
  1278. od_set_attrib(od_control.od_continue_col);
  1279. /* Display page prompt string. */
  1280. od_disp_str(od_control.od_continue);
  1281. /* Restore original text color. */
  1282. od_set_attrib(TextInfo.attribute);
  1283. /* Loop until the user makes a valid choice. */
  1284. for(;;)
  1285. {
  1286. /* Obtain the next key from the user. */
  1287. chKeyPressed = od_get_key(TRUE);
  1288. /* If user chooses to continue. */
  1289. if(chKeyPressed == tolower(od_control.od_continue_yes) ||
  1290. chKeyPressed == toupper(od_control.od_continue_yes) ||
  1291. chKeyPressed == 13 ||
  1292. chKeyPressed == ' ')
  1293. {
  1294. /* Remove the prompt and return. */
  1295. goto finished_pausing;
  1296. }
  1297. /* If user requested nonstop display. */
  1298. else if(chKeyPressed == tolower(od_control.od_continue_nonstop) ||
  1299. chKeyPressed == toupper(od_control.od_continue_nonstop))
  1300. {
  1301. /* Disable page pausing. */
  1302. *pbPausing = FALSE;
  1303. /* Remove the prompt and return. */
  1304. goto finished_pausing;
  1305. }
  1306. /* If user chooses to stop display. */
  1307. else if(chKeyPressed == tolower(od_control.od_continue_no) ||
  1308. chKeyPressed == toupper(od_control.od_continue_no) ||
  1309. chKeyPressed == 's' || chKeyPressed == 'S' || chKeyPressed == 3
  1310. || chKeyPressed == 11 || chKeyPressed == 0x18)
  1311. {
  1312. /* If we are operating in remote mode. */
  1313. if(od_control.baud)
  1314. {
  1315. /* Clear the output buffer. */
  1316. ODComClearOutbound(hSerialPort);
  1317. }
  1318. /* Tell the caller to stop displaying more text. */
  1319. bToReturn = TRUE;
  1320. /* Remove the prompt and return. */
  1321. goto finished_pausing;
  1322. }
  1323. }
  1324. finished_pausing:
  1325. /* Remove the pause prompt. */
  1326. for(btCount = 0; btCount < nPromptLength; ++btCount)
  1327. {
  1328. od_disp_str(szBackspaceWithDelete);
  1329. }
  1330. return(bToReturn);
  1331. }
  1332. /* ----------------------------------------------------------------------------
  1333. * od_control_get()
  1334. *
  1335. * Returns a pointer to the od_control structure containing information
  1336. * and settings associated with the current session.
  1337. *
  1338. * Parameters: None.
  1339. *
  1340. * Return: A pointer to the od_control structure associated with this
  1341. * session.
  1342. */
  1343. ODAPIDEF tODControl * ODCALL od_control_get(void)
  1344. {
  1345. /* Log function entry if running in trace mode */
  1346. TRACE(TRACE_API, "od_disp_str()");
  1347. return(&od_control);
  1348. }