Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

789 lines
21 KiB

  1. /* File: cloopctl.c (created 12/16/93, JKH)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 12 $
  7. * $Date: 5/01/02 1:00p $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. #include <time.h>
  12. // #define DEBUGSTR
  13. #include "stdtyp.h"
  14. #include "session.h"
  15. #include "timers.h"
  16. #include "com.h"
  17. #include "mc.h"
  18. #include "cnct.h"
  19. #include "cloop.h"
  20. #include "cloop.hh"
  21. #include "htchar.h"
  22. #include <tdll\assert.h>
  23. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  24. * FUNCTION: CLoopCreateHandle
  25. *
  26. * DESCRIPTION:
  27. * Creates handle for use of com loop routines. This function assumes that
  28. * the emulator and com handles have already been created and stored in the
  29. * session handle when it is called.
  30. *
  31. * ARGUMENTS:
  32. * hSession -- Session handle
  33. *
  34. * RETURNS:
  35. * A handle to be used in all other CLoop calls or NULL if unsuccessful
  36. */
  37. HCLOOP CLoopCreateHandle(const HSESSION hSession)
  38. {
  39. ST_CLOOP *pstCLoop = (ST_CLOOP *)0;
  40. unsigned ix;
  41. int fSuccess = TRUE;
  42. pstCLoop = malloc(sizeof(*pstCLoop));
  43. if (!pstCLoop)
  44. fSuccess = FALSE;
  45. else
  46. {
  47. // Initialize structure
  48. memset(pstCLoop, 0, sizeof(ST_CLOOP));
  49. pstCLoop->hSession = hSession;
  50. pstCLoop->hEmu = sessQueryEmuHdl(hSession);
  51. pstCLoop->hCom = sessQueryComHdl(hSession);
  52. pstCLoop->afControl = 0;
  53. pstCLoop->afRcvBlocked = 0;
  54. pstCLoop->afSndBlocked = CLOOP_SB_NODATA;
  55. pstCLoop->nRcvBlkCnt = 0;
  56. pstCLoop->fRcvBlkOverride = FALSE;
  57. pstCLoop->fSuppressDsp = FALSE;
  58. pstCLoop->fDataReceived = FALSE;
  59. pstCLoop->htimerRcvDelay = (HTIMER)0;
  60. pstCLoop->pfRcvDelay = CLoopRcvDelayProc;
  61. pstCLoop->pfCharDelay = CLoopCharDelayProc;
  62. pstCLoop->pstFirstOutBlock = NULL;
  63. pstCLoop->pstLastOutBlock = NULL;
  64. pstCLoop->ulOutCount = 0L;
  65. pstCLoop->hOutFile = (HANDLE)0;
  66. pstCLoop->keyLastKey = (KEY_T)0;
  67. pstCLoop->keyHoldKey = (KEY_T)0;
  68. pstCLoop->pstRmtChain = NULL;
  69. pstCLoop->pstRmtChainNext = NULL;
  70. pstCLoop->fRmtChain = FALSE;
  71. pstCLoop->fTextDisplay = FALSE;
  72. pstCLoop->hDisplayBlock = (HANDLE)0;
  73. // Set default user settings
  74. CLoopInitHdl((HCLOOP)pstCLoop);
  75. pstCLoop->lpLearn = (LPVOID)0;
  76. for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
  77. pstCLoop->ahEvents[ix] = (HANDLE)0;
  78. pstCLoop->hEngineThread = (HANDLE)0;
  79. pstCLoop->fDoMBCS = FALSE;
  80. pstCLoop->cLeadByte = 0;
  81. pstCLoop->cLocalEchoLeadByte= 0;
  82. #if defined(CHAR_MIXED)
  83. // Added for debugging
  84. pstCLoop->fDoMBCS = TRUE;
  85. #endif
  86. // Create synchronization objects
  87. InitializeCriticalSection(&pstCLoop->csect);
  88. }
  89. if (!fSuccess)
  90. CLoopDestroyHandle((HCLOOP *)&pstCLoop);
  91. DBGOUT_NORMAL("CLoopCreateHandle(%lX) returned %lX\r\n",
  92. hSession, pstCLoop, 0, 0, 0);
  93. return (HCLOOP)pstCLoop;
  94. }
  95. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  96. * FUNCTION: CLoopDestroyHandle
  97. *
  98. * DESCRIPTION:
  99. * Destroys a handle created by CLoopCreateHandle and sets the storage
  100. * variable to NULL;
  101. *
  102. * ARGUMENTS:
  103. * ppstCLoop -- address of a variable holding a CLoop Handle
  104. *
  105. * RETURNS:
  106. * nothing
  107. */
  108. void CLoopDestroyHandle(HCLOOP * const ppstCLoop)
  109. {
  110. ST_CLOOP *pstCLoop;
  111. assert(ppstCLoop);
  112. pstCLoop = (ST_CLOOP *)*ppstCLoop;
  113. if (pstCLoop)
  114. {
  115. CLoopDeactivate((HCLOOP)pstCLoop);
  116. DeleteCriticalSection(&pstCLoop->csect);
  117. free(pstCLoop);
  118. pstCLoop = NULL;
  119. }
  120. *ppstCLoop = (HCLOOP)0;
  121. DBGOUT_NORMAL("CLoopDestroyHandle(l%X)\r\n", pstCLoop, 0,0,0,0);
  122. }
  123. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  124. * FUNCTION:
  125. * CLoopActivate
  126. *
  127. * DESCRIPTION:
  128. * Prepares cloop handle for actual use by starting its thread.
  129. *
  130. * ARGUMENTS:
  131. * pstCLoop -- CLoop handle returned from CLoopCreateHandle
  132. *
  133. * RETURNS:
  134. * TRUE if thread was started, FALSE otherwise
  135. */
  136. int CLoopActivate(const HCLOOP hCLoop)
  137. {
  138. int fSuccess = TRUE;
  139. ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
  140. unsigned ix;
  141. DWORD dwThreadId;
  142. // Store these in handle for fast access
  143. pstCLoop->hEmu = sessQueryEmuHdl(pstCLoop->hSession);
  144. pstCLoop->hCom = sessQueryComHdl(pstCLoop->hSession);
  145. for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
  146. {
  147. pstCLoop->ahEvents[ix] = CreateEvent(NULL,
  148. TRUE, // must be manually reset
  149. FALSE, // create unsignalled
  150. NULL); // unnamed
  151. if (pstCLoop->ahEvents[ix] == NULL)
  152. {
  153. fSuccess = FALSE;
  154. //
  155. // Make sure to initialize the rest of the event handles to NULL;
  156. //
  157. for (++ix; ix < DIM(pstCLoop->ahEvents); ++ix)
  158. {
  159. pstCLoop->ahEvents[ix] = NULL;
  160. }
  161. }
  162. }
  163. if (fSuccess)
  164. {
  165. // Start the thread to handle cloop's responsibilities
  166. // (Gentleprograms, start your engines
  167. EnterCriticalSection(&pstCLoop->csect);
  168. pstCLoop->hEngineThread = CreateThread(
  169. (LPSECURITY_ATTRIBUTES)0,
  170. 4096,
  171. (LPTHREAD_START_ROUTINE)CLoop,
  172. (LPVOID)pstCLoop,
  173. 0,
  174. &dwThreadId);
  175. if (!pstCLoop->hEngineThread)
  176. fSuccess = FALSE;
  177. #if 0 //jmh 07-10-96
  178. else
  179. SetThreadPriority(pstCLoop->hEngineThread,
  180. THREAD_PRIORITY_HIGHEST);
  181. #endif // 0
  182. LeaveCriticalSection(&pstCLoop->csect);
  183. }
  184. return fSuccess;
  185. }
  186. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  187. * FUNCTION:
  188. * CLoopDeactivate
  189. *
  190. * DESCRIPTION:
  191. * Shuts down cloop but does not destroy the handle
  192. *
  193. * ARGUMENTS:
  194. * pstCLoop -- CLoop handle returned from CLoopCreateHandle
  195. *
  196. * RETURNS:
  197. * nothing
  198. */
  199. void CLoopDeactivate(const HCLOOP hCLoop)
  200. {
  201. ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
  202. unsigned ix;
  203. if (pstCLoop)
  204. {
  205. // This next call should cause the cloop thread to exit
  206. // Don't enter critical section to do this, since thread won't
  207. // be able to exit
  208. if (pstCLoop->hEngineThread)
  209. {
  210. //JMH 05-28-96 CLoop was blowing up when no phone number was
  211. // provided, and you exited, answering no to the save prompt.
  212. // Suspending receive before terminating the thread fixed it.
  213. //
  214. CLoopRcvControl((HCLOOP)pstCLoop, CLOOP_SUSPEND, CLOOP_RB_INACTIVE);
  215. CLoopControl((HCLOOP)pstCLoop, CLOOP_SET, CLOOP_TERMINATE);
  216. // Wait for the engine thread to exit
  217. if (WaitForSingleObject(pstCLoop->hEngineThread, 0) == WAIT_OBJECT_0)
  218. {
  219. CloseHandle(pstCLoop->hEngineThread);
  220. }
  221. else if (WaitForSingleObject(pstCLoop->hEngineThread, 10000) == WAIT_TIMEOUT)
  222. {
  223. TerminateThread(pstCLoop->hEngineThread, 0);
  224. CloseHandle(pstCLoop->hEngineThread);
  225. }
  226. pstCLoop->hEngineThread = (HANDLE)0;
  227. }
  228. for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
  229. {
  230. if (pstCLoop->ahEvents[ix])
  231. {
  232. CloseHandle(pstCLoop->ahEvents[ix]);
  233. pstCLoop->ahEvents[ix] = INVALID_HANDLE_VALUE;
  234. }
  235. }
  236. }
  237. }
  238. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  239. * FUNCTION: CLoopReset
  240. *
  241. * DESCRIPTION:
  242. * Initializes the cloop routines for a new call. This is not really
  243. * necessary prior to the first connection, but prevents left-over flags,
  244. * buffers and such from one connection from affecting later connections.
  245. *
  246. * ARGUMENTS:
  247. * pstCLoop -- CLoop handle returned from CLoopCreateHandle
  248. *
  249. * RETURNS:
  250. * nothing
  251. */
  252. void CLoopReset(const HCLOOP hCLoop)
  253. {
  254. ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
  255. pstCLoop->afControl = 0;
  256. pstCLoop->afRcvBlocked = 0;
  257. pstCLoop->afSndBlocked = CLOOP_SB_NODATA;
  258. CLoopClearOutput((HCLOOP)pstCLoop);
  259. }
  260. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  261. * FUNCTION: CLoopRcvControl
  262. *
  263. * DESCRIPTION:
  264. * Used to suspend and resume receiving in the CLoop routines. Can be
  265. * called from Client or Wudge. Requests can be made to suspend or resume
  266. * receiving for any of several reasons. Receiving can be suspended for
  267. * more than one reason at a time. It will not resume until all reasons
  268. * have been cleared.
  269. *
  270. * ARGUMENTS:
  271. * hCLoop -- CLoop handle returned from CLoopCreateHandle
  272. * iAction -- One of CLOOP_SUSPEND or CLOOP_RESUME
  273. * iReason -- Reason for action as defined in cloop.h
  274. * Ex.: CLOOP_RB_NODATA, CLOOP_RB_INACTIVE
  275. * CLOOP_RB_SCRLOCK, CLOOP_RB_SCRIPT
  276. *
  277. * RETURNS:
  278. * nothing
  279. */
  280. void CLoopRcvControl(const HCLOOP hCLoop,
  281. const unsigned uAction,
  282. const unsigned uReason)
  283. {
  284. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  285. assert(uAction == CLOOP_SUSPEND || uAction == CLOOP_RESUME);
  286. EnterCriticalSection(&pstCLoop->csect);
  287. if (uReason == CLOOP_RB_SCRIPT)
  288. {
  289. /*
  290. * Scripts work a little bit different
  291. */
  292. // DbgOutStr("CLOOP_RB_SCRIPT %d", pstCLoop->nRcvBlkCnt, 0,0,0,0);
  293. switch (uAction)
  294. {
  295. default:
  296. break;
  297. case CLOOP_SUSPEND:
  298. pstCLoop->nRcvBlkCnt += 1;
  299. break;
  300. case CLOOP_RESUME:
  301. pstCLoop->nRcvBlkCnt -= 1;
  302. // There used to be code to prevent this value from going neg.
  303. // but we must allow this to go negative so that cleanup
  304. // can occur when we abort within an API call.
  305. break;
  306. }
  307. // DbgOutStr(" %d\r\n", pstCLoop->nRcvBlkCnt, 0,0,0,0);
  308. if (pstCLoop->fRcvBlkOverride == FALSE)
  309. {
  310. /*
  311. * If someone is overriding us, let them restore the bits
  312. */
  313. if (pstCLoop->nRcvBlkCnt > 0)
  314. {
  315. bitset(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
  316. }
  317. else
  318. {
  319. bitclear(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
  320. }
  321. }
  322. }
  323. else
  324. {
  325. if (uAction == CLOOP_SUSPEND)
  326. bitset(pstCLoop->afRcvBlocked, uReason);
  327. else if (uAction == CLOOP_RESUME)
  328. bitclear(pstCLoop->afRcvBlocked, uReason);
  329. }
  330. DBGOUT_NORMAL("CLoopRcvControl(%08lx):%04X (fRcvBlkOverride=%d, nRcvBlkCnt=%d)\r\n",
  331. pstCLoop, pstCLoop->afRcvBlocked, pstCLoop->fRcvBlkOverride,
  332. pstCLoop->nRcvBlkCnt,0);
  333. if (pstCLoop->afRcvBlocked)
  334. ResetEvent(pstCLoop->ahEvents[EVENT_RCV]);
  335. else
  336. SetEvent(pstCLoop->ahEvents[EVENT_RCV]);
  337. LeaveCriticalSection(&pstCLoop->csect);
  338. }
  339. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  340. * FUNCTION: CLoopOverrideControl
  341. *
  342. * DESCRIPTION:
  343. * This function can be called internally from the engine in order to
  344. * override the CLoopRcvControl \CLOOP_RB_SCRIPT blocking state. It is
  345. * intended to be used during a connection process, when the connection
  346. * stuff needs to see the data coming in.
  347. *
  348. * ARGUEMENTS:
  349. * hCLoop -- CLoop handle returned from CLoopCreateHandle
  350. * fOverride -- TRUE to override, FALSE to restore things
  351. *
  352. * RETURNS:
  353. * Nothing.
  354. */
  355. void CLoopOverrideControl(const HCLOOP hCLoop, const int fOverride)
  356. {
  357. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  358. EnterCriticalSection(&pstCLoop->csect);
  359. if (fOverride)
  360. {
  361. pstCLoop->fRcvBlkOverride = TRUE;
  362. if (pstCLoop->nRcvBlkCnt > 0)
  363. {
  364. bitclear(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
  365. if (!pstCLoop->afRcvBlocked)
  366. SetEvent(pstCLoop->ahEvents[EVENT_RCV]);
  367. }
  368. }
  369. else
  370. {
  371. pstCLoop->fRcvBlkOverride = FALSE;
  372. if (pstCLoop->nRcvBlkCnt > 0)
  373. {
  374. bitset(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
  375. ResetEvent(pstCLoop->ahEvents[EVENT_RCV]);
  376. }
  377. }
  378. LeaveCriticalSection(&pstCLoop->csect);
  379. }
  380. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  381. * FUNCTION: CLoopSndControl
  382. *
  383. * DESCRIPTION:
  384. * Used to suspend and resume sending from the CLoop routines.
  385. * Requests can be made to suspend or resume sending for any of several
  386. * reasons. Sending can be suspended for more than one reason at a time.
  387. * It will not resume until all reasons have been cleared.
  388. *
  389. * ARGUMENTS:
  390. * hCLoop -- CLoop handle returned from CLoopCreateHandle
  391. * uAction -- One of CLOOP_SUSPEND or CLOOP_RESUME
  392. * uReason -- Reason for action as defined in cloop.h
  393. * Ex.: CLOOP_SB_NODATA, CLOOP_SB_INACTIVE
  394. * CLOOP_SB_SCRLOCK, CLOOP_SB_LINEWAIT
  395. *
  396. * RETURNS:
  397. * nothing
  398. */
  399. void CLoopSndControl(const HCLOOP hCLoop,
  400. const unsigned uAction,
  401. const unsigned uReason)
  402. {
  403. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  404. assert(uAction == CLOOP_SUSPEND || uAction == CLOOP_RESUME);
  405. DbgOutStr("CLoopSndControl(%x, %x)\r\n", uAction, uReason, 0,0,0);
  406. EnterCriticalSection(&pstCLoop->csect);
  407. if (uAction == CLOOP_SUSPEND)
  408. {
  409. if (!pstCLoop->afSndBlocked)
  410. {
  411. DbgOutStr("Resetting EVENT_SEND (0x%x)\r\n", 0,0,0,0,0);
  412. ResetEvent(pstCLoop->ahEvents[EVENT_SEND]);
  413. }
  414. bitset(pstCLoop->afSndBlocked, uReason);
  415. }
  416. else if (uAction == CLOOP_RESUME)
  417. {
  418. // Allow this bit to be reset
  419. //
  420. if (bittest(uReason, CLOOP_SB_CNCTDRV))
  421. bitclear(pstCLoop->afSndBlocked, CLOOP_SB_CNCTDRV);
  422. // Only do this if we're not in the process of connecting
  423. //
  424. if (! bittest(pstCLoop->afSndBlocked, CLOOP_SB_CNCTDRV))
  425. {
  426. bitclear(pstCLoop->afSndBlocked, uReason);
  427. // If sending is being resumed because new data has arrived,
  428. // make sure we're connected. If not, send off a message to
  429. // try to connect without dialing
  430. if (bittest(uReason, CLOOP_SB_NODATA))
  431. {
  432. if (cnctQueryStatus(sessQueryCnctHdl(pstCLoop->hSession)) ==
  433. CNCT_STATUS_FALSE)
  434. {
  435. bitset(pstCLoop->afSndBlocked, CLOOP_SB_UNCONNECTED);
  436. }
  437. if (bittest(pstCLoop->afSndBlocked, CLOOP_SB_UNCONNECTED))
  438. {
  439. NotifyClient(pstCLoop->hSession, (int) EVENT_PORTONLY_OPEN, 0);
  440. }
  441. }
  442. }
  443. if (!pstCLoop->afSndBlocked)
  444. {
  445. DbgOutStr("Setting EVENT_SEND\r\n", 0,0,0,0,0);
  446. SetEvent(pstCLoop->ahEvents[EVENT_SEND]);
  447. }
  448. }
  449. LeaveCriticalSection(&pstCLoop->csect);
  450. }
  451. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  452. * FUNCTION: CLoopControl
  453. *
  454. * DESCRIPTION:
  455. * Used to control the action of the CLoop engine.
  456. * The CLoop engine normally processes any characters
  457. * received from the remote system and any characters or keys queued for
  458. * output. This call can be used to alter the normal flow of data for
  459. * special needs such as file transfers and scripts.
  460. *
  461. * ARGUMENTS:
  462. * hCLoop -- Handle returned from call to CLoopCreateHandle
  463. * uAction -- CLOOP_SET or CLOOP_CLEAR to set or clear control bits
  464. * uReason -- Value indicating what is being controlled. Values are
  465. * listed in cloop.h
  466. * Ex:CLOOP_TERMINATE CLOOP_OUTPUT_WAITING CLOOP_TRANSFER_READY
  467. *
  468. * RETURNS:
  469. * nothing
  470. */
  471. void CLoopControl(
  472. const HCLOOP hCLoop,
  473. unsigned uAction,
  474. unsigned uReason)
  475. {
  476. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  477. if ( !pstCLoop )
  478. return; //MPT:10SEP98 to prevent an access violation
  479. EnterCriticalSection(&pstCLoop->csect);
  480. if (bittest(uReason, CLOOP_MBCS))
  481. {
  482. if (uAction == CLOOP_SET)
  483. pstCLoop->fDoMBCS = TRUE;
  484. else
  485. pstCLoop->fDoMBCS = FALSE;
  486. bitclear(uReason, CLOOP_MBCS);
  487. // I am not sure about returning here or not ...
  488. // As is, it requires that this be the only flag used for this call.
  489. LeaveCriticalSection(&pstCLoop->csect);
  490. return;
  491. }
  492. assert(uAction == CLOOP_SET || uAction == CLOOP_CLEAR);
  493. if (bittest(uReason, CLOOP_CONNECTED))
  494. {
  495. if (uAction == CLOOP_SET)
  496. {
  497. CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_UNCONNECTED);
  498. }
  499. else
  500. {
  501. CLoopClearOutput(hCLoop);
  502. CLoopSndControl(hCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
  503. }
  504. // Don't put this flag in afControl
  505. bitclear(uReason, CLOOP_CONNECTED);
  506. }
  507. if (bittest(uReason, CLOOP_SUPPRESS_DSP))
  508. {
  509. // This bit cannot be kept in afControl because doing so would
  510. // keep cloop from suspending itself when appropriate
  511. pstCLoop->fSuppressDsp = (uAction == CLOOP_SET);
  512. bitclear(uAction, CLOOP_SUPPRESS_DSP);
  513. }
  514. #if 0
  515. if (uAction == CLOOP_SET)
  516. {
  517. bitset(pstCLoop->afControl, uReason);
  518. SetEvent(pstCLoop->ahEvents[EVENT_SEND]);
  519. }
  520. else if (uAction == CLOOP_CLEAR)
  521. {
  522. bitclear(pstCLoop->afControl, uReason);
  523. if (!pstCLoop->afControl)
  524. ResetEvent(pstCLoop->ahEvents[EVENT_SEND]);
  525. }
  526. #endif
  527. if (bittest(uReason, CLOOP_MBCS))
  528. {
  529. if (uAction == CLOOP_SET)
  530. pstCLoop->fDoMBCS = TRUE;
  531. else
  532. pstCLoop->fDoMBCS = FALSE;
  533. bitclear(uReason, CLOOP_MBCS);
  534. // I am not sure about returning here or not ...
  535. LeaveCriticalSection(&pstCLoop->csect);
  536. return;
  537. }
  538. if (uAction == CLOOP_SET)
  539. bitset(pstCLoop->afControl, uReason);
  540. else if (uAction == CLOOP_CLEAR)
  541. bitclear(pstCLoop->afControl, uReason);
  542. if (pstCLoop->afControl)
  543. SetEvent(pstCLoop->ahEvents[EVENT_CONTROL]);
  544. else
  545. ResetEvent(pstCLoop->ahEvents[EVENT_CONTROL]);
  546. LeaveCriticalSection(&pstCLoop->csect);
  547. }
  548. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  549. * FUNCTION: CLoopRegisterRmtInputChain
  550. *
  551. * DESCRIPTION:
  552. * Adds a function to a chain of functions that are called whenever
  553. * a new character is received from the remote system.
  554. *
  555. * ARGUMENTS:
  556. * pstCLoop -- Value returned from CLoopCreateHandle
  557. * pfFunc -- Pointer to a function to be called when each remote
  558. * character is received. The function should be declared as:
  559. * VOID FAR PASCAL FunctionName(METACHAR mc, VOID FAR *pvUserData)
  560. * The value passed in the argument should be the return value
  561. * from MakeProcInstance.
  562. * pvUserData -- Any arbitrary value that can be cast to VOID FAR *. This
  563. * value will be maintained in the chain and passed back to
  564. * the caller whenever (l*pfFunc) is called. No use is made
  565. * of this value by the CLoop routines.
  566. *
  567. * RETURNS:
  568. * A void * return handle that must be saved and passed to
  569. * CLoopUnregisterRmtInputChain when the function is no longer needed.
  570. */
  571. void * CLoopRegisterRmtInputChain(const HCLOOP hCLoop,
  572. const CHAINFUNC pfFunc,
  573. void *pvUserData)
  574. {
  575. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  576. ST_FCHAIN *pstNew = NULL;
  577. assert(pfFunc);
  578. assert(pstCLoop);
  579. if ((pstNew = (ST_FCHAIN *)malloc(sizeof(*pstNew))) != NULL)
  580. {
  581. EnterCriticalSection(&pstCLoop->csect);
  582. // Initialize new node
  583. pstNew->pstParent = pstCLoop;
  584. pstNew->pfFunc = pfFunc;
  585. pstNew->pvUserData = pvUserData;
  586. DBGOUT_NORMAL("CLoopRegisterRmtInputChain(0x%lx, 0x%lx) -> %lX\r\n",
  587. (LONG)pstNew->pfFunc, (LONG)pstNew->pvUserData,
  588. pstNew, 0, 0);
  589. // Always link new functions into beginning of chain. That way, if
  590. // a new function is added into the chain from within a current
  591. // callback, it will not be called until the next char. arrives.
  592. pstNew->pstNext = pstCLoop->pstRmtChain;
  593. pstCLoop->pstRmtChain = pstNew;
  594. pstNew->pstPrior = NULL;
  595. pstCLoop->fRmtChain = TRUE;
  596. LeaveCriticalSection(&pstCLoop->csect);
  597. }
  598. return (void *)pstNew;
  599. }
  600. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  601. * FUNCTION: CLoopUnregisterRmtInputChain
  602. *
  603. * DESCRIPTION:
  604. * Removes a function from the chain of functions called when a remote
  605. * character is received.
  606. *
  607. * ARGUMENTS:
  608. * pvHdl -- Value returned from an earlier call to CLoopRegisterRmtInputChain
  609. *
  610. * RETURNS:
  611. * nothing
  612. */
  613. void CLoopUnregisterRmtInputChain(void *pvHdl)
  614. {
  615. ST_FCHAIN *pstNode = (ST_FCHAIN *)pvHdl;
  616. ST_CLOOP *pstCLoop;
  617. assert(pstNode);
  618. pstCLoop = pstNode->pstParent;
  619. EnterCriticalSection(&pstCLoop->csect);
  620. // See if we are removing next scheduled chain function
  621. if (pstNode == pstCLoop->pstRmtChainNext)
  622. {
  623. pstCLoop->pstRmtChainNext = pstNode->pstNext;
  624. }
  625. // Unlink node
  626. if (pstNode->pstPrior)
  627. {
  628. pstNode->pstPrior->pstNext = pstNode->pstNext;
  629. }
  630. else
  631. {
  632. pstCLoop->pstRmtChain = pstNode->pstNext;
  633. if (!pstNode->pstNext)
  634. {
  635. pstCLoop->fRmtChain = FALSE;
  636. }
  637. }
  638. if (pstNode->pstNext)
  639. {
  640. pstNode->pstNext->pstPrior = pstNode->pstPrior;
  641. }
  642. DBGOUT_NORMAL("CLoopUnregisterRmtInputChain(0x%lx)\r\n",
  643. (LONG)pvHdl, 0, 0, 0, 0);
  644. free(pstNode);
  645. pstNode = NULL;
  646. LeaveCriticalSection(&pstCLoop->csect);
  647. }
  648. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  649. * FUNCTION: QueryCLoopMBCSState
  650. *
  651. * DESCRIPTION: Determines the current DBCS mode.
  652. *
  653. * ARGUMENTS:
  654. * hCLoop -- Handle returned from call to CLoopCreateHandle
  655. *
  656. * RETURNS:
  657. * TRUE - if we are in DBCS mode.
  658. * FALSE - if we're not
  659. */
  660. int QueryCLoopMBCSState(HCLOOP hCLoop)
  661. {
  662. ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
  663. assert(pstCLoop);
  664. return(pstCLoop->fDoMBCS);
  665. }
  666. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  667. * FUNCTION: SetCLoopMBCSState
  668. *
  669. * DESCRIPTION: Turns on/off DBCS mode.
  670. *
  671. * ARGUMENTS:
  672. * hCLoop -- Handle returned from call to CLoopCreateHandle
  673. * fState -- TRUE, if we're turning MBCS on,
  674. * FALSE, if we're turning MBCS off.
  675. *
  676. * RETURNS:
  677. * the value of dDoMBCS from the CLoop's internal struct
  678. */
  679. int SetCLoopMBCSState(HCLOOP hCLoop, int fState)
  680. {
  681. ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
  682. assert(pstCLoop);
  683. pstCLoop->fDoMBCS = fState;
  684. return(pstCLoop->fDoMBCS);
  685. }