ODEmu.c 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODEmu.c
  20. *
  21. * Description: Code for the TTY/ANSI/AVATAR terminal emulation routines,
  22. * including .ASC/.ANS/.AVT/.RIP file display functions.
  23. *
  24. * Revisions: Date Ver Who Change
  25. * ---------------------------------------------------------------
  26. * Oct 13, 1994 6.00 BP New file header format.
  27. * Oct 21, 1994 6.00 BP Further isolated com routines.
  28. * Dec 09, 1994 6.00 BP Standardized coding style.
  29. * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
  30. * Jun 07, 1995 6.00 BP Added od_emu_simulate_modem.
  31. * Jul 18, 1995 6.00 BP Fixed warning in call to _ulongdiv().
  32. * Aug 19, 1995 6.00 BP 32-bit portability.
  33. * Nov 11, 1995 6.00 BP Removed register keyword.
  34. * Nov 14, 1995 6.00 BP Added include of odscrn.h.
  35. * Nov 15, 1995 6.00 BP Terminal emulation speed optimization.
  36. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  37. * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
  38. * Dec 24, 1995 6.00 BP Use od_connect_speed for modem sim.
  39. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  40. * Jan 21, 1996 6.00 BP Use ODScrnShowMessage().
  41. * Jan 09, 1996 6.00 BP ODComOutbound() returns actual size.
  42. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  43. * Mar 03, 1996 6.10 BP Begin version 6.10.
  44. * Mar 06, 1996 6.10 BP Prevent TC generated N_LXMUL@ call.
  45. * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
  46. * Oct 18, 2001 6.11 MD Added od_send_file_section()
  47. * Aug 10, 2003 6.23 SH *nix support
  48. */
  49. #define BUILDING_OPENDOORS
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <ctype.h>
  53. #include <string.h>
  54. #include <stdarg.h>
  55. #include "OpenDoor.h"
  56. #include "ODStr.h"
  57. #include "ODCore.h"
  58. #include "ODGen.h"
  59. #include "ODCom.h"
  60. #include "ODTypes.h"
  61. #include "ODScrn.h"
  62. #include "ODKrnl.h"
  63. #include "ODUtil.h"
  64. /* Manifest constants. */
  65. #define MODEM_SIMULATOR_TICK 54L
  66. #define LEVEL_NONE 0
  67. #define LEVEL_ASCII 1
  68. #define LEVEL_ANSI 2
  69. #define LEVEL_AVATAR 3
  70. #define LEVEL_RIP 4
  71. /* Local helper function prototypes. */
  72. static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho);
  73. static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel);
  74. static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight,
  75. BYTE btBottom, char chToFillWith);
  76. /* Current terminal emulator state variables. */
  77. static BYTE btANSISeqLevel = 0;
  78. static INT anANSIParams[10];
  79. static char szCurrentParam[4] = "";
  80. static BYTE btCurrentParamLength;
  81. static BYTE btSavedColumn=1;
  82. static BYTE btSavedRow = 1;
  83. static char szToRepeat[129];
  84. static BYTE btRepeatCount;
  85. static BYTE btAvatarSeqLevel = 0;
  86. static char chPrevParam;
  87. static BYTE btNumParams;
  88. static BYTE btDefaultAttrib = 7;
  89. static BOOL bAvatarInsertMode = FALSE;
  90. static INT8 btScrollLines;
  91. static BYTE btScrollLeft, btScrollTop, btScrollRight, btScrollBottom;
  92. /* Variables for tracking hotkeys while displaying a menu file. */
  93. static char *pszCurrentHotkeys=NULL;
  94. static char chHotkeyPressed;
  95. /* Lookup table to map colors from ANSI values to PC color values. */
  96. static BYTE abtANSIToPCColorTable[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  97. /* ----------------------------------------------------------------------------
  98. * od_hotkey_menu()
  99. *
  100. * Displays a .ASC/.ANS/.AVT/.RIP file, just as od_send_file() does. However,
  101. * unlike od_send_file(), od_hotkey_menu() also allows checks for keypresses
  102. * by the user. If any of the hotkeys listed in pszHotKeys are pressed while
  103. * the file is being displayed, or after the file has finished being displayed,
  104. * od_hotkey_menu() will return this value to the caller. This allows menu
  105. * screens to be easily displayed from on-disk files, while permitting the user
  106. * to choose a menu item at any time.
  107. *
  108. * Parameters: pszFileName - Pointer to the filename to display.
  109. *
  110. * pszHotKeys - Pointer to a string listing the valid keys.
  111. * Keys are not case sensitive.
  112. *
  113. * bWait - If TRUE, od_hotkey_menu() will not return until
  114. * the user presses one of the valid keys. If FALSE,
  115. * then od_hotkey_menu() will return as soon as it
  116. * has finished displaying the file, even if the
  117. * user has not pressed any key;.
  118. *
  119. * Return: The key pressed by the user, or '\0' if no key was pressed.
  120. */
  121. ODAPIDEF char ODCALL od_hotkey_menu(char *pszFileName, char *pszHotKeys,
  122. BOOL bWait)
  123. {
  124. char chPressed;
  125. /* Log function entry if running in trace mode. */
  126. TRACE(TRACE_API, "od_hotkey_menu()");
  127. /* Ensure that OpenDoors has been initialized. */
  128. if(!bODInitialized) od_init();
  129. OD_API_ENTRY();
  130. if(!pszHotKeys)
  131. {
  132. od_control.od_error = ERR_PARAMETER;
  133. OD_API_EXIT();
  134. return('\0');
  135. }
  136. /* Store pointer to string of hotkeys in global hotkey array for access */
  137. /* from od_send_file(). */
  138. pszCurrentHotkeys = (char *)pszHotKeys;
  139. /* Clear the hotkey status variable. */
  140. chHotkeyPressed = '\0';
  141. /* Display the menu file using od_send_file() primitive. */
  142. if(!od_send_file(pszFileName))
  143. {
  144. OD_API_EXIT();
  145. return('\0');
  146. }
  147. /* Clear the global hotkey array. */
  148. pszCurrentHotkeys = NULL;
  149. /* If the file display was interrupted by the pressing of one of the */
  150. /* hotkeys, return the pressed hotkey immediately. */
  151. if(chHotkeyPressed != '\0')
  152. {
  153. OD_API_EXIT();
  154. return(chHotkeyPressed);
  155. }
  156. /* If no hotkey has been pressed key, and the wait flag has been set, */
  157. /* wait for the user to press a valid hotkey. */
  158. if(bWait)
  159. {
  160. /* Wait for a valid hotkey using the od_get_answer() primitive. */
  161. chPressed = od_get_answer(pszHotKeys);
  162. /* If a remote user is connected on this node. */
  163. if(od_control.baud)
  164. {
  165. /* Clear the outbound buffer. */
  166. ODComClearOutbound(hSerialPort);
  167. }
  168. /* Return the hotkey pressed by the user. */
  169. OD_API_EXIT();
  170. return(chPressed);
  171. }
  172. /* No hotkey has been pressed, so return 0. */
  173. /* (Since 0 is used to terminate the string of valid hotkeys, it can */
  174. /* never be a valid hotkey itself, and is therefore a safe value to */
  175. /* indicate the "no key press" state.) */
  176. OD_API_EXIT();
  177. return(0);
  178. }
  179. /* ----------------------------------------------------------------------------
  180. * od_send_file()
  181. *
  182. * Displays a .ASC/.ANS/.AVT/.RIP file to the local and remote screens. If
  183. * OpenDoors is unable to display the required file format locally, an
  184. * equivalent file that is locally displayable is selected. If no such
  185. * equivalent file can be found, then a message box is displayed, indicating
  186. * that the file is being transmitted to the remote system.
  187. *
  188. * Parameters: pszFileName - The name of the file to send. This parameter may
  189. * explicitly specify the full filename and
  190. * extension, or the extension may be omitted. In the
  191. * case that the extension is omitted, this function
  192. * automatically selects the appropriate file type
  193. * for the current display mode (RIP, ANSI, etc.).
  194. *
  195. * Return: TRUE on success, or FALSE on failure.
  196. */
  197. ODAPIDEF BOOL ODCALL od_send_file(const char *pszFileName)
  198. {
  199. FILE *pfRemoteFile;
  200. FILE *pfLocalFile = NULL;
  201. BOOL bAnythingLocal = TRUE;
  202. void *pWindow;
  203. INT nFileLevel;
  204. BYTE btCount;
  205. BOOL bPausing;
  206. char chKey;
  207. char *pchParsing;
  208. char szMessage[74];
  209. /* Log function entry if running in trace mode. */
  210. TRACE(TRACE_API, "od_send_file()");
  211. /* Initialize OpenDoors if it hasn't already been done. */
  212. if(!bODInitialized) od_init();
  213. OD_API_ENTRY();
  214. if(!pszFileName)
  215. {
  216. od_control.od_error = ERR_PARAMETER;
  217. OD_API_EXIT();
  218. return(FALSE);
  219. }
  220. /* Initialize local variables. */
  221. btCount = 2;
  222. /* Turn on page pausing, if available. */
  223. bPausing = od_control.od_page_pausing;
  224. /* If operating in auto-filename mode (no extension specified). */
  225. if(strchr(pszFileName, '.') == NULL)
  226. {
  227. /* Begin by searching for a .RIP file. */
  228. nFileLevel = LEVEL_RIP;
  229. /* If no .ASC/.ANS/.AVT/.RIP file. */
  230. if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
  231. == NULL)
  232. {
  233. /* Then return with an error. */
  234. od_control.od_error = ERR_FILEOPEN;
  235. OD_API_EXIT();
  236. return(FALSE);
  237. }
  238. /* If the file found was a .RIP. */
  239. if(nFileLevel == LEVEL_RIP)
  240. {
  241. /* Search for file to display locally. */
  242. nFileLevel = LEVEL_AVATAR;
  243. /* No page pausing with .RIP display. */
  244. bPausing = FALSE;
  245. if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
  246. == NULL)
  247. {
  248. /* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */
  249. /* local display. */
  250. bAnythingLocal = FALSE;
  251. }
  252. }
  253. else if(nFileLevel == LEVEL_NONE)
  254. {
  255. od_control.od_error = ERR_FILEOPEN;
  256. OD_API_EXIT();
  257. return(FALSE);
  258. }
  259. /* Get filename of remote file. */
  260. strcpy(szODWorkString, pszFileName);
  261. strcat(szODWorkString, ".rip");
  262. strupr(szODWorkString);
  263. }
  264. else
  265. {
  266. /* If the full filename was specified, then attempt to open that file. */
  267. if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL)
  268. {
  269. /* If unable to open file, then return. */
  270. od_control.od_error = ERR_FILEOPEN;
  271. OD_API_EXIT();
  272. return(FALSE);
  273. }
  274. strcpy(szODWorkString, pszFileName);
  275. strupr(szODWorkString);
  276. if(strstr(szODWorkString, ".rip"))
  277. {
  278. /* No page pausing during .RIP display. */
  279. bPausing = FALSE;
  280. /* Disable local display. */
  281. bAnythingLocal = FALSE;
  282. }
  283. }
  284. /* Set default colour to grey on black. */
  285. btDefaultAttrib = 0x07;
  286. /* Reset all terminal emulation. */
  287. btAvatarSeqLevel = 0;
  288. btANSISeqLevel = 0;
  289. /* Turn off AVATAR insert mode. */
  290. bAvatarInsertMode = FALSE;
  291. /* Reset [S]top/[P]ause control key status. */
  292. chLastControlKey = 0;
  293. if(!bAnythingLocal)
  294. {
  295. strcpy(szODWorkString, od_control.od_sending_rip);
  296. strcat(szODWorkString, pszFileName);
  297. ODStringCopy(szMessage, szODWorkString, sizeof(szMessage));
  298. pWindow = ODScrnShowMessage(szMessage, 0);
  299. }
  300. /* Loop to display each line in the file(s) with page pausing, etc. */
  301. for(;;)
  302. {
  303. /* Call the OpenDoors kernel routine. */
  304. CALL_KERNEL_IF_NEEDED();
  305. /* If hotkeys are active. */
  306. if(pszCurrentHotkeys != NULL)
  307. {
  308. /* If a key is waiting in buffer. */
  309. while((chKey = (char)tolower(od_get_key(FALSE))) != 0)
  310. {
  311. /* Check for key in hotkey string. */
  312. pchParsing = (char *)pszCurrentHotkeys;
  313. while(*pchParsing)
  314. {
  315. /* If key is found. */
  316. if(tolower(*pchParsing) == chKey)
  317. {
  318. /* Return, indicating that hotkey was pressed. */
  319. chHotkeyPressed = *pchParsing;
  320. goto abort_send;
  321. }
  322. ++pchParsing;
  323. }
  324. }
  325. }
  326. /* If a control key has been pressed. */
  327. if(chLastControlKey)
  328. {
  329. switch(chLastControlKey)
  330. {
  331. /* If it was a stop control key. */
  332. case 's':
  333. if(od_control.od_list_stop)
  334. {
  335. /* If enabled, clear keyboard buffer. */
  336. abort_send:
  337. /* If operating in remote mode. */
  338. if(od_control.baud)
  339. {
  340. /* Clear the outbound FOSSIL buffer. */
  341. ODComClearOutbound(hSerialPort);
  342. }
  343. /* Return from function. */
  344. goto end_transmission;
  345. }
  346. break;
  347. /* If control key was "pause". */
  348. case 'p':
  349. /* If pause is enabled. */
  350. if(od_control.od_list_pause)
  351. {
  352. /* Clear keyboard buffer. */
  353. od_clear_keybuffer();
  354. /* Wait for any keypress. */
  355. od_get_key(TRUE);
  356. }
  357. }
  358. /* Clear control key status. */
  359. chLastControlKey = 0;
  360. }
  361. /* Get next line, if any. */
  362. if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL)
  363. {
  364. /* If different local file. */
  365. if(pfLocalFile)
  366. {
  367. /* Display rest of it. */
  368. while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile))
  369. {
  370. /* Pass each line to terminal emulator. */
  371. ODEmulateFromBuffer(szODWorkString, FALSE);
  372. }
  373. }
  374. /* Return from od_send_file(). */
  375. goto end_transmission;
  376. }
  377. /* Set parsepos = last char in globworkstr. */
  378. pchParsing = (char *)&szODWorkString;
  379. while(*++pchParsing) ;
  380. --pchParsing;
  381. /* Check for end of page state. */
  382. if((*pchParsing == '\r' || *pchParsing == '\n') &&
  383. ++btCount >= od_control.user_screen_length && bPausing)
  384. {
  385. /* Display page pause prompt. */
  386. if(ODPagePrompt(&bPausing))
  387. {
  388. /* If user chose to abort, then return from od_send_file(). */
  389. goto end_transmission;
  390. }
  391. /* Reset line count. */
  392. btCount = 2;
  393. }
  394. /* If the file is also to be displayed locally. */
  395. if(bAnythingLocal)
  396. {
  397. /* If the local file is different from the remote file, then obtain */
  398. /* the next line from the local file. */
  399. if(pfLocalFile)
  400. {
  401. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  402. if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL)
  403. {
  404. while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile))
  405. {
  406. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  407. }
  408. /* Return from od_send_file(). */
  409. goto end_transmission;
  410. }
  411. ODEmulateFromBuffer(szODWorkString, FALSE);
  412. }
  413. else
  414. {
  415. /* Pass the string through the local terminal emulation */
  416. /* system, and send a copy to the remote system. */
  417. if(od_control.od_no_ra_codes)
  418. {
  419. ODEmulateFromBuffer(szODWorkString, FALSE);
  420. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  421. }
  422. else
  423. {
  424. ODEmulateFromBuffer(szODWorkString,TRUE);
  425. }
  426. }
  427. }
  428. else
  429. {
  430. /* If the file is not being displayed locally, then just send the */
  431. /* entire line to the remote system (if any). */
  432. od_disp(szODWorkString,strlen(szODWorkString),FALSE);
  433. }
  434. }
  435. end_transmission:
  436. /* Close remote file. */
  437. fclose(pfRemoteFile);
  438. /* If there is a different local file, then close it too. */
  439. if(pfLocalFile)
  440. {
  441. fclose(pfLocalFile);
  442. }
  443. /* If we are not displaying anything on the local system. */
  444. if(!bAnythingLocal)
  445. {
  446. /* Wait while file is being sent. */
  447. if(od_control.baud != 0)
  448. {
  449. int nOutboundSize;
  450. do
  451. {
  452. CALL_KERNEL_IF_NEEDED();
  453. ODComOutbound(hSerialPort, &nOutboundSize);
  454. } while(nOutboundSize != 0);
  455. }
  456. /* Get rid of the window. */
  457. ODScrnRemoveMessage(pWindow);
  458. }
  459. OD_API_EXIT();
  460. return(TRUE);
  461. }
  462. /* ----------------------------------------------------------------------------
  463. * od_send_file_section()
  464. *
  465. * Displays a .ASC/.ANS/.AVT/.RIP multi-section file to the local and remote
  466. * screens. If OpenDoors is unable to display the required file format locally,
  467. * an equivalent file that is locally displayable is selected. If no such
  468. * equivalent file can be found, then a message box is displayed, incdicating
  469. * that the file is being transmitted to the remote system.
  470. *
  471. * Note: This function works virtually identical to od_send_file() except it
  472. * checks for the section headers (if found).
  473. *
  474. * Parameters: pszFileName - The name of the file to send. This parameter may
  475. * explicitly specify the full filename and
  476. * extension, or the extension may be omitted. In the
  477. * case that the extension is omitted, this function
  478. * automatically selects the appropriate file type
  479. * for the current display mode (RIP, ANSI, etc.).
  480. * pszSectionname - Name of the section in which to send. This
  481. * parameter must include only the section name
  482. * and not the @# delimiter.
  483. *
  484. * Return: TRUE on success, or FALSE on failure.
  485. */
  486. ODAPIDEF BOOL ODCALL od_send_file_section(char *pszFileName, char *pszSectionName)
  487. {
  488. FILE *pfRemoteFile;
  489. FILE *pfLocalFile = NULL;
  490. BOOL bAnythingLocal = TRUE;
  491. void *pWindow;
  492. INT nFileLevel;
  493. BYTE btCount;
  494. BOOL bPausing;
  495. char chKey;
  496. char *pchParsing;
  497. char szMessage[74];
  498. char szFullSectionName[256];
  499. BOOL bSectionFound = FALSE;
  500. UINT uSectionNameLength;
  501. /* Log function entry if running in trace mode. */
  502. TRACE(TRACE_API, "od_send_file_section()");
  503. /* Initialize OpenDoors if it hasn't already been done. */
  504. if(!bODInitialized) od_init();
  505. OD_API_ENTRY();
  506. if(!pszFileName || !pszSectionName)
  507. {
  508. od_control.od_error = ERR_PARAMETER;
  509. OD_API_EXIT();
  510. return(FALSE);
  511. }
  512. /* Initialize local variables. */
  513. btCount = 2;
  514. /* Turn on page pausing, if available. */
  515. bPausing = od_control.od_page_pausing;
  516. /* If operating in auto-filename mode (no extension specified). */
  517. if(strchr(pszFileName, '.') == NULL)
  518. {
  519. /* Begin by searching for a .RIP file. */
  520. nFileLevel = LEVEL_RIP;
  521. /* If no .ASC/.ANS/.AVT/.RIP file. */
  522. if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
  523. == NULL)
  524. {
  525. /* Then return with an error. */
  526. od_control.od_error = ERR_FILEOPEN;
  527. OD_API_EXIT();
  528. return(FALSE);
  529. }
  530. /* If the file found was a .RIP. */
  531. if(nFileLevel == LEVEL_RIP)
  532. {
  533. /* Search for file to display locally. */
  534. nFileLevel = LEVEL_AVATAR;
  535. /* No page pausing with .RIP display. */
  536. bPausing = FALSE;
  537. if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
  538. == NULL)
  539. {
  540. /* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */
  541. /* local display. */
  542. bAnythingLocal = FALSE;
  543. }
  544. }
  545. else if(nFileLevel == LEVEL_NONE)
  546. {
  547. od_control.od_error = ERR_FILEOPEN;
  548. OD_API_EXIT();
  549. return(FALSE);
  550. }
  551. /* Get filename of remote file. */
  552. strcpy(szODWorkString, pszFileName);
  553. strcat(szODWorkString, ".rip");
  554. strupr(szODWorkString);
  555. }
  556. else
  557. {
  558. /* If the full filename was specified, then attempt to open that file. */
  559. if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL)
  560. {
  561. /* If unable to open file, then return. */
  562. od_control.od_error = ERR_FILEOPEN;
  563. OD_API_EXIT();
  564. return(FALSE);
  565. }
  566. strcpy(szODWorkString, pszFileName);
  567. strupr(szODWorkString);
  568. if(strstr(szODWorkString, ".rip"))
  569. {
  570. /* No page pausing during .RIP display. */
  571. bPausing = FALSE;
  572. /* Disable local display. */
  573. bAnythingLocal = FALSE;
  574. }
  575. }
  576. /* Set default colour to grey on black. */
  577. btDefaultAttrib = 0x07;
  578. /* Reset all terminal emulation. */
  579. btAvatarSeqLevel = 0;
  580. btANSISeqLevel = 0;
  581. /* Turn off AVATAR insert mode. */
  582. bAvatarInsertMode = FALSE;
  583. /* Reset [S]top/[P]ause control key status. */
  584. chLastControlKey = 0;
  585. if(!bAnythingLocal)
  586. {
  587. strcpy(szODWorkString, od_control.od_sending_rip);
  588. strcat(szODWorkString, pszFileName);
  589. ODStringCopy(szMessage, szODWorkString, sizeof(szMessage));
  590. pWindow = ODScrnShowMessage(szMessage, 0);
  591. }
  592. /* Create section name information */
  593. strcpy(szFullSectionName, "@#");
  594. strncat(szFullSectionName, pszSectionName, 254);
  595. /* Get the length of the section name in it's full form */
  596. uSectionNameLength = strlen(szFullSectionName);
  597. /* Loop to display each line in the file(s) with page pausing, etc. */
  598. for(;;)
  599. {
  600. /* Call the OpenDoors kernel routine. */
  601. CALL_KERNEL_IF_NEEDED();
  602. /* If hotkeys are active. */
  603. if(pszCurrentHotkeys != NULL)
  604. {
  605. /* If a key is waiting in buffer. */
  606. while((chKey = (char)tolower(od_get_key(FALSE))) != 0)
  607. {
  608. /* Check for key in hotkey string. */
  609. pchParsing = (char *)pszCurrentHotkeys;
  610. while(*pchParsing)
  611. {
  612. /* If key is found. */
  613. if(tolower(*pchParsing) == chKey)
  614. {
  615. /* Return, indicating that hotkey was pressed. */
  616. chHotkeyPressed = *pchParsing;
  617. goto abort_send;
  618. }
  619. ++pchParsing;
  620. }
  621. }
  622. }
  623. /* If a control key has been pressed. */
  624. if(chLastControlKey)
  625. {
  626. switch(chLastControlKey)
  627. {
  628. /* If it was a stop control key. */
  629. case 's':
  630. if(od_control.od_list_stop)
  631. {
  632. /* If enabled, clear keyboard buffer. */
  633. abort_send:
  634. /* If operating in remote mode. */
  635. if(od_control.baud)
  636. {
  637. /* Clear the outbound FOSSIL buffer. */
  638. ODComClearOutbound(hSerialPort);
  639. }
  640. /* Return from function. */
  641. goto end_transmission;
  642. }
  643. break;
  644. /* If control key was "pause". */
  645. case 'p':
  646. /* If pause is enabled. */
  647. if(od_control.od_list_pause)
  648. {
  649. /* Clear keyboard buffer. */
  650. od_clear_keybuffer();
  651. /* Wait for any keypress. */
  652. od_get_key(TRUE);
  653. }
  654. }
  655. /* Clear control key status. */
  656. chLastControlKey = 0;
  657. }
  658. /* Get next line, if any. */
  659. if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL)
  660. {
  661. /* If different local file. */
  662. if(pfLocalFile)
  663. {
  664. /* Display rest of it. */
  665. while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile))
  666. {
  667. if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0)
  668. {
  669. /* Section Found, allow all lines up to EOF or new section to be displayed */
  670. bSectionFound = TRUE;
  671. /* Read next line, ignore the section line */
  672. continue;
  673. }
  674. else if (!bSectionFound)
  675. {
  676. /* Section not found yet, continue loop */
  677. continue;
  678. }
  679. else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0)
  680. {
  681. /* New Section Intercepted */
  682. goto end_transmission;
  683. }
  684. /* Pass each line to terminal emulator. */
  685. ODEmulateFromBuffer(szODWorkString, FALSE);
  686. }
  687. }
  688. /* Return from od_send_file(). */
  689. goto end_transmission;
  690. }
  691. /* Check for section header @# + pszSectionName */
  692. if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0)
  693. {
  694. /* Flag the section as found */
  695. bSectionFound = TRUE;
  696. /* Read next line, ignore section line */
  697. continue;
  698. }
  699. else if (!bSectionFound)
  700. {
  701. /* Section hasn't been found yet */
  702. continue;
  703. }
  704. else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0)
  705. {
  706. /* New section found, terminate send */
  707. goto end_transmission;
  708. }
  709. /* Set parsepos = last char in globworkstr. */
  710. pchParsing = (char *)&szODWorkString;
  711. while(*++pchParsing) ;
  712. --pchParsing;
  713. /* Check for end of page state. */
  714. if((*pchParsing == '\r' || *pchParsing == '\n') &&
  715. ++btCount >= od_control.user_screen_length && bPausing)
  716. {
  717. /* Display page pause prompt. */
  718. if(ODPagePrompt(&bPausing))
  719. {
  720. /* If user chose to abort, then return from od_send_file(). */
  721. goto end_transmission;
  722. }
  723. /* Reset line count. */
  724. btCount = 2;
  725. }
  726. /* If the file is also to be displayed locally. */
  727. if(bAnythingLocal)
  728. {
  729. /* If the local file is different from the remote file, then obtain */
  730. /* the next line from the local file. */
  731. if(pfLocalFile)
  732. {
  733. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  734. if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL)
  735. {
  736. while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile))
  737. {
  738. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  739. }
  740. /* Return from od_send_file(). */
  741. goto end_transmission;
  742. }
  743. ODEmulateFromBuffer(szODWorkString, FALSE);
  744. }
  745. else
  746. {
  747. /* Pass the string through the local terminal emulation */
  748. /* system, and send a copy to the remote system. */
  749. if(od_control.od_no_ra_codes)
  750. {
  751. ODEmulateFromBuffer(szODWorkString, FALSE);
  752. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  753. }
  754. else
  755. {
  756. ODEmulateFromBuffer(szODWorkString,TRUE);
  757. }
  758. }
  759. }
  760. else
  761. {
  762. /* If the file is not being displayed locally, then just send the */
  763. /* entire line to the remote system (if any). */
  764. od_disp(szODWorkString,strlen(szODWorkString),FALSE);
  765. }
  766. }
  767. end_transmission:
  768. /* Close remote file. */
  769. fclose(pfRemoteFile);
  770. /* If there is a different local file, then close it too. */
  771. if(pfLocalFile)
  772. {
  773. fclose(pfLocalFile);
  774. }
  775. /* If we are not displaying anything on the local system. */
  776. if(!bAnythingLocal)
  777. {
  778. /* Wait while file is being sent. */
  779. if(od_control.baud != 0)
  780. {
  781. int nOutboundSize;
  782. do
  783. {
  784. CALL_KERNEL_IF_NEEDED();
  785. ODComOutbound(hSerialPort, &nOutboundSize);
  786. } while(nOutboundSize != 0);
  787. }
  788. /* Get rid of the window. */
  789. ODScrnRemoveMessage(pWindow);
  790. }
  791. /* If the section was not found, return FALSE for error */
  792. if (!bSectionFound)
  793. {
  794. OD_API_EXIT();
  795. return (FALSE);
  796. }
  797. OD_API_EXIT();
  798. return(TRUE);
  799. }
  800. /* ----------------------------------------------------------------------------
  801. * ODEmulateFindCompatFile() *** PRIVATE FUNCTION ***
  802. *
  803. * Searches for an .ASC/.ANS/.AVT/.RIP file that is compatible with the
  804. * specified display capabilities level.
  805. *
  806. * Parameters: pszBaseName - Base filename to use.
  807. *
  808. * pnLevel - Highest file level to search for. This value is
  809. * updated to indicate the type of file found.
  810. *
  811. * Return: A pointer to a now-open file of the required type, or NULL if
  812. * no match was found.
  813. */
  814. static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel)
  815. {
  816. FILE *pfCompatibleFile;
  817. ASSERT(pszBaseName != NULL);
  818. ASSERT(pnLevel != NULL);
  819. ASSERT(*pnLevel >= 0 && *pnLevel <= 4);
  820. /* Loop though .RIP/.AVT/.ANS/.ASC extensions. */
  821. for(;*pnLevel > LEVEL_NONE; --*pnLevel)
  822. {
  823. /* Get base-filename passed in. */
  824. strcpy(szODWorkString, pszBaseName);
  825. /* Try current extension. */
  826. switch(*pnLevel)
  827. {
  828. case LEVEL_RIP:
  829. if(!od_control.user_rip) continue;
  830. strcat(szODWorkString, ".rip");
  831. break;
  832. case LEVEL_AVATAR:
  833. if(!od_control.user_avatar) continue;
  834. strcat(szODWorkString, ".avt");
  835. break;
  836. case LEVEL_ANSI:
  837. if(!od_control.user_ansi) continue;
  838. strcat(szODWorkString, ".ans");
  839. break;
  840. case LEVEL_ASCII:
  841. strcat(szODWorkString, ".asc");
  842. break;
  843. }
  844. /* If we are able to open this file, then return a pointer to */
  845. /* the file. */
  846. if((pfCompatibleFile = fopen(szODWorkString,"rb")) != NULL)
  847. return(pfCompatibleFile);
  848. }
  849. /* Return NULL if no file was found. */
  850. return(NULL);
  851. }
  852. /* ----------------------------------------------------------------------------
  853. * od_disp_emu()
  854. *
  855. * Sends an entire string to both local and remote systems. The characters
  856. * displayed locally are fed through the local terminal emulation sub-system,
  857. * allowing aribtrary ANSI/AVATAR control sequences to be displayed both
  858. * locally and remotely.
  859. *
  860. * Parameters: pszToDisplay - Pointer to string to display.
  861. *
  862. * bRemoteEcho - TRUE if characters should also be transmitted
  863. * to the remote system.
  864. *
  865. * Return: void
  866. */
  867. ODAPIDEF void ODCALL od_disp_emu(const char *pszToDisplay, BOOL bRemoteEcho)
  868. {
  869. BOOL bTranslateRemote;
  870. /* Log function entry if running in trace mode. */
  871. TRACE(TRACE_API, "od_disp_emu()");
  872. /* Ensure that OpenDoors has been initialized. */
  873. if(!bODInitialized) od_init();
  874. OD_API_ENTRY();
  875. /* Send pszToDisplay to remote system. */
  876. if(bRemoteEcho)
  877. {
  878. if(od_control.od_no_ra_codes)
  879. {
  880. od_disp(pszToDisplay, strlen(pszToDisplay), FALSE);
  881. bTranslateRemote = FALSE;
  882. }
  883. else
  884. {
  885. bTranslateRemote = TRUE;
  886. }
  887. }
  888. else
  889. {
  890. bTranslateRemote = FALSE;
  891. }
  892. /* Pass string to be emulated to local terminal emulation function. */
  893. ODEmulateFromBuffer(pszToDisplay, bTranslateRemote);
  894. OD_API_EXIT();
  895. }
  896. /* ----------------------------------------------------------------------------
  897. * od_emulate()
  898. *
  899. * Sends a single character to both local and remote systems. The characters
  900. * displayed locally are fed through the local terminal emulation sub-system,
  901. * allowing aribtrary ANSII/AVATAR control sequences to be displayed both
  902. * locally and remotely.
  903. *
  904. * Parameters: chToEmulate - Character to feed through the terminal emulator.
  905. *
  906. * Return: void
  907. */
  908. ODAPIDEF void ODCALL od_emulate(char chToEmulate)
  909. {
  910. static char szBuffer[2];
  911. *szBuffer = chToEmulate;
  912. /* Log function entry if running in trace mode. */
  913. TRACE(TRACE_API, "od_emulate()");
  914. /* Ensure that OpenDoors has been initialized. */
  915. if(!bODInitialized) od_init();
  916. OD_API_ENTRY();
  917. /* Pass character to be emulated to local terminal emulation function. */
  918. ODEmulateFromBuffer(szBuffer, TRUE);
  919. OD_API_EXIT();
  920. }
  921. /* ----------------------------------------------------------------------------
  922. * ODEmulateFromBuffer() *** PRIVATE FUNCTION ***
  923. *
  924. * Displays a string on the local screen, interpreting any terminal emulation
  925. * control sequences. The string may also be sent to the remote system at the
  926. * same time.
  927. *
  928. * Parameters: pszBuffer - Pointer to the string to transmit.
  929. *
  930. * bRemoteEcho - TRUE if string should also be sent to the remote
  931. * system, FALSE if it should not be.
  932. *
  933. * Return: void
  934. */
  935. static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho)
  936. {
  937. char chCurrent;
  938. static tODScrnTextInfo TextInfo;
  939. INT nTemp;
  940. BOOL bEchoThisChar;
  941. INT nCharsPerTick;
  942. INT nCharsThisTick;
  943. tODTimer ModemSimTimer;
  944. ASSERT(pszBuffer != NULL);
  945. /* If we should simulate modem transmission speed. */
  946. if(od_control.od_emu_simulate_modem)
  947. {
  948. DWORD lCharsPerSecond;
  949. /* Determine character per second rate to simulate. */
  950. if(od_control.baud == 0)
  951. {
  952. lCharsPerSecond = 960L;
  953. }
  954. else
  955. {
  956. ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL,
  957. od_control.od_connect_speed, 10L);
  958. }
  959. /* Determine number of characters to send per timer tick. */
  960. lCharsPerSecond = ODDWordMultiply(lCharsPerSecond, MODEM_SIMULATOR_TICK);
  961. ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL, lCharsPerSecond, 1000L);
  962. nCharsPerTick = (INT)lCharsPerSecond;
  963. /* Start tick timer. */
  964. ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK);
  965. /* Reset number of characters that we have sent during this tick. */
  966. nCharsThisTick = 0;
  967. }
  968. while(*pszBuffer)
  969. {
  970. /* Read the next character from the buffer into local variable for */
  971. /* access speed efficiency. */
  972. chCurrent = *pszBuffer;
  973. /* If we should simulate modem transmission speed. */
  974. if(od_control.od_emu_simulate_modem)
  975. {
  976. /* If we have now sent all of the characters that should be sent */
  977. /* during this tick. */
  978. if(nCharsThisTick++ >= nCharsPerTick)
  979. {
  980. /* Wait for timer to elapse. */
  981. ODTimerWaitForElapse(&ModemSimTimer);
  982. /* Restart tick timer. */
  983. ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK);
  984. /* Reset characters sent in this tick. */
  985. nCharsThisTick = 0;
  986. }
  987. }
  988. bEchoThisChar = bRemoteEcho;
  989. /* Switch according to ANSI emulator state. */
  990. switch(btANSISeqLevel)
  991. {
  992. /* If we are not in the middle of an ANSI command string. */
  993. case 0:
  994. /* Switch according to current character. */
  995. switch(chCurrent)
  996. {
  997. /* If this is the escape character. */
  998. case 27:
  999. /* If we are not in the middle of an AVATAR sequence. */
  1000. if(btAvatarSeqLevel == 0)
  1001. {
  1002. /* Then treat this as the start an ANSI sequence. */
  1003. btANSISeqLevel = 1;
  1004. break;
  1005. }
  1006. /* Deliberate fallthrough to default case. */
  1007. /* If not start of an ANSI sequence. */
  1008. default:
  1009. /* Check our position in AVATAR sequence. */
  1010. switch(btAvatarSeqLevel)
  1011. {
  1012. /* If not in middle of an AVATAR command. */
  1013. case 0:
  1014. /* Check the character we've been sent. */
  1015. switch(chCurrent)
  1016. {
  1017. /* Check for QBBS/RA pause for keypress code. */
  1018. case 0x01:
  1019. if(od_control.od_no_ra_codes)
  1020. {
  1021. goto output_next_char;
  1022. }
  1023. /* Wait for user to press [ENTER] key. */
  1024. od_get_answer("\n\r");
  1025. bEchoThisChar = FALSE;
  1026. break;
  1027. /* QBBS/RA ^F user parameters. */
  1028. case 0x06:
  1029. if(od_control.od_no_ra_codes)
  1030. {
  1031. goto output_next_char;
  1032. }
  1033. btAvatarSeqLevel = 21;
  1034. bEchoThisChar = FALSE;
  1035. break;
  1036. /* QBBS/RA ^K user parameters. */
  1037. case 0x0b:
  1038. if(od_control.od_no_ra_codes)
  1039. {
  1040. goto output_next_char;
  1041. }
  1042. btAvatarSeqLevel = 22;
  1043. bEchoThisChar = FALSE;
  1044. break;
  1045. case 0x0c:
  1046. bAvatarInsertMode = FALSE;
  1047. ODScrnSetAttribute((BYTE)(
  1048. od_control.od_cur_attrib = btDefaultAttrib));
  1049. ODScrnClear();
  1050. break;
  1051. case 0x19:
  1052. bAvatarInsertMode = FALSE;
  1053. btAvatarSeqLevel = 1;
  1054. break;
  1055. case 0x16: /* ^V */
  1056. btAvatarSeqLevel = 3;
  1057. break;
  1058. default:
  1059. output_next_char:
  1060. /* Output next character. */
  1061. if(bAvatarInsertMode)
  1062. {
  1063. ODScrnGetTextInfo(&TextInfo);
  1064. if(TextInfo.curx < 80)
  1065. {
  1066. ODScrnCopyText(TextInfo.curx,
  1067. TextInfo.cury, 79, TextInfo.cury,
  1068. (BYTE)(TextInfo.curx + 1),
  1069. TextInfo.cury);
  1070. }
  1071. ODScrnDisplayChar(chCurrent);
  1072. }
  1073. else
  1074. {
  1075. ODScrnDisplayChar(chCurrent);
  1076. }
  1077. }
  1078. break;
  1079. case 1:
  1080. bAvatarInsertMode = FALSE;
  1081. chPrevParam = chCurrent;
  1082. btAvatarSeqLevel = 2;
  1083. break;
  1084. case 2:
  1085. for(nTemp = 0; nTemp < (INT)chCurrent;
  1086. ++nTemp)
  1087. {
  1088. ODScrnDisplayChar(chPrevParam);
  1089. }
  1090. btAvatarSeqLevel = 0;
  1091. break;
  1092. case 3:
  1093. switch(chCurrent)
  1094. {
  1095. case 0x01:
  1096. bAvatarInsertMode = FALSE;
  1097. btAvatarSeqLevel = 4;
  1098. break;
  1099. case 0x02:
  1100. bAvatarInsertMode = FALSE;
  1101. ODScrnGetTextInfo(&TextInfo);
  1102. ODScrnSetAttribute((BYTE)
  1103. (od_control.od_cur_attrib =
  1104. TextInfo.attribute | 0x80));
  1105. btAvatarSeqLevel = 0;
  1106. break;
  1107. case 0x03:
  1108. bAvatarInsertMode = FALSE;
  1109. ODScrnGetTextInfo(&TextInfo);
  1110. if(TextInfo.cury > 1)
  1111. {
  1112. ODScrnSetCursorPos(TextInfo.curx,
  1113. (BYTE)(TextInfo.cury - 1));
  1114. }
  1115. btAvatarSeqLevel = 0;
  1116. break;
  1117. case 0x04:
  1118. bAvatarInsertMode = FALSE;
  1119. ODScrnGetTextInfo(&TextInfo);
  1120. if(TextInfo.cury < 25)
  1121. {
  1122. ODScrnSetCursorPos(TextInfo.curx,
  1123. (BYTE)(TextInfo.cury + 1));
  1124. }
  1125. btAvatarSeqLevel = 0;
  1126. break;
  1127. case 0x05:
  1128. bAvatarInsertMode = FALSE;
  1129. ODScrnGetTextInfo(&TextInfo);
  1130. if(TextInfo.curx > 1)
  1131. {
  1132. ODScrnSetCursorPos((BYTE)(TextInfo.curx - 1),
  1133. TextInfo.cury);
  1134. }
  1135. btAvatarSeqLevel = 0;
  1136. break;
  1137. case 0x06:
  1138. bAvatarInsertMode = FALSE;
  1139. ODScrnGetTextInfo(&TextInfo);
  1140. if(TextInfo.curx < 80)
  1141. {
  1142. ODScrnSetCursorPos((BYTE)(TextInfo.curx + 1),
  1143. TextInfo.cury);
  1144. }
  1145. btAvatarSeqLevel = 0;
  1146. break;
  1147. case 0x07:
  1148. bAvatarInsertMode = FALSE;
  1149. ODScrnClearToEndOfLine();
  1150. btAvatarSeqLevel = 0;
  1151. break;
  1152. case 0x08:
  1153. bAvatarInsertMode = FALSE;
  1154. btAvatarSeqLevel = 5;
  1155. break;
  1156. case 0x09: /* ^I */
  1157. bAvatarInsertMode = TRUE;
  1158. btAvatarSeqLevel = 0;
  1159. break;
  1160. case 0x0a: /* ^J */
  1161. btScrollLines = -1;
  1162. btAvatarSeqLevel = 7;
  1163. break;
  1164. case 0x0b: /* ^K */
  1165. btScrollLines = 1;
  1166. btAvatarSeqLevel = 7;
  1167. break;
  1168. case 0x0c: /* ^L */
  1169. btAvatarSeqLevel = 14;
  1170. break;
  1171. case 0x0d: /* ^M */
  1172. btAvatarSeqLevel = 15;
  1173. break;
  1174. case 0x0e: /* ^N */
  1175. ODScrnGetTextInfo(&TextInfo);
  1176. if(TextInfo.curx < 80)
  1177. {
  1178. ODScrnCopyText((BYTE)(TextInfo.curx + 1),
  1179. TextInfo.cury, 80, TextInfo.cury,
  1180. TextInfo.curx, TextInfo.cury);
  1181. }
  1182. ODScrnEnableScrolling(FALSE);
  1183. ODScrnSetCursorPos(80, TextInfo.cury);
  1184. ODScrnDisplayChar(' ');
  1185. ODScrnEnableScrolling(TRUE);
  1186. ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
  1187. btAvatarSeqLevel = 0;
  1188. break;
  1189. case 0x19: /* ^Y */
  1190. btAvatarSeqLevel = 19;
  1191. break;
  1192. default:
  1193. btAvatarSeqLevel = 0;
  1194. }
  1195. break;
  1196. case 4:
  1197. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1198. = chCurrent));
  1199. btAvatarSeqLevel = 0;
  1200. break;
  1201. case 5:
  1202. chPrevParam = chCurrent;
  1203. btAvatarSeqLevel = 6;
  1204. break;
  1205. case 6:
  1206. ODScrnSetCursorPos(chCurrent, chPrevParam);
  1207. btAvatarSeqLevel = 0;
  1208. break;
  1209. case 7:
  1210. if(btScrollLines < 1)
  1211. {
  1212. btScrollLines = chCurrent;
  1213. }
  1214. else
  1215. {
  1216. btScrollLines = -chCurrent;
  1217. }
  1218. btAvatarSeqLevel = 8;
  1219. break;
  1220. case 8:
  1221. btScrollTop = chCurrent;
  1222. btAvatarSeqLevel = 9;
  1223. break;
  1224. case 9:
  1225. btScrollLeft = chCurrent;
  1226. btAvatarSeqLevel = 10;
  1227. break;
  1228. case 10:
  1229. btScrollBottom = chCurrent;
  1230. btAvatarSeqLevel = 11;
  1231. break;
  1232. case 11:
  1233. btScrollRight = chCurrent;
  1234. btAvatarSeqLevel = 12;
  1235. break;
  1236. case 12:
  1237. if(btScrollLines == 0
  1238. || abs(btScrollLines) >
  1239. (btScrollBottom - btScrollTop))
  1240. {
  1241. ODEmulateFillArea(btScrollLeft, btScrollTop,
  1242. btScrollRight, btScrollBottom, ' ');
  1243. }
  1244. else if(btScrollLines < 0)
  1245. {
  1246. ODScrnCopyText(btScrollLeft, btScrollTop,
  1247. btScrollRight,
  1248. (BYTE)(btScrollBottom + btScrollLines),
  1249. btScrollLeft,
  1250. (BYTE)(btScrollTop - btScrollLines));
  1251. ODEmulateFillArea(btScrollLeft, btScrollTop,
  1252. btScrollRight,
  1253. (BYTE)(btScrollTop - (btScrollLines - 1)), ' ');
  1254. }
  1255. else
  1256. {
  1257. ODScrnCopyText(btScrollLeft,
  1258. (BYTE)(btScrollTop + btScrollLines),
  1259. btScrollRight, btScrollBottom,
  1260. btScrollLeft, btScrollTop);
  1261. ODEmulateFillArea(btScrollLeft,
  1262. (BYTE)(btScrollBottom - (btScrollLines - 1)),
  1263. btScrollRight, btScrollBottom, ' ');
  1264. }
  1265. btAvatarSeqLevel = 0;
  1266. break;
  1267. case 14:
  1268. btScrollLines = (chCurrent & 0x7f);
  1269. btScrollRight = ' ';
  1270. btAvatarSeqLevel = 17;
  1271. break;
  1272. case 15:
  1273. btScrollLines = (chCurrent & 0x7f);
  1274. btAvatarSeqLevel = 16;
  1275. break;
  1276. case 16:
  1277. btScrollRight = chCurrent;
  1278. btAvatarSeqLevel = 17;
  1279. break;
  1280. case 17:
  1281. btScrollTop = chCurrent;
  1282. btAvatarSeqLevel = 18;
  1283. break;
  1284. case 18:
  1285. ODScrnGetTextInfo(&TextInfo);
  1286. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1287. = btScrollLines));
  1288. ODEmulateFillArea(TextInfo.curx, TextInfo.cury,
  1289. (BYTE)(TextInfo.curx + chCurrent),
  1290. (BYTE)(TextInfo.cury + btScrollTop), btScrollRight);
  1291. btAvatarSeqLevel = 0;
  1292. break;
  1293. case 19:
  1294. btScrollLines = (chCurrent & 0x7f);
  1295. szToRepeat[btRepeatCount = 0] = '\0';
  1296. btAvatarSeqLevel = 20;
  1297. break;
  1298. case 20:
  1299. if(btRepeatCount < btScrollLines)
  1300. {
  1301. szToRepeat[btRepeatCount] = chCurrent;
  1302. szToRepeat[++btRepeatCount] = '\0';
  1303. }
  1304. else
  1305. {
  1306. for(btRepeatCount = 0; btRepeatCount <
  1307. (BYTE)chCurrent;++btRepeatCount)
  1308. {
  1309. ODScrnDisplayString(szToRepeat);
  1310. }
  1311. btAvatarSeqLevel = 0;
  1312. }
  1313. break;
  1314. /* RA/QBBS ^F control codes. */
  1315. case 21:
  1316. bEchoThisChar = FALSE;
  1317. switch(chCurrent)
  1318. {
  1319. case 'A':
  1320. od_disp_str(od_control.user_name);
  1321. break;
  1322. case 'B':
  1323. od_disp_str(od_control.user_location);
  1324. break;
  1325. case 'C':
  1326. od_disp_str(od_control.user_password);
  1327. break;
  1328. case 'D':
  1329. od_disp_str(od_control.user_dataphone);
  1330. break;
  1331. case 'E':
  1332. od_disp_str(od_control.user_homephone);
  1333. break;
  1334. case 'F':
  1335. od_disp_str(od_control.user_lastdate);
  1336. break;
  1337. case 'G':
  1338. od_disp_str(od_control.user_lasttime);
  1339. break;
  1340. case 'H':
  1341. btScrollLines = 0;
  1342. goto show_flags;
  1343. case 'I':
  1344. btScrollLines = 1;
  1345. goto show_flags;
  1346. case 'J':
  1347. btScrollLines = 2;
  1348. goto show_flags;
  1349. case 'K':
  1350. btScrollLines = 3;
  1351. show_flags: for(btRepeatCount = 0; btRepeatCount < 8;
  1352. ++btRepeatCount)
  1353. {
  1354. if((od_control.user_flags[btScrollLines] >>
  1355. btRepeatCount) & 0x01)
  1356. {
  1357. szToRepeat[btRepeatCount] = 'X';
  1358. }
  1359. else
  1360. {
  1361. szToRepeat[btRepeatCount] = '-';
  1362. }
  1363. }
  1364. szToRepeat[btRepeatCount] = '\0';
  1365. od_disp_str(szToRepeat);
  1366. break;
  1367. case 'L':
  1368. od_printf("%lu", od_control.user_net_credit);
  1369. break;
  1370. case 'M':
  1371. od_printf("%u", od_control.user_messages);
  1372. break;
  1373. case 'N':
  1374. od_printf("%u", od_control.user_lastread);
  1375. break;
  1376. case 'O':
  1377. od_printf("%u", od_control.user_security);
  1378. break;
  1379. case 'P':
  1380. od_printf("%u", od_control.user_numcalls);
  1381. break;
  1382. case 'Q':
  1383. od_printf("%ul", od_control.user_uploads);
  1384. break;
  1385. case 'R':
  1386. od_printf("%ul", od_control.user_upk);
  1387. break;
  1388. case 'S':
  1389. od_printf("%ul", od_control.user_downloads);
  1390. break;
  1391. case 'T':
  1392. od_printf("%ul", od_control.user_downk);
  1393. break;
  1394. case 'U':
  1395. od_printf("%d", od_control.user_time_used);
  1396. break;
  1397. case 'V':
  1398. od_printf("%d", od_control.user_screen_length);
  1399. break;
  1400. case 'W':
  1401. btRepeatCount = 0;
  1402. while(od_control.user_name[btRepeatCount])
  1403. {
  1404. if((szToRepeat[btRepeatCount]
  1405. = od_control.user_name[btRepeatCount])
  1406. == ' ')
  1407. {
  1408. szToRepeat[btRepeatCount] = '\0';
  1409. break;
  1410. }
  1411. ++btRepeatCount;
  1412. }
  1413. od_disp_str(szToRepeat);
  1414. break;
  1415. case 'X':
  1416. if(od_control.user_ansi)
  1417. {
  1418. od_disp_str("ON");
  1419. }
  1420. else
  1421. {
  1422. od_disp_str("OFF");
  1423. }
  1424. break;
  1425. case 'Y':
  1426. if(od_control.user_attribute & 0x04)
  1427. {
  1428. od_disp_str("ON");
  1429. }
  1430. else
  1431. {
  1432. od_disp_str("OFF");
  1433. }
  1434. break;
  1435. case 'Z':
  1436. if(od_control.user_attribute & 0x02)
  1437. {
  1438. od_disp_str("ON");
  1439. }
  1440. else
  1441. {
  1442. od_disp_str("OFF");
  1443. }
  1444. break;
  1445. case '0':
  1446. if(od_control.user_attribute & 0x40)
  1447. {
  1448. od_disp_str("ON");
  1449. }
  1450. else
  1451. {
  1452. od_disp_str("OFF");
  1453. }
  1454. break;
  1455. case '1':
  1456. if(od_control.user_attribute & 0x80)
  1457. {
  1458. od_disp_str("ON");
  1459. }
  1460. else
  1461. {
  1462. od_disp_str("OFF");
  1463. }
  1464. break;
  1465. case '2':
  1466. if(od_control.user_attrib2 & 0x01)
  1467. {
  1468. od_disp_str("ON");
  1469. }
  1470. else
  1471. {
  1472. od_disp_str("OFF");
  1473. }
  1474. break;
  1475. case '3':
  1476. od_disp_str(od_control.user_handle);
  1477. break;
  1478. case '4':
  1479. od_disp_str(od_control.user_firstcall);
  1480. break;
  1481. case '5':
  1482. od_disp_str(od_control.user_birthday);
  1483. break;
  1484. case '6':
  1485. od_disp_str(od_control.user_subdate);
  1486. break;
  1487. case '7':
  1488. /* days until subscrption expiry */
  1489. break;
  1490. case '8':
  1491. if(od_control.user_attrib2 & 0x02)
  1492. {
  1493. od_disp_str("ON");
  1494. }
  1495. else
  1496. {
  1497. od_disp_str("OFF");
  1498. }
  1499. break;
  1500. case '9':
  1501. od_printf("%lu:%lu",
  1502. od_control.user_uploads,
  1503. od_control.user_downloads);
  1504. break;
  1505. case ':':
  1506. od_printf("%lu:%lu",
  1507. od_control.user_upk,
  1508. od_control.user_downk);
  1509. break;
  1510. case ';':
  1511. if(od_control.user_attrib2 & 0x04)
  1512. {
  1513. od_disp_str("ON");
  1514. }
  1515. else
  1516. {
  1517. od_disp_str("OFF");
  1518. }
  1519. }
  1520. btAvatarSeqLevel=0;
  1521. break;
  1522. /* QBBS/RA ^K control codes. */
  1523. case 22:
  1524. bEchoThisChar = FALSE;
  1525. switch(chCurrent)
  1526. {
  1527. case 'A':
  1528. od_printf("%lu", od_control.system_calls);
  1529. break;
  1530. case 'B':
  1531. od_disp_str(od_control.system_last_caller);
  1532. break;
  1533. case 'C':
  1534. /* number of active messages */
  1535. break;
  1536. case 'D':
  1537. /* system starting message number */
  1538. break;
  1539. case 'E':
  1540. /* system ending message number */
  1541. break;
  1542. case 'F':
  1543. /* number of times user has paged sysop */
  1544. break;
  1545. case 'G':
  1546. /* day of the week (Monday, Tuesday, etc.) */
  1547. break;
  1548. case 'H':
  1549. /* number of users in user file */
  1550. break;
  1551. case 'I':
  1552. /* Time in 24 hour format */
  1553. break;
  1554. case 'J':
  1555. /* today's date */
  1556. break;
  1557. case 'K':
  1558. /* minutes connected this call */
  1559. break;
  1560. case 'L':
  1561. /* Seconds connected (0) */
  1562. break;
  1563. case 'M':
  1564. od_printf("%d", od_control.user_time_used);
  1565. break;
  1566. case 'N':
  1567. od_disp_str("00");
  1568. break;
  1569. case 'O':
  1570. /* Minutes remaining today */
  1571. od_printf("%d", od_control.user_timelimit);
  1572. break;
  1573. case 'P':
  1574. /* seconds remaining today (0) */
  1575. break;
  1576. case 'Q':
  1577. od_printf("0", od_control.user_timelimit);
  1578. break;
  1579. case 'R': /* current baud rate */
  1580. od_printf("0", od_control.baud);
  1581. break;
  1582. case 'S':
  1583. /* day of the week (MON, TUE) */
  1584. break;
  1585. case 'T':
  1586. /* Daily download limit (in K) */
  1587. break;
  1588. case 'U':
  1589. /* Minutes until next system event */
  1590. break;
  1591. case 'V':
  1592. ODScrnDisplayString(od_control.event_starttime);
  1593. break;
  1594. case 'W':
  1595. /* line number (from command line) */
  1596. break;
  1597. case 'X':
  1598. od_exit(2, TRUE);
  1599. break;
  1600. case 'Y':
  1601. /* Name of current msg area */
  1602. break;
  1603. case 'Z':
  1604. /* name of current file area */
  1605. break;
  1606. case '0':
  1607. /* # of messages in area */
  1608. break;
  1609. case '1':
  1610. /* # of message area */
  1611. break;
  1612. case '2':
  1613. /* # of file area */
  1614. break;
  1615. }
  1616. btAvatarSeqLevel = 0;
  1617. }
  1618. }
  1619. break;
  1620. case 1:
  1621. switch(chCurrent)
  1622. {
  1623. case '[':
  1624. btANSISeqLevel = 2;
  1625. btCurrentParamLength = 0;
  1626. btNumParams = 0;
  1627. break;
  1628. default:
  1629. btANSISeqLevel = 0;
  1630. ODScrnDisplayChar(27);
  1631. ODScrnDisplayChar(chCurrent);
  1632. }
  1633. break;
  1634. default:
  1635. if((chCurrent >= '0' && chCurrent <= '9') || chCurrent == '?')
  1636. {
  1637. if(btCurrentParamLength < 3)
  1638. {
  1639. szCurrentParam[btCurrentParamLength] = chCurrent;
  1640. szCurrentParam[++btCurrentParamLength] = '\0';
  1641. }
  1642. else
  1643. {
  1644. btANSISeqLevel = 0;
  1645. }
  1646. }
  1647. else if(chCurrent == ';')
  1648. {
  1649. if(btNumParams < 10)
  1650. {
  1651. if(btCurrentParamLength != 0)
  1652. {
  1653. if(strcmp(szCurrentParam, "?9") == 0)
  1654. {
  1655. anANSIParams[btNumParams] = -2;
  1656. }
  1657. else
  1658. {
  1659. anANSIParams[btNumParams] = atoi(szCurrentParam);
  1660. }
  1661. szCurrentParam[0] = '\0';
  1662. btCurrentParamLength = 0;
  1663. ++btNumParams;
  1664. }
  1665. else
  1666. {
  1667. anANSIParams[btNumParams++] = -1;
  1668. }
  1669. }
  1670. else
  1671. {
  1672. btANSISeqLevel = 0;
  1673. }
  1674. }
  1675. else
  1676. {
  1677. btANSISeqLevel = 0;
  1678. if(btCurrentParamLength != 0 && btNumParams < 10)
  1679. {
  1680. if(strcmp(szCurrentParam,"?9") == 0)
  1681. {
  1682. anANSIParams[btNumParams] = -2;
  1683. }
  1684. else
  1685. {
  1686. anANSIParams[btNumParams] = atoi(szCurrentParam);
  1687. }
  1688. szCurrentParam[0] = '\0';
  1689. btCurrentParamLength = 0;
  1690. ++btNumParams;
  1691. }
  1692. ODScrnGetTextInfo(&TextInfo);
  1693. switch(chCurrent)
  1694. {
  1695. case 'A':
  1696. if(btNumParams == 0) anANSIParams[0] = 1;
  1697. if((nTemp = TextInfo.cury - anANSIParams[0]) < 1)
  1698. {
  1699. nTemp = 1;
  1700. }
  1701. if(nTemp > 25) nTemp=25;
  1702. ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp);
  1703. break;
  1704. case 'B':
  1705. if(btNumParams == 0) anANSIParams[0] = 1;
  1706. if((nTemp = TextInfo.cury + anANSIParams[0]) > 25)
  1707. {
  1708. nTemp = 25;
  1709. }
  1710. if(nTemp < 1) nTemp = 1;
  1711. ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp);
  1712. break;
  1713. case 'C':
  1714. if(btNumParams == 0) anANSIParams[0] = 1;
  1715. if((nTemp=TextInfo.curx + anANSIParams[0]) > 80)
  1716. {
  1717. nTemp = 80;
  1718. }
  1719. if(nTemp < 1) nTemp = 1;
  1720. ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury);
  1721. break;
  1722. case 'D':
  1723. if(btNumParams == 0) anANSIParams[0] = 1;
  1724. if((nTemp = TextInfo.curx - anANSIParams[0]) < 1)
  1725. {
  1726. nTemp = 1;
  1727. }
  1728. if(nTemp > 80) nTemp = 80;
  1729. ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury);
  1730. break;
  1731. case 'H':
  1732. case 'f':
  1733. if(btNumParams >= 2)
  1734. {
  1735. if(anANSIParams[0] == -1)
  1736. {
  1737. ODScrnSetCursorPos((BYTE)anANSIParams[1], 1);
  1738. }
  1739. else
  1740. {
  1741. ODScrnSetCursorPos((BYTE)anANSIParams[1],
  1742. (BYTE)anANSIParams[0]);
  1743. }
  1744. }
  1745. else if(btNumParams == 1)
  1746. {
  1747. if(anANSIParams[0] <= 0)
  1748. {
  1749. ODScrnSetCursorPos(1, TextInfo.cury);
  1750. }
  1751. else
  1752. {
  1753. ODScrnSetCursorPos(1, (BYTE)anANSIParams[0]);
  1754. }
  1755. }
  1756. else /* if(num_params==0) */
  1757. {
  1758. ODScrnSetCursorPos(1, 1);
  1759. }
  1760. break;
  1761. case 'J':
  1762. if(btNumParams >= 1 && anANSIParams[0] == 2)
  1763. {
  1764. /* Clear entire screen. */
  1765. ODScrnClear();
  1766. }
  1767. else if(btNumParams == 0 || anANSIParams[0] == 0)
  1768. {
  1769. /* Not supported - Clears from cursor to end of */
  1770. /* screen. */
  1771. }
  1772. else if(btNumParams>=1 && anANSIParams[0]==1)
  1773. {
  1774. /* Not supported - Clears from beginning of screen to */
  1775. /* cursor. */
  1776. }
  1777. break;
  1778. case 'K':
  1779. if(btNumParams == 0 || anANSIParams[0] == 0)
  1780. {
  1781. /* Clear to end of line. */
  1782. ODScrnClearToEndOfLine();
  1783. }
  1784. else if(btNumParams >= 1 && anANSIParams[0] == 1)
  1785. {
  1786. /* Not supported - should clear to beginning of line. */
  1787. }
  1788. else if(btNumParams >= 1 && anANSIParams[0] == 2)
  1789. {
  1790. /* Not supported - should clear entire line. */
  1791. }
  1792. break;
  1793. case 'm':
  1794. for(nTemp = 0; nTemp < btNumParams; ++nTemp)
  1795. {
  1796. if(anANSIParams[nTemp] == 0)
  1797. {
  1798. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1799. = TextInfo.attribute = 0x07));
  1800. }
  1801. else if(anANSIParams[nTemp] == 1)
  1802. {
  1803. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1804. = TextInfo.attribute
  1805. = TextInfo.attribute | 0x08));
  1806. }
  1807. else if(anANSIParams[nTemp] == 2)
  1808. {
  1809. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1810. = TextInfo.attribute
  1811. = TextInfo.attribute & (~0x08)));
  1812. }
  1813. else if(anANSIParams[nTemp] == 4)
  1814. {
  1815. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1816. = TextInfo.attribute
  1817. = (TextInfo.attribute & 0xf8) | (1)));
  1818. }
  1819. else if(anANSIParams[nTemp] == 5)
  1820. {
  1821. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1822. = TextInfo.attribute
  1823. = TextInfo.attribute | 0x80));
  1824. }
  1825. else if(anANSIParams[nTemp] == 7)
  1826. {
  1827. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1828. = TextInfo.attribute
  1829. = (TextInfo.attribute << 4)
  1830. | (TextInfo.attribute >> 4)));
  1831. }
  1832. else if(anANSIParams[nTemp] == 8)
  1833. {
  1834. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1835. = TextInfo.attribute
  1836. = (TextInfo.attribute & 0xf0)
  1837. | ((TextInfo.attribute >> 4) & 0x07)));
  1838. }
  1839. else if(anANSIParams[nTemp] >= 30
  1840. && anANSIParams[nTemp] <= 37)
  1841. {
  1842. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1843. = TextInfo.attribute
  1844. = (TextInfo.attribute & 0xf8)
  1845. + abtANSIToPCColorTable[
  1846. (anANSIParams[nTemp] - 30)]));
  1847. }
  1848. else if(anANSIParams[nTemp] >= 40
  1849. && anANSIParams[nTemp]<=47)
  1850. {
  1851. ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
  1852. = TextInfo.attribute
  1853. = (TextInfo.attribute & 0x8f)
  1854. + (abtANSIToPCColorTable[
  1855. anANSIParams[nTemp] - 40] << 4)));
  1856. }
  1857. }
  1858. break;
  1859. case 's':
  1860. btSavedColumn = TextInfo.curx;
  1861. btSavedRow = TextInfo.cury;
  1862. break;
  1863. case 'u':
  1864. ODScrnSetCursorPos(btSavedColumn, btSavedRow);
  1865. break;
  1866. case '@':
  1867. /* Not supported - inserts spaces at cursor. */
  1868. break;
  1869. case 'P':
  1870. /* Not supported - deletes characters at cursor. */
  1871. break;
  1872. case 'L':
  1873. /* Not supported - inserts lines at cursor. */
  1874. break;
  1875. case 'M':
  1876. /* Not supported - deletes lines at cursor. */
  1877. break;
  1878. case 'r':
  1879. /* Not supported - sets scrolling zone - 1st param is */
  1880. /* top row, 2nd param is bottom row. Cursor may go */
  1881. /* outside zone, but no scrolling occurs there. */
  1882. /* Also resets cursor to row 1, column 1. */
  1883. /* If only one param, bottom row is bottom of screen. */
  1884. break;
  1885. case 'h':
  1886. if(btNumParams >= 1 && anANSIParams[0] == 4)
  1887. {
  1888. /* Not suppored - turn insert mode on. */
  1889. }
  1890. else if(btNumParams >= 1 && anANSIParams[0] == -2)
  1891. {
  1892. /* Home cursor. */
  1893. ODScrnSetCursorPos(1, 1);
  1894. }
  1895. break;
  1896. case 'l':
  1897. if(btNumParams >= 1 && anANSIParams[0] == 4)
  1898. {
  1899. /* Not suppored - turn insert mode off. */
  1900. }
  1901. break;
  1902. case 'E':
  1903. /* Not supported - repeat CRLF specified # of times. */
  1904. break;
  1905. case 'F':
  1906. /* Not supported - repeat reverse CRLF specified # */
  1907. /* of times. Also not suppored ESC M - reverse */
  1908. /* linefeed, ESC D - LF, ESC E - CRLF */
  1909. break;
  1910. }
  1911. }
  1912. }
  1913. if(bEchoThisChar && od_control.baud != 0)
  1914. {
  1915. ODComSendByte(hSerialPort, chCurrent);
  1916. }
  1917. ++pszBuffer;
  1918. }
  1919. }
  1920. /* ----------------------------------------------------------------------------
  1921. * ODEmulateFillArea() *** PRIVATE FUNCTION ***
  1922. *
  1923. * Fills an area of the local screen with the specified character, in the
  1924. * current display color.
  1925. *
  1926. * Parameters: btLeft - The left column of the area to fill.
  1927. *
  1928. * btTop - The top row of the area to fill.
  1929. *
  1930. * btRight - The right column of the area to fill.
  1931. *
  1932. * btBottom - The bottom row of the area to fill.
  1933. *
  1934. * chToFillWith - Character to fill in the specified area with.
  1935. *
  1936. * Return: void
  1937. */
  1938. static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight,
  1939. BYTE btBottom, char chToFillWith)
  1940. {
  1941. BYTE btCount;
  1942. BYTE btLast;
  1943. static char szTemp[81];
  1944. static tODScrnTextInfo TextInfo;
  1945. ODScrnGetTextInfo(&TextInfo);
  1946. btLast = btRight - btLeft;
  1947. for(btCount=0; btCount <= btLast; ++btCount)
  1948. {
  1949. szTemp[btCount] = chToFillWith;
  1950. }
  1951. szTemp[btCount] = 0;
  1952. ODScrnEnableScrolling(FALSE);
  1953. for(btCount = btTop; btCount <= btBottom; ++btCount)
  1954. {
  1955. ODScrnSetCursorPos(btLeft, btCount);
  1956. ODScrnDisplayString(szTemp);
  1957. }
  1958. ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
  1959. ODScrnEnableScrolling(TRUE);
  1960. }