www.pudn.com > FTPC.zip > FTP_CTRL.C
/*--------------------------------------------------------------------- * * Program: AC_FTP.EXE Asynch Ftp Client (TCP) * * filename: FTP_CTRL.C * * copyright by Bob Quinn, 1995 * * Description: * Client application that uses "file transfer protocol" (ftp) * service as described by RFC 959. * * This module contains the functions that deal with the FTP * control connection (for sending commands to FTP server, * receiving replies from FTP server, and processing them. * * 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. * ---------------------------------------------------------------------*/ #include "..\wsa_xtra.h" #include#include #include "..\winsockx.h" #include /* for _fmemcpy() & _fmemset() */ #include #include "resource.h" #include /* for Microsoft find file structure */ #include "ac_ftp.h" /*--------------------------------------------------------------- * Function: InitCtrlConn() * * Description: get a TCP socket, register for async notification, * and then connect to Ftp server */ SOCKET InitCtrlConn(PSOCKADDR_IN pstName, HWND hDlg, u_int nAsyncMsg) { int nRet; SOCKET hCtrlSock; if (bDebug) OutputDebugString("InitCtrlConn()\n"); /* Get a TCP socket for control connection */ hCtrlSock = socket (AF_INET, SOCK_STREAM, 0); if (hCtrlSock == INVALID_SOCKET) { WSAperror(WSAGetLastError(), "socket()", hInst); } else { /* Request async notification for most events */ nRet = WSAAsyncSelect(hCtrlSock, hDlg, nAsyncMsg, (FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE)); if (nRet == SOCKET_ERROR) { WSAperror(WSAGetLastError(), "WSAAsyncSelect()", hInst); closesocket(hCtrlSock); hCtrlSock = INVALID_SOCKET; } else { /* Initiate non-blocking connect to server */ pstName->sin_family = PF_INET; pstName->sin_port = htons(IPPORT_FTP); nRet = connect(hCtrlSock,(LPSOCKADDR)pstName,SOCKADDR_LEN); if (nRet == SOCKET_ERROR) { int WSAErr = WSAGetLastError(); /* Anything but "would block" error is bad */ if (WSAErr != WSAEWOULDBLOCK) { /* Report error and clean up */ WSAperror(WSAErr, "connect()", hInst); closesocket(hCtrlSock); hCtrlSock = INVALID_SOCKET; } } } } return (hCtrlSock); } /* end InitCtrlConn() */ /*-------------------------------------------------------------- * Function: SendFtpCmd() * * Description: Format and send an FTP command to the server */ int SendFtpCmd(void) { int nRet, nLen, nBytesSent = 0; int nFtpCmd = astFtpCmd[1].nFtpCmd; if (bDebug) { wsprintf(achTempBuf, "SendFtpCmd() Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, State:%d\n", nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd, astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, nAppState); OutputDebugString (achTempBuf); } /* Create a command string (if we don't already have one) */ if (szFtpCmd[0] == 0) { switch (nFtpCmd) { case PORT: wsprintf (szFtpCmd, "PORT %d,%d,%d,%d,%d,%d\r\n", stDLclName.sin_addr.S_un.S_un_b.s_b1, /* local addr */ stDLclName.sin_addr.S_un.S_un_b.s_b2, stDLclName.sin_addr.S_un.S_un_b.s_b3, stDLclName.sin_addr.S_un.S_un_b.s_b4, stDLclName.sin_port & 0xFF, /* local port */ (stDLclName.sin_port & 0xFF00)>>8); break; case CWD: case DELE: case PASS: case RETR: case STOR: case TYPE: case USER: /* Ftp commmand and parameter */ wsprintf (szFtpCmd, "%s %s\r\n", aszFtpCmd[nFtpCmd], &(astFtpCmd[1].szFtpParm)); break; case ABOR: case LIST: case PWD: case QUIT: /* Solitary Ftp command string (no parameter) */ wsprintf (szFtpCmd, "%s\r\n", aszFtpCmd[nFtpCmd]); break; default: return (0); /* we have a bogus command! */ } } nLen = strlen(szFtpCmd); if (hCtrlSock != INVALID_SOCKET) { /* Send the ftp command to control socket */ while (nBytesSent < nLen) { nRet = send(hCtrlSock, (LPSTR)szFtpCmd, nLen-nBytesSent, 0); if (nRet == SOCKET_ERROR) { int WSAErr = WSAGetLastError(); /* If "would block" error we'll pickup again with async * FD_WRITE notification, but any other error is bad news */ if (WSAErr != WSAEWOULDBLOCK) WSAperror(WSAErr, "SendFtpCmd()", hInst); break; } nBytesSent += nRet; } } /* if we sent it all, update our status and move everything up * in command queue */ if (nBytesSent == nLen) { int i; if (nFtpCmd == PASS) /* hide password */ memset (szFtpCmd+5, 'x', 10); if (bLogFile) /* log command */ _lwrite (hLogFile, szFtpCmd, strlen(szFtpCmd)); GetDlgItemText (hWinMain, IDC_REPLY, /* display command */ achRplyBuf, RPLY_SIZE-strlen(szFtpCmd)); wsprintf (achTempBuf, "%s%s", szFtpCmd, achRplyBuf); SetDlgItemText (hWinMain, IDC_REPLY, achTempBuf); szFtpCmd[0] = 0; /* disable Ftp command string */ /* move everything up in the command queue */ for (i=0; i < nQLen; i++) { astFtpCmd[i].nFtpCmd = astFtpCmd[i+1].nFtpCmd; astFtpCmd[i+1].nFtpCmd = 0; /* reset old command */ if (*(astFtpCmd[i+1].szFtpParm)) { memcpy (astFtpCmd[i].szFtpParm, astFtpCmd[i+1].szFtpParm, CMD_SIZE); *(astFtpCmd[i+1].szFtpParm) = 0; /* terminate old string */ } else { *(astFtpCmd[i].szFtpParm) = 0; /* terminate unused string */ } } nQLen--; /* decrement the queue length */ switch (nFtpCmd) { case (USER): SetDlgItemText (hWinMain, IDC_STATUS,"Status: connecting"); break; case (STOR): SetDlgItemText (hWinMain, IDC_STATUS,"Status: sending a file"); break; case (RETR): SetDlgItemText (hWinMain, IDC_STATUS,"Status: receiving a file"); break; case (LIST): SetDlgItemText (hWinMain, IDC_STATUS,"Status: receiving directory"); break; case (QUIT): SetDlgItemText (hWinMain, IDC_SERVER, "Server: none"); SetDlgItemText (hWinMain, IDC_STATUS, "Status: not connected"); break; } } return (nBytesSent); } /* end SendFtpCmd() */ /*-------------------------------------------------------------- * Function: QueueFtpCmd() * * Description: Put FTP command in command queue for sending after we * receive responses to pending commands or now if nothing is pending */ BOOL QueueFtpCmd(int nFtpCmd, LPSTR szFtpParm) { if (bDebug) { wsprintf(achTempBuf, "QueueFtpCmd() Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, pend:%d\n", nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd, astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, recv(hCtrlSock, achTempBuf, BUF_SIZE, MSG_PEEK)); OutputDebugString (achTempBuf); } if ((nFtpCmd == ABOR) || (nFtpCmd == QUIT)) { AbortFtpCmd(); if (hCtrlSock != INVALID_SOCKET) SetDlgItemText (hWinMain, IDC_STATUS,"Status: connected"); } else if (nQLen == MAX_CMDS) { /* Notify user if they can't fit in the queue */ MessageBox (hWinMain, "Ftp command queue is full, try again later", "Can't Queue Command", MB_OK | MB_ICONASTERISK); return (FALSE); /* not queued */ } nQLen++; /* increment Ftp command counter */ /* Save command vitals */ astFtpCmd[nQLen].nFtpCmd = nFtpCmd; if (szFtpParm) lstrcpy (astFtpCmd[nQLen].szFtpParm, szFtpParm); if (!(astFtpCmd[0].nFtpCmd) && astFtpCmd[1].nFtpCmd) { /* If nothing pending reply, then send the next command */ SendFtpCmd(); } return (TRUE); /* queued! */ } /* end QueueFtpCmd() */ /*-------------------------------------------------------------- * Function: AbortFtpCmd() * * Description: Clean up routine to abort a pending FTP command and * clear the command queue */ void AbortFtpCmd(void) { int i; if (hLstnSock != INVALID_SOCKET) {/* Close listen socket */ closesocket(hLstnSock); hLstnSock = INVALID_SOCKET; } if (hDataSock != INVALID_SOCKET){ /* Close data socket */ CloseFtpConn(&hDataSock, (astFtpCmd[0].nFtpCmd != STOR) ? achInBuf : (PSTR)0, INPUT_SIZE, hWinMain); EndData(); } for (i=0;i