Source code of Windows XP (NT5)
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.

2366 lines
78 KiB

  1. //Copyright (c) Microsoft Corporation. All rights reserved.
  2. /****************************************************************************
  3. PROGRAM: WinTel.c
  4. PURPOSE: WinTel template for Windows applications
  5. FUNCTIONS:
  6. main() - calls initialization function, processes message loop
  7. InitApplication() - initializes window data and registers window
  8. InitInstance() - saves instance handle and creates main window
  9. MainWndProc() - processes messages
  10. About() - processes messages for "About" dialog box
  11. COMMENTS:
  12. Windows can have several copies of your application running at the
  13. same time. The variable hInst keeps track of which instance this
  14. application is so that processing will be to the correct window.
  15. TABS:
  16. Set for 4 spaces.
  17. ****************************************************************************/
  18. #include <windows.h> // required for all Windows applications
  19. #include <tchar.h> // required for all Windows applications
  20. #pragma warning (disable: 4201) // disable "nonstandard extension used : nameless struct/union"
  21. #include <commdlg.h>
  22. #pragma warning (default: 4201)
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <lmcons.h>
  27. #include <winbase.h>
  28. #include "urlmon.h"
  29. #include "zone.h"
  30. #ifdef WHISTLER_BUILD
  31. #include <ntverp.h>
  32. #else
  33. #include "solarver.h"
  34. #endif
  35. #include <common.ver>
  36. #pragma warning( disable:4706 )
  37. #pragma warning(disable:4100)
  38. #include <imm.h>
  39. #include <locale.h>
  40. #include "WinTel.h" // specific to this program
  41. #include "debug.h"
  42. #include "trmio.h"
  43. #ifndef NO_PCHECK
  44. #ifndef WHISTLER_BUILD
  45. #include "piracycheck.h"
  46. #endif
  47. #endif
  48. #include "commands.h"
  49. #include "LocResMan.h"
  50. #define MAX_USAGE_LEN 1400
  51. TCHAR szUsage[MAX_USAGE_LEN];
  52. #if 0
  53. OPENFILENAME ofn;
  54. TCHAR buffer[256];
  55. #endif
  56. HANDLE g_hCaptureConsoleEvent = NULL;
  57. HINSTANCE ghInstance;
  58. WI gwi;
  59. HANDLE g_hAsyncGetHostByNameEvent = NULL;
  60. HANDLE g_hControlHandlerEvent = NULL;
  61. HANDLE g_hTelnetPromptConsoleBuffer = NULL;
  62. HANDLE g_hSessionConsoleBuffer = NULL;
  63. /* This event synchronizes the output to g_hTelnetPromptConsoleBuffer
  64. and g_hSessionConsoleBuffer. It prevents session data coming at the prompt
  65. and viceversa - BUG 2176*/
  66. HANDLE g_hRemoteNEscapeModeDataSync = NULL;
  67. TCHAR g_szKbdEscape[ SMALL_STRING + 1 ];
  68. BOOL g_bIsEscapeCharValid = TRUE;
  69. DWORD HandleTelnetSession(WI *pwi);
  70. BOOL StuffEscapeIACs( PUCHAR* ppBufDest, UCHAR bufSrc[], DWORD* pdwSize );
  71. BOOL fPrintMessageToSessionConsole = FALSE;
  72. BOOL fClientLaunchedFromCommandPrompt = FALSE;
  73. BOOL g_fConnectFailed = 0;
  74. void ConvertAndSendVTNTData( LPTSTR pData, int iLen );
  75. extern BOOL bDoVtNTFirstTime;
  76. HIMC hImeContext;
  77. extern VOID SetImeWindow(TRM *ptrm);
  78. extern void WriteMessage( DWORD dwMsgId, WCHAR szEnglishString[] );
  79. DWORD CurrentKanjiSelection = 0;
  80. KANJILIST KanjiList[NUMBER_OF_KANJI] =
  81. {
  82. /* KanjiID, KanjiEmulationID, KanjiMessageID, KanjiItemID */
  83. { fdwSJISKanjiMode, dwSJISKanji, IDS_KANJI_SJIS, 0, L"\0" },
  84. { fdwJISKanjiMode, dwJISKanji, IDS_KANJI_JIS, 0, L"\0" },
  85. { fdwJIS78KanjiMode,dwJIS78Kanji, IDS_KANJI_JIS78,0, L"\0" },
  86. { fdwEUCKanjiMode, dwEUCKanji, IDS_KANJI_EUC, 0, L"\0" },
  87. { fdwNECKanjiMode, dwNECKanji, IDS_KANJI_NEC, 0, L"\0" },
  88. { fdwDECKanjiMode, dwDECKanji, IDS_KANJI_DEC, 0, L"\0" },
  89. { fdwACOSKanjiMode, dwACOSKanji, IDS_KANJI_ACOS, 0, L"\0" }
  90. };
  91. BOOL fHSCROLL = FALSE;
  92. TCHAR szVT100KanjiEmulation[SMALL_STRING + 1];
  93. #define NUM_ISO8859_CHARS 3
  94. #define NUM_WINDOWS_CP1252_CHARS 4
  95. UINT gfCodeModeFlags[1+((eCodeModeMax-1)/N_BITS_IN_UINT)];
  96. extern INT GetRequestedTermType( LPTSTR pszTerm );
  97. TCHAR szUserName[ UNLEN + 1 ];
  98. void PrintUsage()
  99. {
  100. DWORD dwWritten = 0;
  101. CHAR szStr[MAX_USAGE_LEN] = { 0 };
  102. MyWriteConsole(g_hSessionConsoleBuffer,szUsage,_tcslen(szUsage));
  103. }
  104. BOOL
  105. FileIsConsole(
  106. HANDLE fp
  107. )
  108. {
  109. unsigned htype;
  110. htype = GetFileType(fp);
  111. htype &= ~FILE_TYPE_REMOTE;
  112. return htype == FILE_TYPE_CHAR;
  113. }
  114. void
  115. MyWriteConsole(
  116. HANDLE fp,
  117. LPWSTR lpBuffer,
  118. DWORD cchBuffer
  119. )
  120. {
  121. //
  122. // Jump through hoops for output because:
  123. //
  124. // 1. printf() family chokes on international output (stops
  125. // printing when it hits an unrecognized character)
  126. //
  127. // 2. WriteConsole() works great on international output but
  128. // fails if the handle has been redirected (i.e., when the
  129. // output is piped to a file)
  130. //
  131. // 3. WriteFile() works great when output is piped to a file
  132. // but only knows about bytes, so Unicode characters are
  133. // printed as two Ansi characters.
  134. //
  135. if (FileIsConsole(fp))
  136. {
  137. WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
  138. }
  139. else
  140. {
  141. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
  142. if (lpAnsiBuffer != NULL)
  143. {
  144. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  145. 0,
  146. lpBuffer,
  147. cchBuffer,
  148. lpAnsiBuffer,
  149. cchBuffer * sizeof(WCHAR),
  150. NULL,
  151. NULL);
  152. if (cchBuffer != 0)
  153. {
  154. WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL);
  155. }
  156. LocalFree(lpAnsiBuffer);
  157. }
  158. }
  159. }
  160. void PromptUserForNtlmCredsTransfer()
  161. {
  162. WCHAR szMsg[MAX_PATH+1];
  163. WCHAR rgchBuffer[MAX_PATH];
  164. DWORD dwLength = 3; //including "\r\n"
  165. WCHAR szZoneName[MAX_PATH+1];
  166. DWORD dwZonePolicy = URLPOLICY_CREDENTIALS_SILENT_LOGON_OK; //anything other than anonymous
  167. ui.bSendCredsToRemoteSite = FALSE;
  168. ui.bPromptForNtlm = FALSE;
  169. wcscpy( szZoneName, L"" );//no overflow.
  170. if( !IsTrustedServer( rgchHostName, szZoneName, sizeof(szZoneName)/sizeof(WCHAR), &dwZonePolicy ) )
  171. {
  172. if( URLPOLICY_CREDENTIALS_ANONYMOUS_ONLY != dwZonePolicy )
  173. {
  174. LoadString( ghInstance, IDS_NTLM_PROMPT, szMsg, MAX_PATH);
  175. Write( szMsg, szZoneName, NULL );
  176. rgchBuffer[0] = L'N';
  177. if( !ReadConsole( gwi.hInput, rgchBuffer, dwLength, &dwLength, NULL ) )
  178. {
  179. goto PromptUserIfNtlmAbort;
  180. }
  181. if( 0 == dwLength ) //when ctrl C is pressed
  182. {
  183. rgchBuffer[0] = L'N';
  184. }
  185. if((towupper(rgchBuffer[0])) == L'Y' )
  186. {
  187. ui.bSendCredsToRemoteSite = TRUE;
  188. goto PromptUserIfNtlmAbort;
  189. }
  190. }
  191. }
  192. else
  193. {
  194. ui.bSendCredsToRemoteSite = TRUE;
  195. }
  196. PromptUserIfNtlmAbort:
  197. return;
  198. }
  199. #define MAX_TELNET_COMMANDS 9
  200. //#endif /* FE_IME */
  201. static TelnetCommand sTelnetCommands[MAX_TELNET_COMMANDS];
  202. BOOL PrintHelpStr(LPTSTR szCommand)
  203. {
  204. DWORD dwWritten;
  205. WriteConsole(gwi.hOutput, szHelp, _tcslen(szHelp), &dwWritten, NULL);
  206. return FALSE;
  207. }
  208. //This uses the global variable g_chEsc and forms a global string g_szKbdEscape
  209. void SetEscapeChar( WCHAR chEsc )
  210. {
  211. USHORT vkBracket = 0;
  212. UINT iRet = 0;
  213. WCHAR szShiftState[ MAX_STRING_LENGTH ];
  214. LPWSTR szTmpShiftState = szShiftState;
  215. SfuZeroMemory(g_szKbdEscape, sizeof(g_szKbdEscape));
  216. CheckEscCharState( &vkBracket, &iRet, chEsc, szTmpShiftState );
  217. g_chEsc = chEsc;
  218. if( 0 == iRet )
  219. {
  220. wcscpy( szShiftState, L"" );//no overflow.
  221. }
  222. //
  223. // If VirtualKey exists then map it into a character
  224. //
  225. if(LOBYTE(vkBracket) != (BYTE)-1)
  226. {
  227. //
  228. // If a key does not exist, goto default mapping
  229. //
  230. if( 0 == iRet )
  231. {
  232. chEsc = L']';
  233. g_chEsc = DEFAULT_ESCAPE_CHAR;
  234. g_EscCharShiftState = DEFAULT_SHIFT_STATE;
  235. }
  236. else
  237. {
  238. chEsc = LOBYTE( iRet );
  239. }
  240. if( isalpha( chEsc ) )
  241. {
  242. chEsc = (SHORT) tolower( chEsc );
  243. }
  244. }
  245. _sntprintf(g_szKbdEscape,SMALL_STRING, szEscapeChar, szShiftState, chEsc);
  246. }
  247. void CheckEscCharState( USHORT *ptrvkBracket, UINT *ptriRet, WCHAR chEscKey, LPWSTR szEscCharShiftState )
  248. {
  249. DWORD dwToCopy = MAX_STRING_LENGTH-1;
  250. *ptrvkBracket = VkKeyScan(chEscKey);
  251. *ptriRet = MapVirtualKey(LOBYTE(*ptrvkBracket), 2);
  252. if( *ptriRet != 0 )
  253. {
  254. g_EscCharShiftState = HIBYTE( *ptrvkBracket );
  255. }
  256. wcscpy( szEscCharShiftState, ( LPTSTR )L"" );//no overflow.
  257. if( g_EscCharShiftState & SHIFT_KEY )
  258. {
  259. _snwprintf( szEscCharShiftState,dwToCopy,( LPTSTR )L"%s", SHIFT_PLUS );
  260. szEscCharShiftState+= wcslen( szEscCharShiftState);
  261. dwToCopy -= wcslen(szEscCharShiftState);
  262. }
  263. if( g_EscCharShiftState & ALT_KEY )
  264. {
  265. _snwprintf( szEscCharShiftState,dwToCopy,( LPTSTR )L"%s", ALT_PLUS );
  266. szEscCharShiftState += wcslen( szEscCharShiftState );
  267. dwToCopy -= wcslen(szEscCharShiftState);
  268. }
  269. if( g_EscCharShiftState & CTRL_KEY )
  270. {
  271. _snwprintf( szEscCharShiftState, dwToCopy,( LPTSTR )L"%s", CTRL_PLUS );
  272. }
  273. }
  274. DWORD g_lExitTelnet = 0;
  275. DWORD DoTelnetCommands( void* p )
  276. {
  277. #define MAX_COMMAND_LEN 256
  278. // make the command buffer hold 256 characters and null terminatior. Note that
  279. // ReadConsole when asked to read 255 characters, will read 254 and the <CR> character
  280. // and then real <LF> in the next call. Where as if we ask it to read 256, it will still limit no
  281. // of characters to 254, but this time return both <CR>, <LF>.
  282. TCHAR szCommand[MAX_COMMAND_LEN+1];
  283. TCHAR *pCmd = NULL;
  284. DWORD dwRead = ( DWORD ) -1, dwWritten = 0;
  285. int iBegin = 0, iEnd = 0, iCmd = 0;
  286. static DWORD dwConsoleMode = 0;
  287. TCHAR szTmp[MAX_COMMAND_LEN] = { 0 };
  288. TCHAR szTmp1[81];
  289. if( dwConsoleMode == 0 )
  290. GetConsoleMode( gwi.hInput, &dwConsoleMode );
  291. SetEscapeChar( g_chEsc ); //This forms g_szKbdEscape
  292. _sntprintf(szTmp,MAX_COMMAND_LEN -1,_T("%s%s%s"),szInfoBanner,g_szKbdEscape,TEXT("\n"));
  293. WriteConsole( gwi.hOutput, szTmp, _tcslen(szTmp), &dwWritten, NULL);
  294. // hack to make the command line paramater to work.
  295. if( rgchHostName[0] )
  296. {
  297. //ugly hack due to remnants of old logic
  298. //by this point, we have already done this kind of stuff once in
  299. //FInitApplication()
  300. TCHAR szCmd[MAX_COMMAND_LEN] = { 0 };
  301. if( g_szPortNameOrNo[ 0 ] != 0 ) //not a null string
  302. {
  303. _sntprintf(szCmd,MAX_COMMAND_LEN -1,TEXT("%s %s"),rgchHostName,g_szPortNameOrNo);
  304. }
  305. else
  306. {
  307. _tcsncpy( szCmd, rgchHostName,MAX_COMMAND_LEN -1);
  308. }
  309. fPrintMessageToSessionConsole = TRUE;
  310. fClientLaunchedFromCommandPrompt = TRUE;
  311. OpenTelnetSession( szCmd );
  312. if( g_fConnectFailed )
  313. {
  314. exit( 0 );
  315. }
  316. }
  317. do {
  318. int iValidCmd = -1;
  319. int iIndex = 0;
  320. int iCount = 0;
  321. BOOL dwStatus = 0;
  322. if( ui.bPromptForNtlm )
  323. {
  324. gwi.hOutput = g_hTelnetPromptConsoleBuffer;
  325. SetConsoleActiveScreenBuffer( gwi.hOutput );
  326. PromptUserForNtlmCredsTransfer();
  327. ui.bPromptForNtlm = FALSE;
  328. SetEvent( g_hCaptureConsoleEvent );
  329. gwi.hOutput = g_hSessionConsoleBuffer;
  330. SetConsoleActiveScreenBuffer( gwi.hOutput );
  331. SetEvent( g_hRemoteNEscapeModeDataSync );
  332. HandleTelnetSession(&gwi);
  333. }
  334. if( g_lExitTelnet )
  335. {
  336. CloseHandle(g_hTelnetPromptConsoleBuffer );
  337. CloseHandle( gwi.hInput );
  338. }
  339. if( dwRead != 0 )
  340. {
  341. SetConsoleMode(gwi.hInput, dwConsoleMode);
  342. gwi.hOutput = g_hTelnetPromptConsoleBuffer;
  343. SetConsoleActiveScreenBuffer( gwi.hOutput );
  344. WriteConsole( gwi.hOutput, szPrompt, _tcslen(szPrompt), &dwWritten, NULL);
  345. SfuZeroMemory(szCommand, MAX_COMMAND_LEN * sizeof(TCHAR));
  346. }
  347. dwRead = ( DWORD ) -1;
  348. dwStatus = ReadConsole(gwi.hInput, szCommand, MAX_COMMAND_LEN, &dwRead, NULL);
  349. szCommand[MAX_COMMAND_LEN] = 0; // null terminate for the extreme case.
  350. if( dwStatus == 0 || dwRead == -1 )
  351. {
  352. /* When NN_LOST is received, we close gwi.hInput so that we
  353. * reach here and do equivalent of quit at telnet prompt */
  354. QuitTelnet( ( LPTSTR )L"" );
  355. continue;
  356. }
  357. if( dwRead == 0 )
  358. {
  359. continue;
  360. }
  361. // no input ??
  362. // This is the case when an enter is hit at telnet prompt
  363. if ( dwRead == 2 )
  364. {
  365. if( fConnected )
  366. {
  367. gwi.hOutput = g_hSessionConsoleBuffer;
  368. SetConsoleActiveScreenBuffer( gwi.hOutput );
  369. SetEvent( g_hRemoteNEscapeModeDataSync );
  370. HandleTelnetSession(&gwi);
  371. }
  372. continue;
  373. }
  374. ASSERT( dwRead >= 2 );
  375. // Null Terminate the string and remove the newline characters.
  376. szCommand[dwRead-1] = 0;
  377. szCommand[dwRead-2] = 0;
  378. while( iswspace( szCommand[iIndex] ) )
  379. {
  380. iIndex++;
  381. }
  382. iCount = iIndex;
  383. if( iIndex != 0 )
  384. {
  385. do
  386. {
  387. szCommand[ iIndex - iCount ] = szCommand[ iIndex++ ];
  388. }
  389. while( szCommand[ iIndex - 1 ] != _T('\0') );
  390. }
  391. if ( *szCommand == _T('?') )
  392. {
  393. PrintHelpStr(szCommand);
  394. continue;
  395. }
  396. // do a binary search based on the first character, if that succeeds then
  397. // see if the typed in command is a substring of the command.
  398. iBegin = 0; iEnd = MAX_TELNET_COMMANDS - 1;
  399. while ( iBegin <= iEnd )
  400. {
  401. iCmd = (iBegin + iEnd)/2;
  402. if ( towlower( *szCommand ) == *sTelnetCommands[iCmd].sName )
  403. break;
  404. if ( towlower( *szCommand ) > *sTelnetCommands[iCmd].sName )
  405. iBegin = iCmd+1;
  406. else
  407. iEnd = iCmd-1;
  408. }
  409. if ( iBegin > iEnd )
  410. {
  411. invalidCmd:
  412. WriteConsole(gwi.hOutput, szInvalid, _tcslen(szInvalid), &dwWritten, NULL);
  413. continue;
  414. }
  415. // go back to the command that has the same first char
  416. while ( iCmd > 0 && towlower( *szCommand ) == *sTelnetCommands[iCmd-1].sName )
  417. iCmd--;
  418. pCmd = _tcstok(szCommand, ( LPTSTR )TEXT(" \t"));
  419. if ( pCmd == NULL )
  420. pCmd = szCommand;
  421. while ( iCmd < MAX_TELNET_COMMANDS && towlower( *szCommand ) == *sTelnetCommands[iCmd].sName )
  422. {
  423. if ( _tcsstr(sTelnetCommands[iCmd].sName, _tcslwr( pCmd )) == sTelnetCommands[iCmd].sName)
  424. {
  425. if( iValidCmd >= 0 )
  426. {
  427. iValidCmd = -1;
  428. break;
  429. }
  430. else
  431. {
  432. iValidCmd = iCmd;
  433. }
  434. }
  435. iCmd++;
  436. }
  437. //if ( iCmd == MAX_TELNET_COMMANDS )
  438. if( iValidCmd < 0 )
  439. {
  440. goto invalidCmd;
  441. }
  442. // process the command.
  443. pCmd = _tcstok(NULL, ( LPTSTR )TEXT(""));
  444. if ( (*sTelnetCommands[iValidCmd].pCmdHandler)(pCmd) )
  445. break;
  446. } while ( ( TRUE, TRUE ) );
  447. return 0;
  448. }
  449. void SetCursorShape()
  450. {
  451. CONSOLE_CURSOR_INFO ccInfo = { 0 , 0 };
  452. GetConsoleCursorInfo( g_hSessionConsoleBuffer, &ccInfo );
  453. if( ccInfo.dwSize < BLOCK_CURSOR )
  454. {
  455. ccInfo.dwSize = BLOCK_CURSOR ;
  456. }
  457. else
  458. {
  459. ccInfo.dwSize = NORMAL_CURSOR;
  460. }
  461. SetConsoleCursorInfo( g_hSessionConsoleBuffer, &ccInfo );
  462. return;
  463. }
  464. BOOL IsAnEscapeChar( WCHAR wcChar, WI *pwi, DWORD dwEventsRead )
  465. {
  466. PUCHAR destBuf = NULL;
  467. DWORD dwSize = 0;
  468. // Is it the escape Key !? i.e. ctrl + ]
  469. if( wcChar == g_chEsc && g_bIsEscapeCharValid )
  470. {
  471. #if 0
  472. //This special case is no more needed as we simulate key up and down
  473. //for each key storke on the server. Lack of this was the cause of losing chars
  474. //on the server side
  475. // this is the really special case where when the user tries
  476. // to enter ctrl + ], first he presses ctrl. this sends a
  477. // ctrl "keydown" input record to the remote side .
  478. // then we get the ctrl + ] and we switch to local mode.
  479. // at this time the ctrl "keyup" input record is consumed by
  480. // us locally. So we have to send a simulated ctrl "keyup"
  481. // input record. Test case : when user is in app like
  482. // "edit.exe", edit is expecting a ctrl "keyup" to follow
  483. // a ctrl "keydown". otherwise it gets "stuck" and you can't
  484. // enter the and letter keys.
  485. //To solve this we are reading MAX_KEYUPS i/p records and
  486. //giving them to the application
  487. if( ( pwi->trm.CurrentTermType == TT_VTNT ) )
  488. {
  489. INPUT_RECORD pIR[ MAX_KEYUPS ];
  490. ReadConsoleInput(pwi->hInput, pIR, MAX_KEYUPS, &dwEventsRead);
  491. dwSize = sizeof( INPUT_RECORD ) * dwEventsRead;
  492. if( !StuffEscapeIACs( &destBuf, (PUCHAR) pIR, &dwSize ) )
  493. {
  494. FWriteToNet( pwi, ( CHAR* ) pIR, dwSize );
  495. }
  496. else
  497. {
  498. FWriteToNet(pwi, ( CHAR* )destBuf, dwSize );
  499. dwSize = 0;
  500. free( destBuf );
  501. }
  502. }
  503. #endif
  504. //Failure of this is not serious. Just that
  505. //Remote data may be seen escape mode.
  506. WaitForSingleObject( g_hRemoteNEscapeModeDataSync, INFINITE );
  507. ResetEvent( g_hRemoteNEscapeModeDataSync );
  508. gwi.hOutput = g_hTelnetPromptConsoleBuffer;
  509. return ( TRUE );
  510. }
  511. return ( FALSE );
  512. }
  513. /*
  514. *
  515. * This function does all the characater translations/mappings
  516. * that are required by the client to do. This function has
  517. * to be called after a Key Event has occurred and before
  518. * anything is written onto the socket. All other places
  519. * where the translations/mappings are being done are to be
  520. * removed.
  521. *
  522. * TODO: Right now I am moving delasbs and bsasdel mappings
  523. * only to fix a few bugs. All mappings should eventually be
  524. * moved here for better maintainability - prakashr
  525. *
  526. */
  527. void HandleCharMappings(WI* pWI, INPUT_RECORD* pInputRecord)
  528. {
  529. // Do not make a call to ForceJISRomanSend in this function
  530. // that will be done while sending the data to the network
  531. // Map backspace to del, in case of 'set bsasdel' setting
  532. // unless either CTRL or SHIFT or ALT is pressed
  533. if (g_bSendBackSpaceAsDel && pInputRecord->Event.KeyEvent.uChar.AsciiChar == ASCII_BACKSPACE &&
  534. !(pInputRecord->Event.KeyEvent.dwControlKeyState & (ALT_PRESSED | CTRL_PRESSED | SHIFT_PRESSED)))
  535. {
  536. pInputRecord->Event.KeyEvent.wVirtualKeyCode = VK_DELETE;
  537. pInputRecord->Event.KeyEvent.uChar.AsciiChar = CHAR_NUL;
  538. pInputRecord->Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
  539. return;
  540. }
  541. // Map del to backspace, in case of 'set delasbs' setting
  542. // unless either CTRL or SHIFT or ALT is pressed
  543. if (g_bSendDelAsBackSpace && pInputRecord->Event.KeyEvent.wVirtualKeyCode == VK_DELETE &&
  544. !(pInputRecord->Event.KeyEvent.dwControlKeyState & (ALT_PRESSED | CTRL_PRESSED | SHIFT_PRESSED)))
  545. {
  546. pInputRecord->Event.KeyEvent.uChar.AsciiChar = ASCII_BACKSPACE;
  547. pInputRecord->Event.KeyEvent.wVirtualKeyCode = ASCII_BACKSPACE;
  548. pInputRecord->Event.KeyEvent.dwControlKeyState &= ~ENHANCED_KEY;
  549. return;
  550. }
  551. }
  552. DWORD HandleTelnetSession(WI *pwi)
  553. {
  554. PUCHAR destBuf = NULL;
  555. DWORD dwSize = 0;
  556. BOOL bBreakFlag = FALSE;
  557. INPUT_RECORD sInputRecord;
  558. DWORD dwEventsRead;
  559. INPUT_RECORD *pInputRecord;
  560. DWORD dwPrevMode = 0, TelnetConsoleMode;
  561. GetConsoleMode(pwi->hInput, &dwPrevMode);
  562. TelnetConsoleMode = dwPrevMode & ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | FOCUS_EVENT);
  563. SetConsoleMode(pwi->hInput, TelnetConsoleMode);
  564. pInputRecord = &sInputRecord;
  565. // DebugBreak();
  566. while ( fConnected && !bBreakFlag )
  567. {
  568. if ( (pwi->trm.CurrentTermType == TT_VTNT) ?
  569. ReadConsoleInput(pwi->hInput, pInputRecord, 1, &dwEventsRead) :
  570. ReadConsoleInputA(pwi->hInput, pInputRecord, 1, &dwEventsRead))
  571. {
  572. switch ( pInputRecord->EventType )
  573. {
  574. case KEY_EVENT:
  575. if (!FGetCodeMode(eCodeModeFarEast) && !FGetCodeMode(eCodeModeVT80))
  576. {
  577. // If ALT key is down and we are not in VTNT mode we check to see if
  578. // user wants to enter extended ASCII characters from the OEM character
  579. // set or from ANSI character set. Also note that currently in V1 the
  580. // SFU server does term type negotiation only after user login.
  581. // So the term type will be ANSI until login succeeds eventhough the
  582. // user sets the preferred term type to VTNT. Unless this protocol ordering
  583. // changes in the server, the below loop will work for VTNT when the
  584. // username or password has extended characters in it.
  585. //
  586. if( (pInputRecord->Event.KeyEvent.dwControlKeyState & ALT_PRESSED) &&
  587. (pwi->trm.CurrentTermType != TT_VTNT) )
  588. {
  589. char szExtendedCharBuf[5];
  590. int idx=0;
  591. SfuZeroMemory( szExtendedCharBuf, sizeof(szExtendedCharBuf) );
  592. while(fConnected)
  593. {
  594. ReadConsoleInputA( pwi->hInput, pInputRecord, 1, &dwEventsRead );
  595. /*++
  596. Continue here ONLY if the client is still connected - which is determined by the
  597. fConnected flag. Otherwise, break from this loop without doing anything.
  598. --*/
  599. if ( FOCUS_EVENT == pInputRecord->EventType
  600. && TRUE == ui.bPromptForNtlm )
  601. {
  602. bBreakFlag = TRUE;
  603. break;
  604. }
  605. if( !(pInputRecord->Event.KeyEvent.dwControlKeyState & ALT_PRESSED)
  606. || (pInputRecord->EventType != KEY_EVENT)
  607. || !( ( pInputRecord->Event.KeyEvent.wVirtualKeyCode >= VK_NUMPAD0
  608. && pInputRecord->Event.KeyEvent.wVirtualKeyCode <= VK_NUMPAD9 )
  609. || IS_NUMPAD_DIGIT_KEY( pInputRecord->Event.KeyEvent ) ) )
  610. //The last one is for allowing entering extended
  611. //chars even when numlock is not on
  612. {
  613. if( idx == NUM_ISO8859_CHARS )
  614. {
  615. int extChar;
  616. WCHAR wcChar[2] = {0};
  617. CHAR cChar[2] = {0};
  618. CHAR cSpace = ' ';
  619. BOOL bUsed = 0;
  620. szExtendedCharBuf[idx] = '\0';
  621. extChar = atoi( szExtendedCharBuf );
  622. /* When casting from int to char, it is using
  623. * CP 1252. To make it use 850, the following jugglery */
  624. MultiByteToWideChar( GetConsoleCP(), 0, ( LPCSTR )&extChar, 1, &wcChar[0], 1 );
  625. wcChar[1] = L'\0';
  626. WideCharToMultiByte( GetConsoleCP(), 0, &wcChar[0], 1, &cChar[0], 1, &cSpace, &bUsed );
  627. cChar[1] = '\0';
  628. if( IsAnEscapeChar( wcChar[0], pwi, dwEventsRead ) )
  629. {
  630. // Restore the console mode.
  631. SetConsoleMode( pwi->hInput, dwPrevMode );
  632. return ( 0 );
  633. }
  634. HandleCharEvent( pwi, cChar[0], pInputRecord->Event.KeyEvent.dwControlKeyState );
  635. break;
  636. }
  637. else if( idx == NUM_WINDOWS_CP1252_CHARS )
  638. {
  639. int extChar;
  640. WCHAR wcChar[2] = {0};
  641. CHAR cChar[2] = {0};
  642. CHAR cSpace = ' ';
  643. BOOL bUsed = 0;
  644. szExtendedCharBuf[idx] = '\0';
  645. extChar = atoi( szExtendedCharBuf );
  646. MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )&extChar, 1, &wcChar[0], 1 );
  647. wcChar[1] = L'\0';
  648. WideCharToMultiByte( GetConsoleCP(), 0, &wcChar[0], 1, &cChar[0], 1, &cSpace, &bUsed );
  649. cChar[1] = '\0';
  650. if( IsAnEscapeChar( wcChar[0], pwi, dwEventsRead ) )
  651. {
  652. // Restore the console mode.
  653. SetConsoleMode( pwi->hInput, dwPrevMode );
  654. return ( 0 );
  655. }
  656. HandleCharEvent( pwi, cChar[0], pInputRecord->Event.KeyEvent.dwControlKeyState );
  657. break;
  658. }
  659. else
  660. {
  661. if( (pInputRecord->Event.KeyEvent.uChar.AsciiChar != 0)
  662. && (pInputRecord->EventType == KEY_EVENT)
  663. && (pInputRecord->Event.KeyEvent.bKeyDown) )
  664. {
  665. break;
  666. }
  667. else if( ( ( pInputRecord->Event.KeyEvent.wVirtualKeyCode >= VK_PRIOR
  668. && pInputRecord->Event.KeyEvent.wVirtualKeyCode <= VK_DELETE )
  669. || ( pInputRecord->Event.KeyEvent.wVirtualKeyCode >= VK_F1
  670. && pInputRecord->Event.KeyEvent.wVirtualKeyCode <= VK_F12 ) )
  671. && pInputRecord->EventType == KEY_EVENT
  672. && pInputRecord->Event.KeyEvent.bKeyDown )
  673. {
  674. //This will handle home, end, pageup, pagedown, function keys etc from
  675. //numeric keypad
  676. break;
  677. }
  678. else if ( pInputRecord->Event.KeyEvent.dwControlKeyState & ENHANCED_KEY )
  679. {
  680. break;
  681. }
  682. else
  683. {
  684. continue;
  685. }
  686. }
  687. }
  688. else
  689. {
  690. if( IS_NUMPAD_DIGIT_KEY( pInputRecord->Event.KeyEvent ) )
  691. {
  692. INT iDigit = 0;
  693. iDigit = MAP_DIGIT_KEYS_TO_VAL( pInputRecord->Event.KeyEvent.wVirtualKeyCode );
  694. szExtendedCharBuf[idx++] = ( CHAR ) ( '0' + iDigit );
  695. }
  696. else
  697. {
  698. szExtendedCharBuf[idx++] = ( CHAR )( (pInputRecord->Event.KeyEvent.wVirtualKeyCode - VK_NUMPAD0) + '0' );
  699. }
  700. ReadConsoleInputA( pwi->hInput, pInputRecord, 1, &dwEventsRead );
  701. continue;
  702. }
  703. }
  704. }
  705. }
  706. if( pInputRecord->Event.KeyEvent.bKeyDown )
  707. {
  708. if( IsAnEscapeChar( pInputRecord->Event.KeyEvent.uChar.UnicodeChar, pwi, dwEventsRead ) )
  709. {
  710. // Restore the console mode.
  711. SetConsoleMode( pwi->hInput, dwPrevMode );
  712. return ( 0 );
  713. }
  714. }
  715. //
  716. // After trapping the escape character, do the mappings now
  717. //
  718. HandleCharMappings(pwi, pInputRecord);
  719. if( pwi->trm.CurrentTermType == TT_VTNT )
  720. {
  721. if( pInputRecord->Event.KeyEvent.wVirtualKeyCode == VK_INSERT_KEY &&
  722. pInputRecord->Event.KeyEvent.bKeyDown )
  723. {
  724. SetCursorShape();
  725. }
  726. CheckForChangeInWindowSize();
  727. dwSize = sizeof( INPUT_RECORD );
  728. if( !StuffEscapeIACs( &destBuf, (PUCHAR) pInputRecord, &dwSize ) )
  729. {
  730. FWriteToNet( pwi, ( CHAR* ) pInputRecord, sizeof( INPUT_RECORD ) );
  731. }
  732. else
  733. {
  734. FWriteToNet(pwi, ( CHAR* )destBuf, dwSize );
  735. dwSize = 0;
  736. free( destBuf );
  737. }
  738. if( ui.nottelnet || (ui.fDebug & fdwLocalEcho ) )
  739. {
  740. //if( !DoVTNTOutput(pwi, &pwi->trm, sizeof(INPUT_RECORD),
  741. // (char*)&sInputRecord ) )
  742. //{
  743. //pwi->trm.CurrentTermType = TT_ANSI;
  744. //DoIBMANSIOutput(pwi, &pwi->trm,
  745. //sizeof(INPUT_RECORD), (char*)&sInputRecord );
  746. //}
  747. }
  748. break;
  749. }
  750. if ( ! pInputRecord->Event.KeyEvent.bKeyDown )
  751. break;
  752. if ( pInputRecord->Event.KeyEvent.dwControlKeyState & ENHANCED_KEY )
  753. {
  754. FHandleKeyDownEvent(pwi, (CHAR)pInputRecord->Event.KeyEvent.wVirtualKeyCode,
  755. pInputRecord->Event.KeyEvent.dwControlKeyState);
  756. break;
  757. }
  758. if ( pInputRecord->Event.KeyEvent.uChar.AsciiChar == 0 )
  759. {
  760. //The following call is for handling home, end, pageup, pagedown etc from
  761. //numeric keypad and also, function keys
  762. FHandleKeyDownEvent(pwi, (CHAR)pInputRecord->Event.KeyEvent.wVirtualKeyCode,
  763. pInputRecord->Event.KeyEvent.dwControlKeyState);
  764. break;
  765. }
  766. HandleCharEvent(pwi, pInputRecord->Event.KeyEvent.uChar.AsciiChar,
  767. pInputRecord->Event.KeyEvent.dwControlKeyState);
  768. break;
  769. case MOUSE_EVENT:
  770. break;
  771. case WINDOW_BUFFER_SIZE_EVENT:
  772. break;
  773. case MENU_EVENT:
  774. break;
  775. case FOCUS_EVENT:
  776. if(TRUE == ui.bPromptForNtlm)
  777. {
  778. bBreakFlag = TRUE;
  779. }
  780. break;
  781. default:
  782. break;
  783. }
  784. }
  785. else
  786. {
  787. QuitTelnet( ( LPTSTR )L"" );
  788. }
  789. }
  790. gwi.hOutput = g_hTelnetPromptConsoleBuffer;
  791. bDoVtNTFirstTime = 1;
  792. // Restore the console mode.
  793. SetConsoleMode(pwi->hInput, dwPrevMode);
  794. return 0;
  795. }
  796. BOOL WINAPI ControlHandler(DWORD dwCtrlType)
  797. {
  798. WCHAR wchCtrl;
  799. switch ( dwCtrlType )
  800. {
  801. case CTRL_C_EVENT:
  802. case CTRL_BREAK_EVENT:
  803. if ( !fConnected ) // normal handling while not connected.
  804. {
  805. //
  806. // (a-roopb) Fix to bug1006:telnet client does not connect when a ^C is hit
  807. // SetEvent( g_hAsyncGetHostByNameEvent );
  808. //
  809. PulseEvent( g_hControlHandlerEvent );
  810. return TRUE;
  811. }
  812. else if( gwi.hOutput != g_hSessionConsoleBuffer )
  813. {
  814. return TRUE;
  815. }
  816. // pass this to the server !!
  817. if( gwi.trm.CurrentTermType == TT_VTNT )
  818. {
  819. wchCtrl = 0x03;
  820. ConvertAndSendVTNTData(&wchCtrl,1);
  821. if (ui.nottelnet || (ui.fDebug & fdwLocalEcho))
  822. {
  823. //if( !DoVTNTOutput( &gwi, &(gwi.trm), sizeof(INPUT_RECORD),
  824. // (char*)&sInputRecord ) )
  825. //{
  826. //pwi->trm.CurrentTermType = TT_ANSI;
  827. //DoIBMANSIOutput(&gwi, gwi.trm, sizeof(INPUT_RECORD),
  828. // (char*)&sInputRecord );
  829. //}
  830. }
  831. }
  832. else
  833. {
  834. HandleCharEvent(&gwi, (CHAR)VK_CANCEL, // '0x03' i.e.
  835. 0);
  836. }
  837. break;
  838. case CTRL_CLOSE_EVENT:
  839. case CTRL_LOGOFF_EVENT:
  840. case CTRL_SHUTDOWN_EVENT:
  841. if ( fConnected )
  842. FHangupConnection(&gwi, &(gwi.nd));
  843. default:
  844. return FALSE;
  845. break;
  846. }
  847. return TRUE;
  848. }
  849. static void InitCodeModeFlags(UINT uConsoleCp)
  850. {
  851. switch (uConsoleCp)
  852. {
  853. case 932:
  854. case 949:
  855. case 936:
  856. case 950:
  857. SetCodeModeON(eCodeModeFarEast);
  858. SetCodeModeON(eCodeModeIMEFarEast);
  859. SetCodeModeON(eCodeModeVT80);
  860. break;
  861. }
  862. }
  863. void CleanUpMemory()
  864. {
  865. if( szUser )
  866. {
  867. free( szUser );
  868. }
  869. if( gwi.nd.lpReadBuffer )
  870. {
  871. (void)LocalFree( (HLOCAL)gwi.nd.lpReadBuffer );
  872. gwi.nd.lpReadBuffer = NULL;
  873. }
  874. if( gwi.nd.lpTempBuffer )
  875. {
  876. (void)LocalFree( (HLOCAL)gwi.nd.lpTempBuffer );
  877. gwi.nd.lpTempBuffer = NULL;
  878. }
  879. return;
  880. }
  881. // CleanupProcess:
  882. void DoProcessCleanup()
  883. {
  884. // first step is to close the Telnet connection if any
  885. if ( fConnected )
  886. FHangupConnection(&gwi, &(gwi.nd));
  887. // next, free the Network resources.
  888. WSACleanup(); // keithmo: get winsock.
  889. // Destroy the window that we created.
  890. DestroyWindow( gwi.hwnd );
  891. CloseHandle(gwi.hNetworkThread);
  892. CloseHandle(g_hControlHandlerEvent);
  893. CloseHandle(g_hAsyncGetHostByNameEvent);
  894. CloseHandle(g_hTelnetPromptConsoleBuffer );
  895. CloseHandle(g_hRemoteNEscapeModeDataSync );
  896. CloseHandle(g_hCaptureConsoleEvent);
  897. // Cleanup the memory.
  898. CleanUpMemory();
  899. }
  900. /****************************************************************************
  901. FUNCTION: main()
  902. PURPOSE: calls initialization function, processes message loop
  903. COMMENTS:
  904. Windows recognizes this function by name as the initial entry point
  905. for the program. This function calls the application initialization
  906. routine, if no other instance of the program is running, and always
  907. calls the instance initialization routine. It then executes a message
  908. retrieval and dispatch loop that is the top-level control structure
  909. for the remainder of execution. The loop is terminated when a WM_QUIT
  910. message is received, at which time this function exits the application
  911. instance by returning the value passed by PostQuitMessage().
  912. If this function must abort before entering the message loop, it
  913. returns the conventional value NULL.
  914. ****************************************************************************/
  915. int __cdecl wmain( int argc, TCHAR** argv )
  916. {
  917. MSG msg;
  918. int err;
  919. DWORD dwThreadId;
  920. HANDLE hStdHandle = INVALID_HANDLE_VALUE;
  921. setlocale(LC_ALL, "");
  922. gwi.ichTelXfer = 0;
  923. hStdHandle = GetStdHandle( STD_INPUT_HANDLE );
  924. if( hStdHandle == INVALID_HANDLE_VALUE)
  925. {
  926. exit( -1 );
  927. }
  928. gwi.hInput = hStdHandle;
  929. hStdHandle = GetStdHandle( STD_OUTPUT_HANDLE );
  930. if( hStdHandle == INVALID_HANDLE_VALUE)
  931. {
  932. exit( -1 );
  933. }
  934. gwi.hOutput = hStdHandle;
  935. g_hSessionConsoleBuffer = gwi.hOutput;
  936. if( GetConsoleScreenBufferInfo( gwi.hOutput, &gwi.sbi ))
  937. {
  938. //set the initial console attributes
  939. //white text on a black background
  940. gwi.sbi.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
  941. // This is so that when we scroll we maintain the
  942. // background color & text color !!
  943. gwi.cinfo.Attributes = gwi.sbi.wAttributes;
  944. gwi.cinfo.Char.AsciiChar = ' ';
  945. if(( err = FInitApplication( argc, argv, &gwi )))
  946. {
  947. exit( err );
  948. }
  949. }
  950. else
  951. {
  952. exit( -1 );
  953. }
  954. g_hControlHandlerEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); // Auto-Reset event
  955. g_hAsyncGetHostByNameEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // Manual-Reset event
  956. g_hCaptureConsoleEvent = CreateEvent( NULL, TRUE, TRUE, NULL ); // Manual-Reset event
  957. // Create the thread that Handles the Keyboard and mouse input.
  958. // The main thread has to keep dispatching the WinSock Messages since
  959. // we use Non-Blocking sockets.
  960. gwi.hNetworkThread = CreateThread( NULL, 0,
  961. ( LPTHREAD_START_ROUTINE )DoTelnetCommands, ( LPVOID ) &gwi, 0, &dwThreadId );
  962. /* Acquire and dispatch messages until a WM_QUIT message is received. */
  963. while ( GetMessage(&msg, gwi.hwnd, 0, 0) )
  964. {
  965. TranslateMessage( &msg );
  966. DispatchMessage( &msg );
  967. }
  968. SetConsoleCtrlHandler(&ControlHandler, FALSE);
  969. DoProcessCleanup();
  970. // Save user settings.
  971. SetUserSettings(&ui);
  972. ExitProcess(0);
  973. return 0;
  974. }
  975. void CreateTelnetPromptConsole()
  976. {
  977. //create a new console screen buffer. this is to be used for the remote
  978. //session data
  979. g_hTelnetPromptConsoleBuffer = CreateConsoleScreenBuffer(
  980. GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  981. NULL, CONSOLE_TEXTMODE_BUFFER, NULL );
  982. if( g_hTelnetPromptConsoleBuffer == INVALID_HANDLE_VALUE )
  983. {
  984. exit( -1 );
  985. }
  986. SetConsoleScreenBufferSize( g_hTelnetPromptConsoleBuffer, gwi.sbi.dwSize );
  987. gwi.hOutput = g_hTelnetPromptConsoleBuffer;
  988. }
  989. /****************************************************************************
  990. FUNCTION: FInitApplication(HINSTANCE)
  991. PURPOSE: Initializes window data and registers window class
  992. COMMENTS:
  993. This function is called at initialization time only if no other
  994. instances of the application are running. This function performs
  995. initialization tasks that can be done once for any number of running
  996. instances.
  997. In this case, we initialize a window class by filling out a data
  998. structure of type WNDCLASS and calling the Windows RegisterClass()
  999. function. Since all instances of this application use the same window
  1000. class, we only need to do this when the first instance is initialized.
  1001. ****************************************************************************/
  1002. int
  1003. FInitApplication(int argc, TCHAR** argv, WI *pwi)
  1004. {
  1005. WNDCLASS wc;
  1006. #ifdef DEBUG
  1007. int argi; // for indexing argc.
  1008. #endif
  1009. WSADATA WsaData;
  1010. int WsaErr;
  1011. BOOL fServerFound = 0;
  1012. TCHAR rgchTerm[ 25 ]; //term type length is 25
  1013. InitCodeModeFlags(GetConsoleOutputCP());
  1014. /* Set the default user settings */
  1015. SfuZeroMemory(&ui, sizeof(UI));//no overflow. size constant.
  1016. ui.nottelnet = TRUE; // Assume that is not a telnet server that we would connect to ...
  1017. //Initialize logging related variables
  1018. ui.bLogging = FALSE;
  1019. ui.hLogFile = NULL;
  1020. ui.dwMaxRow = 0;
  1021. ui.dwMaxCol = 0;
  1022. CreateTelnetPromptConsole();
  1023. // We really do not care about the success or failure of this function.
  1024. HrLoadLocalizedLibrarySFU(GetModuleHandle(NULL), ( LPTSTR )L"telnetcr.dll", &ghInstance, NULL);
  1025. ASSERT(ghInstance);
  1026. #ifndef NO_PCHECK
  1027. #ifndef WHISTLER_BUILD
  1028. if ( !IsLicensedCopy() )
  1029. {
  1030. TCHAR g_szErrRegDelete[ MAX_STRING_LENGTH ];
  1031. LoadString(ghInstance, IDS_ERR_LICENSE, g_szErrRegDelete,
  1032. sizeof(g_szErrRegDelete) / sizeof(TCHAR));
  1033. MessageBox(NULL, g_szErrRegDelete, ( LPTSTR )_T(" "), MB_OK);
  1034. exit( 1 );
  1035. }
  1036. #endif
  1037. #endif
  1038. LoadString(ghInstance, IDS_APPNAME, (LPTSTR) szAppName, SMALL_STRING);
  1039. GetUserSettings(&ui);
  1040. ui.nCyChar = 1; // char height
  1041. ui.nCxChar = 1; // char width
  1042. WsaErr = WSAStartup( 0x0101, &WsaData ); // make sure winsock is happy - noop for now
  1043. if( WsaErr )
  1044. {
  1045. ErrorMessage(szCantInitSockets, szAppName);
  1046. SetLastError( WsaErr );
  1047. return WsaErr;
  1048. }
  1049. switch (GetConsoleOutputCP())
  1050. {
  1051. case 932:
  1052. case 949:
  1053. SetThreadLocale(
  1054. MAKELCID(
  1055. MAKELANGID( PRIMARYLANGID(GetSystemDefaultLangID()),
  1056. SUBLANG_ENGLISH_US),
  1057. SORT_DEFAULT
  1058. )
  1059. );
  1060. break;
  1061. case 936:
  1062. SetThreadLocale(
  1063. MAKELCID(
  1064. MAKELANGID( PRIMARYLANGID(GetSystemDefaultLangID()),
  1065. SUBLANG_CHINESE_SIMPLIFIED),
  1066. SORT_DEFAULT
  1067. )
  1068. );
  1069. break;
  1070. case 950:
  1071. SetThreadLocale(
  1072. MAKELCID(
  1073. MAKELANGID( PRIMARYLANGID(GetSystemDefaultLangID()),
  1074. SUBLANG_CHINESE_TRADITIONAL),
  1075. SORT_DEFAULT
  1076. )
  1077. );
  1078. break;
  1079. default:
  1080. SetThreadLocale(
  1081. MAKELCID(
  1082. MAKELANGID( LANG_ENGLISH,
  1083. SUBLANG_ENGLISH_US ),
  1084. SORT_DEFAULT
  1085. )
  1086. );
  1087. break;
  1088. }
  1089. LoadString(ghInstance, IDS_USAGE, (LPTSTR) szUsage, 1399);
  1090. LoadString(ghInstance, IDS_VERSION, (LPTSTR) szVersion, SMALL_STRING);
  1091. LoadString(ghInstance, IDS_CONNECTIONLOST, (LPTSTR) szConnectionLost, 254);
  1092. LoadString(ghInstance, IDS_TITLEBASE, (LPTSTR) szTitleBase, SMALL_STRING);
  1093. LoadString(ghInstance, IDS_TITLENONE, (LPTSTR) szTitleNone, SMALL_STRING);
  1094. LoadString(ghInstance, IDS_TOOMUCHTEXT, (LPTSTR) szTooMuchText, 255);
  1095. LoadString(ghInstance, IDS_CONNECTING, (LPTSTR) szConnecting, SMALL_STRING);
  1096. LoadString(ghInstance, IDS_CONNECTFAILED, (LPTSTR) szConnectFailed, 254);
  1097. LoadString(ghInstance, IDS_CONNECTFAILEDMSG, (LPTSTR) szConnectFailedMsg, 254);
  1098. LoadString(ghInstance, IDS_ONPORT, szOnPort, SMALL_STRING );
  1099. LoadString(ghInstance, IDS_CANT_INIT_SOCKETS, szCantInitSockets, SMALL_STRING );
  1100. LoadString(ghInstance, IDS_INFO_BANNER, szInfoBanner, 511 );
  1101. LoadString(ghInstance, IDS_ESCAPE_CHAR, szEscapeChar, SMALL_STRING );
  1102. LoadString(ghInstance, IDS_PROMPT_STR, szPrompt, SMALL_STRING );
  1103. LoadString(ghInstance, IDS_INVALID_STR, szInvalid, 254 );
  1104. LoadString(ghInstance, IDS_BUILD_INFO, szBuildInfo, 254 );
  1105. LoadString(ghInstance, IDS_CLOSE, szClose, SMALL_STRING );
  1106. LoadString(ghInstance, IDS_DISPLAY, szDisplay, SMALL_STRING );
  1107. LoadString(ghInstance, IDS_HELP, szHelpStr, SMALL_STRING );
  1108. LoadString(ghInstance, IDS_OPEN, szOpen, SMALL_STRING );
  1109. LoadString(ghInstance, IDS_OPENTO, szOpenTo, SMALL_STRING );
  1110. LoadString(ghInstance, IDS_OPENUSAGE, szOpenUsage, SMALL_STRING );
  1111. LoadString(ghInstance, IDS_QUIT, szQuit, SMALL_STRING );
  1112. LoadString(ghInstance, IDS_SEND, szSend, SMALL_STRING );
  1113. LoadString(ghInstance, IDS_SET, szSet, SMALL_STRING );
  1114. LoadString(ghInstance, IDS_STATUS, szStatus, SMALL_STRING );
  1115. LoadString(ghInstance, IDS_UNSET, szUnset, SMALL_STRING );
  1116. //#if defined(FE_IME)
  1117. // LoadString(ghInstance, IDS_ENABLE_IME_SUPPORT, szEnableIMESupport, SMALL_STRING );
  1118. // LoadString(ghInstance, IDS_DISABLE_IME_SUPPORT, szDisableIMESupport, SMALL_STRING );
  1119. //#endif /* FE_IME */
  1120. LoadString(ghInstance, IDS_WILL_AUTH, szWillAuth, SMALL_STRING );
  1121. LoadString(ghInstance, IDS_WONT_AUTH, szWontAuth, SMALL_STRING );
  1122. LoadString(ghInstance, IDS_LOCAL_ECHO_ON, szLocalEchoOn, SMALL_STRING );
  1123. LoadString(ghInstance, IDS_LOCAL_ECHO_OFF, szLocalEchoOff, SMALL_STRING );
  1124. //#if defined(FE_IME)
  1125. // LoadString(ghInstance, IDS_ENABLE_IME_ON, szEnableIMEOn, SMALL_STRING );
  1126. //#endif /* FE_IME */
  1127. LoadString(ghInstance, IDS_CONNECTED_TO, szConnectedTo, SMALL_STRING );
  1128. LoadString(ghInstance, IDS_NOT_CONNECTED, szNotConnected, SMALL_STRING );
  1129. LoadString(ghInstance, IDS_NEGO_TERM_TYPE, szNegoTermType, SMALL_STRING );
  1130. LoadString(ghInstance, IDS_PREF_TERM_TYPE, szPrefTermType, 255 );
  1131. LoadString(ghInstance, IDS_SET_FORMAT, szSetFormat, 254 );
  1132. LoadString(ghInstance, IDS_SUPPORTED_TERMS, szSupportedTerms, 254 );
  1133. LoadString(ghInstance, IDS_UNSET_FORMAT, szUnsetFormat, 254 );
  1134. if((GetACP() == JAP_CODEPAGE) && FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1135. {
  1136. LoadString(ghInstance, IDS_SET_HELP_JAP, szSetHelp, 1023 );
  1137. LoadString(ghInstance, IDS_UNSET_HELP_JAP, szUnsetHelp, 1023 );
  1138. LoadString(ghInstance, IDS_HELP_STR_JAP, szHelp, 1023 );
  1139. }
  1140. else
  1141. {
  1142. LoadString(ghInstance, IDS_SET_HELP, szSetHelp, 1023 );
  1143. LoadString(ghInstance, IDS_UNSET_HELP, szUnsetHelp, 1023 );
  1144. LoadString(ghInstance, IDS_HELP_STR, szHelp, 1023 );
  1145. }
  1146. //#if defined(FE_IME)
  1147. // LoadString(ghInstance, IDS_ENABLE_IME_FORMAT, szEnableIMEFormat, SMALL_STRING );
  1148. // LoadString(ghInstance, IDS_ENABLE_IME_HELP, szEnableIMEHelp, 254 );
  1149. // LoadString(ghInstance, IDS_DISABLE_IME_FORMAT, szDisableIMEFormat, SMALL_STRING );
  1150. // LoadString(ghInstance, IDS_DISABLE_IME_HELP, szDisableIMEHelp, 254 );
  1151. //#endif /* FE_IME */
  1152. //LoadString(ghInstance, IDS_ESCAPE_CHARACTER, szEscapeCharacter, 2 );
  1153. SetEnvironmentVariable( TEXT( SFUTLNTVER ), TEXT( "2" ) );
  1154. wcscpy( szUserName, ( LPTSTR )L""); //This is used as a flag to detect presence of
  1155. // -l -a options.
  1156. //no overflow.
  1157. wcscpy( g_szLogFile, ( LPTSTR )L"" );//no overflow.
  1158. if(argc > 1)
  1159. {
  1160. INT i = 1;
  1161. while( i < argc )
  1162. {
  1163. if( argv[i][0] == L'-' || argv[i][0] == L'/' )
  1164. {
  1165. switch( argv[i][ 1 ] )
  1166. {
  1167. case L'f':
  1168. case L'F':
  1169. if( argv[i][2] == L'\0' )
  1170. {
  1171. if( ++i >= argc )
  1172. {
  1173. //exit with usage message
  1174. i--;
  1175. argv[i][0] = L'-';
  1176. argv[i][1] = L'?';
  1177. continue;
  1178. }
  1179. _tcsncpy( g_szLogFile, argv[i],
  1180. min( _tcslen(argv[i]) + 1, MAX_PATH + 1 ) );
  1181. }
  1182. else
  1183. {
  1184. _tcsncpy( g_szLogFile, ( argv[i] + wcslen( ( LPWSTR )L"-f" ) ),
  1185. min( _tcslen(argv[i]) + 1, MAX_PATH + 1 ) );
  1186. }
  1187. g_szLogFile[ MAX_PATH + 1 ] = L'\0';
  1188. if( !InitLogFile( g_szLogFile ) )
  1189. {
  1190. DWORD dwWritten = 0;
  1191. TCHAR szMsg[ MAX_STRING_LENGTH ];
  1192. LoadString( ghInstance, IDS_BAD_LOGFILE, szMsg, MAX_STRING_LENGTH );
  1193. WriteConsole( g_hSessionConsoleBuffer, szMsg,
  1194. _tcslen(szMsg), &dwWritten, NULL);
  1195. exit(0);
  1196. }
  1197. ui.bLogging = TRUE;
  1198. break;
  1199. case L'l':
  1200. case L'L':
  1201. if( argv[i][2] == L'\0' )
  1202. {
  1203. if( ++i >= argc )
  1204. {
  1205. //exit with usage message
  1206. i--;
  1207. argv[i][0] = L'-';
  1208. argv[i][1] = L'?';
  1209. continue;
  1210. }
  1211. _tcsncpy( szUserName, argv[i],
  1212. min( _tcslen(argv[i]) + 1, UNLEN ) );
  1213. }
  1214. else
  1215. {
  1216. //when the term name is given after -t without
  1217. //any spaces. 2 accounts for -t.
  1218. _tcsncpy( szUserName, ( argv[i] + 2 ),
  1219. min( _tcslen(argv[i]) - 1, UNLEN ) );
  1220. }
  1221. //Will help if a loooong user name is given
  1222. szUserName[ UNLEN ] = L'\0';
  1223. break;
  1224. case L'a':
  1225. case L'A':
  1226. if( argv[i][2] == L'\0' )
  1227. {
  1228. DWORD dwSize = UNLEN + 1;
  1229. GetUserName( szUserName, &dwSize );
  1230. }
  1231. else
  1232. {
  1233. argv[i][1] = L'?'; //go back and print usage message
  1234. i--;
  1235. }
  1236. break;
  1237. case L'e':
  1238. case L'E':
  1239. if( argv[i][2] == L'\0' )
  1240. {
  1241. if( ++i >= argc )
  1242. {
  1243. //exit with usage message
  1244. i--;
  1245. argv[i][0] = L'-';
  1246. argv[i][1] = L'?';
  1247. continue;
  1248. }
  1249. g_chEsc = argv[i][0]; //Get the first char
  1250. }
  1251. else
  1252. {
  1253. g_chEsc = argv[i][2]; //Get the first char
  1254. }
  1255. break;
  1256. case L't':
  1257. case L'T':
  1258. if( argv[i][2] == L'\0' )
  1259. {
  1260. if( ++i >= argc )
  1261. {
  1262. //exit with usage message
  1263. i--;
  1264. argv[i][0] = L'-';
  1265. argv[i][1] = L'?';
  1266. continue;
  1267. }
  1268. _tcsncpy( rgchTerm, argv[i],
  1269. min( _tcslen(argv[i]) + 1, 24 ) );
  1270. }
  1271. else
  1272. {
  1273. //when the term name is given after -t without
  1274. //any spaces. 2 accounts for -t.
  1275. _tcsncpy( rgchTerm, ( argv[i] + 2 ),
  1276. min( _tcslen(argv[i]) - 1, 24 ) );
  1277. }
  1278. //This statement is helpful only when term type
  1279. //length exceeds 24 chars.
  1280. rgchTerm[24] = L'\0';
  1281. gwi.trm.RequestedTermType =
  1282. GetRequestedTermType( rgchTerm );
  1283. if( gwi.trm.RequestedTermType < 0 )
  1284. {
  1285. DWORD dwWritten;
  1286. WriteConsole(g_hSessionConsoleBuffer, szSupportedTerms,
  1287. _tcslen(szSupportedTerms), &dwWritten, NULL);
  1288. exit(0);
  1289. }
  1290. break;
  1291. case L'?':
  1292. default:
  1293. PrintUsage();
  1294. exit(0);
  1295. }
  1296. }
  1297. else
  1298. {
  1299. if( fServerFound )
  1300. {
  1301. PrintUsage();
  1302. exit(0);
  1303. }
  1304. fServerFound = 1;
  1305. _tcsncpy( rgchHostName, argv[i],
  1306. min( _tcslen(argv[i]), cchMaxHostName/sizeof(TCHAR) -
  1307. sizeof(TCHAR) ));
  1308. g_szPortNameOrNo[ 0 ] = 0;
  1309. if( ++i >= argc )
  1310. {
  1311. continue;
  1312. }
  1313. if( IsCharAlpha( argv[i][0] ) ||
  1314. IsCharAlphaNumeric( argv[i][0] ) )
  1315. {
  1316. _tcsncpy( g_szPortNameOrNo, argv[i],
  1317. min( _tcslen(argv[i]), cchMaxHostName -
  1318. sizeof(TCHAR) ));
  1319. g_szPortNameOrNo[ cchMaxHostName -1 ] = 0;
  1320. }
  1321. else
  1322. {
  1323. // neither a port number nor a string representing
  1324. // a service. need to print usage
  1325. i--;
  1326. }
  1327. }
  1328. i++;
  1329. }
  1330. }
  1331. //MBSC user name value now available in szUser
  1332. if( wcscmp( szUserName, ( LPTSTR )L"" ) != 0 )
  1333. {
  1334. DWORD dwNum = 0;
  1335. dwNum = WideCharToMultiByte( GetConsoleCP(), 0, szUserName, -1, NULL, 0, NULL, NULL );
  1336. if(dwNum)
  1337. szUser = ( CHAR * ) malloc( dwNum * sizeof( CHAR ) );
  1338. else
  1339. return 0;
  1340. if( !szUser )
  1341. {
  1342. return 0;
  1343. }
  1344. dwNum = WideCharToMultiByte( GetConsoleCP(), 0, szUserName, -1, szUser, dwNum, NULL, NULL );
  1345. }
  1346. sTelnetCommands[0].sName = szClose;
  1347. sTelnetCommands[0].pCmdHandler = CloseTelnetSession;
  1348. sTelnetCommands[1].sName = szDisplay;
  1349. sTelnetCommands[1].pCmdHandler = DisplayParameters;
  1350. sTelnetCommands[2].sName = szHelpStr;
  1351. sTelnetCommands[2].pCmdHandler = PrintHelpStr;
  1352. sTelnetCommands[3].sName = szOpen;
  1353. sTelnetCommands[3].pCmdHandler = OpenTelnetSession;
  1354. sTelnetCommands[4].sName = szQuit;
  1355. sTelnetCommands[4].pCmdHandler = QuitTelnet;
  1356. sTelnetCommands[5].sName = szSend;
  1357. sTelnetCommands[5].pCmdHandler = SendOptions;
  1358. sTelnetCommands[6].sName = szSet;
  1359. sTelnetCommands[6].pCmdHandler = SetOptions;
  1360. sTelnetCommands[7].sName = szStatus;
  1361. sTelnetCommands[7].pCmdHandler = PrintStatus;
  1362. sTelnetCommands[8].sName = szUnset;
  1363. sTelnetCommands[8].pCmdHandler = UnsetOptions;
  1364. if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1365. {
  1366. int i;
  1367. for( i=0 ; i<NUMBER_OF_KANJI ; i++ )
  1368. {
  1369. LoadString(ghInstance, KanjiList[i].KanjiMessageID,
  1370. KanjiList[i].KanjiDescription, 255);
  1371. }
  1372. LoadString(ghInstance, IDS_VT100KANJI_EMULATION, szVT100KanjiEmulation, SMALL_STRING);
  1373. }
  1374. // Setup the Handle Routine for Ctrl-C etc.
  1375. SetConsoleCtrlHandler(&ControlHandler, TRUE);
  1376. /* Fill in window class structure with parameters that describe the
  1377. * main window.
  1378. */
  1379. wc.style = CS_VREDRAW | CS_HREDRAW;
  1380. wc.lpfnWndProc = MainWndProc;
  1381. wc.cbClsExtra = 0;
  1382. wc.cbWndExtra = sizeof(HANDLE)+sizeof(SVI *);
  1383. wc.hInstance = ghInstance;
  1384. wc.hIcon = NULL;
  1385. wc.hCursor = NULL;
  1386. wc.hbrBackground= ( HBRUSH )( COLOR_WINDOW + 1 );
  1387. wc.lpszMenuName = NULL;
  1388. wc.lpszClassName= ( LPTSTR )TEXT("TelnetClient");
  1389. /* Register the window class and return success/failure code. */
  1390. if ( RegisterClass(&wc) == 0 )
  1391. return GetLastError();
  1392. pwi->hwnd = CreateWindow( ( LPTSTR )TEXT("TelnetClient"),
  1393. NULL,
  1394. WS_POPUP, // not visible
  1395. 0, 0, 0, 0, // not height or width
  1396. NULL, NULL, ghInstance, (LPVOID)pwi);
  1397. if ( pwi->hwnd == NULL )
  1398. return GetLastError();
  1399. g_hRemoteNEscapeModeDataSync = CreateEvent( NULL, TRUE, TRUE, NULL );
  1400. if( !g_hRemoteNEscapeModeDataSync )
  1401. {
  1402. return GetLastError();
  1403. }
  1404. return 0;
  1405. }
  1406. // maps window messages to their names.
  1407. /****************************************************************************
  1408. FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM)
  1409. PURPOSE: Processes messages
  1410. COMMENTS:
  1411. To process the IDM_ABOUT message, call MakeProcInstance() to get the
  1412. current instance address of the About() function. Then call Dialog
  1413. box which will create the box according to the information in your
  1414. WinTel.rc file and turn control over to the About() function. When
  1415. it returns, free the intance address.
  1416. ****************************************************************************/
  1417. LRESULT CALLBACK
  1418. MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1419. {
  1420. static HANDLE hInst = NULL;
  1421. static BOOL fInited = FALSE;
  1422. WI *pwi = NULL;
  1423. BOOL fRet = FALSE;
  1424. CHARSETINFO csi;
  1425. DWORD_PTR dw;
  1426. if ( message != WM_CREATE )
  1427. pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  1428. switch ( message )
  1429. {
  1430. case WM_CREATE:
  1431. DEBUG_PRINT(("WM_CREATE received\n"));
  1432. hInst = ((LPCREATESTRUCT)lParam)->hInstance;
  1433. pwi = (WI *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  1434. SetWindowLongPtr(hwnd, WL_TelWI, (LONG_PTR)pwi);
  1435. fHungUp = FALSE;
  1436. if( FGetCodeMode(eCodeModeIMEFarEast) )
  1437. {
  1438. if ( ui.fDebug & fdwKanjiModeMask )
  1439. {
  1440. dw = GetACP();
  1441. if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
  1442. {
  1443. csi.ciCharset = ANSI_CHARSET;
  1444. }
  1445. ui.lf.lfCharSet = (UCHAR)csi.ciCharset;
  1446. ui.lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  1447. ui.lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  1448. ui.lf.lfQuality = DEFAULT_QUALITY;
  1449. ui.lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  1450. //
  1451. // Get IME Input Context.
  1452. //
  1453. hImeContext = ImmGetContext(hwnd);
  1454. //
  1455. // Assoicate current font to Input Context.
  1456. //
  1457. ImmSetCompositionFont(hImeContext,&ui.lf);
  1458. }
  1459. }
  1460. if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1461. // (a-roopb) we set this in GetUserSettings()
  1462. // pwi->trm.puchCharSet = rgchCharSetWorkArea;
  1463. // if(!SetConsoleOutputCP(932))
  1464. // MessageBox(NULL, _T("Failed to load Codepage 932"), _T("ERROR"), MB_OK);
  1465. ;
  1466. else
  1467. pwi->trm.puchCharSet = rgchNormalChars;
  1468. if (pwi->nd.lpReadBuffer = (LPSTR)LocalAlloc(LPTR, sizeof(UCHAR)*READ_BUF_SZ))
  1469. {
  1470. pwi->nd.SessionNumber = nSessionNone;
  1471. fRet = TRUE;
  1472. }
  1473. else
  1474. {
  1475. DestroyWindow( hwnd );
  1476. break;
  1477. }
  1478. if (!(pwi->nd.lpTempBuffer = (LPSTR)LocalAlloc(LPTR, sizeof(UCHAR)*READ_BUF_SZ)))
  1479. {
  1480. DestroyWindow( hwnd );
  1481. break;
  1482. }
  1483. pwi->nd.cbOld = 0;
  1484. pwi->nd.fRespondedToWillEcho = FALSE;
  1485. pwi->nd.fRespondedToWillSGA = FALSE;
  1486. pwi->nd.fRespondedToDoAUTH = FALSE;
  1487. pwi->nd.fRespondedToDoNAWS = FALSE;
  1488. //we are making sure that we always have VT100 arrow key support
  1489. ClearVTArrow(&pwi->trm);
  1490. //
  1491. // (a-roopb) We set these in GetUserSettings()
  1492. //ui.fDebug &= ~(fdwVT52Mode|fdwVT80Mode);
  1493. //ClearVT80(&gwi.trm);
  1494. //ClearKanjiStatus(&gwi.trm, CLEAR_ALL);
  1495. //ClearKanjiFlag(&gwi.trm);
  1496. //SetupCharSet(&gwi.trm);
  1497. //
  1498. #if 0
  1499. if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1500. {
  1501. if (ui.fDebug & fdwVT80Mode)
  1502. {
  1503. DWORD iMode = (ui.fDebug & fdwKanjiModeMask);
  1504. INT i;
  1505. SetVT80(&pwi->trm);
  1506. /* set current selection */
  1507. for(i=0 ; i<NUMBER_OF_KANJI ; i++)
  1508. {
  1509. if(iMode == KanjiList[i].KanjiID) {
  1510. SetKanjiMode(&pwi->trm,KanjiList[i].KanjiEmulationID);
  1511. break;
  1512. }
  1513. }
  1514. if(i == NUMBER_OF_KANJI ) {
  1515. /* set default */
  1516. SetSJISKanji(&pwi->trm);
  1517. ui.fDebug &= ~fdwKanjiModeMask;
  1518. ui.fDebug |= fdwSJISKanjiMode;
  1519. }
  1520. }
  1521. else
  1522. {
  1523. ClearKanjiFlag(&pwi->trm);
  1524. ClearVT80(&pwi->trm);
  1525. }
  1526. }
  1527. if (ui.fDebug & fdwVT100CursorKeys)
  1528. {
  1529. ClearVTArrow(&pwi->trm);
  1530. }
  1531. else
  1532. {
  1533. SetVTArrow(&pwi->trm);
  1534. }
  1535. /* Append the most recently connected machines to the Machine menu */
  1536. hmenu = HmenuGetMRUMenu(hwnd, &ui);
  1537. if (ui.cMachines > 0) {
  1538. AppendMenu(hmenu, MF_SEPARATOR, 0, 0);
  1539. }
  1540. for (i=0; i<ui.cMachines; ++i)
  1541. {
  1542. wsprintf(pchNBBuffer, szMachineMenuItem, (short)(i+1),
  1543. (BYTE *)(ui.rgchMachine[i]));
  1544. AppendMenu(hmenu, (UINT)(MF_ENABLED | MF_STRING), (UINT)(IDM_MACHINE1+i),
  1545. (LPCSTR)pchNBBuffer);
  1546. }
  1547. /* Disable maximizing or resizing the main window */
  1548. hmenu = GetSystemMenu(hwnd, FALSE);
  1549. // EnableMenuItem(hmenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
  1550. // EnableMenuItem(hmenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
  1551. DrawMenuBar( hwnd );
  1552. #endif
  1553. fInited = TRUE;
  1554. break;
  1555. case WM_CLOSE:
  1556. if (pwi->ichTelXfer != 0)
  1557. {
  1558. if (!FTelXferEnd(pwi, SV_DISCONNECT))
  1559. break;
  1560. }
  1561. break;
  1562. case WM_DESTROY:
  1563. if (pwi != NULL)
  1564. {
  1565. if (pwi->trm.uTimer != 0)
  1566. {
  1567. KillTimer(hwnd, uTerminalTimerID);
  1568. pwi->trm.uTimer = 0;
  1569. }
  1570. if (pwi->ichTelXfer != 0)
  1571. {
  1572. (void)FTelXferEnd(pwi, SV_QUIT);
  1573. }
  1574. /*
  1575. * If in session then cancel current transmission and
  1576. * hangup on the host, close shop and head out of town...
  1577. */
  1578. if (fInited == TRUE)
  1579. {
  1580. SetUserSettings(&ui);
  1581. FCloseConnection(hwnd);
  1582. }
  1583. }
  1584. SetWindowLong(hwnd, WL_TelWI, 0L);
  1585. if( FGetCodeMode(eCodeModeIMEFarEast) )
  1586. {
  1587. if ( ui.fDebug & fdwKanjiModeMask )
  1588. {
  1589. //
  1590. // Release input context.
  1591. //
  1592. ImmReleaseContext(hwnd,hImeContext);
  1593. }
  1594. }
  1595. break;
  1596. #if 0
  1597. case NN_HOSTRESOLVED:
  1598. if ( WSAGETASYNCERROR(lParam) == 0 )
  1599. pwi->nd.host = (struct hostent *)pwi->nd.szResolvedHost;
  1600. else
  1601. {
  1602. g_dwSockErr = WSAGETASYNCERROR(lParam);
  1603. }
  1604. SetEvent( g_hAsyncGetHostByNameEvent );
  1605. break;
  1606. #endif
  1607. case NN_LOST: /* Connection Lost */
  1608. DEBUG_PRINT(("NN_LOST received\n"));
  1609. if (fConnected && !fHungUp)
  1610. {
  1611. DWORD dwNumWritten;
  1612. WriteConsole(pwi->hOutput, szConnectionLost, _tcslen(szConnectionLost), &dwNumWritten, NULL);
  1613. }
  1614. /*
  1615. * If a connection attempt is made when we already have a
  1616. * connection, we hang up the connection and then attempt
  1617. * to connect to the desired machine. A side effect of the
  1618. * hang up of the previous connection is that we get a
  1619. * NN_LOST notification. So after a
  1620. * connection-hangup-connection, we ignore the first NN_LOST
  1621. * notification.
  1622. */
  1623. if ( fHungUp )
  1624. {
  1625. fHungUp = FALSE;
  1626. break;
  1627. }
  1628. if( fClientLaunchedFromCommandPrompt )
  1629. {
  1630. g_lExitTelnet++;
  1631. }
  1632. else
  1633. {
  1634. DWORD dwWritten;
  1635. INPUT_RECORD iRec;
  1636. TCHAR wcChar;
  1637. TCHAR szContinue[ MAX_STRING_LENGTH ];
  1638. LoadString(ghInstance, IDS_CONTINUE, szContinue,
  1639. sizeof(szContinue)/sizeof(TCHAR) );
  1640. SetConsoleActiveScreenBuffer( g_hSessionConsoleBuffer );
  1641. WriteConsole(g_hSessionConsoleBuffer, szContinue,
  1642. _tcslen(szContinue), &dwWritten, NULL);
  1643. ReadConsole(pwi->hInput, &wcChar, 1, &dwWritten, NULL );
  1644. SetConsoleActiveScreenBuffer( g_hTelnetPromptConsoleBuffer );
  1645. /*
  1646. We had connection and it broke off. Our ReadConsoleInput is stuck.
  1647. we need to wake it up by writing something to Console Input.
  1648. */
  1649. {
  1650. iRec.EventType = FOCUS_EVENT;
  1651. WriteConsoleInput(pwi->hInput, &iRec, 1, &dwWritten );
  1652. }
  1653. CloseTelnetSession( NULL );
  1654. }
  1655. if (pwi->ichTelXfer != 0)
  1656. {
  1657. (void)FTelXferEnd(pwi, SV_HANGUP);
  1658. }
  1659. fConnected = FHangupConnection(pwi, &pwi->nd);
  1660. DoTermReset(pwi, &pwi->trm);
  1661. //when the term name is given after -t without
  1662. //any spaces. 2 accounts for -t.
  1663. pwi->nd.cbOld = 0;
  1664. pwi->nd.fRespondedToWillEcho = FALSE;
  1665. pwi->nd.fRespondedToWillSGA = FALSE;
  1666. pwi->nd.fRespondedToDoAUTH = FALSE;
  1667. pwi->nd.fRespondedToDoNAWS = FALSE;
  1668. pwi->nd.hsd = INVALID_SOCKET;
  1669. break;
  1670. #ifdef USETCP
  1671. case WS_ASYNC_SELECT:
  1672. #ifdef TCPTEST
  1673. snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "WS_ASYNC_SELECT(%d) received\n",
  1674. WSAGETSELECTEVENT(lParam));
  1675. OutputDebugString(DebugBuffer);
  1676. #endif
  1677. switch (WSAGETSELECTEVENT(lParam)) {
  1678. case FD_READ:
  1679. DEBUG_PRINT(("FD_READ received\n"));
  1680. FProcessFDRead(hwnd);
  1681. break;
  1682. case FD_WRITE:
  1683. DEBUG_PRINT(( "FD_WRITE received\n" ));
  1684. //FProcessFDWrite(hwnd);
  1685. break;
  1686. case FD_CLOSE:
  1687. DEBUG_PRINT(("FD_CLOSE received\n"));
  1688. (void)PostMessage((HWND)hwnd, (UINT)NN_LOST, (WPARAM)0, (LPARAM)(void FAR *)hwnd);
  1689. break;
  1690. case FD_OOB:
  1691. DEBUG_PRINT(("FD_OOB received\n"));
  1692. FProcessFDOOB(hwnd);
  1693. break;
  1694. }
  1695. #endif
  1696. default: /* Passes it on if unprocessed */
  1697. // defresp:
  1698. // DEBUG_PRINT(( "<-- MainWndProc()\n" ));
  1699. return (DefWindowProc(hwnd, message, wParam, lParam));
  1700. }
  1701. DEBUG_PRINT(( "<-- MainWndProc() returning 0.\n" ));
  1702. return (0);
  1703. }
  1704. void
  1705. GetUserSettings(UI *pui)
  1706. {
  1707. LONG lErr;
  1708. HKEY hkey = 0;
  1709. DWORD dwType;
  1710. DWORD dwDisp = 0;
  1711. TCHAR rgchValue[48];
  1712. LCID lcid;
  1713. DWORD dwMode = ( DWORD )-1;
  1714. DWORD dwSize = 0;
  1715. TCHAR szTlntMode[ SMALL_STRING+1 ];
  1716. BOOL bResetVT80 = TRUE;
  1717. DWORD dwStatus = 0;
  1718. lcid = GetThreadLocale();
  1719. lErr = RegCreateKeyEx(HKEY_CURRENT_USER,TEXT("Software\\Microsoft\\Telnet"),
  1720. 0, NULL, REG_OPTION_NON_VOLATILE,
  1721. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1722. NULL, &hkey, &dwDisp);
  1723. if (lErr != ERROR_SUCCESS)
  1724. {
  1725. if ( FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1726. gwi.trm.puchCharSet = rgchCharSetWorkArea;
  1727. return;
  1728. }
  1729. dwDisp = sizeof(gwi.trm.RequestedTermType);
  1730. if( ERROR_SUCCESS != (RegQueryValueEx(hkey, TEXT("TERMTYPE"), NULL, &dwType,
  1731. (LPBYTE)&gwi.trm.RequestedTermType, &dwDisp)))
  1732. {
  1733. gwi.trm.RequestedTermType = TT_ANSI;
  1734. }
  1735. dwDisp = sizeof(DWORD);
  1736. if( ERROR_SUCCESS != (RegQueryValueEx(hkey,TEXT("NTLM"), NULL, &dwType,
  1737. (LPBYTE)&ui.bWillAUTH, &dwDisp)))
  1738. {
  1739. ui.bWillAUTH = TRUE;
  1740. }
  1741. /* Get the value of the left size of the Window */
  1742. LoadString(ghInstance, IDS_DEBUGFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1743. dwDisp = sizeof(pui->fDebug);
  1744. if ( FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1745. {
  1746. if( ERROR_SUCCESS != RegQueryValueEx(hkey, rgchValue, NULL, &dwType,
  1747. (LPBYTE)&pui->fDebug, &dwDisp))
  1748. {
  1749. /* default is VT80/Kanji and Shift-Jis mode */
  1750. pui->fDebug |= (fdwVT80Mode | fdwSJISKanjiMode);
  1751. }
  1752. }
  1753. else
  1754. (void)RegQueryValueEx(hkey, rgchValue, NULL, &dwType,
  1755. (LPBYTE)&pui->fDebug, &dwDisp);
  1756. LoadString(ghInstance, IDS_PROMPTFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1757. dwDisp = sizeof(pui->fPrompt);
  1758. (void)RegQueryValueEx(hkey, rgchValue, NULL, &dwType,
  1759. (LPBYTE)&pui->fPrompt, &dwDisp);
  1760. dwDisp = sizeof(BOOL);
  1761. if( ERROR_SUCCESS != (RegQueryValueEx(hkey, TEXT("BSASDEL"), 0, &dwType,
  1762. (LPBYTE)&g_bSendBackSpaceAsDel, &dwDisp )))
  1763. {
  1764. g_bSendBackSpaceAsDel = 0;
  1765. }
  1766. dwDisp = sizeof(BOOL);
  1767. if( ERROR_SUCCESS != (RegQueryValueEx(hkey, TEXT("DELASBS"), 0, &dwType,
  1768. (LPBYTE)&g_bSendDelAsBackSpace, &dwDisp )))
  1769. {
  1770. g_bSendDelAsBackSpace = 0;
  1771. }
  1772. dwDisp = sizeof( ui.dwCrLf );
  1773. if( ERROR_SUCCESS != (RegQueryValueEx(hkey, TEXT("CRLF"), 0, &dwType, (LPBYTE)&ui.dwCrLf, &dwDisp )))
  1774. {
  1775. /*++
  1776. The most significant bit in ui.fDebug ( read from HKCU\Software\Microsoft\telnet\DebugFlags)
  1777. corresponds to CRLF setting on w2k. If this bit is 1, then the client sends only CR.
  1778. If this bit is 0, client sends both CR,LF. When we don't find CRLF value
  1779. in HKCU\Software\Microsoft\telnet, that could mean two things
  1780. 1. User has upgraded from w2k : In this case, we should check whether the user had
  1781. changed CRLF setting and honor that setting. So if MSBit of ui.fDebug is 1, setting is CR
  1782. else it's CR & LF.
  1783. 2. Fresh whistler installation : In this case, MSBit of fDebug will be 0
  1784. so the client will send CR & LF, which is the default.
  1785. --*/
  1786. if(ui.fDebug & fdwOnlyCR)
  1787. {
  1788. ui.dwCrLf = FALSE;
  1789. ClearLineMode( &( gwi.trm ) );
  1790. }
  1791. else //this means that we upgraded from w2k and CRLF was set on w2k so preserve
  1792. {
  1793. ui.dwCrLf = TRUE;
  1794. SetLineMode( &( gwi.trm ) );
  1795. }
  1796. }
  1797. else
  1798. {
  1799. ui.dwCrLf ? SetLineMode(&( gwi.trm )): ClearLineMode(&(gwi.trm));
  1800. }
  1801. dwDisp = MAX_PATH + 1;
  1802. dwStatus = RegQueryValueEx(hkey, TEXT("MODE"), 0, &dwType, (LPBYTE)szTlntMode, &dwDisp );
  1803. if( _tcsicmp( szTlntMode, L"Stream" ) != 0 && _tcsicmp( szTlntMode, L"Console" ) != 0)
  1804. {
  1805. _tcscpy( szTlntMode, L"Console" );//no overflow. Source string is const wchar *.
  1806. }
  1807. SetEnvironmentVariable( TEXT( SFUTLNTMODE ), szTlntMode );
  1808. if ( FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1809. {
  1810. // Bug Emulation in VT100/Kanji(VT80)
  1811. // Abnormal AP is mh-e6.2 for PC-UX.
  1812. LoadString(ghInstance, IDS_BUGEMUFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1813. dwDisp = sizeof(pui->fBugEmulation);
  1814. if( ERROR_SUCCESS != RegQueryValueEx(hkey, rgchValue, NULL, &dwType,
  1815. (LPBYTE)&pui->fBugEmulation, &dwDisp))
  1816. {
  1817. /* default is non Emulation */
  1818. pui->fBugEmulation = (DWORD)0;
  1819. }
  1820. // ACOS-KANJI Support Flga
  1821. LoadString(ghInstance, IDS_ACOSFLAG, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1822. dwDisp = sizeof(pui->fAcosSupportFlag);
  1823. if( ERROR_SUCCESS != RegQueryValueEx(hkey, rgchValue, NULL, &dwType,
  1824. (LPBYTE)&pui->fAcosSupportFlag, &dwDisp
  1825. )) {
  1826. /* Set default support */
  1827. #if defined(_X86_)
  1828. /* if NEC_98 */
  1829. if (( FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)) &&
  1830. (HIBYTE(LOWORD(GetKeyboardType(1))) == 0x0D))
  1831. pui->fAcosSupportFlag = fAcosSupport;
  1832. else
  1833. #endif // defined(_X86_)
  1834. pui->fAcosSupportFlag = (DWORD)0;
  1835. }
  1836. if ( !(pui->fAcosSupportFlag & fAcosSupport)
  1837. && ((fdwVT80Mode | fdwACOSKanjiMode) == (pui->fDebug & (fdwVT80Mode |
  1838. fdwACOSKanjiMode))) ) {
  1839. pui->fDebug &= ~(fdwVT80Mode | fdwACOSKanjiMode);
  1840. pui->fDebug |= (fdwVT80Mode | fdwSJISKanjiMode);
  1841. }
  1842. if( (GetACP() == JAP_CODEPAGE ) && ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("CODESET"), NULL, &dwType,
  1843. (LPBYTE)&dwMode, &dwDisp))
  1844. {
  1845. if( (LONG)dwMode >= 0 )
  1846. {
  1847. int i;
  1848. for( i=0 ; i<NUMBER_OF_KANJI ; ++i )
  1849. {
  1850. if( dwMode == KanjiList[i].KanjiID )
  1851. {
  1852. bResetVT80 = FALSE;
  1853. SetVT80(&gwi.trm);
  1854. ui.fDebug &= ~fdwKanjiModeMask;
  1855. ClearKanjiFlag(&gwi.trm);
  1856. ui.fDebug |= KanjiList[i].KanjiID;
  1857. ui.fDebug |= fdwVT80Mode;
  1858. SetKanjiMode(&gwi.trm,KanjiList[i].KanjiEmulationID);
  1859. gwi.trm.puchCharSet = rgchCharSetWorkArea;
  1860. SetupCharSet(&gwi.trm);
  1861. break;
  1862. }
  1863. }
  1864. }
  1865. }
  1866. if( bResetVT80 )
  1867. {
  1868. ui.fDebug &= ~(fdwVT52Mode|fdwVT80Mode);
  1869. ui.fDebug &= ~(fdwKanjiModeMask);
  1870. ClearVT80(&gwi.trm);
  1871. ClearKanjiStatus(&gwi.trm, CLEAR_ALL);
  1872. ClearKanjiFlag(&gwi.trm);
  1873. gwi.trm.puchCharSet = rgchCharSetWorkArea;
  1874. SetupCharSet(&gwi.trm);
  1875. }
  1876. }
  1877. RegCloseKey( hkey );
  1878. }
  1879. void
  1880. SetUserSettings(UI *pui)
  1881. {
  1882. LONG lErr;
  1883. HKEY hkey = 0;
  1884. TCHAR rgchValue[48];
  1885. LCID lcid;
  1886. DWORD dwMode = ( DWORD )-1;
  1887. DWORD dwSize = 0;
  1888. TCHAR szTlntMode[ SMALL_STRING+1 ];
  1889. lcid = GetThreadLocale();
  1890. lErr = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Telnet"),
  1891. 0, KEY_SET_VALUE, &hkey);
  1892. if (lErr != ERROR_SUCCESS)
  1893. {
  1894. return;
  1895. }
  1896. #ifdef TCPTEST
  1897. snprintf(DebugBuffer, sizeof(DebugBuffer)-1,"End pui -> text = %lx, back = %lx\n",
  1898. pui->clrText, pui->clrBk);
  1899. OutputDebugString(DebugBuffer);
  1900. #endif
  1901. RegSetValueEx(hkey, TEXT("TERMTYPE"), 0, REG_DWORD,
  1902. (LPBYTE)&gwi.trm.RequestedTermType, sizeof(DWORD));
  1903. RegSetValueEx(hkey, TEXT("NTLM"), 0, REG_DWORD,
  1904. (LPBYTE)&ui.bWillAUTH, sizeof(DWORD));
  1905. //Make localecho non-sticky.
  1906. pui->fDebug &= ~fdwLocalEcho;
  1907. LoadString(ghInstance, IDS_DEBUGFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1908. (void)RegSetValueEx(hkey, rgchValue, 0, REG_DWORD,
  1909. (LPBYTE)&pui->fDebug, sizeof(DWORD));
  1910. LoadString(ghInstance, IDS_PROMPTFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1911. (void)RegSetValueEx(hkey, rgchValue, 0, REG_DWORD,
  1912. (LPBYTE)&pui->fPrompt, sizeof(DWORD));
  1913. RegSetValueEx(hkey, TEXT("BSASDEL"), 0, REG_DWORD,
  1914. (LPBYTE)&g_bSendBackSpaceAsDel, sizeof(DWORD));
  1915. RegSetValueEx(hkey, TEXT("DELASBS"), 0, REG_DWORD,
  1916. (LPBYTE)&g_bSendDelAsBackSpace, sizeof(DWORD));
  1917. RegSetValueEx(hkey, ( LPTSTR )TEXT("CRLF"), 0, REG_DWORD, (LPBYTE)&ui.dwCrLf, sizeof(DWORD));
  1918. dwSize = GetEnvironmentVariable( TEXT( SFUTLNTMODE ), szTlntMode, SMALL_STRING+1 );
  1919. if( dwSize <= 0 )
  1920. {
  1921. wcscpy( szTlntMode, L"Console" );//no overflow. Source string is const wchar *.
  1922. }
  1923. dwSize = 2 * wcslen( szTlntMode );
  1924. RegSetValueEx(hkey,TEXT("MODE"), 0, REG_SZ, (LPBYTE)szTlntMode, dwSize );
  1925. if ( (GetACP() == JAP_CODEPAGE ) && FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
  1926. {
  1927. // Bug Emulation in VT100/Kanji(VT80)
  1928. // Abnormal AP is mh-e6.2 for PC-UX.
  1929. LoadString(ghInstance, IDS_BUGEMUFLAGS, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1930. (void)RegSetValueEx(hkey, rgchValue, 0, REG_DWORD,
  1931. (LPBYTE)&pui->fBugEmulation, sizeof(DWORD));
  1932. // ACOS-KANJI Support Flga
  1933. LoadString(ghInstance, IDS_ACOSFLAG, rgchValue, sizeof(rgchValue)/sizeof(TCHAR));
  1934. (void)RegSetValueEx(hkey, rgchValue, 0, REG_DWORD,
  1935. (LPBYTE)&pui->fAcosSupportFlag, sizeof(DWORD));
  1936. if ( ui.fDebug & fdwKanjiModeMask )
  1937. {
  1938. dwMode = ui.fDebug & fdwKanjiModeMask;
  1939. }
  1940. (void)RegSetValueEx(hkey, TEXT("CODESET"), 0, REG_DWORD, (LPBYTE)&dwMode, sizeof(DWORD));
  1941. }
  1942. RegCloseKey( hkey );
  1943. }
  1944. /*
  1945. Description:
  1946. Set SO_EXCLUSIVEADDRUSE on a socket.
  1947. Parameters:
  1948. [in] socket
  1949. Return Values: On error, returns SOCKET_ERROR.
  1950. */
  1951. int SafeSetSocketOptions(SOCKET s)
  1952. {
  1953. int iStatus;
  1954. int iSet = 1;
  1955. iStatus = setsockopt( s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE , ( char* ) &iSet,
  1956. sizeof( iSet ) );
  1957. return ( iStatus );
  1958. }
  1959. void
  1960. ErrorMessage(LPCTSTR pStr1, LPCTSTR pStr2)
  1961. {
  1962. DWORD dwWritten;
  1963. WriteConsole(gwi.hOutput, pStr1, _tcslen(pStr1), &dwWritten, NULL);
  1964. WriteConsole(gwi.hOutput, ( LPTSTR )TEXT(": "), _tcslen( ( LPTSTR )TEXT(": ")), &dwWritten, NULL);
  1965. WriteConsole(gwi.hOutput, pStr2, _tcslen(pStr2), &dwWritten, NULL);
  1966. WriteConsole(gwi.hOutput, ( LPTSTR )TEXT("\n"), _tcslen( ( LPTSTR )TEXT("\n")), &dwWritten, NULL);
  1967. }
  1968. void ConnectTimeErrorMessage(LPCTSTR pStr1, LPCTSTR pStr2)
  1969. {
  1970. DWORD dwWritten;
  1971. WriteConsole(gwi.hOutput, pStr1, _tcslen(pStr1), &dwWritten, NULL);
  1972. WriteConsole(gwi.hOutput, ( LPTSTR )TEXT("."), _tcslen( ( LPTSTR )TEXT(".")), &dwWritten, NULL);
  1973. WriteConsole(gwi.hOutput, ( LPTSTR )TEXT("\n"), _tcslen( ( LPTSTR )TEXT("\n")), &dwWritten, NULL);
  1974. WriteConsole(gwi.hOutput, pStr2, _tcslen(pStr2), &dwWritten, NULL);
  1975. WriteConsole(gwi.hOutput, ( LPTSTR )TEXT("\n"), _tcslen( ( LPTSTR )TEXT("\n")), &dwWritten, NULL);
  1976. }