|
|
//Copyright (c) Microsoft Corporation. All rights reserved.
/****************************************************************************
FILE: NetIO.c
Functions for connecting to machines and handling data transfers between machines.
TABS:
Set for 4 spaces.
****************************************************************************/
#include <stdio.h>
#include <windows.h> // required for all Windows applications
#include <lmcons.h>
#include <tchar.h>
#pragma warning (disable: 4201) // disable "nonstandard extension used : nameless struct/union"
#include <commdlg.h>
#pragma warning (default: 4201)
#include <stdlib.h>
#include "WinTel.h" // specific to this program
#include "commands.h"
#include "debug.h"
#pragma warning( disable : 4100 )
#ifdef USETCP
#include "telnet.h"
#endif
char *rgchTermType[] = { "ANSI", "VT100", "VT52", "VTNT" };
extern void NTLMCleanup(); extern BOOL DoNTLMAuth(WI *pwi, PUCHAR pBuffer, DWORD dwSize); extern int SafeSetSocketOptions(SOCKET s);
BOOL g_fSentWillNaws = FALSE; static BOOL FAttemptServerConnect(WI *pwi, LPSTR, LPNETDATA); static void xfGetData(char, char *, DWORD, int); #ifdef USETCP
#ifdef TELXFER
static DWORD xfGetSomeData(char *, DWORD, int); #endif //TELXFER
#endif //USETCP
static void xfPutc(char, int);
static int term_inx = 0;
extern BOOL StartNTLMAuth(WI *); extern TCHAR szUserName[ UNLEN + 1 ]; extern CHAR* szUser;
TCHAR szCombinedFailMsg [255];
extern HANDLE g_hControlHandlerEvent; extern HANDLE g_hCaptureConsoleEvent; extern HANDLE g_hAsyncGetHostByNameEvent; extern HANDLE g_hRemoteNEscapeModeDataSync; extern BOOL g_fConnectFailed;
void GetErrMsgString( DWORD dwErrNum, LPTSTR *lpBuffer ) { DWORD dwStatus = 0; LCID old_thread_locale;
switch (GetACP()) { // for Hebrew and arabic winerror.h is not localized..so get the english one for all these
case 1256: case 1255:
old_thread_locale = GetThreadLocale();
SetThreadLocale( MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT ) ); break;
default: old_thread_locale = -1; }
dwStatus = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrNum, LANG_NEUTRAL, ( LPTSTR )lpBuffer, 0, NULL );
if( !dwStatus ) { *lpBuffer = NULL; }
if (old_thread_locale != -1) { SetThreadLocale(old_thread_locale); }
return; }
BOOL FConnectToServer(WI *pwi, LPSTR szHostName, LPNETDATA lpData) { BOOL fResult;
// Before we Connect we make sure we are not connected.
// This ASSERT should never blowup !!
ASSERT(fConnected==FALSE);
// We initialize stuff for this connection.
pwi->trm.SentTermType = TT_UNKNOWN; pwi->trm.CurrentTermType = TT_ANSI; /* this is our default term type*/
fResult = FAttemptServerConnect(pwi, szHostName, lpData);
if( fResult != TRUE ) { TCHAR szStr[ cchMaxHostName ]; g_fConnectFailed = TRUE;
if( g_szPortNameOrNo[ 0 ] == 0 ) { _sntprintf( g_szPortNameOrNo,cchMaxHostName-1,( LPCTSTR )L"%d", rgService ); }
_sntprintf( szStr, cchMaxHostName -1 ,szOnPort, g_szPortNameOrNo ); _sntprintf(szCombinedFailMsg,ARRAY_SIZE(szCombinedFailMsg)-1,_T("%s%s"),szConnectFailedMsg,szStr);
g_szPortNameOrNo[ 0 ] = 0;
if( g_dwSockErr == 0 ) { //Not an error we want to inform abt
ErrorMessage( szCombinedFailMsg, szConnectFailed ); } else { DWORD dwWritten = 0; LPTSTR lpBuffer = NULL;
GetErrMsgString( g_dwSockErr, &lpBuffer ); if( lpBuffer ) { ConnectTimeErrorMessage( szCombinedFailMsg, lpBuffer ); LocalFree( lpBuffer ); } else { ErrorMessage( szCombinedFailMsg, szConnectFailed ); } } }
return fResult; }
#ifdef USETCP
/*** FPostReceive - post an asynchronous receive
*/ BOOL FPostReceive(LPNETDATA lpData) {
#ifdef NBTEST
OutputDebugString("PostReceive In\n"); #endif
#ifdef NBTEST
OutputDebugString("PostReceive Out\n"); #endif
return TRUE; }
int FWriteToNet(WI *pwi, LPSTR addr, int cnt) { int len = 0, retries = 0; if(pwi->nd.hsd == INVALID_SOCKET) { len = SOCKET_ERROR; goto Done; } do { len = send( pwi->nd.hsd, addr, cnt, 0 ); retries ++; } while ((len == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK) && (retries < 5)); Done: return(len); }
BOOL FCommandPending(WI *pwi) { return(FALSE); }
/*
void FSendTM( HWND hwnd ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[] = { IAC, DO, TO_TM };
ui.fFlushOut = 1; send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0); } */
//Our server still doesn't support urgent data handling..
void FSendSynch(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[] = { IAC, DM };
send( pwi->nd.hsd, ( char * )sbuf, 1, 0 );
send( pwi->nd.hsd, ( char * )( sbuf + 1 ), 1, MSG_OOB ); }
void FSendTelnetCommands( HWND hwnd, char chCommand ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[]={ IAC , 0 };
sbuf[1] = chCommand;
send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0 ); }
void FSendChars(HWND hwnd, WCHAR rgchChar[], int iLength ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); CHAR rgchMBChar[ SMALL_STRING ];
iLength = WideCharToMultiByte( GetConsoleCP(), 0, rgchChar, iLength, rgchMBChar, (SMALL_STRING - sizeof(CHAR)), NULL, NULL );
send( pwi->nd.hsd, rgchMBChar, iLength, 0 ); }
void FDisableFlush(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
if (ui.fFlushOut) { ui.fFlushOut = 0; DoIBMANSIOutput(pwi, &pwi->trm, strlen( ( CHAR * ) szNewLine), szNewLine); #ifdef TCPTEST
OutputDebugString("Disable Flush\n"); #endif
} }
void FProcessDont(WI *pwi, LPSTR *ps) { unsigned char sbuf[16];
sbuf[0] = IAC; sbuf[1] = WONT;
switch (*(unsigned char FAR *)(*ps)) {
default: sbuf[2] = *(unsigned char FAR *)(*ps); break; }
FWriteToNet(pwi, ( char* )sbuf, 3);
if( *(*ps) == TO_NAWS ) { g_bDontNAWSReceived = TRUE; } }
void DoNawsSubNegotiation( WI *pwi ) { unsigned char sbuf[16]; INT iIndex = 0;
sbuf[iIndex++] = IAC; sbuf[iIndex++] = SB; sbuf[iIndex++] = TO_NAWS; sbuf[iIndex++] = 0; sbuf[iIndex++] = ( UCHAR ) ( (pwi->sbi.srWindow.Right - pwi->sbi.srWindow.Left) + 1 ) ; sbuf[iIndex++] = 0; sbuf[iIndex++] = ( UCHAR )( ( pwi->sbi.srWindow.Bottom - pwi->sbi.srWindow.Top ) + 1 ); sbuf[iIndex++] = IAC; sbuf[iIndex++] = SE;
FWriteToNet(pwi, ( char* )sbuf, iIndex ); }
void FProcessDo(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; BOOL bWriteToNet = TRUE;
sbuf[0] = IAC; sbuf[1] = WONT;
switch (*(unsigned char FAR *)(*ps)) { case TO_NEW_ENVIRON: sbuf[1] = WILL; sbuf[2] = TO_NEW_ENVIRON; break; case TO_NAWS: { INT iIndex = 1;
if( !g_fSentWillNaws ) { sbuf[iIndex++] = WILL; sbuf[iIndex++] = TO_NAWS; FWriteToNet(pwi, ( char* )sbuf, iIndex ); g_fSentWillNaws = TRUE; }
DoNawsSubNegotiation( pwi ); pwi->nd.fRespondedToDoNAWS = TRUE; bWriteToNet = FALSE; } break;
case TO_ECHO: sbuf[1] = WILL; sbuf[2] = TO_ECHO; break;
case TO_BINARY: sbuf[1] = WILL; sbuf[2] = TO_BINARY; break;
case TO_TERM_TYPE: /* terminal type */ sbuf[1] = WILL; sbuf[2] = TO_TERM_TYPE;
if( !pwi->nd.fRespondedToDoNAWS && !g_fSentWillNaws ) { sbuf[3] = IAC; sbuf[4] = WILL; sbuf[5] = TO_NAWS; bWriteToNet = FALSE; FWriteToNet(pwi, ( char* )sbuf, 6); g_fSentWillNaws = TRUE; }
// haven't sent the termtype over yet.
pwi->trm.SentTermType = TT_UNKNOWN; break; case TO_AUTH:
if( pwi->nd.fRespondedToDoAUTH ) return;
if( ui.bWillAUTH ) sbuf[1] = WILL; sbuf[2] = TO_AUTH; pwi->nd.fRespondedToDoAUTH = TRUE; break;
case TO_SGA: // will SUPPRESS-GO-AHEAD
sbuf[1] = WILL; sbuf[2] = TO_SGA;
break;
default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } if ( bWriteToNet ) { FWriteToNet(pwi, ( char* )sbuf, 3); } }
void FProcessWont(WI *pwi, LPSTR *ps) { unsigned char sbuf[16];
sbuf[0] = IAC; sbuf[1] = DONT;
switch (*(unsigned char FAR *)(*ps)) {
case TO_ECHO: sbuf[2] = TO_ECHO; break; case TO_TERM_TYPE: sbuf[2] = TO_TERM_TYPE; break; case TO_TM: FDisableFlush(pwi->hwnd); return; default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } FWriteToNet(pwi, ( char* )sbuf, 3); }
void FProcessWill(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; BOOL bWriteToNet = TRUE;
sbuf[0] = IAC; sbuf[1] = DONT;
switch (*(unsigned char FAR *)(*ps)) {
case TO_ECHO:
if( pwi->nd.fRespondedToWillEcho ) return;
sbuf[1] = DO; sbuf[2] = TO_ECHO; pwi->nd.fRespondedToWillEcho = TRUE; break;
case TO_TM: FDisableFlush(pwi->hwnd); return;
case TO_SGA:
if( pwi->nd.fRespondedToWillSGA ) return;
sbuf[1] = DO; sbuf[2] = TO_SGA; pwi->nd.fRespondedToWillSGA = TRUE; break;
case TO_BINARY:
sbuf[1] = DO; sbuf[2] = TO_BINARY; break;
#if 0
case TO_NTLM:
if ( pwi->nd.fRespondedToWillNTLM ) return;
if ( ui.bDoNTLM ) sbuf[1] = DO; sbuf[2] = TO_NTLM; pwi->nd.fRespondedToWillNTLM = TRUE; if ( ui.bDoNTLM ) { bWriteToNet = FALSE; FWriteToNet(pwi, sbuf, 3); StartNTLMAuth(pwi); } break; #endif
default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } if ( bWriteToNet ) FWriteToNet(pwi, ( char* )sbuf, 3); }
BOOL StuffEscapeIACs( PUCHAR* ppBufDest, UCHAR bufSrc[], DWORD* pdwSize ) { size_t length; int cursorDest = 0; int cursorSrc = 0; BOOL found = FALSE; PUCHAR pDest = NULL; if( *pdwSize <= 0 ) { return ( found ); }
//get the location of the first occurrence of IAC
pDest = (PUCHAR) memchr( bufSrc, IAC, *pdwSize ); //attack? pdwsize could not be traced back to see if it's always valid.
if( pDest == NULL ) { return ( found ); }
*ppBufDest = (PUCHAR) malloc( *pdwSize * 2 ); if( *ppBufDest == NULL ) { ASSERT( ( 0, 0 ) ); return ( found ); } while( pDest != NULL ) { //copy data upto and including that point
length = (pDest - ( bufSrc + cursorSrc)) + 1 ; memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc, length ); //attack? length could not be traced back to see if it's always valid.
cursorDest += length;
//stuff another TC_IAC
(*ppBufDest)[ cursorDest ] = IAC; cursorDest++; cursorSrc += length; pDest = (PUCHAR) memchr( bufSrc + cursorSrc, IAC, *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid.
} //copy remaining data
memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc, *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid.
if( cursorDest ) { *pdwSize += cursorDest - cursorSrc; found = TRUE; } return ( found ); }
INT GetVariable( UCHAR rgchBuffer[], CHAR szVar[] ) { INT iIndex = 0; INT iVarIndex = 0;
while( iIndex < MAX_BUFFER_SIZE && iVarIndex < MAX_STRING_LENGTH && rgchBuffer[ iIndex ] != VAR && rgchBuffer[ iIndex ] != USERVAR && ( !( rgchBuffer[ iIndex ] == IAC && rgchBuffer[ iIndex + 1 ] == SE ) ) ) { if( rgchBuffer[ iIndex ] == ESC ) { //ignore ESC and take the next char as part of name
iIndex++; } szVar[ iVarIndex++ ] = rgchBuffer[ iIndex++ ]; }
szVar[ iVarIndex ] = 0; return iIndex; }
void PutDefaultVarsInBuffer( UCHAR ucBuffer[], INT *iIndex ) { ASSERT( iIndex );
if( wcscmp( szUserName, ( LPTSTR )L"" ) != 0 ) { DWORD dwNum;
ASSERT( szUser );
if( *iIndex + ( strlen( USER ) + 1 ) + ( strlen( szUser ) + 1 ) + ( strlen( SYSTEMTYPE ) + 1 ) + ( strlen( WIN32_STRING ) + 1 ) > MAX_STRING_LENGTH ) { ASSERT( 0 ); return; }
{ //variable USER
ucBuffer[ ( *iIndex )++ ] = VAR; strcpy( ucBuffer + ( *iIndex ), USER ); //no overflow. USER is const char *
*iIndex = *iIndex + strlen( USER ) ; ucBuffer[ ( *iIndex )++ ] = VALUE; strcpy(ucBuffer+( *iIndex ), szUser ); //no overflow. SzUser is valid, NULL terminated.
*iIndex = ( *iIndex ) + strlen( szUser); }
{ //variable SYSTEMTYPE
ucBuffer[( *iIndex )++] = VAR; strcpy(ucBuffer+( *iIndex ), SYSTEMTYPE ); //no overflow. SYSTEMTYPE is const char *
*iIndex = ( *iIndex ) + strlen( SYSTEMTYPE ); ucBuffer[( *iIndex )++] = VALUE; strcpy(ucBuffer+( *iIndex ), WIN32_STRING );//no overflow. WIN32_STRING is const char *
*iIndex = ( *iIndex ) + strlen( WIN32_STRING ); } }
return; }
void FProcessSB(WI * pwi, LPSTR *ps, int *recvsize) { unsigned char sbuf[16]; int inx; int i = 0; int cbLeft = *recvsize;
//
// Is the end of this option in the receive buffer?
//
while ( cbLeft ) { if ( ((unsigned char) (*ps)[i]) == (unsigned char) SE ) goto Found;
cbLeft--; i++; }
//
// We ran out of buffer before finding the end of the option. IAC and
// SB were already eaten so add them
//
#ifdef TCPTEST
OutputDebugString("FProcessSB: saving incomplete option for next recv\n");
#endif
pwi->nd.lpTempBuffer[0] = (unsigned char) IAC; pwi->nd.lpTempBuffer[1] = (unsigned char) SB;
for ( i = 2, cbLeft = (*recvsize+2); i < cbLeft; i++ ) pwi->nd.lpTempBuffer[i] = (*ps)[i-2];
pwi->nd.cbOld = *recvsize + 2; *recvsize = 0;
return;
Found: switch (*(unsigned char FAR *)(*ps)) {
case TO_NEW_ENVIRON:
//MBSC user name value now available in szUser
if( *(unsigned char FAR *)(*ps+1) == TT_SEND ) { PUCHAR ucServerSentBuffer = *ps;
UCHAR ucBuffer[ MAX_BUFFER_SIZE + 2 ]; int iIndex = 0; ucBuffer[ iIndex++ ] = ( UCHAR )IAC; ucBuffer[ iIndex++] = ( UCHAR )SB; ucBuffer[ iIndex++] = TO_NEW_ENVIRON; ucBuffer[ iIndex++] = TT_IS; inx = iIndex; if( *(unsigned char FAR *)(ucServerSentBuffer+2) == IAC && *(unsigned char FAR *)(ucServerSentBuffer+3) == SE ) { PutDefaultVarsInBuffer( ucBuffer, &inx ); }
else { ucServerSentBuffer = ucServerSentBuffer + 2 ; // eat TO_NEW_ENVIRON, TT_SEND
while ( !( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) && inx < MAX_BUFFER_SIZE ) { CHAR szVar[ MAX_STRING_LENGTH ]; CHAR *pcVal = NULL;
switch( *(unsigned char FAR *)(ucServerSentBuffer) ) { case VAR: ( ucServerSentBuffer )++; //eat VAR
if( ( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) || *ucServerSentBuffer == USERVAR ) { //send defaults
PutDefaultVarsInBuffer( ucBuffer, &inx ); } else { ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar ); //GetVariable returns consumed net data
if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[ inx++ ] = VAR;
//copy name of the variable
strncpy( ucBuffer+inx, szVar, MAX_BUFFER_SIZE - inx); inx += strlen( szVar ); }
//now copy the value if defined
if( strcmp( szVar, USER ) == 0 ) { if( inx + strlen( szUser ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = VALUE; strncpy(ucBuffer+inx, szUser, MAX_BUFFER_SIZE - inx ); inx = inx + strlen( szUser); } } else if( strncmp( szVar, SYSTEMTYPE, strlen( SYSTEMTYPE ) ) == 0 ) { if( inx + strlen( WIN32_STRING ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = VALUE; strncpy(ucBuffer+ inx, WIN32_STRING,MAX_BUFFER_SIZE - inx ); inx = inx + strlen( WIN32_STRING ); } } else { //do nothing. It means, variable is undefined
} } break;
case USERVAR: ( ucServerSentBuffer )++; //eat USERVAR
if( ( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) || *ucServerSentBuffer == VAR ) { //send defaults ie; NONE
} else { //Send the variable that is asked for
DWORD dwSize = 0; ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar ); if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = USERVAR; strncpy( ucBuffer+inx, szVar,MAX_BUFFER_SIZE - inx ); inx += strlen( szVar ); } dwSize = GetEnvironmentVariableA( szVar, NULL, 0 );
if( dwSize > 0 ) { pcVal = ( CHAR * ) malloc( dwSize + DELTA ); //This delta is meant for
//holding any ESC chars
if( !pcVal ) { return; } if( GetEnvironmentVariableA( szVar, pcVal, dwSize ) ) { INT x = 0; INT iNeedForEsc = 0; CHAR cVar = VAR, cUserVar = USERVAR;
x = strlen( pcVal ) - 1; while( x >= 0 ) { if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar ) { //needs an ESC char
iNeedForEsc++; }
x--; }
if( iNeedForEsc && iNeedForEsc < DELTA ) { x = strlen( pcVal );
//Null char is same as of VAR. So, special case.
pcVal[ x + iNeedForEsc ] = pcVal[ x-- ];
while( x >= 0 ) { pcVal[ x + iNeedForEsc ] = pcVal[ x ]; if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar ) { //needs an ESC char
iNeedForEsc--; pcVal[ x + iNeedForEsc ] = ESC; }
x--; } }
if( inx + strlen( pcVal ) + 1 < MAX_STRING_LENGTH ) { //write VALUE keyword
ucBuffer[inx++] = VALUE; //write actual value
strncpy(ucBuffer+ inx, pcVal,MAX_BUFFER_SIZE - inx ); inx = inx + strlen( pcVal ); } } free( pcVal ); } } break;
default: ASSERT( 0 ); //This should not happen. Only types we know are VAR and USERVAR
break; } } }
ucBuffer[inx++] = ( UCHAR )IAC; ucBuffer[inx++] = ( UCHAR )SE; FWriteToNet(pwi, ucBuffer, inx); }
break;
case TO_TERM_TYPE:
// This is guaranteed to happen after an authentication has happened so we can start obeying the
// local echo settings...
ui.fDebug |= ui.honor_localecho; // restore the saved echo settings.
if( *(unsigned char FAR *)(*ps+1) == TT_SEND ) {
sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_TERM_TYPE; sbuf[3] = TT_IS; inx = 4;
if( pwi->trm.SentTermType == TT_UNKNOWN && pwi->trm.RequestedTermType != TT_UNKNOWN ) { // we haven't started the negotiation yet and the user has specified
// a preferred term type, so we start with that.
// RequestedTermType here is the user's setting not the server's.
pwi->trm.CurrentTermType = pwi->trm.RequestedTermType; pwi->trm.FirstTermTypeSent = pwi->trm.CurrentTermType; } else { pwi->trm.CurrentTermType = (pwi->trm.CurrentTermType + 1) % 4;
if( pwi->trm.CurrentTermType == pwi->trm.FirstTermTypeSent ) pwi->trm.CurrentTermType = pwi->trm.SentTermType; } //write maximum number of n bytes where n = sizeof(sbuf)-CurrentLength(sbuf)-2BytesForIACandSE-1ForNULL
strncpy( (char *) sbuf+4, rgchTermType[pwi->trm.CurrentTermType],16 - strlen(sbuf) -2 -1); inx += strlen(rgchTermType[pwi->trm.CurrentTermType]);
sbuf[inx++] = IAC; sbuf[inx++] = SE;
// set the Sent TermType to what we just sent
pwi->trm.SentTermType = pwi->trm.CurrentTermType ;
FWriteToNet(pwi, ( char * )sbuf, inx); }
break;
#if 1
case TO_AUTH:
if( (*(unsigned char FAR *)(*ps+1) == AU_SEND) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) ) { if ( pwi->eState!= Connecting || !PromptUser() || !StartNTLMAuth(pwi) ) { // there has been an error.
pwi->eState = Telnet;
sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE;
FWriteToNet(pwi, ( char * )sbuf, 8);
} } else if( (*(unsigned char FAR *)(*ps+1) == AU_REPLY) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) ) { // ps + 3 is the modifier and for NTLM it is AUTH_CLIENT_TO_SERVER & AUTH_ONE_WAY.
// ps + 4 is the NTLM accept or NTLM challenge or NTLM reject
switch ( *(unsigned char FAR *)(*ps+4) ) {
case NTLM_CHALLENGE: if( pwi->eState != Authenticating || !DoNTLMAuth(pwi, (unsigned char FAR *)(*ps+5), *recvsize-5) ) { // there has been an error.
pwi->eState = Telnet;
sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE;
FWriteToNet(pwi, ( char * )sbuf, 8); } break; case NTLM_ACCEPT: //fall through
case NTLM_REJECT: //fall through
default: pwi->eState = Telnet; if( pwi->eState == Authenticating || pwi->eState == AuthChallengeRecvd ) { NTLMCleanup(); } break; }
} else { pwi->eState = Telnet;
sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE;
FWriteToNet(pwi, ( char * )sbuf, 8); }
break; #endif
default:
break; }
while (*(unsigned char FAR *)(*ps) != SE) { (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 1; }
//
// Do one more to step over the SE
//
(*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 1;
}
void FProcessIAC( HWND hwnd, WI * pwi, LPSTR * ps, LPSTR * pd, int * recvsize, int * t_size) { UCHAR ch = *(unsigned char FAR *)(*ps);
ui.nottelnet = FALSE; // We can safely say that we are talking to a telnet server now...
//
// The IAC has already been subtracted from *recvsize
//
//
// Make sure we have enough recv buffer to process the rest of the IAC
// We know the DO, DONT etc. options always take two bytes plus the IAC.
//
if ( ((ch == DONT || ch == DO || ch == WILL || ch == WONT) && *recvsize < 2) || (ch != SB && *recvsize < 1) ) { int i;
#ifdef TCPTEST
OutputDebugString("FProcessIAC: saving incomplete option for next recv\n"); #endif
//
// IAC was previously eaten
//
pwi->nd.lpTempBuffer[0] = (unsigned char) IAC;
for ( i = 1; i < (*recvsize+1); i++ ) pwi->nd.lpTempBuffer[i] = (*ps)[i-1];
pwi->nd.cbOld = *recvsize + 1; *recvsize = 0;
return; }
switch (*(unsigned char FAR *)(*ps)) {
case DONT: (*ps) = (char FAR *)(*ps) + 1;
/* process options */ FProcessDont(pwi, ps);
#ifdef TCPTEST
OutputDebugString("DONT \n"); #endif
(*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 2; break;
case DO:
(*ps) = (char FAR *)(*ps) + 1;
/* process options */ FProcessDo(pwi, ps); #ifdef TCPTEST
OutputDebugString("DO \n"); #endif
(*ps) = (char FAR *)(*ps) + 1;
*recvsize = *recvsize - 2; break;
case WONT:
(*ps) = (char FAR *)(*ps) + 1;
/* process options */ FProcessWont(pwi, ps); #ifdef TCPTEST
OutputDebugString("WONT \n"); #endif
(*ps) = (char FAR *)(*ps) + 1;
*recvsize = *recvsize - 2; break;
case WILL:
(*ps) = (char FAR *)(*ps) + 1;
/* process options */ FProcessWill(pwi, ps);
#ifdef TCPTEST
OutputDebugString("WILL \n"); #endif
(*ps) = (char FAR *)(*ps) + 1;
*recvsize = *recvsize - 2; break;
case SB:
(*ps) = (char FAR *)(*ps) + 1;
*recvsize -= 1;
/* process options */ FProcessSB(pwi, ps, recvsize); break;
default:
(*ps) = (char FAR *)(*ps) + 1;
*recvsize -= 1; break;
}
}
#ifdef TCPTEST
VOID DumpBuffer( VOID FAR * pbuff, DWORD cb ) { #define NUM_CHARS 16
DWORD i, limit; CHAR TextBuffer[NUM_CHARS + 1]; LPBYTE BufferPtr;
if ( !pbuff ) { OutputDebugString("No buffer\n"); return; }
BufferPtr = (LPBYTE) pbuff;
//
// Hex dump of the bytes
//
limit = ((cb - 1) / NUM_CHARS + 1) * NUM_CHARS;
for (i = 0; i < limit; i++) {
if (i < cb) {
snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "%02x ", BufferPtr[i]); OutputDebugString( DebugBuffer );
if (BufferPtr[i] < 31 ) { TextBuffer[i % NUM_CHARS] = '.'; } else if (BufferPtr[i] == '\0') { TextBuffer[i % NUM_CHARS] = ' '; } else { TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i]; }
} else {
OutputDebugString(" "); TextBuffer[i % NUM_CHARS] = ' '; }
if ((i + 1) % NUM_CHARS == 0) { TextBuffer[NUM_CHARS] = 0; snprintf(DebugBuffer,sizeof(DebugBuffer)-1, " %s\n", TextBuffer); OutputDebugString( DebugBuffer ); } } } #endif
void FProcessSessionData( int cBytes, PUCHAR pchNBBuffer, WI *pwi ) { WaitForSingleObject( g_hCaptureConsoleEvent, INFINITE );
WaitForSingleObject( g_hRemoteNEscapeModeDataSync, INFINITE ); if( pwi->hOutput != g_hSessionConsoleBuffer ) { pwi->hOutput = g_hSessionConsoleBuffer; SetConsoleActiveScreenBuffer(g_hSessionConsoleBuffer); } /*This is needed so that we don't write data to the session even after disconnection of client */ if( !fConnected ) { return; }
ResetEvent( g_hRemoteNEscapeModeDataSync ); if( pwi->trm.CurrentTermType == TT_VTNT ) { if( !DoVTNTOutput(pwi, &pwi->trm, cBytes, pchNBBuffer) ) { //
// The following two lines were originally added as a
// mechanism of defaulting to VT100 in case of some servers
// accepting VTNT, during term type negotiation, even though
// in reality they do not support VTNT. Specifically, Linux
// was showing this behavior during our testing. But the
// function DoVTNTOutput returns FALSE even in other cases
// such as, when we get some junk data from the server. In
// such cases we should not call DoIBMANSIOutput (bug 1119).
//
pwi->trm.CurrentTermType = TT_ANSI; DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer); } } else { DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer); }
pwi->ichTelXfer = 0; SetEvent( g_hRemoteNEscapeModeDataSync ); }
void FProcessFDRead(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); int recvsize, t_size; LPSTR ps, pd;
//
// pwi->nd.cbOld Is the number of bytes left over from the previous
// packet that we kept in pwi->nd.lpTempBuffer
//
if ((recvsize=recv(pwi->nd.hsd, pwi->nd.lpTempBuffer + pwi->nd.cbOld, READ_BUF_SZ - pwi->nd.cbOld, 0)) < 0) { return; }
//
// Fix to bug 284
//
Sleep(0);
recvsize += pwi->nd.cbOld; pwi->nd.cbOld = 0;
ps = pwi->nd.lpTempBuffer; pd = pwi->nd.lpReadBuffer; t_size = 0;
while( recvsize-- ) {
if( *(unsigned char FAR *) ps == (unsigned char)IAC ) {
if( recvsize == 0 ) { pwi->nd.lpTempBuffer[0] = (unsigned char) IAC; pwi->nd.cbOld = 1; break; }
ps++;
if( *(unsigned char FAR *)ps == (unsigned char)IAC ) {
//
// This was an escaped IAC so put it in the normal
// input buffer
//
ps++; *(unsigned char FAR *)pd = (unsigned char)IAC; pd++;
recvsize--;
t_size++; } else { FProcessIAC(hwnd, pwi, &ps, &pd, &recvsize, &t_size); } } else {
*(char FAR *)pd = *(char FAR *)ps; pd++; ps++;
t_size++; } }
if( t_size ) { /* add received data to buffer */ if ( !(ui.fFlushOut) || ui.nottelnet ) { FProcessSessionData( t_size, pwi->nd.lpReadBuffer, pwi ); } } }
void FProcessFDOOB(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); int recvsize; LPSTR ps;
if ((recvsize=recv(pwi->nd.hsd, pwi->nd.lpTempBuffer, READ_BUF_SZ, MSG_OOB)) < 0) { #ifdef TCPTEST
OutputDebugString("recv error \n"); #endif
return; }
ps = pwi->nd.lpTempBuffer;
if (*(unsigned char *)ps == (unsigned char)DM) { #ifdef TCPTEST
OutputDebugString("DM received\n"); #endif
FDisableFlush(hwnd); } }
BOOL FAttemptServerConnect(WI *pwi, LPSTR szHostName, LPNETDATA lpData) { BOOL got_connected = FALSE; struct servent *serv; struct sockaddr_storage myad; int on = 1; char szService[256]; char *pszService = NULL; struct addrinfo *aiTemp = NULL;
g_dwSockErr = 0; //Intialize to no error
if(rgService) { pszService = szService; _snprintf(pszService,sizeof(szService)-1, "%d",rgService); } else { got_connected = FALSE; return(got_connected); } strncpy(lpData->szHostName, szHostName,sizeof(lpData->szHostName)); if(getaddrinfo(szHostName, pszService, NULL, &lpData->ai ) != 0 ) { got_connected = FALSE; return(got_connected); } aiTemp = lpData->ai; ui.nottelnet = TRUE; // Assume that it is not a telnet server for starters, later when it is set this flag... to false.
ui.honor_localecho = (ui.fDebug & fdwLocalEcho); // Save this and restore after a logon has happned in case of telnet
ui.fDebug &= ~fdwLocalEcho; // Clear it.
//Continue till connection is successfully established or till the list is exausted
while(aiTemp) { if ((lpData->hsd = socket( aiTemp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET) { DEBUG_PRINT(("socket failed \n")); aiTemp = aiTemp->ai_next; continue; } SfuZeroMemory(&myad, sizeof(myad)); //no overflow. Size is constant.
myad.ss_family = (u_short)aiTemp->ai_family; if(bind( lpData->hsd, (struct sockaddr *)&myad, sizeof(myad))<0) { DEBUG_PRINT(("bind failed\n")); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; aiTemp = aiTemp->ai_next; continue; } on = 1; { BOOL value_to_set = TRUE;
setsockopt( lpData->hsd, SOL_SOCKET, SO_DONTLINGER, ( char * )&value_to_set, sizeof( value_to_set ) ); } if( setsockopt( lpData->hsd, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on) ) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; DEBUG_PRINT(("setsockopt SO_OOBINLINE failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); freeaddrinfo(lpData->ai); lpData->ai = NULL; return(got_connected); } else DEBUG_PRINT(("setsockopt SO_OOBINLINE worked\n"));
if(SafeSetSocketOptions(lpData->hsd) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; DEBUG_PRINT(("setsockopt SO_EXCLUSIVEADDRUSE failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); freeaddrinfo(lpData->ai); lpData->ai = NULL; return(got_connected); } // ================================================================
// MohsinA, 09-Dec-96.
if(connect( lpData->hsd, (PVOID)aiTemp->ai_addr,aiTemp->ai_addrlen )<0) { DEBUG_PRINT(("connect failed\n")); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; aiTemp = aiTemp->ai_next; continue; } break; } freeaddrinfo(lpData->ai); lpData->ai = NULL; if(aiTemp == NULL) { DEBUG_PRINT(("FAttemptServerConnect Out\n")); g_dwSockErr = WSAGetLastError(); if(lpData->hsd != INVALID_SOCKET) closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; return(got_connected); } aiTemp=NULL; // ================================================================
lpData->SessionNumber = 1;
if (lpData->SessionNumber != nSessionNone) { DEBUG_PRINT(("sess# <> nsessnone\n")); /* post Async select */ if (WSAAsyncSelect( lpData->hsd, pwi->hwnd, WS_ASYNC_SELECT, (FD_READ | FD_WRITE | FD_CLOSE | FD_OOB)) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; lpData->SessionNumber = nSessionNone; DEBUG_PRINT(("WSAAsyncSelect failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); return(got_connected); } else DEBUG_PRINT(("WSAAsyncSelect worked\n")); got_connected = TRUE; } else DEBUG_PRINT(("sess# <> nsessnone\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); return got_connected; }
void FCloseConnection(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); if(pwi->nd.hsd != INVALID_SOCKET) { closesocket( pwi->nd.hsd ); pwi->nd.hsd = INVALID_SOCKET; } }
#endif
#ifdef __NOT_USED
#define INC(i) (((i)+1 == DATA_BUF_SZ) ? 0 : (i)+1)
#define DEC(i) (((i)-1 < 0) ? DATA_BUF_SZ-1 : (i)-1)
WORD WGetData(LPNETDATA lpData, LPSTR lpBuffer, WORD cLen) { WORD cb;
#ifdef TCPTEST
snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "WGetData length %d\n", cLen); OutputDebugString(DebugBuffer); #endif
if (lpData->iHead < lpData->iTail) { cb = ( USHORT ) ( (cLen < (lpData->iTail - lpData->iHead - 1)) ? cLen : (lpData->iTail - lpData->iHead - 1) ); memcpy(lpBuffer, &lpData->achData[lpData->iHead+1], cb); //Attack ? size not known. No caller.
lpData->iHead = ( USHORT ) ( lpData->iHead + cb ); } else { for(cb=0; (cb<cLen) && ((WORD)INC(lpData->iHead) != lpData->iTail); ++cb) { lpData->iHead = ( USHORT ) INC(lpData->iHead); *lpBuffer++ = lpData->achData[lpData->iHead]; } }
#ifdef TCPTEST
snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "WGetData returning %d bytes (head = %d, tail = %d)\n", cb, lpData->iHead, lpData->iTail ); OutputDebugString(DebugBuffer); #endif
return cb; }
BOOL FStoreData(LPNETDATA lpData, int max) { BOOL fSuccess = TRUE; WORD tail = lpData->iTail; LPSTR p = lpData->lpReadBuffer;
#ifdef TCPTEST
snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData max %d, (head = %d, tail = %d)\n", max, tail, lpData->iHead ); OutputDebugString(DebugBuffer); #endif
if ((max+tail) < DATA_BUF_SZ) { memcpy(&lpData->achData[tail], p, max); //Attack ? Size not known. No caller.
tail = ( USHORT ) ( tail + max ); } else { WORD head = lpData->iHead; int i;
for (i=0; i<max; ++i) { if (tail == head) { /* the buffer is full! Rest of the data will be lost */ fSuccess = FALSE; break; } else { lpData->achData[tail] = *p++; tail = ( USHORT ) INC(tail); } } }
lpData->iTail = tail;
#ifdef TCPTEST
snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData returning %d\n", fSuccess ); OutputDebugString(DebugBuffer); #endif
return fSuccess; } #endif
void CALLBACK NBReceiveData(PVOID pncb) { }
/* following four routines modified from VTP's routines. */
BOOL FTelXferStart(WI *pwi, int nSessionNumber) { #ifdef TELXFER
unsigned short u; char rgchFileOrig[OFS_MAXPATHNAME]; char rgchFile[OFS_MAXPATHNAME];
xfGetData(0, (char *)&u, 2, nSessionNumber); // Mode
SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. Size is constant
pwi->svi.hfile = INVALID_HANDLE_VALUE; pwi->svi.lExit = -1; pwi->svi.lCleanup = -1;
if (u != 0) // For now must be zero
return FALSE;
pwi->trm.fHideCursor = TRUE;
xfGetData(1, (char *)&u, 2, nSessionNumber); // Length of name
xfGetData(2, rgchFileOrig, u, nSessionNumber); // Name
xfGetData(3, (char *)&pwi->svi.cbFile, 4, nSessionNumber); // Filesize
lstrcpyn(rgchFile, rgchFileOrig, OFS_MAXPATHNAME -1);
/* If the user doesn't have the shift key down, prompt for */ /* a directory and name for the file */ if (!(ui.fPrompt & fdwSuppressDestDirPrompt) && (GetAsyncKeyState(VK_SHIFT) >= 0)) { if ( !FGetFileName(hwnd, rgchFile, NULL) ) { goto err; } }
pwi->svi.hfile = CreateFile(rgchFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (pwi->svi.hfile == INVALID_HANDLE_VALUE) { ErrorMessage(szCantOpenFile, szAppName); goto err; } pwi->svi.puchBuffer = LocalAlloc(LPTR, SV_DATABUF); if (pwi->svi.puchBuffer == NULL) { ErrorMessage(szOOM, szAppName); goto err; }
pwi->svi.nSessionNumber = nSessionNumber; pwi->svi.hthread = CreateThread(NULL, 0, SVReceive, &pwi->svi, CREATE_SUSPENDED, &pwi->svi.dwThreadId); if (pwi->svi.hthread == NULL) { ErrorMessage(szNoThread, szAppName); goto err; }
// Skip 4 which is ^D
xfPutc(5, nSessionNumber); // Get file
_snwprintf(rgchFile, OFS_MAXPATHNAME -1, szBannerMessage, rgchFileOrig, pwi->svi.cbFile); DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(rgchFile), rgchFile);
DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(szInitialProgress), szInitialProgress);
/* In case the screen just scrolled up, paint the window */ UpdateWindow( hwnd ); ResumeThread( pwi->svi.hthread );
return TRUE;
err: if ( pwi ) { if (pwi->svi.puchBuffer != NULL) LocalFree( (HANDLE)pwi->svi.puchBuffer ); if (pwi->svi.hfile != INVALID_HANDLE_VALUE) CloseHandle( pwi->svi.hfile );
SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. size is constant.
pwi->svi.hfile = INVALID_HANDLE_VALUE; pwi->svi.lExit = -1; pwi->svi.lCleanup = -1; } pwi->trm.fHideCursor = FALSE;
return FALSE; #else
return TRUE; #endif
}
BOOL FTelXferEnd(WI *pwi, DWORD dwWhy) { #ifdef TELXFER
DWORD dwStatus = NO_ERROR; BOOL fTransferOK = FALSE; BOOL fAbortDownload = FALSE; BOOL fCleanup = FALSE; LPNETDATA lpData = &pwi->nd; SVI *psvi = &pwi->svi; MSG msg;
switch ( dwWhy ) { case SV_DISCONNECT: case SV_HANGUP: case SV_QUIT: if (InterlockedIncrement(&psvi->lExit) == 0) { if (psvi->hthread != NULL) { (void)GetExitCodeThread(psvi->hthread, &dwStatus); if (dwStatus == STILL_ACTIVE) { if (MessageBox(hwnd, szAbortDownload, szAppName, MB_DEFBUTTON2 | MB_YESNO | MB_ICONEXCLAMATION) == IDYES) { fAbortDownload = fCleanup = TRUE; }
/* See if the thread has finished yet */ GetExitCodeThread(psvi->hthread, &dwStatus);
if ( fAbortDownload ) { /* If the thread hasn't finished yet, tell it to stop */ if (dwStatus == STILL_ACTIVE) { HCURSOR hcursorOld; hcursorOld = SetCursor( LoadCursor(NULL, IDC_WAIT)); psvi->dwCommand = 1; WaitForSingleObject(psvi->hthread, INFINITE); GetExitCodeThread(psvi->hthread, &dwStatus); (void)SetCursor( hcursorOld ); }
/* "Eat" any progress messages that might be around */ while (PeekMessage(&msg, hwnd, SV_PROGRESS, SV_DONE, PM_REMOVE)) { if (msg.message == SV_PROGRESS) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } } else if (dwStatus != STILL_ACTIVE) { fCleanup = TRUE; } } else { fAbortDownload = fCleanup = TRUE; }
/* If we've stopped the download, then close the thread */ if ( fCleanup ) { CloseHandle( psvi->hthread ); psvi->hthread = NULL; if (lpData->SessionNumber != nSessionNone) { xfPutc((char)(!fTransferOK ? 0x7F : 0x06), lpData->SessionNumber); if ( !fAbortDownload ) (void)FPostReceive( lpData ); } } if (dwStatus == NO_ERROR) fTransferOK = TRUE; } InterlockedDecrement( &psvi->lExit );
/* If the thread wasn't aborted and it hasn't finished, return */ if (!fAbortDownload && !fCleanup) return fAbortDownload; } else { InterlockedDecrement( &psvi->lExit ); break; }
case SV_DONE: if (dwWhy == SV_DONE) { fAbortDownload = fCleanup = TRUE; }
/* If we're the only thread in the function, close everything down */ if (InterlockedIncrement(&psvi->lExit) == 0) { if (psvi->hthread != NULL) { WaitForSingleObject(psvi->hthread, INFINITE); GetExitCodeThread(psvi->hthread, &dwStatus); CloseHandle( psvi->hthread ); psvi->hthread = NULL; if (dwStatus == NO_ERROR) fTransferOK = TRUE; } }
/* Do cleanup of struct only once */ if ((InterlockedIncrement(&psvi->lCleanup) == 0) && (psvi->puchBuffer != NULL)) { LocalFree( (HANDLE)psvi->puchBuffer ); psvi->puchBuffer = NULL;
if (psvi->hfile != INVALID_HANDLE_VALUE) { CloseHandle( psvi->hfile ); psvi->hfile = INVALID_HANDLE_VALUE; }
psvi->cbFile = 0; psvi->cbReadTotal = 0; psvi->dwCommand = 0; psvi->dwThreadId = 0; psvi->nSessionNumber = nSessionNone;
if ((dwStatus == NO_ERROR) || (dwStatus == ERROR_OPERATION_ABORTED)) { lstrcpyn(pchNBBuffer, szSendTelEnd,sizeof(pchNBBuffer)-1); } else { _snwprintf(pchNBBuffer,sizeof(pchNBBuffer)-1,szSendTelError, dwStatus); } DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(pchNBBuffer), pchNBBuffer);
pwi->ichTelXfer = 0; pwi->trm.fHideCursor = FALSE; } InterlockedDecrement( &psvi->lCleanup );
if ((dwWhy == SV_DONE) && (lpData->SessionNumber != nSessionNone)) { xfPutc((char)(!fTransferOK ? 0x7F : 0x06), lpData->SessionNumber); (void)FPostReceive( lpData ); } InterlockedDecrement( &psvi->lExit ); break; default: break; }
return fAbortDownload; #else
return TRUE; #endif
}
#ifdef TELXFER
static void xfGetData(char c, char *pchBuffer, DWORD cbBuffer, int nSessionNumber) { DWORD cbRead;
xfPutc(c, nSessionNumber); while ( cbBuffer ) { cbRead = xfGetSomeData(pchBuffer, cbBuffer, nSessionNumber); if (cbRead == 0) break; cbBuffer -= cbRead; pchBuffer += cbRead; } } #endif
#ifdef USETCP
#ifdef TELXFER
static DWORD xfGetSomeData(char *pchBuffer, DWORD cbBuffer, int nSessionNumber) { return 1; } #endif //TELXFER
#ifdef TELXFER
static void xfPutc(char c, int nSessionNumber) {
} #endif
#endif
#ifdef TELXFER
BOOL FGetFileName(HWND hwndOwner, char *rgchFile, char *rgchTitle) { OPENFILENAME ofn;
/* Fill in struct. */ ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndOwner; ofn.hInstance = NULL; ofn.lpstrFilter = (LPSTR) szAllFiles; ofn.lpstrCustomFilter = (LPSTR) NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = (LPSTR) rgchFile; ofn.nMaxFile = OFS_MAXPATHNAME; ofn.lpstrFileTitle = (LPSTR) rgchTitle; ofn.nMaxFileTitle = OFS_MAXPATHNAME; ofn.lpstrInitialDir = (LPSTR) 0; ofn.lpstrTitle = (LPSTR) szDownloadAs; ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = (LPSTR) NULL; ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL;
if ( !GetSaveFileName(&ofn) ) { return FALSE; } return TRUE; } #endif
DWORD WINAPI SVReceive(SVI *psvi) { DWORD dwReturn = NO_ERROR;
#ifdef TELXFER
if ( psvi ) { while ((psvi->cbFile > 0) && (psvi->dwCommand == 0)) { DWORD cbSomeData; DWORD cbRead;
cbRead = 0; while ((psvi->cbFile > 0) && (cbRead < 1024)) { cbSomeData = xfGetSomeData(psvi->puchBuffer+cbRead, (unsigned short) 0x4000 - cbRead, psvi->nSessionNumber);
if (cbSomeData > psvi->cbFile) cbSomeData = psvi->cbFile;
psvi->cbFile -= cbSomeData; cbRead += cbSomeData; }
if (!WriteFile(psvi->hfile, psvi->puchBuffer, cbRead, &cbSomeData, NULL)) { dwReturn = GetLastError(); break; }
psvi->cbReadTotal += cbRead; PostMessage(hwndMain, SV_PROGRESS, 0, psvi->cbReadTotal); }
/* caller must've signaled and waited for thread to stop */ if ((dwReturn == NO_ERROR) && (psvi->dwCommand != 0) && (psvi->cbFile > 0)) { dwReturn = ERROR_OPERATION_ABORTED; } else if ((psvi->dwCommand == 0) || (psvi->cbFile == 0)) { /* If thread stopped by itself, need to tell caller to kill it
* BUT ONLY if the main thread isn't tying to kill off this * thread. */ if (InterlockedIncrement(&psvi->lExit) == 0) PostMessage(hwndMain, SV_END, 0, 0L); InterlockedDecrement( &psvi->lExit ); } } else if (psvi->lExit < 0) { /* If thread stopped by itself, need to tell caller to kill it */ PostMessage(hwndMain, SV_END, 0, 0L); } #endif
return dwReturn; }
#ifdef USETCP
BOOL FHangupConnection(WI *pwi, LPNETDATA lpData) {
if (lpData->SessionNumber != nSessionNone) { if(lpData->hsd != INVALID_SOCKET) { closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; } lpData->SessionNumber = nSessionNone; }
return FALSE; } #endif
|