www.pudn.com > vcʵÏÖftp.rar > VIEW.CPP


// MiniFTP copyright 1997 Paul Gerhart pgerhart@voicenet.com 
// View.cpp : implementation of the CMiniFTPView class 
// 
// search for....			// THIS IS WHERE THIS APP REALLY STARTS 
 
 
#include "stdafx.h" 
#include "miniftp.h" 
 
#include "Doc.h" 
#include "View.h" 
//#include "cwinsock.h"    // in this files .h 
#include "mainfrm.h" 
#include "conndlg.h" 
#include "XportDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#define WM_WINSOCK_EVENT_FRAME_CONTROL (WM_USER+4)	 // for winsock messages 
#define WM_WINSOCK_EVENT_VU_CONTROL (WM_USER+4+10)	 // for winsock messages 
#define WM_WINSOCK_EVENT_FRAME_LISTEN (WM_USER+6)	 // for winsock messages 
#define WM_WINSOCK_EVENT_VU_LISTEN (WM_USER+6+10)	 // for winsock messages 
#define WM_WINSOCK_EVENT_FRAME_DATA (WM_USER+8)	 // for winsock messages 
#define WM_WINSOCK_EVENT_VU_DATA (WM_USER+8+10)	 // for winsock messages 
 
///////////////////////////////////////////////////////////////////////////// 
// CMiniFTPView 
 
IMPLEMENT_DYNCREATE(CMiniFTPView, CEditView) 
 
BEGIN_MESSAGE_MAP(CMiniFTPView, CEditView) 
	//{{AFX_MSG_MAP(CMiniFTPView) 
	ON_COMMAND(ID_CONNECT, OnConnect) 
	ON_COMMAND(ID_CLOSECONN, OnCloseconn) 
	ON_COMMAND(ID_CLEARVIEW, OnClearview) 
	ON_UPDATE_COMMAND_UI(ID_CLOSECONN, OnUpdateCloseconn) 
	ON_UPDATE_COMMAND_UI(ID_CONNECT, OnUpdateConnect) 
	ON_WM_TIMER() 
	ON_COMMAND(ID_FSETTINGS, OnFsettings) 
	//}}AFX_MSG_MAP 
	ON_MESSAGE(WM_WINSOCK_EVENT_VU_CONTROL,OnWinsockEventControl) 
	ON_MESSAGE(WM_WINSOCK_EVENT_VU_LISTEN,OnWinsockEventListen) 
	ON_MESSAGE(WM_WINSOCK_EVENT_VU_DATA,OnWinsockEventData) 
 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CMiniFTPView construction/destruction 
