📄 ac_ftp.c
字号:
/*---------------------------------------------------------------------
*
* Program: AC_FTP.EXE Asynch Ftp Client (TCP)
*
* filename: ac_ftp.c
*
* copyright by Bob Quinn, 1995
*
* Description:
* Client application that uses "file transfer protocol" (ftp)
* service as described by RFC 959. This application demonstrates
* bulk data transfer techniques, and reading variable length records
* from a byte stream (TCP socket). The user interface is minimized
* in order to emphasize the network code.
*
* This software is not subject to any export provision of
* the United States Department of Commerce, and may be
* exported to any country or planet.
*
* Permission is granted to anyone to use this software for any
* purpose on any computer system, and to alter it and redistribute
* it freely, subject to the following restrictions:
*
* 1. The author is not responsible for the consequences of
* use of this software, no matter how awful, even if they
* arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented,
* either by explicit claim or by omission. Since few users
* ever read sources, credits must appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* Since few users ever read sources, credits must appear in
* the documentation.
*
* 4. This notice may not be removed or altered.
*
---------------------------------------------------------------------*/
#define STRICT
#include "..\wsa_xtra.h"
#include <windows.h>
#include <windowsx.h>
#include <string.h> /* for _fmemcpy() & _fmemset() */
#include <winsock.h>
#include "resource.h"
#include <time.h>
#include <stdio.h>
#include <direct.h> /* for getcwd() */
#include "..\winsockx.h"
#include "ac_ftp.h"
/* Ftp commmand strings (indexed by our command macro values) */
LPSTR aszFtpCmd[] = {
"", "CWD", "DELE", "PASS","PORT","RETR","STOR",
"TYPE","USER","ABOR","LIST","PWD", "QUIT"
};
char szAppName[] = "AC_FTP";
BOOL nAppState=NOT_CONNECTED; /* Application State */
BOOL bToNul =FALSE; /* Get to NUL device file */
BOOL bFromNul=FALSE; /* Put from NUL device file */
BOOL bIOBeep =FALSE; /* Beep on FD_READ, FD_WRITE */
BOOL bDebug =FALSE; /* Debug output to WinDebug */
BOOL bReAsync=TRUE; /* Call WSAAsyncSelect after accept() */
BOOL bLogFile=TRUE; /* Write Cmds and Replies to logfile */
SOCKET hCtrlSock=INVALID_SOCKET; /* Ftp control socket */
SOCKET hLstnSock=INVALID_SOCKET; /* Listening data socket */
SOCKET hDataSock=INVALID_SOCKET; /* Connected data socket */
char szHost[MAXHOSTNAME]={0}; /* Remote host name or address */
char szUser[MAXUSERNAME]={0}; /* User ID */
char szPWrd[MAXPASSWORD]={0}; /* User password */
SOCKADDR_IN stCLclName; /* Control socket name (local client) */
SOCKADDR_IN stCRmtName; /* (remote server) */
SOCKADDR_IN stDLclName; /* Data socket name (local client)*/
SOCKADDR_IN stDRmtName; /* (remote server) */
char achInBuf [INPUT_SIZE]; /* Network input data buffer */
char achOutBuf [INPUT_SIZE]; /* Network output buffer */
char szFtpRply [RPLY_SIZE]={0}; /* Ftp reply (input) buffer */
char szDataFile[MAXFILENAME]={0};/* Filename */
char szFtpCmd [CMD_SIZE]={0}; /* Ftp command buffer */
char achRplyBuf[BUF_SIZE]; /* Reply display buffer */
/* first one (index=0) is awaiting a reply
* second (index=1) is next to be sent, etcetera */
FTPCMD astFtpCmd[MAX_CMDS]; /* Ftp command queue */
int nQLen; /* Number of entries in Ftp cmd queue */
int nFtpRplyCode; /* Ftp reply code from server */
int iNextRply; /* Index to next reply string */
int iLastRply;
HFILE hDataFile=HFILE_ERROR; /* File handle for open data file */
LONG lStartTime; /* Start time for data transfer */
LONG lByteCount;
char szLogFile[] = "ac_ftp.log"; /* Ftp command and reply log file */
HFILE hLogFile=HFILE_ERROR;
/*--------------------------------------------------------------------
* Function: WinMain()
*
* Description:
* initialize WinSock and open main dialog box
*
*/
int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
MSG msg;
int nRet;
lpszCmdLine = lpszCmdLine; /* avoid warning */
hPrevInstance = hPrevInstance;
nCmdShow = nCmdShow;
hInst = hInstance; /* save instance handle */
/*-------------initialize WinSock DLL------------*/
nRet = WSAStartup(WSA_VERSION, &stWSAData);
/* WSAStartup() returns error value if failed (0 on success) */
if (nRet != 0) {
WSAperror(nRet, "WSAStartup()", hInst);
/* No sense continuing if we can't use WinSock */
} else {
DialogBox (hInst, MAKEINTRESOURCE(AC_FTP), NULL, Dlg_Main);
/*---------------release WinSock DLL--------------*/
nRet = WSACleanup();
if (nRet == SOCKET_ERROR)
WSAperror(WSAGetLastError(), "WSACleanup()", hInst);
}
return msg.wParam;
} /* end WinMain() */
/*--------------------------------------------------------------------
* Function: Dlg_Main()
*
* Description: Do all the message processing for the main dialog box
*/
BOOL CALLBACK Dlg_Main
(HWND hDlg,
UINT msg,
UINT wParam,
LPARAM lParam)
{
int nAddrSize = sizeof(SOCKADDR);
WORD WSAEvent, WSAErr;
SOCKET hSock;
BOOL bOk, bRet = FALSE;
int nRet;
LONG lRet;
switch (msg) {
case WSA_ASYNC+1:
/*-------------------------------------------------
* Data socket async notification message handlers
*-------------------------------------------------*/
hSock = (SOCKET)wParam; /* socket */
WSAEvent = WSAGETSELECTEVENT (lParam); /* extract event */
WSAErr = WSAGETSELECTERROR (lParam); /* extract error */
/* if error, display to user (listen socket should not have
* an error, but some WinSocks incorrectly post it) */
if ((WSAErr) && (hSock == hDataSock)) {
int i,j;
for (i=0, j=WSAEvent; j; i++, j>>=1); /* convert bit to index */
WSAperror(WSAErr,aszWSAEvent[i], hInst);
/* fall-through to call reenabling function for this event */
}
switch (WSAEvent) {
case FD_READ:
if (bIOBeep)
MessageBeep(0xFFFF);
if (hDataSock != INVALID_SOCKET) {
/* Receive file data or directory list */
RecvData(hDataSock, hDataFile, achInBuf, INPUT_SIZE);
}
break;
case FD_ACCEPT:
if (hLstnSock != INVALID_SOCKET) {
/* Accept the incoming data connection request */
hDataSock =
AcceptDataConn(hLstnSock, &stDRmtName);
nAppState |= DATACONNECTED;
/* Close the Listening Socket */
closesocket(hLstnSock);
hLstnSock = INVALID_SOCKET;
lStartTime = GetTickCount();
/* Data transfer should begin with FD_WRITE or FD_READ. We
* fall through to jumpstart sends since FD_WRITE is not
* always implemented correctly */
}
case FD_WRITE:
/* Send file data */
if (astFtpCmd[0].nFtpCmd == STOR) {
lRet = SendData(&hDataSock, hDataFile, MTU_SIZE);
}
break;
case FD_CLOSE: /* Data connection closed */
if (hSock == hDataSock) {
/* Read any remaining data into buffer and close connection */
CloseFtpConn(&hDataSock,
(astFtpCmd[0].nFtpCmd != STOR) ? achInBuf : (LPSTR)0,
INPUT_SIZE, hDlg);
EndData ();
}
break;
default:
break;
} /* end switch(WSAEvent) */
break;
case WSA_ASYNC:
/*-----------------------------------------------------
* Control socket async notification message handlers
*-----------------------------------------------------*/
WSAEvent = WSAGETSELECTEVENT (lParam); /* extract event */
WSAErr = WSAGETSELECTERROR (lParam); /* extract error */
if (WSAErr) { /* if error, display to user */
int i,j;
for (i=0, j=WSAEvent; j; i++, j>>=1); /* convert bit to index */
WSAperror(WSAErr,aszWSAEvent[i], hInst);
/* fall-through to call reenabling function for this event */
}
hSock = (SOCKET)wParam;
switch (WSAEvent) {
case FD_READ:
if (!iNextRply) {
/* Receive reply from server */
iLastRply = RecvFtpRply(hCtrlSock, szFtpRply, RPLY_SIZE);
}
if (iLastRply && (iLastRply != SOCKET_ERROR)) {
/* Display the reply Message */
GetDlgItemText (hWinMain, IDC_REPLY, achRplyBuf,
RPLY_SIZE-strlen(szFtpRply));
wsprintf (achTempBuf, "%s%s", szFtpRply, achRplyBuf);
SetDlgItemText (hWinMain, IDC_REPLY, achTempBuf);
/* Save index to next reply (if there is one) */
nRet = strlen(szFtpRply);
if (iLastRply > nRet+2) {
iNextRply = nRet+3;
/* Adjust if reply only had LF (no CR) */
if (szFtpRply[nRet+2])
iNextRply = nRet+2;
}
}
/* Figure out what to do with reply based on last command */
ProcessFtpRply (szFtpRply, RPLY_SIZE);
break;
case FD_WRITE:
/* Send command to server */
if (astFtpCmd[1].nFtpCmd)
SendFtpCmd();
break;
case FD_CONNECT:
/* Control connected at TCP level */
nAppState = CTRLCONNECTED;
wsprintf(achTempBuf, "Server: %s", szHost);
SetDlgItemText (hDlg, IDC_SERVER, achTempBuf);
SetDlgItemText (hDlg, IDC_STATUS, "Status: connected");
break;
case FD_CLOSE:
if (nAppState & CTRLCONNECTED) {
nAppState = NOT_CONNECTED; /* Reset app state */
AbortFtpCmd();
if (hCtrlSock != INVALID_SOCKET) /* Close control socket */
CloseFtpConn(&hCtrlSock, (PSTR)0, 0, hDlg);
SetDlgItemText (hDlg, IDC_SERVER, "Server: none");
SetDlgItemText (hDlg, IDC_STATUS, "Status: not connected");
}
break;
default:
break;
} /* end switch(WSAEvent) */
break;
case WM_COMMAND:
switch (wParam) {
case IDC_CONNECT:
/* If we already have a socket open, tell user to close it */
if (nAppState & CTRLCONNECTED) {
MessageBox (hDlg,"Close the active connection first",
"Can't Connect", MB_OK | MB_ICONASTERISK);
} else {
/* Prompt user for server and login user information */
bOk = DialogBox (hInst, MAKEINTRESOURCE(IDD_SERVER),
hDlg, Dlg_Login);
if (bOk) {
/* Check the destination address and resolve if necessary */
stCRmtName.sin_addr.s_addr = GetAddr(szHost);
if (stCRmtName.sin_addr.s_addr == INADDR_ANY) {
/* Tell user to enter a host */
wsprintf(achTempBuf,
"Sorry, server %s is invalid. Try again", szHost);
MessageBox (hDlg, achTempBuf,
"Can't connect!", MB_OK | MB_ICONASTERISK);
} else {
/* Initiate connect attempt to server */
hCtrlSock =
InitCtrlConn(&stCRmtName, hDlg, WSA_ASYNC);
}
}
}
break;
case IDC_CLOSE:
if (nAppState & CTRLCONNECTED) {
/* Set application state so nothing else is processed */
nAppState = NOT_CONNECTED;
/* If we're listening, stop now */
if (hLstnSock != INVALID_SOCKET) {
closesocket(hLstnSock);
hLstnSock = INVALID_SOCKET;
}
/* If there is a data connection, then abort it */
if (hDataSock != INVALID_SOCKET)
QueueFtpCmd (ABOR, 0);
/* Quit the control connection */
if (hCtrlSock != INVALID_SOCKET)
QueueFtpCmd (QUIT, 0);
SetDlgItemText (hDlg, IDC_SERVER, "Server: none");
SetDlgItemText (hDlg, IDC_STATUS, "Status: not connected");
}
break;
case IDC_RETR:
/* Prompt for name of remote file to get */
if (nAppState & CTRLCONNECTED) {
bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME),
hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
if (bOk && szDataFile[0]) {
if (!bToNul) {
/* If user provided a filename open same name here for write.
* Truncate the filename to 8 chars plus 3, if necessary */
hDataFile = CreateLclFile (szDataFile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -