windows-nt/Source/XPSP1/NT/net/tcpip/services/telnet/client/netio.c
2020-09-26 16:20:57 +08:00

2034 lines
58 KiB
C

//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