CMiniFTPView::CMiniFTPView() 
{ 
	WSAData WsaData; 
	int ret = WSAStartup(0x0101, &WsaData); 
	if( ret != 0 ) 
	{ 
		AfxMessageBox("WSAStartup failed"); 
	} 
 
	m_bWaitingForTimeout = FALSE; 
	m_bTimerOn = FALSE;  
	m_sktControl = INVALID_SOCKET; 
	m_sktListen = INVALID_SOCKET; 
	m_sktData = INVALID_SOCKET; 
	m_pXferFilePointer = NULL; 
	MakeSafeState(TRUE); 
	m_nRadioASCII = AfxGetApp()->GetProfileInt("Setting", "ASCII", 0); 
	m_sIncomingPath = AfxGetApp()->GetProfileString("Setting", "Name", "c:"); 
	m_uTimeout = AfxGetApp()->GetProfileInt("Connect", "Timeout", 30); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::MakeSafeState(BOOL bKillTimers) 
{ 
	if( bKillTimers ) // always call with TRUE except destructor 
	{ 
		if( m_bWaitingForTimeout ) 
		{ 
			KillTimer( ID_MYTIMEOUT ); 
		} 
		m_bWaitingForTimeout = FALSE; 
		if( m_bTimerOn ) 
		{ 
			KillTimer( ID_MYTIMER ); 
		} 
		m_bTimerOn = FALSE;  
	} 
	 
	if( m_sktData != INVALID_SOCKET ) 
	{ 
		closesocket(m_sktData); 
	} 
	m_sktData = INVALID_SOCKET; 
	if( m_sktListen != INVALID_SOCKET ) 
	{ 
		closesocket(m_sktListen); 
	}	 
	m_sktListen = INVALID_SOCKET; 
	if( m_sktControl != INVALID_SOCKET ) 
	{ 
		closesocket(m_sktControl); 
	}	 
	m_sktControl = INVALID_SOCKET; 
 
	if( m_pXferFilePointer != NULL) 
	{ 
		fclose( m_pXferFilePointer ); 
		m_pXferFilePointer = NULL; 
	} 
 
	m_nState = 0; 
	m_bReplyReceived = FALSE; 
	m_bTimerOn = FALSE; 
	m_bBusy = FALSE; 
	m_bWaitingForTimeout = FALSE; 
	m_bReceivingFile = FALSE; 
	m_bSendingFile = FALSE; 
	m_bFileHasBeenReceived = FALSE; 
	m_bFileHasBeenSent = FALSE; 
	if( !m_sCommandList.IsEmpty() ) 
	{ 
		m_sCommandList.RemoveAll(); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnInitialUpdate()  
{ 
	CEditView::OnInitialUpdate(); 
	 
	LOGFONT lf;  // Used to create the CFont. 
	memset(&lf, 0, sizeof(LOGFONT));   // Clear out structure. 
 
	m_font.DeleteObject();	// pre delete (it may or may not exist) 
 
	lf.lfHeight = 100; 
	lf.lfWeight = 400;	// plain 
	strcpy(lf.lfFaceName,"Courier");  
	m_font.CreatePointFontIndirect(&lf);    // Create the font. 
	GetEditCtrl().SetFont(&m_font);	 // change the edit control (the CURLegalView)	 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
CMiniFTPView::~CMiniFTPView() 
{ 
	MakeSafeState( FALSE ); 
	WSACleanup(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
BOOL CMiniFTPView::DestroyWindow()  
{ 
	// will get assert if KillTimer in destructor. 
	if( m_bWaitingForTimeout ) 
	{ 
		KillTimer( ID_MYTIMEOUT ); 
	} 
	m_bWaitingForTimeout = FALSE; 
	if( m_bTimerOn ) 
	{ 
		KillTimer( ID_MYTIMER ); 
	} 
	m_bTimerOn = FALSE;  
	 
	return CEditView::DestroyWindow(); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
BOOL CMiniFTPView::PreCreateWindow(CREATESTRUCT& cs) 
{ 
	BOOL bPreCreated = CEditView::PreCreateWindow(cs); 
 
	cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL);	// Enable word-wrapping 
 
	cs.style |=	ES_READONLY; // make read only - it is a log window 
	return bPreCreated; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMiniFTPView drawing 
void CMiniFTPView::OnDraw(CDC* pDC) 
{ 
	CMiniFTPDoc* pDoc = GetDocument(); 
	ASSERT_VALID(pDoc); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMiniFTPView diagnostics 
 
#ifdef _DEBUG 
void CMiniFTPView::AssertValid() const 
{ 
	CEditView::AssertValid(); 
} 
 
void CMiniFTPView::Dump(CDumpContext& dc) const 
{ 
	CEditView::Dump(dc); 
} 
 
CMiniFTPDoc* CMiniFTPView::GetDocument() // non-debug version is inline 
{ 
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMiniFTPDoc))); 
	return (CMiniFTPDoc*)m_pDocument; 
} 
#endif //_DEBUG 
 
///////////////////////////////////////////////////////////////////////////// 
// CMiniFTPView message handlers 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::Log(const char * szBuffer) 
{ 
	int nChars=GetWindowTextLength();    // get the index of the last line 
 
 	// point end of document 
	GetEditCtrl().SetSel( nChars,nChars ); 
	GetEditCtrl().ReplaceSel((LPCSTR)szBuffer);     // display text 
 
	// defeat the final "save document" dialog on app exit 
	GetDocument()->SetModifiedFlag(FALSE);  
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnTimer(UINT nIDEvent)  
{ 
	if( nIDEvent == ID_MYTIMER) 
	{ 
		StateMachine(); 
	} 
	else if( nIDEvent == ID_MYTIMEOUT) 
	{ 
		MakeSafeState(TRUE); 
		Log("\r\nMiniFTP Status>Client Timeout\r\n\r\n"); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////// 
// the major sequencer for client/server stuff 
void CMiniFTPView::StateMachine(void)  
{ 
	CString sOut; 
 
	switch ( m_nState ) 	  // which state are we in now ? 
	{ 
		case 0: 
			if( !m_sCommandList.IsEmpty() && !m_bBusy ) 
			{ 
				m_bBusy = TRUE; 
				SetTimer(ID_MYTIMEOUT, 1000*m_uTimeout, NULL); 
				m_bWaitingForTimeout = TRUE; 
				m_bReplyReceived = FALSE; 
				sOut = m_sCommandList.GetHead(); 
				m_sCommandList.RemoveHead(); 
				DoCommand( sOut ); 
				m_nState = 1; 
			} 
			break; 
		case 1: 
			if( m_bReplyReceived ) 
			{ 
				m_bReplyReceived = FALSE; 
				m_nState = 0; 
				KillTimer(ID_MYTIMEOUT); 
				m_bWaitingForTimeout = FALSE; 
				if( m_sCommandList.IsEmpty() ) 
				{ 
					KillTimer(ID_MYTIMER); 
					m_bTimerOn =FALSE; 
				} 
				m_bBusy = FALSE; 
				// is there some undisplayed text from the CONTROL socket READ case? 
				if( strlen(m_szControlReplyBuffer) > 0 ) 
				{ 
					// yes, so display it now 
					DisplaySktRead(m_szControlReplyBuffer); 
				} 
			} 
			break; 
		default: 
			break; 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::DisplaySktRead( char * szBuffer ) 
{ 
	char * str=strtok(szBuffer,"\n"); 
	while( str && *str) 
	{ 
		Log((const char *)str); 
		int nLen = strlen(str); 
		int nCount = (int)(str-szBuffer)+nLen; 
		if( nCount != BUFSIZE ) 
		{ 
		   Log("\r\n"); 
		} 
		else 
		{ 
			ASSERT( nCount == BUFSIZE ); 
			char c = *(szBuffer + BUFSIZE -1); 
			if( c == '\n' ) 
			{ 
				Log("\r\n"); 
			} 
		} 
		str=strtok((char *)NULL,"\n"); 
	} 
	// this nulling is used as a signal to StateMachine() so it can 
	//		clean out and text that the CONTROL socket READ case 
	//		deferred displaying. 
	*szBuffer = 0; // null it to zero length 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// the CONTROL socket 
LONG CMiniFTPView::OnWinsockEventControl (WPARAM wParam, LPARAM lParam) 
{ 
	ASSERT( m_sktControl == wParam ); 
	memset( m_szControlReplyBuffer, 0, BUFSIZE+2); 
	// this memset trick avoids having strtok insert a wild \0 somewhere bad 
	//		it is guaranteed to find a \n (the delimiter in this case) before 
	//		running off into other memory 
	memset( m_szControlReplyBuffer+BUFSIZE, '\n', 1);  
	CString sOut; 
 
	switch ( WSAGETSELECTEVENT(lParam) ) 	  // which message arrived? 
	{ 
		case FD_CLOSE: 
			sOut.Format( "\r\nMiniFTP Status>Control Connection closed by server (socket %d)\r\n\r\n", wParam); 
			Log(sOut); 
			closesocket( m_sktControl ); 
			m_sktControl = INVALID_SOCKET; 
			break; 
 
		case FD_READ: 
			recv( m_sktControl, m_szControlReplyBuffer, BUFSIZE, 0 ); 
			// if there is a Data socket open, this socket will defer 
			//		let the Data socket do its stuff to the screen. 
			//		StateMachine() will do the call to	DisplaySktRead() 
			//		when the command list is exhausted. 
			if( m_sktData == INVALID_SOCKET ) 
			{ 
				DisplaySktRead( m_szControlReplyBuffer ); 
			} 
			m_bReplyReceived = TRUE; 
			break; 
 
		case FD_WRITE: 
			// this only gets hit as a response to the intial Control skt connect() 
				recv( m_sktControl, m_szControlReplyBuffer, BUFSIZE, 0 ); 
				DisplaySktRead( m_szControlReplyBuffer ); 
			break; 
		default: 
			break; 
	} 
	return 0L; 
} 
 
/*  FOR REFERENCE 
#define FD_READ         0x01 
#define FD_WRITE        0x02 
#define FD_OOB          0x04 
#define FD_ACCEPT       0x08 
#define FD_CONNECT      0x10 
#define FD_CLOSE        0x20 */ 
 
///////////////////////////////////////////////////////////////////////////// 
// the LISTEN socket 
LONG CMiniFTPView::OnWinsockEventListen (WPARAM wParam, LPARAM lParam) 
{ 
	CString sOut;	    
 
	switch ( WSAGETSELECTEVENT(lParam) ) 	  // which message arrived? 
	{ 
		case FD_CLOSE: 
			sOut.Format( "\r\nMiniFTP Status>Listen Connection closed by server (socket %d)\r\n\r\n", wParam); 
			Log(sOut); 
			closesocket( m_sktListen ); 
			m_sktListen = INVALID_SOCKET; 
			break; 
 
		case FD_ACCEPT: 
			m_sktData = accept( m_sktListen, NULL, NULL); 
			setsockopt( m_sktData, SOL_SOCKET, SO_LINGER, 0, 0);	 
			setsockopt( m_sktData, SOL_SOCKET, SO_REUSEADDR, 0, 0); 
			setsockopt( m_sktData, SOL_SOCKET, SO_KEEPALIVE, 0, 0); 
			WSAAsyncSelect ( m_sktData, AfxGetMainWnd()->m_hWnd,  
					WM_WINSOCK_EVENT_FRAME_DATA,  
					FD_WRITE|FD_READ|FD_CLOSE/*|FD_ACCEPT*/); 
			sOut.Format("\r\nMiniFTP Status>Data Connection made OK (socket %d)\r\n\r\n", m_sktData); 
			Log(sOut); 
			break; 
 
		default: 
			break; 
	} 
	return 0L; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// the DATA socket 
LONG CMiniFTPView::OnWinsockEventData (WPARAM wParam, LPARAM lParam) 
{ 
	ASSERT( m_sktData == wParam ); 
	memset( m_szDataBuffer, 0, BUFSIZE+2); 
	// this memset trick avoids having strtok insert a wild \0 somewhere bad 
	//		it is guaranteed to find a \n (the delimiter in this case) before 
	//		running off into other memory 
	memset( m_szDataBuffer+BUFSIZE, '\n', 1);  
 
	CString sOut; 
	int nClose; 
 
	switch ( WSAGETSELECTEVENT(lParam) ) 	  // which message arrived? 
	{ 
		case FD_CLOSE: 
			sOut.Format( "\r\nMiniFTP Status>Data Connection closed by server (socket %d)\r\n\r\n", wParam); 
			Log(sOut); 
			nClose = closesocket(m_sktData); 
			m_sktData = INVALID_SOCKET; 
			// close the listener too 
			if( m_sktListen != INVALID_SOCKET ) 
			{ 
				nClose = closesocket(m_sktListen); 
			} 
			m_sktListen = INVALID_SOCKET; 
			break; 
 
		case FD_READ: //asdf 
			// just a plain data socket (no file saving)  - get the data to the screen 
			if( !m_bReceivingFile )  
			{ 
				recv( m_sktData, m_szDataBuffer, BUFSIZE, 0 ); 
				DisplaySktRead( m_szDataBuffer ); 
				TRACE("in  DATA for non-file READ case\n"); 
			} 
			else // we are saving file 
			{ 
				BeginWaitCursor(); // show hourglass  
				ServiceIncomingFile();  
				EndWaitCursor(); // kill hourglass  
			} 
			break; 
 
		case FD_WRITE: 
			if( m_bSendingFile)  
			{ 
				BeginWaitCursor(); // show hourglass  
				ServiceOutgoingFile(); 
				EndWaitCursor(); // kill hourglass  
			}  
			break; 
		default: 
			break; 
	} 
	return 0L; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// a helper for the DATA socket WRITE case 
void CMiniFTPView::ServiceOutgoingFile()  
{ 
	TRACE("in  ServiceOutgoingFile\n"); 
	UINT nr; 
	CString sOut; 
 
	if( m_bWaitingForTimeout ) // may be a big file 
	{ 
		KillTimer(ID_MYTIMEOUT); 
		m_bWaitingForTimeout = FALSE; 
	} 
 
	ASSERT( m_pXferFilePointer==NULL ); 
	m_pXferFilePointer = fopen( (const char *)m_sStoringFilePath, "rb" ); 
	if( !m_pXferFilePointer ) 
	{ 
		sOut.Format( "Specifed file\n%s\ncannot be found", m_sStoringFilePath ); 
		if( AfxMessageBox( sOut ) == IDOK ) 
		{ 
			m_bSendingFile = FALSE; 
			return; 
		} 
	} 
	do 
	{ 
		nr = fread( (char *)m_szDataBuffer, sizeof( char ), BUFSIZE, m_pXferFilePointer );  
		if( nr > 0 ) 
		{ 
			send( m_sktData, m_szDataBuffer, nr, 0); 
		} 
	} while( nr > 0 ); 
	m_bSendingFile = FALSE; 
	m_bFileHasBeenSent = TRUE; 
	fclose( m_pXferFilePointer ); 
	m_pXferFilePointer = NULL; 
	TRACE("setting  m_bSendingFile to FALSE\n"); 
	closesocket(m_sktData); 
	m_sktData = INVALID_SOCKET; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::ServiceIncomingFile()  
{ 
	TRACE("in  ServiceIncomingFile\n"); 
	// a helper function for the DATA socket READ case 
	CString sOut; 
	BOOL bCancel = FALSE; 
	int nRet, nLen; 
	char *str; 
 
	if( m_bWaitingForTimeout ) // may be a big file 
	{ 
		KillTimer(ID_MYTIMEOUT); 
		m_bWaitingForTimeout = FALSE; 
	} 
 
	ASSERT( m_pXferFilePointer==NULL ); 
	ASSERT( m_sIncomingFilePath.GetLength() ); 
	m_pXferFilePointer = fopen( (const char *)m_sIncomingFilePath, "r" ); 
 
	if( m_pXferFilePointer ) 
	{ 
		fclose( m_pXferFilePointer ); 
		sOut.Format( "File %s\nalready exists.\n\nOverwrite?", m_sIncomingFilePath); 
		if( AfxMessageBox( sOut, MB_YESNO ) != IDYES ) 
		{ 
			bCancel = TRUE; 
		} 
	} 
 
	if( bCancel ) 
	{ 
		BurnIncomingData(); 
	} 
 
	else if( !bCancel && !m_nRadioASCII ) 
	{ 
		// a binary store to disk 
		ASSERT( m_sIncomingFilePath.GetLength() ); 
		m_pXferFilePointer = fopen( (const char *)m_sIncomingFilePath, "wb" ); 
		if( m_pXferFilePointer ) 
		{ 
			do 
			{ 
				nRet = recv( m_sktData, m_szDataBuffer, BUFSIZE, 0 ); 
				if( nRet != SOCKET_ERROR && nRet > 0 ) 
				{ 
					fwrite( (char *)m_szDataBuffer, sizeof( char ), nRet, m_pXferFilePointer ); 
				} 
			} while( nRet != SOCKET_ERROR && nRet > 0 );  
			fclose(m_pXferFilePointer); 
		} 
		else 
		{ 
			sOut.Format( "Specifed path\n%s\nis invalid", m_sIncomingFilePath ); 
			AfxMessageBox( sOut ); 
 
			BurnIncomingData(); 
		} 
	} 
 
	else if( !bCancel && m_nRadioASCII ) 
	{ 
		// an ASCII store to disk 
		ASSERT( m_sIncomingFilePath.GetLength() ); 
		m_pXferFilePointer = fopen( (const char *)m_sIncomingFilePath, "w" ); 
		if( m_pXferFilePointer ) 
		{ 
			do 
			{ 
				memset(m_szDataBuffer,0,BUFSIZE+2); 
				// this memset trick avoids having strtok insert a wild \0 somewhere bad 
				//		it is guaranteed to find a \n (the delimiter in this case) before 
				//		running off into other memory 
				memset(m_szDataBuffer+BUFSIZE, '\n', 1);  
 
				nRet = recv( m_sktData, m_szDataBuffer, BUFSIZE, 0 ); 
				if( nRet != SOCKET_ERROR && nRet > 0 ) 
				{ 
					str=strtok(m_szDataBuffer,"\n"); 
					while( str && *str) 
					{ 
						char temp[BUFSIZE+1]; 
						strcpy( temp, str); 
						nLen = strlen(str); 
						if( nLen > 0 ) 
						{ 
							if( *( str + nLen - 1 ) == 0x0d) // remove the 0x0d aka \r 
							{ 
								*( str + nLen - 1 ) = 0; 
								fprintf( m_pXferFilePointer, "%s\n", str ); 
							} 
							else 
							{ 
								fprintf( m_pXferFilePointer, "%s", str ); 
							} 
						} 
						str=strtok((char *)NULL,"\n"); 
					} 
				} 
			} while( nRet != SOCKET_ERROR && nRet > 0 );  
			fclose(m_pXferFilePointer); 
		} 
		else 
		{ 
			sOut.Format( "Specifed path\n%s\nis invalid", m_sIncomingFilePath ); 
			AfxMessageBox( sOut ); 
			BurnIncomingData(); 
		} 
	} // end of else if on !bCancel && m_nRadioASCII  
 
	// always clean up the same way 
	m_bFileHasBeenReceived = TRUE;  
	m_bReceivingFile = FALSE; 
	TRACE("setting  m_bReceivingFile to FALSE\n"); 
	m_pXferFilePointer = NULL; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// a helper for failures on DATA socket READ case 
void CMiniFTPView::BurnIncomingData(void)  
{ 
	int nRet; 
	do 
	{ 
		nRet = recv( m_sktData, m_szDataBuffer, BUFSIZE, 0 ); 
	} while( nRet != SOCKET_ERROR && nRet > 0 ); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnConnect()  
{ 
	MakeSafeState( TRUE ); // double check that everything is safe 
 
	CConnectDlg dlg; 
	dlg.m_sHost = AfxGetApp()->GetProfileString("Connect", "Host", ""); 
	dlg.m_sName = AfxGetApp()->GetProfileString("Connect", "Name", ""); 
	dlg.m_sPassword = AfxGetApp()->GetProfileString("Connect", "Password", ""); 
	dlg.m_uTimeout = AfxGetApp()->GetProfileInt("Connect", "Timeout", 30); 
 
	// run dialog 
	if( dlg.DoModal() == IDOK)	   
	{ 
		// housecleaning? 
		if( dlg.m_bClearWindow ) 
		{ 
			GetEditCtrl().SetWindowText(""); 
		} 
 
		// make the connection 
		BeginWaitCursor(); // show hourglass  
		m_sktControl = ConnectOrBind( FALSE, (const char *)dlg.m_sHost, "21" ); 
		EndWaitCursor(); // kill hourglass  
 
		if( SOCKET_ERROR != m_sktControl && INVALID_SOCKET != m_sktControl ) 
		{ 
			WSAAsyncSelect ( m_sktControl, AfxGetMainWnd()->m_hWnd,  
					WM_WINSOCK_EVENT_FRAME_CONTROL,  
					FD_WRITE|FD_READ|FD_CLOSE/*|FD_ACCEPT*/); 
 
			int nChars=GetWindowTextLength();    // get the index of the last line 
			if( nChars != 0 ) 
			{ 
				Log("\r\n"); // only do if not the first line in the CEdit 
			} 
			CString sOut; 
			sOut.Format("MiniFTP Status>Control Connection made OK (socket %d)\r\n\r\n",  
							m_sktControl ); 
			Log(sOut); 
 
			// save settings in ini file 
			AfxGetApp()->WriteProfileString("Connect", "Host", dlg.m_sHost); 
			AfxGetApp()->WriteProfileString("Connect", "Name", dlg.m_sName); 
			AfxGetApp()->WriteProfileString("Connect", "Password", dlg.m_sPassword); 
			AfxGetApp()->WriteProfileInt("Connect", "Timeout", dlg.m_uTimeout); 
			m_uTimeout = dlg.m_uTimeout; // save for state machine 
			//  need to logon 
 
			// form command list 
			// send name 
			sOut = "USER "; 
			sOut += dlg.m_sName; 
			m_sCommandList.AddTail(sOut); 
 
			// send	password 
			sOut = "PASS "; 
			sOut += dlg.m_sPassword; 
			m_sCommandList.AddTail(sOut); 
 
			// kick off the state machine  
			// THIS IS WHERE THIS APP REALLY STARTS 
			ASSERT( !m_bTimerOn ); 
			SetTimer(ID_MYTIMER, REPTIME, NULL); 
			m_bTimerOn = TRUE; 
		} 
		else 
		{ 
			CString sOut, sMoreout; 
			sOut.Format("Connection error code %d", m_sktControl); 
			sMoreout = ""; 
			switch (m_sktControl) 	  // which error? 
			{ 
				case SOCKET_ERROR: 
					sMoreout = " (SOCKET_ERROR or INVALID_SOCKET)"; 
					break; 
		/*		case INVALID_SOCKET: 
					sMoreout = " (INVALID_SOCKET)"; 
					break;  */ 
			} // end of switch 
			sOut += sMoreout; 
			AfxMessageBox(sOut); 
		} 
	} // end of if on domodal 
	// defeat the final "save document" dialog on app exit 
	GetDocument()->SetModifiedFlag(FALSE);  
} 
 
///////////////////////////////////////////////////////////////////////////// 
// use this function to connect to a host on a port 
BOOL CMiniFTPView::UserCommand(CString sCommand) 
{ 
	BOOL bRet = FALSE; 
	if( sCommand.GetLength() == 0 ) 
	{ 
		bRet = TRUE; 
		return bRet; 
	} 
 
	if( m_sktListen != INVALID_SOCKET ) 
	{ 
		closesocket(m_sktListen); 
	} 
	m_sktListen = INVALID_SOCKET; 
 
   	CString sOut; 
	m_sktListen = ConnectOrBind( TRUE, "0", "0"); 
	if( m_sktListen == INVALID_SOCKET ) 
	{ 
		Log("\r\nMiniFTP Status>Could not form Listen socket"); 
		::MessageBeep(MB_OK); 
		bRet = TRUE; 
		return bRet; 
	} 
	else 
	{ 
		WSAAsyncSelect ( m_sktListen, AfxGetMainWnd()->m_hWnd,  
					WM_WINSOCK_EVENT_FRAME_LISTEN,  
					/*FD_WRITE|FD_READ|*/FD_CLOSE|FD_ACCEPT); 
 
		sOut.Format("\r\nMiniFTP Status>Listen Connection made OK (socket %d)\r\n\r\n",  
						m_sktListen ); 
		Log(sOut); 
 
		// set the socket to listen 
		listen( m_sktListen, 3 ); 
 
		// inform remote end about our port that we created. 
		// get the port name that we got for later transmission in PORT cmd 
		struct sockaddr_in saCtrlAddr; 
		int iLength=sizeof(saCtrlAddr); 
		getsockname(m_sktListen,(struct sockaddr *)&saCtrlAddr,&iLength); 
 
		struct sockaddr_in saTmpAddr; 
		iLength = sizeof (saTmpAddr); 
		if (getsockname(m_sktControl,(LPSOCKADDR)&saTmpAddr, &iLength) 
						==SOCKET_ERROR) 
		{ 
			AfxMessageBox("getsockname problem"); 
		} 
 
		char *a,*p; 
		a = (char *)&saTmpAddr.sin_addr; 
		p = (char *)&saCtrlAddr.sin_port; 
		#define  UC(b)  (((int)b)&0xff) 
		CString sPort= "PORT "; 
		sPort.Format( "PORT %d,%d,%d,%d,%d,%d", 
				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 
				UC(p[0]), UC(p[1]) ); 
		// put the PORT command on the meesage list 
		m_sCommandList.AddTail(sPort); 
 
		// what else to add to list	? 
		CString sTemp = sCommand; 
		sTemp = sTemp.Left(4); 
		sTemp.MakeUpper(); 
		if( sTemp == "RETR" || sTemp == "STOR" ) 
		{ 
			if(sTemp == "RETR") 
			{ 
				m_bReceivingFile = TRUE; 
				m_bFileHasBeenReceived = FALSE; 
				sTemp = sCommand; 
				sTemp = sTemp.Right( sTemp.GetLength() - 5); 
				sTemp.TrimRight(); 
				sTemp.TrimLeft(); 
				m_sIncomingFilePath = m_sIncomingPath; 
				m_sIncomingFilePath += "\\"; 
				m_sIncomingFilePath += sTemp; 
			} 
			if(sTemp == "STOR") 
			{ 
				m_bSendingFile = TRUE; 
				m_bFileHasBeenSent = FALSE; 
				sTemp = sCommand; 
				sTemp = sTemp.Right( sTemp.GetLength() - 5); 
				sTemp.TrimRight(); 
				sTemp.TrimLeft(); 
				m_sStoringFilePath = sTemp; // save it so the event handler can reference 
			} 
			sTemp = "TYPE "; 
			if( m_nRadioASCII ) 
			{ 
				sTemp += "A"; 
			} 
			else 
			{ 
				sTemp += "I"; 
			} 
			m_sCommandList.AddTail(sTemp); 
		} 
 
		// finally put on the list what the user actaully wanted 
		m_sCommandList.AddTail(sCommand); 
		// start the state machine 
		ASSERT( !m_bTimerOn ); 
		SetTimer(ID_MYTIMER, REPTIME, NULL); 
		m_bTimerOn = TRUE; 
		return bRet; 
	} // end of else on m_sktListen 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// use this function to connect to a host on a port 
// return 0 if OK 
BOOL CMiniFTPView::DoCommand(CString s) 
{ 
	BOOL bRet = FALSE; 
	if( m_sktControl != INVALID_SOCKET ) 
	{ 
		send( m_sktControl, (const char *)s, s.GetLength(), 0); 
		CString sTemp; 
		sTemp = s; 
		sTemp.MakeUpper(); 
		sTemp = sTemp.Left(4); 
		if( sTemp == "PASS" ) 
		{ 
			Log( "PASS (hidden)"); 
		} 
		else 
		{ 
			Log(s); 
		} 
		CString sCRLF = "\r\n"; 
		send( m_sktControl, (const char *)sCRLF, sCRLF.GetLength(), 0); 
		Log(sCRLF); 
	} 
	else 
	{ 
		bRet = TRUE; 
	} 
	return( bRet ); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// use this function to connect or bind to a host on a port 
// pass bBind TRUE to do a bind() i.e. Listen 
// pass bBind FALSE to do a connect() 
SOCKET CMiniFTPView::ConnectOrBind(BOOL bBind, const char *name, const char *port) 
{ 
	SOCKET s = INVALID_SOCKET; 
 
	struct sockaddr_in far server; 
	struct hostent far *hp; 
	char msg[100]; 
 
	int portnum = atoi(port); 
 
	while( *name != 0 && *name == ' ' ) 
	{ 
		name++; 
	} 
 
	/*if( *name == 0 || portnum == 0) 
	{ 
		return INVALID_SOCKET; 
	}*/ // this is not a good test in the Listen/Bind case 
 
	if( (name[0] >= '0') && (name[0] <= '9') )  
	{ 
		memset((char *) &server,0,sizeof(server)); 
		server.sin_family      = AF_INET; 
		server.sin_addr.s_addr = inet_addr(name); 
		server.sin_port        = htons(portnum); 
	} 
	else 
	{  
		if ( (hp = (hostent far *) gethostbyname(name)) == NULL) 
		{ 
			sprintf(msg,"Error: Connecting to %s.", name); 
 
			if(AfxMessageBox( msg ) == IDOK) 
			{ 
				return INVALID_SOCKET; 
			} 
		} 
		memset( (char *) &server, 0, sizeof(server)); 
		memcpy( (char *) &server.sin_addr, hp->h_addr, hp->h_length ); 
		server.sin_family = hp->h_addrtype; 
		server.sin_port = htons( portnum );   
	}// end of else  
 
	// create socket  
	if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 1)  
	{ 
		sprintf( msg,"Error opening stream socket" ); 
		if(AfxMessageBox( msg ) == IDOK) 
		{ 
			return INVALID_SOCKET; 
		} 
	} 
   
	if( !bBind )	// do connect to server 
	{ 
		if (connect( s, (struct sockaddr far *)&server, sizeof(server))< 0 ) 
		{ 
			sprintf( msg,"Cannot connect to %s on port %s",name,port); 
			if(AfxMessageBox( msg ) == IDOK) 
			{ 
				return INVALID_SOCKET; 
			} 
		} 
	} 
	else	   // do a bind so we listen 
	{ 
		if (bind(s, (struct sockaddr far *)&server, sizeof(server))< 0) 
		{ 
			sprintf(msg,"Cannot bind to %s on port %s",name,port); 
			if(AfxMessageBox( msg ) == IDOK) 
			{ 
				return INVALID_SOCKET; 
			} 
		} 
	} 
 
	setsockopt( s, SOL_SOCKET, SO_LINGER, 0, 0 );	 
	setsockopt( s, SOL_SOCKET, SO_REUSEADDR, 0, 0 ); 
	setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, 0, 0 ); 
 
	return s;		    
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnFsettings()  
{ 
	CXport dlg; 
	dlg.m_nRadioASCII = m_nRadioASCII; // was initialized in constructor 
	dlg.m_sIncomingPath = m_sIncomingPath; // was initialized in constructor 
  
	if( dlg.DoModal() == IDOK)	   
	{ 
		// save settings in ini file 
		AfxGetApp()->WriteProfileInt("Setting", "ASCII", dlg.m_nRadioASCII ); 
		AfxGetApp()->WriteProfileString("Setting", "Name", dlg.m_sIncomingPath); 
		m_nRadioASCII = dlg.m_nRadioASCII; 
		m_sIncomingPath = dlg.m_sIncomingPath; 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnCloseconn()  
{ 
	MakeSafeState(TRUE); 
	Log("\r\nMiniFTP Status>Connection closed by client\r\n\r\n"); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnClearview()  
{ 
	// clear the user input edit box 
	GetEditCtrl().SetWindowText(""); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnUpdateCloseconn(CCmdUI* pCmdUI)  
{ 
	if( m_sktControl != INVALID_SOCKET ) 
	{ 
		pCmdUI->Enable(1 );  
	} 
	else 
	{ 
		pCmdUI->Enable(0); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////// 
void CMiniFTPView::OnUpdateConnect(CCmdUI* pCmdUI)  
{ 
	if( m_sktControl == INVALID_SOCKET ) 
	{ 
		pCmdUI->Enable(1 );  
	} 
	else 
	{ 
		pCmdUI->Enable(0); 
	} 
}