📄 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -