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.

2048 lines
62 KiB

  1. // scraper.cpp : This file contains the
  2. // Created: Dec '97
  3. // History:
  4. // Copyright (C) 1997 Microsoft Corporation
  5. // All rights reserved.
  6. // Microsoft Confidential
  7. #include <windows.h>
  8. #include <wincon.h>
  9. #include <msgFile.h>
  10. #include <telnetd.h>
  11. #include <debug.h>
  12. #include <regutil.h>
  13. #include <TermCap.h>
  14. #include <Scraper.h>
  15. #include <Session.h>
  16. #include <TlntUtils.h>
  17. #include <Ipc.h>
  18. #include <vtnt.h>
  19. #define ONE_KB 1024
  20. #pragma warning( disable: 4706 )
  21. #pragma warning( disable: 4127 )
  22. using namespace _Utils;
  23. using CDebugLevel::TRACE_DEBUGGING;
  24. using CDebugLevel::TRACE_HANDLE;
  25. using CDebugLevel::TRACE_SOCKET;
  26. WORD wRows;
  27. WORD wCols;
  28. COORD coExpectedCursor = { ~0, ~0 };
  29. extern HANDLE g_hSyncCloseHandle;
  30. CTermCap* pTermCap = 0;
  31. LPSTR lpszCMStr1 = 0;
  32. LPSTR lpszCMStr2 = 0;
  33. CHAR szSGRStr[25]; //the string is of the form <ESC>[ Ps m
  34. bool fNegativeImage = false, fBold = false;
  35. WORD wExistingAttributes = 0;
  36. WORD wDefaultAttributes = 0;
  37. static PUCHAR g_pucSendBuffer = 0;
  38. static DWORD g_dwSendBufferSize = 0;
  39. static PUCHAR g_pucSendInsertPoint = 0;
  40. void
  41. CScraper::DeleteCMStrings()
  42. {
  43. delete[] lpszCMStr1;
  44. delete[] lpszCMStr2;
  45. }
  46. void
  47. CScraper::LoadStrings()
  48. {
  49. //ce --> String to clear from the cursor to the end of the line
  50. lpszCMStr1 = pTermCap->GetString( "ce" );
  51. //cm --> String to position the cursor at row r, column c
  52. lpszCMStr2 = pTermCap->GetString( "cm" );
  53. }
  54. CScraper::CScraper()
  55. {
  56. pLastSeen = NULL;
  57. pCurrent = NULL;
  58. m_dwHowLongIdle = 0;
  59. m_bCheckForScrolling = 1;
  60. m_dwTerm = 0;
  61. m_hConBufIn = NULL;
  62. m_hConBufOut = NULL;
  63. }
  64. CScraper::~CScraper()
  65. {
  66. // Cleanup before exit
  67. TELNET_CLOSE_HANDLE( m_hConBufIn );
  68. delete [] pCurrent;
  69. delete [] pLastSeen;
  70. delete [] g_pucSendBuffer;
  71. DeleteCMStrings();
  72. delete pTermCap;
  73. }
  74. bool
  75. CScraper::InitializeNonVtntTerms()
  76. {
  77. if( !pTermCap->LoadEntry( m_pSession->m_pszTermType ) )
  78. {
  79. LPWSTR szTermType = NULL;
  80. _TRACE( TRACE_DEBUGGING, "TermCap LoadEntry() failed : %s",
  81. m_pSession->m_pszTermType );
  82. ConvertSChartoWChar( m_pSession->m_pszTermType, &szTermType );
  83. LogEvent( EVENTLOG_ERROR_TYPE, MSG_NOENTRY_IN_TERMCAP, szTermType );
  84. if( !pTermCap->LoadEntry( VT100 ) )
  85. {
  86. _TRACE( TRACE_DEBUGGING, "TermCap LoadEntry() failed" );
  87. LogEvent( EVENTLOG_ERROR_TYPE, MSG_ERROR_READING_TERMCAP, _T("") );
  88. return( FALSE );
  89. }
  90. _TRACE( TRACE_DEBUGGING, "TermType is vt100");
  91. }
  92. LoadStrings();
  93. if( ( lpszCMStr1 == NULL ) || ( lpszCMStr2 == NULL ) )
  94. {
  95. DeleteCMStrings();
  96. if( !pTermCap->LoadEntry( VT100 ) )
  97. {
  98. _TRACE( TRACE_DEBUGGING, "TermCap LoadEntry() failed" );
  99. LogEvent( EVENTLOG_ERROR_TYPE, MSG_ERROR_READING_TERMCAP, _T("") );
  100. }
  101. else
  102. {
  103. _TRACE( TRACE_DEBUGGING, "TermType is vt100");
  104. LogEvent( EVENTLOG_ERROR_TYPE, MSG_NOENTRY_IN_TERMCAP, _T("") );
  105. LoadStrings();
  106. }
  107. }
  108. pTermCap->ProcessString( &lpszCMStr1 );
  109. pTermCap->ProcessString( &lpszCMStr2 );
  110. if( m_pSession->CSession::m_bIsStreamMode )
  111. {
  112. //ask for crlf for an enter when in stream mode
  113. //Set new line mode for the virtual terminal
  114. CHAR szLNMString[ SMALL_ARRAY + 1];
  115. _snprintf( szLNMString, SMALL_ARRAY, "%c[%dh", VT_ESC, LNM );
  116. szLNMString[SMALL_ARRAY] = '\0';
  117. SendString( szLNMString );
  118. }
  119. return( TRUE );
  120. }
  121. bool AllocateSendBuffer( )
  122. {
  123. g_dwSendBufferSize = DEFAULT_SEND_BUFFER_SIZE;
  124. g_pucSendBuffer = new UCHAR[g_dwSendBufferSize];
  125. g_pucSendInsertPoint = g_pucSendBuffer;
  126. if( !g_pucSendBuffer )
  127. {
  128. return( FALSE );
  129. }
  130. SfuZeroMemory((LPVOID)g_pucSendBuffer, g_dwSendBufferSize);
  131. return( TRUE );
  132. }
  133. bool
  134. CScraper::InitTerm()
  135. {
  136. //The following is just to avoid recurring string comparisions
  137. m_dwTerm = TERMVT100;
  138. if( _stricmp( m_pSession->m_pszTermType, VTNT ) == 0 )
  139. {
  140. m_dwTerm = TERMVTNT;
  141. }
  142. else if ( _stricmp( m_pSession->m_pszTermType, VT52 ) == 0 )
  143. {
  144. m_dwTerm = TERMVT52;
  145. }
  146. else if ( _stricmp( m_pSession->m_pszTermType, VT100 ) == 0 )
  147. {
  148. m_dwTerm = TERMVT100;
  149. }
  150. else if ( _stricmp( m_pSession->m_pszTermType, VT80 ) == 0 )
  151. {
  152. m_dwTerm = TERMVT80;
  153. }
  154. else if ( _stricmp( m_pSession->m_pszTermType, ANSI ) == 0 )
  155. {
  156. m_dwTerm = TERMANSI;
  157. }
  158. if( !( m_dwTerm & TERMVTNT ) )
  159. {
  160. if( !InitializeNonVtntTerms() )
  161. {
  162. return( FALSE );
  163. }
  164. }
  165. SfuZeroMemory( &LastCSBI, sizeof( LastCSBI ) );
  166. if( g_pucSendBuffer == NULL )
  167. {
  168. if( !AllocateSendBuffer() )
  169. {
  170. return ( FALSE );
  171. }
  172. }
  173. return( TRUE );
  174. }
  175. bool
  176. CScraper::SetWindowInfo()
  177. {
  178. //No Security Attrs needed.
  179. _chVERIFY2( m_hConBufOut = CreateFile( TEXT("CONOUT$"), GENERIC_READ |
  180. GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  181. FILE_ATTRIBUTE_NORMAL, 0 ) );
  182. if( INVALID_HANDLE_VALUE == m_hConBufOut)
  183. {
  184. //Could be an application that does not share its screen buffer
  185. return ( TRUE );
  186. }
  187. SMALL_RECT sr;
  188. sr.Top = 0;
  189. sr.Bottom = ( WORD )( m_pSession->CSession::m_wRows - 1 );
  190. sr.Right = ( WORD ) ( m_pSession->CSession::m_wCols - 1 );
  191. sr.Left = 0;
  192. COORD coordSize;
  193. coordSize.X = m_pSession->CSession::m_wCols;
  194. coordSize.Y = m_pSession->CSession::m_wRows;
  195. CONSOLE_SCREEN_BUFFER_INFO csbi;
  196. _chVERIFY2( GetConsoleScreenBufferInfo( m_pSession->CScraper::m_hConBufOut,
  197. &csbi) );
  198. // Logic: If the Old Window Size is less than the new Size then we set
  199. // the Screen Buffer Size first and then set the Window Size.
  200. // If the Old Window Size is Greater than the new Size then we set the
  201. // window Size first and then the Screen Buffer.
  202. // The above is because the Buffer Size always has to be greater than or
  203. // equal to the Window Size.
  204. if ( (csbi.dwSize.X < coordSize.X) || (csbi.dwSize.Y < coordSize.Y) )
  205. {
  206. COORD coordTmpSize = { 0, 0 };
  207. coordTmpSize .X = ( csbi.dwSize.X < coordSize.X ) ? coordSize.X : csbi.dwSize.X;
  208. coordTmpSize .Y = ( csbi.dwSize.Y < coordSize.Y ) ? coordSize.Y : csbi.dwSize.Y;
  209. _chVERIFY2( SetConsoleScreenBufferSize
  210. ( m_pSession->CScraper::m_hConBufOut, coordTmpSize ) );
  211. _chVERIFY2( SetConsoleWindowInfo
  212. ( m_pSession->CScraper::m_hConBufOut, TRUE, &sr ) );
  213. _chVERIFY2( SetConsoleScreenBufferSize
  214. ( m_pSession->CScraper::m_hConBufOut, coordSize ) );
  215. }
  216. else
  217. {
  218. _chVERIFY2( SetConsoleWindowInfo( m_pSession->CScraper::m_hConBufOut,
  219. TRUE, &sr ) );
  220. _chVERIFY2( SetConsoleScreenBufferSize( m_pSession->CScraper::
  221. m_hConBufOut, coordSize ) );
  222. }
  223. TELNET_CLOSE_HANDLE( m_hConBufOut );
  224. return( TRUE );
  225. }
  226. bool
  227. CScraper::SetCmdInfo()
  228. {
  229. if( !SetWindowInfo() )
  230. {
  231. return( FALSE );
  232. }
  233. wRows = m_pSession->m_wRows;
  234. wCols = m_pSession->m_wCols;
  235. if( pLastSeen )
  236. {
  237. delete[] pLastSeen;
  238. }
  239. if( pCurrent )
  240. {
  241. delete[] pCurrent;
  242. }
  243. pLastSeen = ( PCHAR_INFO ) new char[wRows * wCols * sizeof( CHAR_INFO )];
  244. pCurrent = ( PCHAR_INFO ) new char[wRows * wCols * sizeof( CHAR_INFO )];
  245. if( !pLastSeen || !pCurrent )
  246. {
  247. return ( FALSE );
  248. }
  249. SfuZeroMemory( pLastSeen, wRows * wCols * sizeof( CHAR_INFO ) );
  250. return( TRUE );
  251. }
  252. void
  253. CScraper::Init( CSession *pSession )
  254. {
  255. _chASSERT( pSession );
  256. m_pSession = pSession;
  257. m_dwCurrentCodePage = GetACP();
  258. }
  259. bool
  260. CScraper::InitSession()
  261. {
  262. wRows = m_pSession->m_wRows;
  263. wCols = m_pSession->m_wCols;
  264. CONVERT_TO_MILLI_SECS( m_pSession->CSession::m_dwIdleSessionTimeOut );
  265. m_dwPollInterval = MIN_POLL_INTERVAL;
  266. GetRegistryValues( );
  267. //Load the term cap entry
  268. pTermCap = _Utils::CTermCap::Instance();
  269. if( !pTermCap )
  270. {
  271. return( FALSE );
  272. }
  273. pLastSeen = NULL;
  274. pCurrent = NULL;
  275. m_dwInputSequneceState = IP_INIT;
  276. m_dwDigitInTheSeq = 0;
  277. if( !InitTerm() )
  278. {
  279. return( FALSE );
  280. }
  281. if( !SetCmdInfo() )
  282. {
  283. return( FALSE );
  284. }
  285. //
  286. // If Japanese NT use VT80 scraping loop
  287. //
  288. return( TRUE );
  289. }
  290. void
  291. CScraper::Shutdown()
  292. {
  293. }
  294. bool
  295. CScraper::OnWaitTimeOut()
  296. {
  297. bool bRetVal = TRUE;
  298. bool fDifferenceFound = false;
  299. if( m_pSession->CSession::m_bIsStreamMode )
  300. {
  301. //No scraping.
  302. if( g_pucSendInsertPoint != g_pucSendBuffer )
  303. {
  304. fDifferenceFound = true;
  305. CScraper::Transmit();
  306. }
  307. }
  308. else
  309. {
  310. // Time to check the screen
  311. if( ( m_dwTerm & TERMVTNT ) != 0 )
  312. {
  313. bRetVal = CompareAndUpdateVTNT( wRows, wCols, pCurrent, pLastSeen,
  314. &CSBI, &LastCSBI, &fDifferenceFound );
  315. }
  316. else
  317. {
  318. bRetVal = COMPARE_AND_UPDATE ( wRows, wCols, pCurrent,
  319. pLastSeen, &CSBI, &LastCSBI, &fDifferenceFound );
  320. }
  321. }
  322. if( fDifferenceFound )
  323. {
  324. m_dwPollInterval = MIN_POLL_INTERVAL;
  325. }
  326. else
  327. {
  328. m_dwPollInterval = MAX_POLL_INTERVAL;
  329. }
  330. return( bRetVal );
  331. }
  332. bool
  333. CScraper::IsSessionTimedOut()
  334. {
  335. if( m_dwPollInterval == MAX_POLL_INTERVAL )
  336. {
  337. m_dwHowLongIdle += MAX_POLL_INTERVAL;
  338. m_pSession->CIoHandler::UpdateIdleTime( UPDATE_IDLE_TIME );
  339. if( m_dwHowLongIdle > m_pSession->CSession::m_dwIdleSessionTimeOut &&
  340. !ISSESSION_TIMEOUT_DISABLED( m_pSession->CSession::m_dwIdleSessionTimeOut) )
  341. {
  342. LPWSTR szMsg = NULL;
  343. szMsg = new WCHAR[ 2 * wcslen( _T( "\r\n" ) ) + wcslen( _T( TIMEOUT_STR ) ) + wcslen( _T( TERMINATE ) ) + 1];
  344. if( szMsg )
  345. {
  346. wcscpy( szMsg, _T( "\r\n" ) );
  347. wcscat( szMsg, _T( TERMINATE ) );
  348. wcscat( szMsg, _T( TIMEOUT_STR ) );
  349. wcscat( szMsg, _T( "\r\n" ) );
  350. m_pSession->CIoHandler::SendMessageToClient( szMsg, NO_HEADER );
  351. delete[] szMsg;
  352. }
  353. return( true ); //This will take us out of WaitForIo
  354. }
  355. }
  356. else
  357. {
  358. if( m_dwHowLongIdle != 0 )
  359. {
  360. m_pSession->CIoHandler::UpdateIdleTime( RESET_IDLE_TIME );
  361. }
  362. m_dwHowLongIdle = 0;
  363. }
  364. return( false );
  365. }
  366. void CScraper::EchoVtntCharToClient( INPUT_RECORD *pIR )
  367. {
  368. _chASSERT( pIR );
  369. CHAR rgchInput;
  370. if( !pIR )
  371. {
  372. return;
  373. }
  374. DWORD dwSize = 0;
  375. PUCHAR pResponse = NULL;
  376. rgchInput = pIR->Event.KeyEvent.uChar.AsciiChar;
  377. m_pSession->CRFCProtocol::StrToVTNTResponse( &( rgchInput ), 1, ( VOID **)&pResponse, &dwSize );
  378. SendBytes( pResponse, dwSize );
  379. delete[] pResponse;
  380. }
  381. inline void
  382. CScraper::EchoCharBackToClient( UCHAR ucChar )
  383. {
  384. SendChar( ucChar );
  385. }
  386. bool
  387. CScraper::EmulateAndWriteToCmdConsoleInput()
  388. {
  389. CHAR cPrevChar;
  390. DWORD dwCount;
  391. SHORT vk;
  392. BYTE vkcode;
  393. DWORD dwShiftcode;
  394. WORD wScanCode;
  395. DWORD i;
  396. BOOL dwStatus = 0;
  397. DWORD dwBytesTransferred = 0;
  398. cPrevChar = '\0';
  399. dwBytesTransferred = m_pSession->CIoHandler::m_dwReadFromSocketIoLength;
  400. m_dwPollInterval = MIN_POLL_INTERVAL;
  401. if( ( m_dwTerm & TERMVTNT ) != 0 )
  402. {
  403. DWORD dwBytesRemaining = 0;
  404. DWORD dwBytesProcessed = 0;
  405. INPUT_RECORD* pIR = (INPUT_RECORD*) m_pSession->CIoHandler::
  406. m_ReadFromSocketBuffer;
  407. dwBytesTransferred += (DWORD)(m_pSession->CIoHandler::m_pReadFromSocketBufferCursor - m_pSession->CIoHandler::m_ReadFromSocketBuffer);
  408. if( m_pSession->CSession::m_bIsStreamMode &&
  409. pIR->EventType == KEY_EVENT &&
  410. pIR->Event.KeyEvent.bKeyDown &&
  411. pIR->Event.KeyEvent.uChar.AsciiChar
  412. )
  413. {
  414. EchoVtntCharToClient( pIR );
  415. }
  416. if( pIR->Event.KeyEvent.uChar.AsciiChar != '\r' )
  417. {
  418. m_bCheckForScrolling = 0 ;
  419. }
  420. if( (pIR->EventType == KEY_EVENT) &&
  421. pIR->Event.KeyEvent.uChar.AsciiChar == CTRLC )
  422. {
  423. DWORD dwMode = 0;
  424. _chVERIFY2( GetConsoleMode( m_hConBufIn, &dwMode ) );
  425. if( ( ( dwMode & ENABLE_PROCESSED_INPUT ) && pIR->Event.KeyEvent.bKeyDown )
  426. || pIR->Event.KeyEvent.wVirtualKeyCode == VKEY_CTRL_BREAK )
  427. {
  428. _chVERIFY2( GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0));
  429. return( TRUE );
  430. }
  431. }
  432. if( dwBytesRemaining = (dwBytesTransferred % sizeof(INPUT_RECORD)) )
  433. {
  434. dwBytesProcessed = dwBytesTransferred - dwBytesRemaining;
  435. }
  436. else
  437. {
  438. dwBytesProcessed=dwBytesTransferred;
  439. }
  440. _chVERIFY2( dwStatus = WriteConsoleInput( m_hConBufIn,
  441. pIR, dwBytesProcessed/sizeof(INPUT_RECORD), &dwCount));
  442. if( !dwStatus )
  443. {
  444. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE,
  445. MSG_ERR_WRITE_CONSOLE, GetLastError() );
  446. return ( FALSE );
  447. }
  448. if( dwBytesRemaining > 0 )
  449. {
  450. memmove( (void *)m_pSession->CIoHandler::m_ReadFromSocketBuffer, (void *)(m_pSession->CIoHandler::m_ReadFromSocketBuffer+dwBytesProcessed), dwBytesRemaining);
  451. }
  452. m_pSession->CIoHandler::m_pReadFromSocketBufferCursor = (PUCHAR)(m_pSession->CIoHandler::m_ReadFromSocketBuffer + dwBytesRemaining);
  453. }
  454. else
  455. {
  456. m_bCheckForScrolling = 1;
  457. if( dwBytesTransferred == 1 )
  458. {
  459. if( m_pSession->CIoHandler::m_ReadFromSocketBuffer[0] != '\r' )
  460. {
  461. m_bCheckForScrolling = 0;
  462. }
  463. }
  464. for( i=0; i < dwBytesTransferred; i++ )
  465. {
  466. if( m_pSession->CSession::m_bIsStreamMode )
  467. {
  468. EchoCharBackToClient( m_pSession->CIoHandler::
  469. m_ReadFromSocketBuffer[i] );
  470. }
  471. if( ProcessEnhancedKeys( m_pSession->CIoHandler::
  472. m_ReadFromSocketBuffer[i], &cPrevChar,
  473. dwBytesTransferred == 1) )
  474. {
  475. m_bCheckForScrolling = 0;
  476. continue;
  477. }
  478. if( cPrevChar != '\r' || m_pSession->CIoHandler::
  479. m_ReadFromSocketBuffer[i] != '\n' )
  480. {
  481. if( m_pSession->CIoHandler::m_ReadFromSocketBuffer[i] == CTRLC )
  482. {
  483. //The follwing is the observed behaviour of CTRL C
  484. //When ENABLE_PROCESSED_INPUT mode is not enabled, pass CTRL C as
  485. //input to the console input buffer.
  486. //When ENABLE_PROCESSED_INPUT mode is enabled, generate CTTRL C signal
  487. //and also unblock any ReadConsoleInput. This behaviour is what is observed
  488. // and not from any documentation.
  489. DWORD dwMode = 0;
  490. _chVERIFY2( GetConsoleMode( m_hConBufIn, &dwMode ) );
  491. if( dwMode & ENABLE_PROCESSED_INPUT )
  492. {
  493. _chVERIFY2( GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0));
  494. continue;
  495. }
  496. }
  497. vk = VkKeyScan( m_pSession->CIoHandler::
  498. m_ReadFromSocketBuffer[i] );
  499. if( vk != 0xffff )
  500. {
  501. vkcode = LOBYTE( vk );
  502. wScanCode = ( WORD )MapVirtualKey( vkcode, 0 );
  503. dwShiftcode = 0;
  504. if( HIBYTE( vk ) & 1 )
  505. dwShiftcode |= SHIFT_PRESSED;
  506. if( HIBYTE( vk ) & 2 )
  507. dwShiftcode |= LEFT_CTRL_PRESSED;
  508. if( HIBYTE( vk ) & 4 )
  509. dwShiftcode |= LEFT_ALT_PRESSED;
  510. dwStatus = WriteAKeyToCMD( vkcode, wScanCode,
  511. m_pSession->CIoHandler::m_ReadFromSocketBuffer[i],
  512. dwShiftcode );
  513. if( !dwStatus )
  514. {
  515. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE,
  516. MSG_ERR_WRITE_CONSOLE, GetLastError() );
  517. return ( FALSE );
  518. }
  519. }
  520. }
  521. cPrevChar = m_pSession->CIoHandler::m_ReadFromSocketBuffer[i];
  522. }
  523. }
  524. return( TRUE );
  525. }
  526. DWORD
  527. CScraper::WriteAKeyToCMD( WORD wVKCode, WORD wVSCode, CHAR cChar, DWORD dwCKState )
  528. {
  529. DWORD dwStatus = 0;
  530. DWORD dwCount = 0;
  531. INPUT_RECORD input;
  532. SfuZeroMemory( &input, sizeof( INPUT_RECORD ) );
  533. input.EventType = KEY_EVENT;
  534. input.Event.KeyEvent.bKeyDown = TRUE;
  535. input.Event.KeyEvent.wRepeatCount = 1;
  536. input.Event.KeyEvent.wVirtualKeyCode = wVKCode;
  537. input.Event.KeyEvent.wVirtualScanCode = wVSCode;
  538. input.Event.KeyEvent.uChar.AsciiChar = cChar;
  539. input.Event.KeyEvent.dwControlKeyState = dwCKState;
  540. _chVERIFY2 ( dwStatus = WriteConsoleInputA( m_hConBufIn, &input, 1, &dwCount ) );
  541. if( !IsDBCSLeadByte(cChar) )
  542. {
  543. input.Event.KeyEvent.bKeyDown = FALSE;
  544. _chVERIFY2 ( dwStatus = WriteConsoleInputA( m_hConBufIn, &input, 1, &dwCount ) );
  545. }
  546. return dwStatus;
  547. }
  548. bool
  549. CScraper::ProcessEnhancedKeys( unsigned char cCurrentChar, char* pchPrevChar, bool fSingleByte )
  550. {
  551. bool bRetVal = true;
  552. *pchPrevChar = cCurrentChar;
  553. switch( m_dwInputSequneceState )
  554. {
  555. case IP_INIT:
  556. if( cCurrentChar == m_pSession->m_dwAltKeyMapping )
  557. {
  558. WriteAKeyToCMD( VK_MENU, VS_MENU, cCurrentChar, ENHANCED_KEY );
  559. }
  560. else if( cCurrentChar == ASCII_DELETE ) //vt100 delete key
  561. {
  562. WriteAKeyToCMD( VK_DELETE, VS_DELETE, 0, ENHANCED_KEY );
  563. }
  564. else if( cCurrentChar == ESC )
  565. {
  566. if( fSingleByte )
  567. {
  568. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  569. }
  570. else
  571. {
  572. m_dwInputSequneceState = IP_ESC_RCVD;
  573. }
  574. }else
  575. {
  576. //Not any special char
  577. bRetVal = false;
  578. }
  579. break;
  580. case IP_ESC_RCVD:
  581. if( cCurrentChar == '[' )
  582. {
  583. m_dwInputSequneceState = IP_ESC_BRACKET_RCVD;
  584. }
  585. else if( cCurrentChar == 'O' )
  586. {
  587. m_dwInputSequneceState = IP_ESC_O_RCVD;
  588. }
  589. else
  590. {
  591. //Write already received escape as it is and return false
  592. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  593. bRetVal = false;
  594. m_dwInputSequneceState = IP_INIT;
  595. }
  596. break;
  597. case IP_ESC_O_RCVD:
  598. m_dwInputSequneceState = IP_INIT;
  599. switch( cCurrentChar )
  600. {
  601. case 'P':
  602. WriteAKeyToCMD( VK_F1, VS_F1, 0, ENHANCED_KEY );
  603. break;
  604. case 'Q':
  605. WriteAKeyToCMD( VK_F2, VS_F2, 0, ENHANCED_KEY );
  606. break;
  607. case 'R':
  608. WriteAKeyToCMD( VK_F3, VS_F3, 0, ENHANCED_KEY );
  609. break;
  610. case 'S':
  611. WriteAKeyToCMD( VK_F4, VS_F4, 0, ENHANCED_KEY );
  612. break;
  613. default:
  614. //Write already received escape as it is and return false which
  615. //will make the current char also to be written to the cmd
  616. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  617. WriteAKeyToCMD( 'O', VS_O, 'O', CAPSLOCK_ON ); //write O
  618. bRetVal = false;
  619. }
  620. break;
  621. case IP_ESC_BRACKET_RCVD:
  622. m_dwInputSequneceState = IP_INIT;
  623. switch( cCurrentChar )
  624. {
  625. case 'A':
  626. WriteAKeyToCMD( VK_UP, VS_UP, 0, ENHANCED_KEY );
  627. break;
  628. case 'B':
  629. WriteAKeyToCMD( VK_DOWN, VS_DOWN, 0, ENHANCED_KEY );
  630. break;
  631. case 'C':
  632. WriteAKeyToCMD( VK_RIGHT, VS_RIGHT, 0, ENHANCED_KEY );
  633. break;
  634. case 'D':
  635. WriteAKeyToCMD( VK_LEFT, VS_LEFT, 0, ENHANCED_KEY );
  636. break;
  637. case VT302_PAUSE: //'P'
  638. WriteAKeyToCMD( VK_PAUSE, VS_PAUSE, 0, ENHANCED_KEY );
  639. break;
  640. default:
  641. if( isdigit( cCurrentChar ) )
  642. {
  643. m_dwInputSequneceState = IP_ESC_BRACKET_DIGIT_RCVD;
  644. m_dwDigitInTheSeq = cCurrentChar - '0';
  645. }
  646. else
  647. {
  648. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  649. WriteAKeyToCMD( VK_OEM_4, VS_OEM_4, '[', 0 );
  650. bRetVal = false;
  651. }
  652. break;
  653. }
  654. break;
  655. case IP_ESC_BRACKET_DIGIT_RCVD:
  656. m_dwInputSequneceState = IP_INIT;
  657. if( isdigit( cCurrentChar ) )
  658. {
  659. m_dwDigitInTheSeq = m_dwDigitInTheSeq * 10 + ( cCurrentChar - '0' ) ;
  660. m_dwInputSequneceState = IP_ESC_BRACKET_DIGIT_RCVD;
  661. }
  662. else if( cCurrentChar == '~' )
  663. {
  664. switch( m_dwDigitInTheSeq )
  665. {
  666. case VT302_NEXT:
  667. WriteAKeyToCMD( VK_NEXT, VS_NEXT, 0, ENHANCED_KEY );
  668. break;
  669. case VT302_PRIOR:
  670. WriteAKeyToCMD( VK_PRIOR, VS_PRIOR, 0, ENHANCED_KEY );
  671. break;
  672. case VT302_END:
  673. WriteAKeyToCMD( VK_END, VS_END, 0, ENHANCED_KEY );
  674. break;
  675. case VT302_INSERT:
  676. WriteAKeyToCMD( VK_INSERT, VS_INSERT, 0, ENHANCED_KEY );
  677. break;
  678. case VT302_HOME:
  679. WriteAKeyToCMD( VK_HOME, VS_HOME, 0, ENHANCED_KEY );
  680. break;
  681. case VT302_F5:
  682. WriteAKeyToCMD( VK_F5, VS_F5, 0, ENHANCED_KEY );
  683. break;
  684. case VT302_F6:
  685. WriteAKeyToCMD( VK_F6, VS_F6, 0, ENHANCED_KEY );
  686. break;
  687. case VT302_F7:
  688. WriteAKeyToCMD( VK_F7, VS_F7, 0, ENHANCED_KEY );
  689. break;
  690. case VT302_F8:
  691. WriteAKeyToCMD( VK_F8, VS_F8, 0, ENHANCED_KEY );
  692. break;
  693. case VT302_F9:
  694. WriteAKeyToCMD( VK_F9, VS_F9, 0, ENHANCED_KEY );
  695. break;
  696. case VT302_F10:
  697. WriteAKeyToCMD( VK_F10, VS_F10, 0, ENHANCED_KEY );
  698. break;
  699. case VT302_F11:
  700. WriteAKeyToCMD( VK_F11, VS_F11, 0, ENHANCED_KEY );
  701. break;
  702. case VT302_F12:
  703. WriteAKeyToCMD( VK_F12, VS_F12, 0, ENHANCED_KEY );
  704. break;
  705. default:
  706. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  707. WriteAKeyToCMD( VK_OEM_4, VS_OEM_4, '[', 0 );
  708. _chASSERT( 0 );
  709. bRetVal = false;
  710. }
  711. }
  712. else
  713. {
  714. WriteAKeyToCMD( VK_ESCAPE, VS_ESCAPE, ESC, ENHANCED_KEY );
  715. WriteAKeyToCMD( VK_OEM_4, VS_OEM_4, '[', 0 );
  716. _chASSERT( 0 );
  717. bRetVal = false;
  718. }
  719. break;
  720. default:
  721. //Should not happen
  722. _chASSERT( 0 );
  723. }
  724. return bRetVal;
  725. }
  726. void
  727. CScraper::SendChar( char ch )
  728. {
  729. SendBytes( ( PUCHAR )&ch, 1 );
  730. }
  731. void
  732. CScraper::SendBytes( PUCHAR pucBuf, DWORD dwLength )
  733. {
  734. bool bSuccess=false;
  735. bool bTransmitDone = false;
  736. if( pucBuf == NULL )
  737. return;
  738. if( g_pucSendBuffer == NULL )
  739. {
  740. return;
  741. }
  742. else
  743. {
  744. if( g_dwSendBufferSize >= MAX_SOCKET_BUFFER_SIZE )
  745. {
  746. bSuccess = Transmit();
  747. bTransmitDone = true;
  748. }
  749. if( ((bTransmitDone&&bSuccess)||(!bTransmitDone))&&( g_pucSendInsertPoint + dwLength ) > ( g_pucSendBuffer + g_dwSendBufferSize ) )
  750. {
  751. // do realloc
  752. DWORD dwOffset = (DWORD)( g_pucSendInsertPoint - g_pucSendBuffer );
  753. DWORD dwTmpBufSize = dwLength + dwOffset;
  754. PUCHAR pTmpBuf = new UCHAR[dwTmpBufSize];
  755. if( !pTmpBuf )
  756. {
  757. return;
  758. }
  759. memcpy( pTmpBuf, g_pucSendBuffer, dwOffset ); // No attack, calculated allocation already. Baskar.
  760. delete [] g_pucSendBuffer;
  761. g_pucSendBuffer = pTmpBuf;
  762. g_dwSendBufferSize = dwTmpBufSize;
  763. g_pucSendInsertPoint = g_pucSendBuffer + dwOffset;
  764. }
  765. }
  766. if(g_pucSendInsertPoint)
  767. {
  768. memcpy( g_pucSendInsertPoint, pucBuf, dwLength ); // No size info for destination, Baskar - Attack ?
  769. g_pucSendInsertPoint += dwLength;
  770. }
  771. }
  772. void
  773. CScraper::SendString( LPSTR pszString )
  774. {
  775. if( pszString == 0 )
  776. return;
  777. SendBytes( ( PUCHAR )pszString, strlen( pszString ) );
  778. }
  779. void
  780. CScraper::SendFmt( LPSTR fmt, ... )
  781. {
  782. va_list arg;
  783. CHAR szBuffer[ONE_KB + 1] = { 0 };
  784. va_start( arg,fmt );
  785. _vsnprintf( szBuffer, ONE_KB, fmt, arg );
  786. va_end( arg );
  787. SendString( szBuffer );
  788. }
  789. bool
  790. CScraper::Transmit( )
  791. {
  792. if( g_pucSendInsertPoint != g_pucSendBuffer )
  793. {
  794. if( !TransmitBytes( g_pucSendBuffer, (DWORD)( g_pucSendInsertPoint - g_pucSendBuffer ) ) )
  795. {
  796. return( FALSE );
  797. }
  798. //We need to tune this DEFAULT_SEND_BUFFER_SIZE
  799. if( g_dwSendBufferSize > DEFAULT_SEND_BUFFER_SIZE )
  800. {
  801. //Don't keep if it is a huge buffer
  802. delete [] g_pucSendBuffer;
  803. g_dwSendBufferSize = 0;
  804. if( !AllocateSendBuffer() )
  805. {
  806. return( FALSE );
  807. }
  808. }
  809. g_pucSendInsertPoint = g_pucSendBuffer;
  810. }
  811. return( TRUE );
  812. }
  813. bool
  814. CScraper::TransmitBytes( PUCHAR pSendBuffer, DWORD dwSize)
  815. {
  816. bool bRetVal = TRUE;
  817. DWORD dwCurrentPacket = 0;
  818. DWORD dwTotalBytesSent = 0;
  819. //StuffEsacapeIACs may put some escape chars. I am expecting atmost
  820. //DELTA such chars. Typically there will be none. With out this, we
  821. //have to make pass over the pOutBuf once just to find the right number
  822. //in a routine that may be executed once every 100ms.
  823. while( dwTotalBytesSent < dwSize )
  824. {
  825. ( ( dwSize - dwTotalBytesSent ) >
  826. ( MAX_WRITE_SOCKET_BUFFER - DELTA ) )?
  827. dwCurrentPacket = ( MAX_WRITE_SOCKET_BUFFER - DELTA ):
  828. dwCurrentPacket = dwSize - dwTotalBytesSent;
  829. DWORD dwNumBytesWritten = 0;
  830. //Block until Previous Io is finished
  831. if( !FinishIncompleteIo( (HANDLE) m_pSession->CIoHandler::m_sSocket,
  832. &( m_pSession->CIoHandler::m_oWriteToSocket ), &dwNumBytesWritten ) )
  833. {
  834. bRetVal = FALSE ;
  835. break;
  836. }
  837. DWORD dwCountWithEscapes = dwCurrentPacket;
  838. StuffEscapeIACs( m_pSession->CIoHandler::m_WriteToSocketBuff,
  839. pSendBuffer + dwTotalBytesSent, &dwCountWithEscapes );
  840. m_pSession->CIoHandler::m_dwWriteToSocketIoLength=dwCountWithEscapes;
  841. if( !m_pSession->CIoHandler::WriteToClient( ) )
  842. {
  843. bRetVal = FALSE ;
  844. break;
  845. }
  846. dwTotalBytesSent += dwCurrentPacket;
  847. }
  848. return( bRetVal );
  849. }
  850. void
  851. CScraper::SendColorInfo( WORD wAttributes )
  852. {
  853. if( wAttributes & BACKGROUND_INTENSITY )
  854. {
  855. //do nothing.
  856. //There is no equivalent capability on vt100
  857. }
  858. if( wAttributes & FOREGROUND_INTENSITY )
  859. {
  860. if( !fBold )
  861. {
  862. _snprintf(szSGRStr, (sizeof(szSGRStr) - 1), "%c[%dm", 27, 1 ); //Bold
  863. SendString( szSGRStr );
  864. fBold = true;
  865. }
  866. }
  867. else
  868. {
  869. if( fBold )
  870. {
  871. _snprintf(szSGRStr, (sizeof(szSGRStr) - 1), "%c[%dm", 27, 22 ); //Bold off
  872. SendString( szSGRStr );
  873. fBold = false;
  874. }
  875. }
  876. WORD wColor = 0;
  877. if( wAttributes & FOREGROUND_BLUE )
  878. {
  879. wColor = ( WORD )( wColor | 0x0004 );
  880. }
  881. if( wAttributes & FOREGROUND_GREEN )
  882. {
  883. wColor = ( WORD )( wColor | 0x0002 );
  884. }
  885. if( wAttributes & FOREGROUND_RED )
  886. {
  887. wColor = ( WORD )( wColor | 0x0001 );
  888. }
  889. wColor += 30; //Base value for foreground colors
  890. _snprintf(szSGRStr, (sizeof(szSGRStr) - 1), "%c[%dm", 27, wColor );
  891. SendString( szSGRStr );
  892. //WORD wColor = 0;
  893. wColor = 0;
  894. if( wAttributes & BACKGROUND_BLUE )
  895. {
  896. wColor = ( WORD )( wColor | 0x0004 );
  897. }
  898. if( wAttributes & BACKGROUND_GREEN )
  899. {
  900. wColor = ( WORD )( wColor | 0x0002 );
  901. }
  902. if( wAttributes & BACKGROUND_RED )
  903. {
  904. wColor = ( WORD )( wColor | 0x0001 );
  905. }
  906. wColor += 40; //Base value for Background colors
  907. _snprintf(szSGRStr, (sizeof(szSGRStr) - 1), "%c[%dm", 27, wColor );
  908. SendString( szSGRStr );
  909. }
  910. #define COMPARE_ROWS(currentRow, lastSeenRow, result) \
  911. for(i = 0; i < wCols; ++i ) \
  912. { \
  913. if( pCurrent[ ( currentRow ) * wCols + i].Char.AsciiChar != \
  914. pLastSeen[ ( lastSeenRow ) * wCols + i].Char.AsciiChar ) \
  915. {\
  916. (result) = 0; \
  917. break;\
  918. } \
  919. if( ( wDefaultAttributes != pCurrent[ ( currentRow ) * wCols + i]. \
  920. Attributes ) && \
  921. ( pCurrent[ ( currentRow ) * wCols + i].Attributes != \
  922. pLastSeen[ ( lastSeenRow ) * wCols + i].Attributes ) ) \
  923. { \
  924. (result) = 0; \
  925. break; \
  926. } \
  927. }
  928. #define GET_DEFAULT_COLOR \
  929. if( wDefaultAttributes == 0 ) \
  930. { \
  931. wDefaultAttributes = pCurrent[ 0 ].Attributes; \
  932. wExistingAttributes = pCurrent[ 0 ].Attributes; \
  933. }
  934. //row, column are over the wire should be w.r.t screen.
  935. //So, +1 for both row, column
  936. #define POSITION_CURSOR( row, column ) \
  937. { \
  938. LPSTR lpszCMStr3 = pTermCap->CursorMove( lpszCMStr2, \
  939. ( WORD ) ( ( row ) + 1 ), \
  940. ( WORD ) ( ( column ) + 1 ) ); \
  941. SendString( lpszCMStr3 ); \
  942. delete [] lpszCMStr3; \
  943. }
  944. #define SEND_ROW( row, begin, end ) \
  945. for(LONG c = ( begin ); c < ( end ); ++c ) \
  946. { \
  947. if( wExistingAttributes != pCurrent[( row ) * wCols + c].Attributes ) \
  948. { \
  949. wExistingAttributes = pCurrent[ ( row ) * wCols + c].Attributes; \
  950. wDefaultAttributes = ( WORD )~0; \
  951. SendColorInfo( wExistingAttributes ); \
  952. } \
  953. SendChar( pCurrent[ ( row ) * wCols + c].Char.AsciiChar ); \
  954. }
  955. #define IS_BLANK( row, col ) \
  956. ( pCurrent[ ( row ) * wCols + ( col ) ].Char.AsciiChar == ' ' )
  957. #define IS_DIFFERENT_COLOR( row, col, attribs ) \
  958. ( pCurrent[ ( row ) * wCols + ( col ) ].Attributes != ( attribs ) )
  959. #define IS_CHANGE_IN_COLOR( row, col ) \
  960. ( pCurrent[ ( row ) * wCols + ( col ) ].Attributes != \
  961. pLastSeen[ ( row ) * wCols + ( col ) ].Attributes )
  962. #define IS_CHANGE_IN_CHAR( row, col ) \
  963. ( pCurrent[ ( row ) * wCols + ( col ) ].Char.AsciiChar != \
  964. pLastSeen[ ( row ) * wCols + ( col )].Char.AsciiChar )
  965. bool
  966. CScraper::CompareAndUpdateVT100( WORD wRows, WORD wCols, PCHAR_INFO pCurrent,
  967. PCHAR_INFO pLastSeen,
  968. PCONSOLE_SCREEN_BUFFER_INFO pCSBI,
  969. PCONSOLE_SCREEN_BUFFER_INFO pLastCSBI,
  970. bool *pfDifferenceFound )
  971. {
  972. _TRACE( TRACE_DEBUGGING, "CompareAndUpdateVT100()" );
  973. INT i;
  974. WORD wRow, wCol;
  975. INT iStartCol,iEndCol;
  976. bool fBlankLine;
  977. COORD coordDest;
  978. COORD coordOrigin;
  979. SMALL_RECT srSource;
  980. coordDest.X = wCols;
  981. coordDest.Y = wRows;
  982. coordOrigin.X = 0;
  983. coordOrigin.Y = 0;
  984. srSource.Left = 0;
  985. srSource.Top = 0;
  986. srSource.Right = ( WORD ) ( wCols - 1 );
  987. srSource.Bottom = ( WORD ) ( wRows - 1 );
  988. _chASSERT( pfDifferenceFound )
  989. *pfDifferenceFound = false;
  990. _chVERIFY2( m_hConBufOut = CreateFile( TEXT("CONOUT$"), GENERIC_READ |
  991. GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  992. FILE_ATTRIBUTE_NORMAL, 0 ) );
  993. if( INVALID_HANDLE_VALUE == m_hConBufOut)
  994. {
  995. //Could be an application that does not share its screen buffer
  996. return ( TRUE );
  997. }
  998. BOOL dwStatus = 0;
  999. _chVERIFY2( dwStatus = ReadConsoleOutputA( m_hConBufOut, pCurrent, coordDest,
  1000. coordOrigin, &srSource ) );
  1001. if( !dwStatus )
  1002. {
  1003. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1004. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1005. return ( FALSE );
  1006. }
  1007. // Read the current cursor position
  1008. _chVERIFY2( dwStatus = GetConsoleScreenBufferInfo( m_hConBufOut, pCSBI ) );
  1009. if( !dwStatus )
  1010. {
  1011. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1012. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1013. return ( FALSE );
  1014. }
  1015. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1016. GET_DEFAULT_COLOR;
  1017. //Check if the text was scrolled
  1018. LONG currentBuffBottom, lastSeenBuffBottom, currentBuffTop, lastSeenBuffTop;
  1019. LONG lastRow, currentRow;
  1020. bool checkRestOfBuffer;
  1021. bool isScrolled = 0;
  1022. currentBuffBottom = lastSeenBuffBottom = wRows - 1;
  1023. currentBuffTop = lastSeenBuffTop = 0;
  1024. //The following check is to prevent scrolling when the user hasn't pressed
  1025. //ENTER. This case is reproduced by typing the same command (for eg: dir in
  1026. //a directory with not too many files) many times until the screen is filled
  1027. //and then type one char extra or less for that command (For "dir", it is
  1028. //"di" or "dir /" ) then the screen scrolls
  1029. //The solution is to see if the only change since the last scraping is
  1030. //only one key stroke( one byte ), if so don't scroll.
  1031. //This may lead to the case that it may scroll when you press up arrow key
  1032. //( 3 bytes ).
  1033. //Note: This is may lead to scrolling when you press a single
  1034. //key stroke on a japanese machine. Multi byte chars etc.
  1035. if( !m_bCheckForScrolling )
  1036. {
  1037. isScrolled = 1;
  1038. }
  1039. m_bCheckForScrolling = 1;
  1040. //
  1041. //When scrolling occurs because of coincidental matching of blank lines at
  1042. //the bottom of the text in the cmd, it creates problems when clearing the
  1043. //screen. repro steps: goto last but one line in the client window.
  1044. //change directory. now list files. try clearing screen.
  1045. if( !( ( pLastCSBI->dwCursorPosition.Y == pCSBI->dwCursorPosition.Y ) &&
  1046. ( pCSBI->dwCursorPosition.Y == pCSBI->srWindow.Bottom ) ) )
  1047. {
  1048. isScrolled = 1; //just to skip the following loop
  1049. }
  1050. while( currentBuffBottom >= currentBuffTop && !isScrolled )
  1051. {
  1052. checkRestOfBuffer = 1;
  1053. COMPARE_ROWS(currentBuffBottom, lastSeenBuffBottom, checkRestOfBuffer );
  1054. if ( checkRestOfBuffer )
  1055. {
  1056. isScrolled = 1;
  1057. if( currentBuffBottom > 0 )
  1058. {
  1059. //need not compare the same line again. Decrement by one.
  1060. currentRow = currentBuffBottom - 1;
  1061. lastRow = lastSeenBuffBottom - 1;
  1062. while( currentRow >= currentBuffTop && isScrolled )
  1063. {
  1064. COMPARE_ROWS(currentRow, lastRow, isScrolled );
  1065. currentRow--;
  1066. lastRow--;
  1067. }
  1068. }
  1069. }
  1070. currentBuffBottom--;
  1071. }
  1072. currentBuffBottom++;
  1073. //Patch to make this work for ONE blank line at the top
  1074. //Without this patch, screen scrolls for each char typed after "cls"
  1075. if( currentBuffBottom == currentBuffTop )
  1076. {
  1077. //check if it is a blank line. Then it is not scrolling.
  1078. for(i = 0; i < wCols; ++i )
  1079. {
  1080. if( !IS_BLANK( currentBuffTop , i ) )
  1081. {
  1082. break;
  1083. }
  1084. isScrolled = 0;
  1085. }
  1086. }
  1087. //if it is the same screen
  1088. if( currentBuffBottom + 1 >= wRows )
  1089. {
  1090. isScrolled = 0;
  1091. }
  1092. if( isScrolled )
  1093. {
  1094. //Now Send all the lines from currentBuffBottom
  1095. //till the end of the buffer
  1096. *pfDifferenceFound = true;
  1097. _TRACE( TRACE_DEBUGGING, "About to send from:%d till:%d",
  1098. currentBuffBottom + 1, wRows);
  1099. WORD lastChar = wCols;
  1100. for(LONG r = currentBuffBottom + 1; r < wRows ; r++)
  1101. {
  1102. SendChar( 0x0D );
  1103. SendChar( 0x0A );
  1104. lastChar = wCols;
  1105. while( lastChar > 0 && IS_BLANK( r, lastChar - 1 ) &&
  1106. !IS_DIFFERENT_COLOR( r, lastChar - 1, wExistingAttributes ) )
  1107. {
  1108. lastChar--;
  1109. }
  1110. SEND_ROW( r, 0, lastChar );
  1111. if( lastChar < wCols )
  1112. {
  1113. SendString( lpszCMStr1 );
  1114. }
  1115. }
  1116. //
  1117. //Do line by line scraping only if it was not scrolling
  1118. goto next;
  1119. }
  1120. _TRACE( TRACE_DEBUGGING, "NO scrolling");
  1121. // Search both the two-dimensional arrays for differences.
  1122. wRow = wCol = 0;
  1123. while( wRow < wRows )
  1124. {
  1125. if( memcmp( &pCurrent[wRow * wCols], &pLastSeen[wRow * wCols],
  1126. wCols * sizeof( CHAR_INFO ) ) != 0 )
  1127. {
  1128. // _TRACE( TRACE_DEBUGGING, "difference found in row %d\n", wRow );
  1129. *pfDifferenceFound = true;
  1130. iStartCol = -1;
  1131. iEndCol = -1;
  1132. fBlankLine = true;
  1133. for(i = 0 ; i < wCols; ++i )
  1134. {
  1135. if( IS_DIFFERENT_COLOR( wRow, i, wDefaultAttributes ) &&
  1136. IS_CHANGE_IN_COLOR( wRow, i ) )
  1137. {
  1138. if( iStartCol == -1 )
  1139. {
  1140. iStartCol = i;
  1141. }
  1142. iEndCol = i;
  1143. fBlankLine = false;
  1144. }
  1145. if( IS_CHANGE_IN_CHAR( wRow, i ) )
  1146. {
  1147. if( iStartCol == -1 )
  1148. {
  1149. iStartCol = i;
  1150. }
  1151. iEndCol = i;
  1152. }
  1153. if( fBlankLine && !IS_BLANK( wRow, i ) )
  1154. {
  1155. fBlankLine = false;
  1156. }
  1157. }
  1158. if( fBlankLine )
  1159. {
  1160. POSITION_CURSOR( wRow, 0 );
  1161. SendString( lpszCMStr1 );
  1162. coExpectedCursor.Y = wRow;
  1163. coExpectedCursor.X = 0;
  1164. }
  1165. else if( iStartCol != -1 )
  1166. {
  1167. if( wRow != coExpectedCursor.Y || iStartCol != coExpectedCursor.X )
  1168. {
  1169. POSITION_CURSOR( wRow, iStartCol );
  1170. coExpectedCursor.X = ( SHORT )iStartCol;
  1171. coExpectedCursor.Y = wRow;
  1172. }
  1173. SEND_ROW( wRow, iStartCol, iEndCol+1 );
  1174. coExpectedCursor.X = ( SHORT ) ( coExpectedCursor.X +
  1175. iEndCol - iStartCol + 1 );
  1176. }
  1177. }
  1178. ++wRow;
  1179. }
  1180. next :
  1181. if( ( pCSBI->dwCursorPosition.X != coExpectedCursor.X ||
  1182. pCSBI->dwCursorPosition.Y != coExpectedCursor.Y ) &&
  1183. ( memcmp( &pCSBI->dwCursorPosition, &pLastCSBI->dwCursorPosition,
  1184. sizeof( COORD ) ) != 0 || g_pucSendInsertPoint != g_pucSendBuffer ) )
  1185. {
  1186. POSITION_CURSOR( pCSBI->dwCursorPosition.Y,
  1187. pCSBI->dwCursorPosition.X );
  1188. *pfDifferenceFound = true;
  1189. coExpectedCursor.X = pCSBI->dwCursorPosition.X;
  1190. coExpectedCursor.Y = pCSBI->dwCursorPosition.Y;
  1191. }
  1192. if( *pfDifferenceFound )
  1193. {
  1194. _TRACE( TRACE_DEBUGGING, "difference found: %d \n", m_dwPollInterval );
  1195. // Copy pCurrent onto pLastSeen
  1196. memcpy( pLastSeen, pCurrent, wCols * wRows * sizeof( CHAR_INFO ) );
  1197. memcpy( pLastCSBI, pCSBI, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
  1198. if( !Transmit( ) )
  1199. {
  1200. return( FALSE );
  1201. }
  1202. }
  1203. else
  1204. {
  1205. _TRACE( TRACE_DEBUGGING, "NO difference found: %d \n", m_dwPollInterval );
  1206. }
  1207. return( TRUE );
  1208. }
  1209. bool
  1210. CScraper::CompareAndUpdateVT80( WORD wRows, WORD wCols,
  1211. PCHAR_INFO pCurrent, PCHAR_INFO pLastSeen,
  1212. PCONSOLE_SCREEN_BUFFER_INFO pCSBI,
  1213. PCONSOLE_SCREEN_BUFFER_INFO pLastCSBI,
  1214. bool *pfDifferenceFound )
  1215. {
  1216. _TRACE( TRACE_DEBUGGING, "CompareAndUpdateVT80()" );
  1217. WORD i, j;
  1218. WORD wRow, wCol;
  1219. SHORT iStartCol,iEndCol;
  1220. bool fBlankLine;
  1221. bool fMatching;
  1222. COORD coordDest;
  1223. COORD coordOrigin;
  1224. SMALL_RECT srSource;
  1225. *pfDifferenceFound = false;
  1226. coordDest.X = wCols;
  1227. coordDest.Y = wRows;
  1228. coordOrigin.X = 0;
  1229. coordOrigin.Y = 0;
  1230. srSource.Left = 0;
  1231. srSource.Top = 0;
  1232. srSource.Right = ( WORD )( wCols - 1 );
  1233. srSource.Bottom = ( WORD )( wRows - 1 );
  1234. _chVERIFY2( m_hConBufOut = CreateFile( TEXT("CONOUT$"), GENERIC_READ |
  1235. GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  1236. FILE_ATTRIBUTE_NORMAL, 0 ) );
  1237. if( INVALID_HANDLE_VALUE == m_hConBufOut)
  1238. {
  1239. //Could be an application that does not share its screen buffer
  1240. return ( TRUE );
  1241. }
  1242. BOOL dwStatus = 0;
  1243. _chVERIFY2( dwStatus = ReadConsoleOutput( m_hConBufOut, pCurrent, coordDest,
  1244. coordOrigin, &srSource ) );
  1245. if( !dwStatus )
  1246. {
  1247. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1248. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1249. return ( FALSE );
  1250. }
  1251. // Read the current cursor position
  1252. _chVERIFY2( dwStatus = GetConsoleScreenBufferInfo( m_hConBufOut, pCSBI ) );
  1253. if( !dwStatus )
  1254. {
  1255. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1256. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1257. return ( FALSE );
  1258. }
  1259. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1260. // Search both the two-dimensional arrays for differences.
  1261. fMatching = true;
  1262. wRow = wCol = 0;
  1263. bool bCurrentClippedLeadByte = false, bLastSeenClippedLeadByte = false;
  1264. while( wRow < wRows )
  1265. {
  1266. if( memcmp( &pCurrent[wRow * wCols], &pLastSeen[wRow * wCols],
  1267. wCols * sizeof( CHAR_INFO ) ) != 0 )
  1268. {
  1269. _TRACE( TRACE_DEBUGGING, "difference found in row %d\n", wRow );
  1270. *pfDifferenceFound = true;
  1271. iStartCol = -1;
  1272. iEndCol = -1;
  1273. fBlankLine = true;
  1274. for( i = 0, j = 0; (i < wCols) && (j < wCols); NULL )
  1275. {
  1276. if( (i == 0) && bCurrentClippedLeadByte )
  1277. {
  1278. ++i;
  1279. bCurrentClippedLeadByte = false;
  1280. continue;
  1281. }
  1282. if( (j==0) && bLastSeenClippedLeadByte )
  1283. {
  1284. ++j;
  1285. bLastSeenClippedLeadByte = false;
  1286. continue;
  1287. }
  1288. if( pCurrent[wRow * wCols + i].Char.UnicodeChar !=
  1289. pLastSeen[wRow * wCols + j].Char.UnicodeChar )
  1290. {
  1291. if( iStartCol == -1 )
  1292. {
  1293. iStartCol = i;
  1294. }
  1295. iEndCol = i;
  1296. }
  1297. if( (pCurrent[wRow * wCols + i].Char.UnicodeChar != L' ') )
  1298. {
  1299. fBlankLine = false;
  1300. }
  1301. if( pCurrent[wRow * wCols + i].Attributes & COMMON_LVB_LEADING_BYTE )
  1302. {
  1303. i += 2;
  1304. }
  1305. else
  1306. {
  1307. ++i;
  1308. }
  1309. if( pLastSeen[wRow * wCols + j].Attributes & COMMON_LVB_LEADING_BYTE )
  1310. {
  1311. j += 2;
  1312. }
  1313. else
  1314. {
  1315. ++j;
  1316. }
  1317. if( (j >= wCols) && (i < wCols) )
  1318. {
  1319. (i == wCols) ? (i = ( WORD ) (wCols-1)) : NULL;
  1320. if( iStartCol == -1 )
  1321. {
  1322. iStartCol = i;
  1323. }
  1324. iEndCol = ( WORD ) ( wCols - 1 );
  1325. break;
  1326. }
  1327. }
  1328. if( pCurrent[wRow * wCols + (wCols - 1)].Attributes & COMMON_LVB_LEADING_BYTE )
  1329. {
  1330. bCurrentClippedLeadByte = true;
  1331. }
  1332. if( pLastSeen[wRow * wCols + (wCols - 1)].Attributes & COMMON_LVB_LEADING_BYTE )
  1333. {
  1334. bLastSeenClippedLeadByte = true;
  1335. }
  1336. if( fBlankLine )
  1337. {
  1338. LPSTR lpszCMStr3 = pTermCap->CursorMove( lpszCMStr2,
  1339. ( WORD )( wRow + 1 ), 1 );
  1340. SendString( lpszCMStr3 );
  1341. delete [] lpszCMStr3;
  1342. SendString( lpszCMStr1 );
  1343. }
  1344. else
  1345. {
  1346. if( iStartCol != -1 )
  1347. {
  1348. LPSTR lpszCMStr3 = pTermCap->CursorMove( lpszCMStr2,
  1349. ( WORD ) ( wRow + 1 ) ,
  1350. ( WORD ) ( iStartCol + 1 ) );
  1351. SendString( lpszCMStr3 );
  1352. delete [] lpszCMStr3;
  1353. for( wCol = iStartCol; wCol <= iEndCol; ++wCol )
  1354. {
  1355. CHAR mbCurrent[5];
  1356. int ret, xy;
  1357. WCHAR wcBuf[2];
  1358. wcBuf[0] = pCurrent[wRow * wCols + wCol].Char.UnicodeChar;
  1359. wcBuf[1] = L'\0';
  1360. ret = WideCharToMultiByte( CP_ACP, 0, wcBuf, -1, mbCurrent, 4, NULL, NULL );
  1361. if( (ret != 0) )
  1362. {
  1363. //if( pCurrent[ wRow * wCols + wCol].Char.AsciiChar > 31 )
  1364. //SendChar( pCurrent[wRow * wCols + wCol].Char.AsciiChar );
  1365. for( xy=0; xy < ret; ++xy)
  1366. {
  1367. SendChar( mbCurrent[xy] );
  1368. }
  1369. }
  1370. if( pCurrent[wRow * wCols + wCol].Attributes & COMMON_LVB_LEADING_BYTE )
  1371. {
  1372. ++wCol;
  1373. }
  1374. }
  1375. }
  1376. }
  1377. }
  1378. ++wRow;
  1379. }
  1380. if( memcmp( &pCSBI->dwCursorPosition, &pLastCSBI->dwCursorPosition,
  1381. sizeof( COORD ) ) != 0 || g_pucSendInsertPoint != g_pucSendBuffer )
  1382. {
  1383. LPSTR lpszCMStr3 = pTermCap->CursorMove( lpszCMStr2,
  1384. ( WORD ) ( pCSBI->dwCursorPosition.Y + 1 ),
  1385. ( WORD ) ( pCSBI->dwCursorPosition.X + 1 ));
  1386. SendString( lpszCMStr3 );
  1387. delete [] lpszCMStr3;
  1388. *pfDifferenceFound = true;
  1389. }
  1390. if( *pfDifferenceFound )
  1391. {
  1392. // Copy pCurrent onto pLastSeen
  1393. memcpy( pLastSeen, pCurrent, wCols * wRows * sizeof( CHAR_INFO ) );
  1394. memcpy( pLastCSBI, pCSBI, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
  1395. if( !Transmit( ) )
  1396. {
  1397. return( FALSE );
  1398. }
  1399. }
  1400. else
  1401. {
  1402. _TRACE( TRACE_DEBUGGING, "NO difference found\n" );
  1403. }
  1404. return( TRUE );
  1405. }
  1406. bool
  1407. CScraper::GetRegistryValues( void )
  1408. {
  1409. HKEY hk;
  1410. bool success;
  1411. DWORD dwDisp = 0;
  1412. if ( TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
  1413. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0) )
  1414. {
  1415. LogEvent( EVENTLOG_ERROR_TYPE, MSG_REGISTRYKEY, REG_PARAMS_KEY );
  1416. return( FALSE );
  1417. }
  1418. HKEY hk1;
  1419. LPTSTR lpszTelnetInstallPath = NULL;
  1420. if( !TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_SERVICE_KEY, NULL, NULL,
  1421. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk1, &dwDisp, 0 ) )
  1422. {
  1423. success = GetRegistryString( hk1, NULL, L"ImagePath", &lpszTelnetInstallPath,
  1424. L"",FALSE );
  1425. RegCloseKey( hk1 );
  1426. if (! success)
  1427. {
  1428. RegCloseKey(hk);
  1429. return( FALSE );
  1430. }
  1431. }
  1432. else
  1433. {
  1434. RegCloseKey(hk);
  1435. LogEvent( EVENTLOG_ERROR_TYPE, MSG_REGISTRYKEY, REG_SERVICE_KEY );
  1436. return (FALSE);
  1437. }
  1438. WCHAR *pLastBackSlash = wcsrchr( lpszTelnetInstallPath, L'\\' );
  1439. if( pLastBackSlash != NULL )
  1440. {
  1441. *pLastBackSlash = 0;
  1442. }
  1443. LPWSTR lpszDefaultTermcapFullPathName =
  1444. new WCHAR[ ( wcslen( lpszTelnetInstallPath ) +
  1445. wcslen( DEFAULT_TERMCAP ) + 2 ) ];
  1446. if( !lpszDefaultTermcapFullPathName )
  1447. {
  1448. RegCloseKey(hk);
  1449. return( FALSE );
  1450. }
  1451. wcscpy( lpszDefaultTermcapFullPathName, lpszTelnetInstallPath );
  1452. wcscat( lpszDefaultTermcapFullPathName, L"\\" );
  1453. wcscat( lpszDefaultTermcapFullPathName, DEFAULT_TERMCAP );
  1454. LPWSTR pszFileName;
  1455. success = GetRegistryString( hk, NULL, L"Termcap", &pszFileName,
  1456. lpszDefaultTermcapFullPathName,FALSE );
  1457. RegCloseKey(hk);
  1458. if (! success)
  1459. {
  1460. return( FALSE );
  1461. }
  1462. WCHAR szCmdBuf[ONE_KB];
  1463. ExpandEnvironmentStrings( pszFileName, szCmdBuf, (sizeof(szCmdBuf)/sizeof(szCmdBuf[0])) );
  1464. delete [] lpszDefaultTermcapFullPathName;
  1465. delete [] lpszTelnetInstallPath;
  1466. delete [] pszFileName;
  1467. CTermCap::m_pszFileName = new CHAR[ wcslen(szCmdBuf) +1];
  1468. if( !CTermCap::m_pszFileName )
  1469. {
  1470. return( FALSE );
  1471. }
  1472. _snprintf( CTermCap::m_pszFileName, ONE_KB -1 ,"%lS", szCmdBuf ); // No attack, we allocate the necesary buffer here - Baskar.
  1473. return ( TRUE );
  1474. }
  1475. bool
  1476. CScraper::CompareAndUpdateVTNT ( WORD wRows, WORD wCols, PCHAR_INFO pCurrent,
  1477. PCHAR_INFO pLastSeen,
  1478. PCONSOLE_SCREEN_BUFFER_INFO pCSBI,
  1479. PCONSOLE_SCREEN_BUFFER_INFO pLastCSBI,
  1480. bool *pfDifferenceFound )
  1481. {
  1482. _TRACE( TRACE_DEBUGGING, "CompareAndUpdateVTNT()" );
  1483. INT result;
  1484. COORD coordDest;
  1485. COORD coSize;
  1486. SMALL_RECT srSource;
  1487. *pfDifferenceFound = false;
  1488. coordDest.X = wCols;
  1489. coordDest.Y = wRows;
  1490. coSize.X = 0;
  1491. coSize.Y = 0;
  1492. srSource.Left = 0;
  1493. srSource.Top = 0;
  1494. srSource.Right = ( WORD ) ( wCols - 1 );
  1495. srSource.Bottom = ( WORD ) ( wRows - 1 );
  1496. SHORT loop1;
  1497. SHORT loop2;
  1498. DWORD dwLineSize;
  1499. LPSTR lpCurrentWindow;
  1500. LPSTR lpLastSeenWindow;
  1501. LPSTR lpCurrentFirstLine;
  1502. LPSTR lpLastSeenFirstLine;
  1503. _chVERIFY2( m_hConBufOut = CreateFile( TEXT("CONOUT$"), GENERIC_READ |
  1504. GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1505. FILE_ATTRIBUTE_NORMAL, 0 ) );
  1506. if( INVALID_HANDLE_VALUE == m_hConBufOut)
  1507. {
  1508. //Could be an application that does not share its screen buffer
  1509. return ( TRUE );
  1510. }
  1511. BOOL dwStatus = 0;
  1512. _chVERIFY2( dwStatus = ReadConsoleOutput( m_hConBufOut, pCurrent, coordDest,
  1513. coSize, &srSource ) );
  1514. if( !dwStatus )
  1515. {
  1516. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1517. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1518. return ( FALSE );
  1519. }
  1520. _chVERIFY2( dwStatus = GetConsoleScreenBufferInfo( m_hConBufOut, pCSBI ) );
  1521. if( !dwStatus )
  1522. {
  1523. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READ_CONSOLE, GetLastError() );
  1524. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1525. return ( FALSE );
  1526. }
  1527. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1528. dwLineSize = wCols * sizeof( CHAR_INFO ) ;
  1529. //VERSION2 : to optimize we can compare the whole window
  1530. //and if no change, return
  1531. LONG currentBuffBottom, lastSeenBuffBottom, currentBuffTop, lastSeenBuffTop;
  1532. LONG lastRow, currentRow;
  1533. bool checkRestOfBuffer;
  1534. bool isScrolled = 0;
  1535. int i = 0;
  1536. currentBuffBottom = lastSeenBuffBottom = wRows - 1;
  1537. currentBuffTop = lastSeenBuffTop = 0;
  1538. //The following check is to prevent scrolling when the user hasn't pressed
  1539. //ENTER. This case is reproduced by typing the same command (for eg: dir in
  1540. //a directory with not too many files) many times until the screen is filled
  1541. //and then type one char extra or less for that command (For "dir", it is
  1542. //"di" or "dir /" ) then the screen scrolls
  1543. //The solution is to see if the only change since the last scraping is
  1544. //only one key stroke( one byte ), if so don't scroll.
  1545. //This may lead to the case that it may scroll when you press up arrow key
  1546. //( 3 bytes ).
  1547. if( !m_bCheckForScrolling )
  1548. {
  1549. isScrolled = 1;
  1550. }
  1551. m_bCheckForScrolling = 1;
  1552. if( !m_pSession->CSession::m_bIsTelnetVersion2 )
  1553. {
  1554. //This will make it a non scrolling case.
  1555. isScrolled = 1;
  1556. }
  1557. while( currentBuffBottom >= currentBuffTop && !isScrolled )
  1558. {
  1559. checkRestOfBuffer = 1;
  1560. lpCurrentWindow = ( LPSTR ) ( pCurrent + wCols * currentBuffBottom ) ;
  1561. lpLastSeenWindow = ( LPSTR ) ( pLastSeen + wCols * lastSeenBuffBottom ) ;
  1562. if( memcmp( lpCurrentWindow, lpLastSeenWindow, dwLineSize ) != 0 )
  1563. {
  1564. checkRestOfBuffer = 0;
  1565. }
  1566. if ( checkRestOfBuffer )
  1567. {
  1568. isScrolled = 1;
  1569. if( currentBuffBottom > 0 )
  1570. {
  1571. //need not compare the same line again. Decrement by one.
  1572. currentRow = currentBuffBottom - 1;
  1573. lastRow = lastSeenBuffBottom - 1;
  1574. while( currentRow >= currentBuffTop && isScrolled )
  1575. {
  1576. lpCurrentWindow = ( LPSTR ) ( pCurrent + wCols * currentRow ) ;
  1577. lpLastSeenWindow = ( LPSTR ) ( pLastSeen + wCols * lastRow ) ;
  1578. if( memcmp( lpCurrentWindow, lpLastSeenWindow, dwLineSize ) != 0 )
  1579. {
  1580. isScrolled = 0;
  1581. }
  1582. currentRow--;
  1583. lastRow--;
  1584. }
  1585. }
  1586. }
  1587. currentBuffBottom--;
  1588. }
  1589. currentBuffBottom++;
  1590. //Patch to make this work for ONE blank line at the top
  1591. //Without this patch, screen scrolls for each char typed after "cls"
  1592. if( currentBuffBottom == currentBuffTop )
  1593. {
  1594. //check if it is a blank line. Then it is not scrolling.
  1595. for(i = 0; i < wCols; ++i )
  1596. {
  1597. if( !IS_BLANK( currentBuffTop , i ) )
  1598. {
  1599. break;
  1600. }
  1601. isScrolled = 0;
  1602. }
  1603. }
  1604. //if it is the same screen
  1605. if( currentBuffBottom + 1 >= wRows )
  1606. {
  1607. isScrolled = 0;
  1608. }
  1609. if( isScrolled )
  1610. {
  1611. //Now Send all the lines from currentBuffBottom
  1612. //till the end of the buffer
  1613. COORD coordSaveCursorPos = {0,0};
  1614. *pfDifferenceFound = true;
  1615. _TRACE( TRACE_DEBUGGING, "About to send from:%d till:%d",
  1616. currentBuffBottom + 1, wRows);
  1617. WORD lastChar = wCols;
  1618. // Determine size of changes
  1619. coSize.X = wCols;
  1620. coSize.Y = ( SHORT ) ( ( wRows - 1 ) - currentBuffBottom );
  1621. coordSaveCursorPos.X = pCSBI->dwCursorPosition.X;
  1622. coordSaveCursorPos.Y = pCSBI->dwCursorPosition.Y;
  1623. SendVTNTData( RELATIVE_COORDS, coordSaveCursorPos, coSize,
  1624. &srSource, pCurrent + (currentBuffBottom+1) * wCols );
  1625. //
  1626. //Do line by line scraping only if it was not scrolling
  1627. goto next1;
  1628. }
  1629. _TRACE( TRACE_DEBUGGING, "NO scrolling");
  1630. // Compare all lines
  1631. lpCurrentWindow = ( LPSTR ) pCurrent;
  1632. lpLastSeenWindow = ( LPSTR ) pLastSeen;
  1633. for( loop1 = 0 ; loop1 < wRows; )
  1634. {
  1635. result = memcmp( lpCurrentWindow, lpLastSeenWindow, dwLineSize );
  1636. loop1++;
  1637. lpCurrentFirstLine = lpCurrentWindow;
  1638. lpLastSeenFirstLine = lpLastSeenWindow;
  1639. lpLastSeenWindow += dwLineSize;
  1640. lpCurrentWindow += dwLineSize;
  1641. if( !result )
  1642. continue;
  1643. *pfDifferenceFound = true;
  1644. for( loop2 = loop1 ; loop2 < wRows ; loop2++ )
  1645. {
  1646. if( !memcmp ( lpLastSeenWindow, lpCurrentWindow, dwLineSize ) )
  1647. break ;
  1648. lpLastSeenWindow += dwLineSize;
  1649. lpCurrentWindow += dwLineSize;
  1650. }
  1651. if( loop2 == wRows )
  1652. {
  1653. lpLastSeenWindow += dwLineSize ;
  1654. lpCurrentWindow += dwLineSize ;
  1655. }
  1656. // Determine size of changes
  1657. coSize.X = wCols;
  1658. coSize.Y = ( WORD ) ( loop2 - loop1 + 1 );
  1659. srSource.Left = 0;
  1660. srSource.Top = ( WORD )( 0 + loop1 - 1 );
  1661. srSource.Right = ( WORD )( wCols - 1 );
  1662. srSource.Bottom = ( WORD ) ( srSource.Top + coSize.Y - 1 );
  1663. _TRACE( TRACE_DEBUGGING, "Scrape rom row %d to row %d", loop1, loop2 );
  1664. if( !SendVTNTData( ABSOLUTE_COORDS, pCSBI->dwCursorPosition, coSize,
  1665. &srSource, ( PCHAR_INFO ) lpCurrentFirstLine ) )
  1666. {
  1667. return( FALSE );
  1668. }
  1669. loop1 = loop2 ;
  1670. }
  1671. next1:
  1672. if( !( *pfDifferenceFound ) )
  1673. {
  1674. if( memcmp( &pCSBI->dwCursorPosition, &pLastCSBI->dwCursorPosition,
  1675. sizeof( COORD ) ) != 0 )
  1676. {
  1677. *pfDifferenceFound = true;
  1678. //sending no data; only pCSBI->dwCursorPosition are valid
  1679. //(useful)
  1680. coSize.X = coSize.Y = 0;
  1681. srSource.Top = srSource.Bottom = srSource.Left = srSource.Right = 0;
  1682. if( !SendVTNTData( ABSOLUTE_COORDS, pCSBI->dwCursorPosition, coSize,
  1683. &srSource, NULL ) )
  1684. {
  1685. return( FALSE );
  1686. }
  1687. }
  1688. }
  1689. if( *pfDifferenceFound )
  1690. {
  1691. if( !Transmit() )
  1692. {
  1693. return( FALSE );
  1694. }
  1695. // Copy pCurrent onto pLastSeen
  1696. memcpy( pLastSeen, pCurrent, wCols * wRows * sizeof( CHAR_INFO ) );
  1697. memcpy( pLastCSBI, pCSBI, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
  1698. }
  1699. else
  1700. {
  1701. _TRACE( TRACE_DEBUGGING, "NO difference found\n" );
  1702. }
  1703. return( TRUE );
  1704. }
  1705. bool
  1706. CScraper::SendVTNTData( WORD wCoordType,
  1707. COORD coCursor, COORD coRegionSize,
  1708. SMALL_RECT* lpScreenRegion, CHAR_INFO* lpScreenRegionCharInfo )
  1709. {
  1710. bool bRetVal = TRUE;
  1711. VTNT_CHAR_INFO pOutCharInfo;
  1712. DWORD dwSize = sizeof( VTNT_CHAR_INFO ) +
  1713. ( coRegionSize.X * coRegionSize.Y * sizeof( CHAR_INFO ) );
  1714. SfuZeroMemory(&pOutCharInfo,sizeof(VTNT_CHAR_INFO));
  1715. //csbi.wAttributes is filled by v2 server with following meaning
  1716. //When a scrolling case is detected, this is set to 1.
  1717. pOutCharInfo.csbi.wAttributes = wCoordType;
  1718. pOutCharInfo.coDest.X = 0;
  1719. pOutCharInfo.coDest.Y = 0;
  1720. pOutCharInfo.coCursorPos = coCursor;
  1721. pOutCharInfo.coSizeOfData = coRegionSize;
  1722. pOutCharInfo.srDestRegion = *lpScreenRegion;
  1723. SendBytes( ( PUCHAR ) &pOutCharInfo, sizeof( VTNT_CHAR_INFO ) );
  1724. SendBytes( ( PUCHAR ) lpScreenRegionCharInfo, dwSize - sizeof( VTNT_CHAR_INFO) );
  1725. return( bRetVal );
  1726. }
  1727. void
  1728. CScraper::WriteMessageToCmd( WCHAR szMsg[] )
  1729. {
  1730. DWORD dwWritten = 0;
  1731. if( m_pSession->CIoHandler::m_SocketControlState == m_pSession->CIoHandler::STATE_SESSION )
  1732. {
  1733. _chVERIFY2( m_hConBufOut = CreateFile( TEXT("CONOUT$"), GENERIC_READ |
  1734. GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1735. FILE_ATTRIBUTE_NORMAL, 0 ) );
  1736. if( INVALID_HANDLE_VALUE == m_hConBufOut)
  1737. {
  1738. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERRCONSOLE, GetLastError() );
  1739. return;
  1740. }
  1741. _chVERIFY2( WriteConsole( m_hConBufOut, szMsg, wcslen( szMsg ), &dwWritten, NULL ) );
  1742. TELNET_CLOSE_HANDLE( m_hConBufOut );
  1743. }
  1744. return;
  1745. }