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.

575 lines
15 KiB

  1. /* File: cloopout.c (created 12/28/93, JKH)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 5 $
  7. * $Date: 7/08/02 6:39p $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. // #define DEBUGSTR
  12. #include "stdtyp.h"
  13. #include "session.h"
  14. #include <tdll\assert.h>
  15. #include "mc.h"
  16. #include "timers.h"
  17. #include "file_msc.h"
  18. #include "misc.h"
  19. #include "tdll.h"
  20. #include <term\res.h>
  21. #include "htchar.h"
  22. #include "cloop.h"
  23. #include "cloop.hh"
  24. #include "chars.h"
  25. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  26. * FUNCTION: CLoopSend
  27. *
  28. * DESCRIPTION:
  29. *
  30. *
  31. * ARGUMENTS:
  32. *
  33. *
  34. * RETURNS:
  35. *
  36. */
  37. int CLoopSend
  38. (
  39. const HCLOOP hCLoop,
  40. void *pvData,
  41. const size_t sztItems,
  42. unsigned uOptions)
  43. {
  44. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  45. int fRetval = TRUE;
  46. ST_CLOOP_OUT *pstLast;
  47. ST_CLOOP_OUT *pstNew = NULL;
  48. size_t sztBytes;
  49. size_t sztAllocate;
  50. assert(pstCLoop);
  51. assert(pvData);
  52. if (!sztItems)
  53. return TRUE;
  54. EnterCriticalSection(&pstCLoop->csect);
  55. sztBytes = sztItems;
  56. if (bittest(uOptions, CLOOP_KEYS))
  57. sztBytes *= sizeof(KEY_T);
  58. // Notify the client that characters went out so the terminal can
  59. // do the appropriate tracking so user gets feedback about the
  60. // send operation, so there! - mrw
  61. NotifyClient(pstCLoop->hSession, (WORD)EVENT_CLOOP_SEND, 0);
  62. pstLast = pstCLoop->pstLastOutBlock;
  63. bitset(uOptions, CLOOP_CHARACTERS);
  64. // If new data is not in an allocated block and it will fit in the
  65. // block currently at the end of the chain, just add it in.
  66. if (!bittest(uOptions, CLOOP_ALLOCATED | CLOOP_SHARED) &&
  67. pstLast &&
  68. bittest(pstLast->uOptions, CLOOP_KEYS | CLOOP_CHARACTERS) ==
  69. bittest(uOptions, CLOOP_KEYS | CLOOP_CHARACTERS) &&
  70. sztBytes < (size_t)(pstLast->puchLimit - pstLast->puchHead))
  71. {
  72. // Copy data into existing block
  73. if (pstLast->puchHead == pstLast->puchTail)
  74. {
  75. // block is empty, reset pointers to beginning
  76. pstLast->puchHead = pstLast->puchTail = pstLast->puchData;
  77. }
  78. if (sztBytes)
  79. MemCopy(pstLast->puchHead, pvData, sztBytes);
  80. pstLast->puchHead += sztBytes;
  81. }
  82. else
  83. {
  84. // Couldn't put data into an existing block, try to add a new block
  85. // First create the block control structure
  86. if ((pstNew = CLoopNewOutBlock(pstCLoop, 0)) == NULL)
  87. {
  88. fRetval = FALSE;
  89. goto done;
  90. }
  91. pstNew->uOptions = uOptions;
  92. // Unless data is already in allocated memory that we can keep,
  93. // try to allocate memory for the new block
  94. if (!bittest(uOptions, CLOOP_ALLOCATED | CLOOP_SHARED))
  95. {
  96. sztAllocate = sztBytes;
  97. if (sztAllocate <= STD_BLOCKSIZE)
  98. {
  99. sztAllocate = STD_BLOCKSIZE;
  100. bitset(pstNew->uOptions, CLOOP_STDSIZE);
  101. }
  102. if ((pstNew->puchData = malloc(sztAllocate)) == NULL)
  103. {
  104. fRetval = FALSE;
  105. goto done;
  106. }
  107. if (sztBytes)
  108. MemCopy(pstNew->puchData, pvData, sztBytes);
  109. }
  110. else if (bittest(uOptions, CLOOP_SHARED))
  111. {
  112. // pvData actually contains a shared memory handle
  113. pstNew->hdlShared = (HGLOBAL)pvData;
  114. pstNew->puchData = GlobalLock(pstNew->hdlShared);
  115. sztAllocate = sztBytes;
  116. }
  117. else
  118. {
  119. // block was passed to us as allocated block that we now own.
  120. pstNew->puchData = pvData;
  121. sztAllocate = sztBytes;
  122. }
  123. pstNew->puchLimit = pstNew->puchData + sztAllocate;
  124. pstNew->puchHead = pstNew->puchData + sztBytes; // where data goes in
  125. pstNew->puchTail = pstNew->puchData; // where data comes out
  126. }
  127. done:
  128. if (!fRetval)
  129. {
  130. if (pstNew)
  131. {
  132. if (pstNew->puchData)
  133. {
  134. free(pstNew->puchData);
  135. pstNew->puchData = NULL;
  136. }
  137. free(pstNew);
  138. pstNew = NULL;
  139. }
  140. }
  141. else
  142. {
  143. pstCLoop->ulOutCount += sztItems;
  144. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_RESUME, CLOOP_SB_NODATA);
  145. }
  146. LeaveCriticalSection(&pstCLoop->csect);
  147. return fRetval;
  148. }
  149. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  150. * FUNCTION: CLoopSendTextFile
  151. *
  152. * DESCRIPTION:
  153. *
  154. *
  155. * ARGUMENTS:
  156. *
  157. *
  158. * RETURNS:
  159. *
  160. */
  161. int CLoopSendTextFile(const HCLOOP hCLoop, TCHAR *pszFileName)
  162. {
  163. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  164. ST_CLOOP_OUT FAR *pstNew = NULL;
  165. int fRetval = FALSE;
  166. unsigned long ulFileSize;
  167. size_t fileNameLen;
  168. assert(pstCLoop);
  169. assert(pszFileName);
  170. fileNameLen = (size_t)StrCharGetByteCount(pszFileName) + sizeof(TCHAR);
  171. EnterCriticalSection(&pstCLoop->csect);
  172. if (GetFileSizeFromName(pszFileName, &ulFileSize) && ulFileSize > 0)
  173. {
  174. if ((pstNew = CLoopNewOutBlock(pstCLoop, fileNameLen)) == NULL)
  175. goto done; // leave fRetval FALSE
  176. pstNew->uOptions = CLOOP_TEXTFILE;
  177. StrCharCopyN(pstNew->puchData, pszFileName, fileNameLen);
  178. pstNew->ulBytes = ulFileSize;
  179. pstCLoop->ulOutCount += ulFileSize;
  180. // Set head and tail pointers even though they will not be directly
  181. // used. When they are set to equal each other, the block will be
  182. // removed from the chain
  183. pstNew->puchTail = pstNew->puchData;
  184. pstNew->puchHead = pstNew->puchData + 1;
  185. fRetval = TRUE;
  186. }
  187. done:
  188. if (!fRetval)
  189. {
  190. if (pstNew)
  191. {
  192. if (pstNew->puchData)
  193. {
  194. free(pstNew->puchData);
  195. pstNew->puchData = NULL;
  196. }
  197. free(pstNew);
  198. pstNew = NULL;
  199. }
  200. }
  201. else
  202. CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_NODATA);
  203. LeaveCriticalSection(&pstCLoop->csect);
  204. return fRetval;
  205. }
  206. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  207. * FUNCTION: CLoopClearOutput
  208. *
  209. * DESCRIPTION:
  210. * Clears all pending output from CLoop
  211. *
  212. * ARGUMENTS:
  213. * pstCLoop -- The CLoop handle
  214. *
  215. * RETURNS:
  216. * nothing
  217. */
  218. void CLoopClearOutput(const HCLOOP hCLoop)
  219. {
  220. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  221. EnterCriticalSection(&pstCLoop->csect);
  222. pstCLoop->ulOutCount = 0L;
  223. //* CLoopTextDspStop(pstCLoop);
  224. pstCLoop->fTextDisplay = FALSE;
  225. while (pstCLoop->pstFirstOutBlock)
  226. CLoopRemoveFirstOutBlock(pstCLoop);
  227. //* ComSendClear(pstCLoop->hCom);
  228. CLoopSndControl(hCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
  229. LeaveCriticalSection(&pstCLoop->csect);
  230. }
  231. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  232. * FUNCTION: CLoopGetOutputCount
  233. *
  234. * DESCRIPTION:
  235. * Returns the number of characters queued for output
  236. *
  237. * ARGUMENTS:
  238. * hCLoop -- The CLoop handle
  239. *
  240. * RETURNS:
  241. * The number of characters queued for output
  242. */
  243. unsigned long CLoopGetOutputCount(const HCLOOP hCLoop)
  244. {
  245. unsigned uCount;
  246. EnterCriticalSection(&((ST_CLOOP *)hCLoop)->csect);
  247. uCount = ((ST_CLOOP *)hCLoop)->ulOutCount;
  248. LeaveCriticalSection(&((ST_CLOOP *)hCLoop)->csect);
  249. return uCount;
  250. }
  251. /* --- Internal routines --- */
  252. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  253. * FUNCTION: CLoopGetNextOutput
  254. *
  255. * DESCRIPTION:
  256. * Fetchs the next item from the output queue for transmission.
  257. *
  258. * ARGUMENTS:
  259. * hCLoop -- The CLoop handle
  260. * pkKey -- Place to put the next item to be transmitted
  261. *
  262. * RETURNS:
  263. * TRUE if there is data to be transmitted.
  264. */
  265. int CLoopGetNextOutput(ST_CLOOP * const pstCLoop, KEY_T * const pkKey)
  266. {
  267. ST_CLOOP_OUT FAR * pstBlock;
  268. int fRetval = FALSE;
  269. unsigned long nBytesRead = 0L;
  270. KEY_T *pkGet;
  271. TCHAR chFileChar;
  272. TCHAR chChar;
  273. HWND hwndDsp;
  274. CHAR achBuf[2];
  275. assert(pstCLoop);
  276. assert(pkKey); // Caller must provide pointer for result
  277. if (pstCLoop->keyHoldKey)
  278. {
  279. *pkKey = pstCLoop->keyHoldKey;
  280. pstCLoop->keyHoldKey = (KEY_T)0;
  281. fRetval = TRUE;
  282. }
  283. else if (pstCLoop->ulOutCount || pstCLoop->pstFirstOutBlock)
  284. {
  285. pstBlock = pstCLoop->pstFirstOutBlock;
  286. assert(pstBlock); // should never be NULL while ulOutCount > 0
  287. // Skip any empty blocks (shouldn't be more than one)
  288. while (pstBlock->puchHead == pstBlock->puchTail)
  289. {
  290. CLoopRemoveFirstOutBlock(pstCLoop);
  291. pstBlock = pstCLoop->pstFirstOutBlock;
  292. assert(pstBlock); // should never remove all blocks
  293. }
  294. if (bittest(pstBlock->uOptions, CLOOP_CHARACTERS))
  295. {
  296. if (bittest(pstBlock->uOptions, CLOOP_KEYS))
  297. {
  298. pkGet = (KEY_T *)pstBlock->puchTail;
  299. *pkKey = *pkGet++;
  300. pstBlock->puchTail = (TCHAR *)pkGet;
  301. --pstCLoop->ulOutCount;
  302. fRetval = TRUE;
  303. }
  304. else
  305. {
  306. chChar = *pstBlock->puchTail++;
  307. *pkKey = (KEY_T)chChar;
  308. --pstCLoop->ulOutCount;
  309. // We must strip the LF from CR-LF pairs. This data may come from
  310. // the clipboard, in which case, line endings will be stored as
  311. // CR-LF. Terminals normally send only a CR at line ends. If we
  312. // DO need to send the LF, it will be added in the cloop output
  313. // routines if the append LF option is set.
  314. if (chChar != TEXT('\n') ||
  315. (pstBlock->chLastChar != TEXT('\r') &&
  316. pstBlock->chLastChar != (VK_RETURN | VIRTUAL_KEY)))
  317. {
  318. pstBlock->chLastChar = chChar;
  319. fRetval = TRUE;
  320. }
  321. }
  322. }
  323. else if (bittest(pstBlock->uOptions, CLOOP_OPENFILE))
  324. {
  325. //* TODO: this stuff will have to be expanded eventually to
  326. // handle SBCS, DBCS and Unicode input files. For now, all
  327. // text files are assumed to be SBCS.
  328. if (ReadFile(pstCLoop->hOutFile, achBuf, 1, &nBytesRead,
  329. (LPOVERLAPPED)0))
  330. {
  331. if (nBytesRead > 0)
  332. {
  333. //OemToCharBuff(achBuf, &chFileChar, 1);- mrw:10/20/95
  334. chFileChar = achBuf[0]; // mrw:10/20/95
  335. pstCLoop->ulSentSoFar += 1;
  336. *pkKey = (KEY_T)chFileChar;
  337. --pstBlock->ulBytes;
  338. --pstCLoop->ulOutCount;
  339. // We must strip the LF from CR-LF pairs. If line ends are
  340. // set to CR-LF in the settings, an LF will be added back in
  341. // later.
  342. if (chFileChar != TEXT('\n') ||
  343. (pstBlock->chLastChar != TEXT('\r') &&
  344. pstBlock->chLastChar != (VK_RETURN | VIRTUAL_KEY)))
  345. {
  346. pstBlock->chLastChar = chFileChar;
  347. fRetval = TRUE;
  348. }
  349. }
  350. else
  351. {
  352. // When ReadFile returns TRUE but 0 chars. were read,
  353. // it indicates end of file.
  354. CloseHandle(pstCLoop->hOutFile);
  355. pstCLoop->hOutFile = (HANDLE *)0;
  356. pstBlock->puchTail = pstBlock->puchHead;
  357. }
  358. }
  359. else
  360. {
  361. // ReadFile returned an error
  362. //* TODO: display error message
  363. CloseHandle(pstCLoop->hOutFile);
  364. pstCLoop->hOutFile = (HANDLE *)0;
  365. pstBlock->puchTail = pstBlock->puchHead;
  366. // pstCLoop->ulOutCount -= pstBlock->ulBytes;
  367. pstCLoop->ulOutCount = 0; //JMH 03-25-96
  368. }
  369. }
  370. else if (bittest(pstBlock->uOptions, CLOOP_TEXTFILE))
  371. {
  372. // New block with text file name, open file & start emptying
  373. pstCLoop->hOutFile = CreateFile(pstBlock->puchData,
  374. GENERIC_READ, FILE_SHARE_READ,
  375. (LPSECURITY_ATTRIBUTES)0, OPEN_EXISTING,
  376. FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)0);
  377. if (pstCLoop->hOutFile == INVALID_HANDLE_VALUE)
  378. {
  379. //* Display file error
  380. pstCLoop->hOutFile = (HANDLE *)0;
  381. pstBlock->puchTail = pstBlock->puchHead; // Remove from queue
  382. pstCLoop->ulOutCount = 0;
  383. PostMessage(sessQueryHwnd(pstCLoop->hSession),
  384. WM_ERROR_MSG, (WPARAM) IDS_ER_OPEN_FAILED, 0);
  385. }
  386. else
  387. {
  388. pstCLoop->ulTotalSend += pstBlock->ulBytes;
  389. //* CLoopTextDspFilename(pstCLoop, (LPTSTR)pstBlock->puchData);
  390. bitset(pstBlock->uOptions, CLOOP_OPENFILE);
  391. }
  392. }
  393. else if (bittest(pstBlock->uOptions, CLOOP_TEXTDSP))
  394. {
  395. MemCopy(&hwndDsp, pstBlock->puchData, sizeof(hwndDsp));
  396. //* CLoopDoTextDsp(pstCLoop, hwndDsp);
  397. // Set puchHead == puchTail to cause this block to be dropped
  398. pstBlock->puchHead = pstBlock->puchTail = pstBlock->puchData;
  399. }
  400. if (pstCLoop->ulOutCount == 0 && !pstBlock->pstNext)
  401. {
  402. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
  403. // mrw:3/11/96 - fixes send files being locked open after done.
  404. //
  405. if (pstCLoop->hOutFile)
  406. {
  407. CloseHandle(pstCLoop->hOutFile);
  408. pstCLoop->hOutFile = (HANDLE *)0;
  409. pstBlock->puchTail = pstBlock->puchHead;
  410. }
  411. }
  412. }
  413. if (fRetval)
  414. {
  415. if (*pkKey == TEXT('\r') && pstCLoop->keyLastKey == TEXT('\r') &&
  416. pstCLoop->stWorkSettings.fExpandBlankLines)
  417. {
  418. pstCLoop->keyHoldKey = *pkKey; // this will be returned next call
  419. *pkKey = TEXT(' '); // add space to expand blank line
  420. }
  421. pstCLoop->keyLastKey = *pkKey;
  422. }
  423. return fRetval;
  424. }
  425. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  426. * FUNCTION: CLoopNewOutBlock
  427. *
  428. * DESCRIPTION:
  429. * Internal routine to allocate and initialize a control block for the
  430. * output chain.
  431. *
  432. * ARGUMENTS:
  433. * siztData -- If non-zero, the routine will attempt to allocate memory
  434. * of the specfied size and assign it to the puchData member.
  435. * If zero the puchData member is set to NULL.
  436. *
  437. * RETURNS:
  438. * Pointer to a new control block for the output chain
  439. */
  440. ST_CLOOP_OUT *CLoopNewOutBlock(ST_CLOOP *pstCLoop, const size_t sizetData)
  441. {
  442. ST_CLOOP_OUT *pstNew = NULL;
  443. if ((pstNew = (ST_CLOOP_OUT *)malloc(sizeof(*pstNew))) != NULL)
  444. {
  445. pstNew->pstNext = NULL;
  446. pstNew->uOptions = 0;
  447. pstNew->hdlShared = (HGLOBAL)0;
  448. pstNew->puchData = NULL;
  449. pstNew->puchLimit = NULL;
  450. pstNew->puchHead = NULL;
  451. pstNew->puchTail = NULL;
  452. pstNew->ulBytes = 0L;
  453. pstNew->chLastChar = 0;
  454. if (sizetData > 0)
  455. {
  456. if ((pstNew->puchData = (TCHAR *)malloc(sizetData)) == NULL)
  457. {
  458. free(pstNew);
  459. pstNew = NULL;
  460. }
  461. }
  462. }
  463. if (!pstNew)
  464. {
  465. //* utilReportError(pstCLoop->hSession, RE_ERROR | RE_OK, NM_NEED_MEM,
  466. //* strldGet(mGetStrldHdl(pstCLoop->hSession), NM_XFER_DISPLAY));
  467. }
  468. else
  469. {
  470. // link new block into chain
  471. if (pstCLoop->pstLastOutBlock)
  472. pstCLoop->pstLastOutBlock->pstNext = pstNew;
  473. else
  474. {
  475. assert(!pstCLoop->pstFirstOutBlock);
  476. pstCLoop->pstFirstOutBlock = pstNew;
  477. }
  478. pstCLoop->pstLastOutBlock = pstNew;
  479. }
  480. return pstNew;
  481. }
  482. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  483. * FUNCTION: CLoopRemoveFirstOutBlock
  484. *
  485. * DESCRIPTION:
  486. *
  487. *
  488. * ARGUMENTS:
  489. *
  490. *
  491. * RETURNS:
  492. *
  493. */
  494. void CLoopRemoveFirstOutBlock(ST_CLOOP * const pstCLoop)
  495. {
  496. ST_CLOOP_OUT *pstBlock;
  497. pstBlock = pstCLoop->pstFirstOutBlock;
  498. if (pstBlock)
  499. {
  500. // link around block to be removed
  501. pstCLoop->pstFirstOutBlock = pstBlock->pstNext;
  502. if (!pstCLoop->pstFirstOutBlock)
  503. {
  504. // empty list
  505. assert(pstCLoop->pstLastOutBlock == pstBlock);
  506. pstCLoop->pstLastOutBlock = (ST_CLOOP_OUT *)0;
  507. }
  508. // free storage memory
  509. if (bittest(pstBlock->uOptions, CLOOP_SHARED))
  510. {
  511. GlobalUnlock(pstBlock->hdlShared);
  512. GlobalFree(pstBlock->hdlShared);
  513. }
  514. else
  515. {
  516. free(pstBlock->puchData);
  517. pstBlock->puchData = NULL;
  518. }
  519. // Now free the block control structure
  520. free(pstBlock);
  521. pstBlock = NULL;
  522. }
  523. }