📄 qftplib.cpp
字号:
#include <stdlib.h> // Required for atoi()
#include <string.h> // Required for _fstrstr()
#include "..\winsock.h" // Winsock header file
#define PROG_NAME "Quick FTP.DLL"
#define WINSOCK_VERSION 0x0101 // Program requires Winsock version 1.1
#define DEFAULT_PROTOCOL 0 // No protocol specified, use default
#define NO_FLAGS 0 // No special flags specified
#define QUEUE_SIZE 1 // Size of connection queue for listen()
#define LINEFEED 0x0A // Line-feed character
#define MULTILINE_REPLY '-' // FTP flag for multiline replies
#define EOL_MARKER "\r\n" // FTP end-of-line marker
char gsServerReplyText[2048]; // FTP server reply buffer
char gszCommandBuffer[100]; // Buffer used to format FTP commands
LPSTR lpszFunctionName; // Pointer to function names
char gsReplyBuffer[2048]; // Buffer for peeking at FTP server replies
char gsDataBuffer[4096]; // Storage buffer for data channel
extern "C" UINT FAR PASCAL GetReplyCode(LPSTR lpszServerReply)
{
UINT nCode; // Reply code as a number
char c; // Temporary storage
// lpszFunctionName = "GetReplyCode";
c = *(lpszServerReply+3); // Save the character
*(lpszServerReply+3) = '\0'; // Terminate the code
nCode = atoi((const char *)lpszServerReply); // Convert code to number
*(lpszServerReply+3) = c; // Restore the character
return(nCode); // Return the reply code
}
extern "C" BOOL FAR PASCAL IsReadyToRead(SOCKET hSocket)
{
FD_SET setReadyToRead; // Socket set to test ready-to-read status
TIMEVAL timeTimeOut; // Amount of time to wait for status change
int nReady; // Ready-to-read flag
lpszFunctionName = "IsReadyToRead";
timerclear(&timeTimeOut);
FD_ZERO(&setReadyToRead);
FD_SET(hSocket, &setReadyToRead);
if ((nReady = select(NULL, (LPFD_SET)&setReadyToRead, NULL, NULL,
&timeTimeOut)) == SOCKET_ERROR)
{
int iWinsockErr = WSAGetLastError();
wsprintf(gszCommandBuffer, "Error %d from the select() function!!",
iWinsockErr);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONSTOP);
return(FALSE);
}
return(nReady ? TRUE : FALSE);
}
extern "C" UINT FAR PASCAL ReadReplyLine(LPSTR lpszReplyBuffer)
{
LPSTR lpEOL; // End-of-line
UINT nLimitReplyBytes; // Length of first reply in the buffer
PSTR pLastLineCode = "123?"; // Storage buffer for reply code
LPSTR lpLastLine; // Pointer to the last line
int i; // General purpose index
// lpszFunctionName = "ReadReplyLine";
nLimitReplyBytes = 0;
if (*(lpszReplyBuffer+3) == MULTILINE_REPLY)
{
// Get the code from the reply buffer
for (i = 0; i <3; i++ )
*(pLastLineCode+i) = *(lpszReplyBuffer+i);
// Use a trailing space to look for the last line
*(pLastLineCode+i) = ' ';
// Search the buffer for the last line
if ((lpLastLine = _fstrstr(lpszReplyBuffer, pLastLineCode)))
{
// Okay, be cautious and make sure a CRLF exists
lpEOL = (LPSTR)_fstrstr(lpLastLine, EOL_MARKER);
// Note length to read if more than one reply is in the buffer
nLimitReplyBytes = lpEOL ? (UINT)((lpEOL - lpszReplyBuffer)+2) : 0;
}
else
nLimitReplyBytes = 0;
}
else
{
// If the reply is not multiline then find the end of the line.
lpEOL = (LPSTR)_fstrstr(lpszReplyBuffer, EOL_MARKER);
// If an end-of-line marker was not found, read everything
// (i.e. don't limit the reply size). Otherwise, only read to the
// end of line marker.
nLimitReplyBytes = lpEOL ? (UINT)((lpEOL - lpszReplyBuffer)+2) : 0;
}
return(nLimitReplyBytes);
}
extern "C" LPSTR _export FAR PASCAL GetFTPServerReplyText(VOID)
{
return((LPSTR)gsServerReplyText); // Return full text of server's reply
}
extern "C" UINT FAR PASCAL ReadFTPServerReply(SOCKET hControlChannel)
{
int iBytesRead; // Bytes read from the control channel
int iBufferLength; // Length of the server reply buffer
int iEnd; // Index into the server reply buffer
int iSpaceRemaining; // Space remaining in the buffer
int iReplySize; // Length of first reply in the buffer
lpszFunctionName = "ReadFTPServerReply";
// Be cautious and zero fill the buffer
_fmemset(gsReplyBuffer, 0, sizeof(gsReplyBuffer));
// Be tricky and peek ahead to see what's in the buffer.
if ((iBytesRead = recv(hControlChannel,
(LPSTR)(gsReplyBuffer), sizeof(gsReplyBuffer), MSG_PEEK)) > 0)
{
if ((iReplySize = ReadReplyLine(gsReplyBuffer)) == 0)
iBufferLength = iSpaceRemaining = sizeof(gsServerReplyText);
else
iBufferLength = iSpaceRemaining = iReplySize;
}
else
{
MessageBeep(MB_ICONINFORMATION);
MessageBox(NULL,
(LPSTR)"Nothing on the control channel to read!",
lpszFunctionName, MB_OK|MB_ICONINFORMATION);
return(999);
}
iEnd = 0; // Start with zero bytes.
do
{
iSpaceRemaining -= iEnd;
iBytesRead = recv(hControlChannel,
(LPSTR)(gsServerReplyText+iEnd), iSpaceRemaining, NO_FLAGS);
iEnd+=iBytesRead;
// Make sure CRLF was not the the last byte pair received.
// Otherwise, recv() will wait forever for the next packet.
if (*(gsServerReplyText+(iEnd-1)) == LINEFEED)
{
LPSTR lpLineFeed;
LPSTR lpLastLine;
// Temporarily replace the real last line marker (LF)
// with a NULL so _fstrstr doesn't go crazy.
*(gsServerReplyText+(iEnd-1)) = '\0';
// See if any other line-feeds exist in the buffer
// (which means the buffer contains multiple lines).
lpLineFeed = _fstrrchr(gsServerReplyText, LINEFEED);
// Restore the line-feed character.
*(gsServerReplyText+(iEnd-1)) = LINEFEED;
if (lpLineFeed)
// If a line-feed was found then the next character is
// the start of the last line.
lpLastLine = lpLineFeed+1;
else
// Otherwise, the buffer contains only have one line
lpLastLine = gsServerReplyText;
// Be cautious and make sure the last line includes a reply code
if (GetReplyCode(lpLastLine))
{
// Test the reply code to see if it indicates more lines
if (*(lpLastLine+3) != MULTILINE_REPLY)
break; // If not, break out of the loop.
}
else
; // Whoops, somebody's server is not playing by the rules.
}
}
while (iBytesRead > 0 && iEnd < iBufferLength);
if (iBytesRead == SOCKET_ERROR)
{
int iWinsockErr = WSAGetLastError();
wsprintf(gszCommandBuffer, "Error %d from the recv() function!!",
iWinsockErr);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONSTOP);
// Return 999 to indicate an error has occurred
return(999);
}
gsServerReplyText[iEnd] = '\0';
#ifdef _DEBUG
MessageBeep(MB_ICONINFORMATION);
MessageBox(NULL, (LPSTR)gsServerReplyText, lpszFunctionName,
MB_OK|MB_ICONINFORMATION);
#endif
// Extract the reply code from the server reply and return as an integer
return(GetReplyCode(gsServerReplyText));
}
extern "C" UINT _export FAR PASCAL SendFTPCommand(SOCKET hControlChannel, LPSTR gszCommandBuffer)
{
lpszFunctionName = "SendFTPCommand";
// Send the FTP command
if ((send(hControlChannel, (LPSTR)gszCommandBuffer,
lstrlen(gszCommandBuffer), NO_FLAGS)) == SOCKET_ERROR)
{
int iWinsockErr = WSAGetLastError();
wsprintf(gszCommandBuffer, "Error %d from the send() function!!",
iWinsockErr);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONSTOP);
// Return 999 to indicate an error has occurred
return(999);
}
// Read the server's reply and return the reply code as an integer
return(ReadFTPServerReply(hControlChannel));
}
extern "C" UINT _export FAR PASCAL ReadDataChannel(SOCKET hControlSocket,
SOCKET hDataSocket, LPSTR lpszFileName)
{
int nBytesRecv; // Bytes received from the data channel
HFILE hFile; // File handle for data file
OFSTRUCT openFileBuff; // The Windows open file data structure
LONG lData = 0L; // Bytes received and written to the data file
lpszFunctionName = "ReadDataChannel";
if ((hFile = OpenFile(lpszFileName, (OFSTRUCT far *)&openFileBuff,
OF_CREATE)) == HFILE_ERROR)
{
_lclose(hFile);
wsprintf(gszCommandBuffer,"Error creating file: %s\n", lpszFileName);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName, MB_OK|MB_ICONSTOP);
return(FALSE);
}
do // Ready read and write
{
nBytesRecv = recv(hDataSocket, (LPSTR)&gsDataBuffer,
sizeof(gsDataBuffer), NO_FLAGS);
lData += nBytesRecv;
if (nBytesRecv > 0 )
{
if (HFILE_ERROR == _lwrite (hFile, gsDataBuffer, nBytesRecv))
{
wsprintf(gszCommandBuffer,"Error writing file: %s\n", lpszFileName);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONSTOP);
break;
}
}
}
while (nBytesRecv > 0);
// Close the file and check for error returns.
_lclose(hFile);
if (nBytesRecv == SOCKET_ERROR)
{
int iWinsockErr = WSAGetLastError();
wsprintf(gszCommandBuffer,
"Error #%d occurred receiving: %s\n",
iWinsockErr, lpszFileName);
MessageBeep(MB_ICONSTOP);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONSTOP);
return(FALSE);
}
else if (lData == 0)
{
MessageBeep(MB_ICONINFORMATION);
MessageBox(NULL,
(LPSTR)"Nothing on the data channel to read!",
lpszFunctionName, MB_OK|MB_ICONINFORMATION);
return(FALSE);
}
#ifdef _DEBUG
else
{
wsprintf(gszCommandBuffer,"%lu bytes written to %s\n", lData,
lpszFileName);
MessageBeep(MB_ICONINFORMATION);
MessageBox(NULL, gszCommandBuffer, lpszFunctionName,
MB_OK|MB_ICONINFORMATION);
}
#endif
// Read the control channel to see what the server thought about it.
return(ReadFTPServerReply(hControlSocket));
}
extern "C" UINT _export FAR PASCAL TransferFile(SOCKET hControlSocket,
SOCKET hDataSocket, HFILE hFile)
{
char szFileData[1024]; // Buffer to hold file data
int nCharRecv; // Number of characters received
char szMsg[100]; // General purpose buffer for messages
nCharRecv = recv(hDataSocket, (LPSTR)&szFileData, sizeof(szFileData), NO_FLAGS);
if (nCharRecv > 0 )
{
if (HFILE_ERROR == _lwrite (hFile, szFileData, nCharRecv))
{
_lclose(hFile);
wsprintf(szMsg,"%d Error occurred during recv()!", nCharRecv);
MessageBox(NULL, szMsg, PROG_NAME, MB_OK|MB_ICONSTOP);
return(HFILE_ERROR);
}
}
else if (nCharRecv == SOCKET_ERROR)
{
_lclose(hFile);
nCharRecv = WSAGetLastError();
wsprintf(szMsg,"%d Error occurred during recv()!", nCharRecv);
MessageBox(NULL, szMsg, PROG_NAME, MB_OK|MB_ICONSTOP);
return(SOCKET_ERROR);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -