⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 view.cpp

📁 简单的ftp客户端下载程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -