// ftp.c: Implements FTP routines // INCLUDES #include "ftp.h" // DEFINITIONS #define TYPE_I 'I' #define TYPE_A 'A' #define TYPE_E 'E' #define TYPE_L 'L' #define uiFtpPort 21 #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #ifndef MAXPACKET #define MAXPACKET 4096 #endif #define HOST_TYPE_AUTO 6000 #define HOST_TYPE_CHAMELEON 6001 #define HOST_TYPE_PCTCP 6002 #define HOST_TYPE_IBM_TCP 6003 #define HOST_TYPE_IBM_VM 6004 #define HOST_TYPE_NOS 6005 #define HOST_TYPE_NCSA 6006 #define HOST_TYPE_SINTFTPD 6007 #define HOST_TYPE_SUPER 6008 #define HOST_TYPE_U5000 6009 #define HOST_TYPE_UNIX 6010 #define HOST_TYPE_VMS_MULTINET 6011 #define HOST_TYPE_VMS_UCX 6012 #define HOST_TYPE_QVT 6013 #define HOST_TYPE_WINDOWS_NT 6014 #define HOST_TYPE_SOLARIS 6015 #define HOST_TYPE_INNOV_WINDOWS_NT 6016 #define HOST_TYPE_OS2_L8 6017 // FUNCTION PROTOTYPES /* --------------------- SOCKETS FUNCTIONS --------------------- */ volatile SOCKET connectsock(char *host,char *service,char *protocol); volatile SOCKET connectTCP(char *host,char *service); volatile SOCKET GetFTPListenSocket(SOCKET ctrl_skt); /* --------------------- COMMUNICATION FUNCTIONS --------------------- */ int command(SOCKET ctrl_skt, char *fmt,...); int getreply(SOCKET ctrl_skt,LPSTR cmdstring); int sendstr(SOCKET sSocket,LPSTR pBuf,int nBytesToWrite); int SendPacket(SOCKET sockfd,LPSTR msg); int ReadLine(SOCKET sockfd); int ReadDisplayLine(SOCKET sockfd); int ReadMass(SOCKET sockfd,LPSTR filename, LPSTR shortname, BOOL binaryflag); int SendMass(SOCKET sockfd,LPSTR filename,BOOL binaryflag); int RetrieveFile(SOCKET,LPSTR,LPSTR,LPSTR,char); int SendFile(SOCKET,LPSTR,LPSTR,char); /* --------------------- ERROR FUNCTIONS --------------------- */ LPSTR ReturnWSError(UINT Err,LPSTR lpszBuf); void ReportWSError(LPSTR lpszMsg,UINT Err); // GLOBAL VARIABLES char szMsgBuf[MAXPACKET]; // main i/o buffer char szMsgBuf2[MAXPACKET]; // main i/o buffer char szDlgEdit[80]; // used by input dialog for output char szRemoteHost[80]; // remote host name/addr to connect to char szString[512]; // temp string area char cType = TYPE_I; // file transfer type char szTmpFile[] = "C:\\FTP.TMP"; // used for directory listings char szRecvFile[] = "C:\\FTPRECV.TMP"; // file for receiving files u_char szSendPkt[MAXPACKET]; // output transfer buffer int iMultiLine = 0; int iCode = 0; int nHostType; volatile SOCKET data_socket; // data channel socket volatile SOCKET listen_socket; // data listen socket struct sockaddr saDestAddr; struct sockaddr_in saSockAddr; // endpoint address struct sockaddr_in saSockAddr1; // used when bSendPort == 0 struct sockaddr_in saCtrlAddr; // FUNCTION DEFINITIONS /* --------------------- CONNECTION FUNCTIONS --------------------- */ /* * DoClose: * user close routine */ volatile SOCKET DoClose(SOCKET sockfd) { LINGER ntlinger; if (sockfd != INVALID_SOCKET) { shutdown(sockfd,2); ntlinger.l_onoff = (u_short)TRUE; ntlinger.l_linger = (u_short)0; setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (LPSTR)&ntlinger, sizeof(ntlinger) ); if (closesocket(sockfd) == SOCKET_ERROR) printf("Error\n"); else { //printf("[%u] Socket closed.\n",sockfd); sockfd=INVALID_SOCKET; } } if (sockfd != INVALID_SOCKET) printf("%u Failed to close socket.\n",sockfd); return(sockfd); } /* DoConnect */ volatile SOCKET DoConnect(LPSTR ftp_host, LPSTR userid, LPSTR password, LPSTR account) { int iLength,iRetCode; int iFlag = 1; char host[80]; volatile SOCKET ctrl_skt; strcpy(host, ftp_host); // create a connected socket if ((ctrl_skt = connectTCP(host,"ftp")) == INVALID_SOCKET) { MessageBox(NULL, "Debug", "Connection failed", MB_OK) ; return(INVALID_SOCKET); } // get information about local end of the connection iLength = sizeof (saCtrlAddr); if (getsockname(ctrl_skt, (struct sockaddr *)&saCtrlAddr, &iLength) == SOCKET_ERROR) { DoClose(ctrl_skt); return(INVALID_SOCKET); } // get initial message from remote end // lgk need to set the global control_socket to ctrl_skt here since // it will be returned but abort does not work unless it is set here iMultiLine = 0; iCode = 0; while ((iRetCode = ReadDisplayLine(ctrl_skt)) == FTP_PRELIM) // 93.12.04 if (nHostType == HOST_TYPE_AUTO) { if (strstr(szMsgBuf, "(EXOS") != NULL) nHostType=HOST_TYPE_U5000; } // if it succeeded if (iRetCode == FTP_COMPLETE) { if (nHostType == HOST_TYPE_AUTO) { if (strstr(szMsgBuf,"(EXOS") != NULL) nHostType = HOST_TYPE_U5000; } if (setsockopt(ctrl_skt, SOL_SOCKET, SO_OOBINLINE, (LPSTR)&iFlag, sizeof(iFlag)) == SOCKET_ERROR) { // printf("ReportWSError setsockopt\n"); } // send our userid to the ftp_host if((iRetCode = command(ctrl_skt,"USER %s",userid)) == FTP_CONTINUE) { // if the remote system requires a password, send it. if((iRetCode = command(ctrl_skt,"PASS %s",password)) == FTP_CONTINUE) iRetCode = command(ctrl_skt, "ACCT %s", account); } printf("return code: %d\n", iRetCode); // if we are successfully logged on,..... if (iRetCode != FTP_COMPLETE) { printf("logon failure, so quitting\n"); DoClose((SOCKET)ctrl_skt); return(INVALID_SOCKET); } } else { DoClose((SOCKET)ctrl_skt); return(INVALID_SOCKET); } return (ctrl_skt); } /* CheckConnection */ int CheckConnection(SOCKET sockfd) { if ( SendPacket(sockfd, "ping") <= 0 ) return -1; else return 1; } /* --------------------- FTP COMMAND FUNCTIONS --------------------- */ /* DoCHMOD */ int DoCHMOD(SOCKET ctrl_skt,LPSTR modes,LPSTR filename) { return(command(ctrl_skt, "SITE CHMOD %s %s", modes, filename)); } /* DoCWD */ int DoCWD(SOCKET ctrl_skt,LPSTR path) { int iRetCode; if ( ( iRetCode = command(ctrl_skt, "CWD %s", path)) == FTP_ERROR && iCode==500 ) iRetCode = command(ctrl_skt, "XCWD %s", path); return iRetCode; } /* DoDirList */ int DoDirList(SOCKET ctrl_skt,LPSTR szCMD) { int nRC; nRC = RetrieveFile(ctrl_skt, szCMD, szTmpFile, szTmpFile, TYPE_I); return(nRC); } /* DoDirList2 */ int DoDirList2(SOCKET ctrl_skt, LPSTR szCMD, DIRINFO *output) { char *pStr; char temp[120]; FILE *fd; int result = 0; int nRC; int maxhfextent = 0; int maxhdextent = 0; strcpy(temp, szCMD); if (strlen(temp) != 0) { char temp2[200]; strcpy(temp2, "LIST -an "); strcat(temp2, temp); nRC = DoDirList(ctrl_skt,temp2); } else nRC = DoDirList(ctrl_skt,"LIST -an"); if (nRC == FTP_COMPLETE) { if ((fd = fopen(szTmpFile,"r")) != NULL) { while (fgets(szString,180,fd) != NULL) { if ((pStr = strchr(szString,'\n')) != NULL) *pStr = 0; if ( strchr("dlf-", szString[0]) != NULL ) DirInfo_Add(output, szString); } fclose(fd); } } return nRC; } /* DoDELE */ int DoDELE(SOCKET ctrl_skt,LPSTR pathname) { int iRetCode; iRetCode = command(ctrl_skt, "DELE %s", pathname); return iRetCode; } /* DoMKD */ int DoMKD(SOCKET ctrl_skt,LPSTR pathname) { int iRetCode; if( ( iRetCode = command(ctrl_skt, "MKD %s", pathname) ) == FTP_ERROR && iCode==500) iRetCode = command(ctrl_skt,"XMKD %s",pathname); /* if (iCode != 550) return(iCode/100); else return iCode; */ return iRetCode; } /* DoPWD */ int DoPWD(SOCKET ctrl_skt) { int iRetCode; if ( ( iRetCode = command(ctrl_skt, "PWD") ) == FTP_ERROR && iCode==500) iRetCode = command(ctrl_skt, "XPWD"); return(iRetCode); } /* DoQUOTE */ int DoQUOTE(SOCKET ctrl_skt,LPSTR string) { int iRetCode; if(strncmp(string, "LIST", 4) == 0 || strncmp(string, "NLST", 4) == 0) iRetCode = DoDirList(ctrl_skt,string); else iRetCode = command(ctrl_skt,string); return(iRetCode); } /* DoRMD */ int DoRMD(SOCKET ctrl_skt,LPSTR pathname) { int iRetCode; if( ( iRetCode = command(ctrl_skt, "RMD %s", pathname) ) == FTP_ERROR && iCode==500) iRetCode = command(ctrl_skt, "XRMD %s", pathname); return(iRetCode); } /* DoRename */ int DoRename(SOCKET ctrl_skt, LPSTR nameto, LPSTR namefrom) { int iRetCode; command(ctrl_skt, "RNFR %s", namefrom); iRetCode = command(ctrl_skt, "RNTO %s", nameto); return(iRetCode); } /* DoValidPath */ int DoValidPath(SOCKET ctrl_skt, LPSTR pathname) { DIRINFO *dir = DirInfo_Create(); DoDirList2(ctrl_skt, pathname, dir); if ( DirInfo_GetNum > 0 ) { DirInfo_Destroy(dir); return 1; } else { DirInfo_Destroy(dir); return 0; } } /* GetFile */ int GetFile(SOCKET ctrl_skt, LPSTR remotepath, LPSTR localpath) { char cmd[128]; sprintf(cmd, "RETR %s", remotepath); return RetrieveFile(ctrl_skt, cmd, localpath, localpath, TYPE_I); } /* PutFile */ int PutFile(SOCKET ctrl_skt, LPSTR remotepath, LPSTR localpath) { char cmd[128]; sprintf(cmd, "STOR %s", remotepath); return SendFile(ctrl_skt, cmd, localpath, TYPE_I); } /* --------------------- USEFUL FUNCTIONS --------------------- */ /* * MakeLocalName: * convert remotename into something DOS can deal with here nt * can deal with longer names */ int MakeLocalName(LPSTR localname, LPSTR shortname, LPSTR remotename) { int nIndex; char Name[10], Ext[4], *s; char Name2[140], Ext2[80]; char savedname[256]; lstrcpy(savedname, remotename); while (*remotename != 0 && *remotename == '.') remotename++; for (nIndex = 0 ; nIndex < 140 ; nIndex++) { if (*remotename != 0 && *remotename != '.' && *remotename != ' ') { if (nIndex < 8) Name[nIndex] = *remotename; Name2[nIndex] = *remotename++; } else break; } if (nIndex <= 8) Name[nIndex] = 0; else Name[8] = 0; Name2[nIndex] = 0; Ext2[0] = 0; Ext[0] = 0; if ((s = strchr(remotename,'.')) != NULL) remotename = s; while (*remotename != 0 && (*remotename == '.' || *remotename == ' ')) remotename++; if (*remotename != 0) { for (nIndex = 0 ; nIndex < 80 ; nIndex++) { if (*remotename != 0 && *remotename != '.' && *remotename != ' ') { if (nIndex < 3) Ext[nIndex] = *remotename; Ext2[nIndex] = *remotename++; } else break; } if (nIndex <= 3) Ext[nIndex] = 0; else Ext[3] = 0; Ext2[nIndex] = 0; } if(Ext[0] == 0) lstrcpy(shortname, Name); else wsprintf(shortname, "%s.%s", Name, Ext); if(Ext2[0] == 0) lstrcpy(localname, Name2); else wsprintf(localname, "%s.%s", Name2, Ext); if(lstrlen(shortname) == 0) { lstrcpy(Name, "aaremote"); lstrcpy(shortname, Name); } if(lstrlen(localname) == 0) { lstrcpy(Name, "aaremote"); lstrcpy(localname, Name2); } // on nt try whole name for local name lstrcpy(localname, savedname); // fix vax however { char *colonloc = strchr(savedname, ';'); if (colonloc != 0) { int i = 0; while (savedname[i] != ';') { Name2[i] = savedname[i]; ++i; } Name2[i] = '\0'; lstrcpy(localname,Name2); } } return(TRUE); } /* * FindName: * find filename in a UNIX directory listing */ LPSTR FindName(LPSTR szLine) { int nIndex; char *pStr; // strip trailing garbage from the line if there is any. while ((nIndex = strlen(szLine)) > 2 && (szLine[nIndex - 1] == 0x0a || szLine[nIndex - 1] == 0x0d || szLine[nIndex - 1] == ' ' || szLine[nIndex - 1] == 0x09)) szLine[nIndex] = 0; // now the name SHOULD be the last thing on the line if ((pStr = strrchr(szLine,' ')) != NULL || (pStr = strrchr(szLine,0x09)) != NULL) { while (*pStr && (*pStr == ' ' || *pStr == 0x09)) pStr++; return(pStr); } return(szLine); } /* --------------------- SOCKETS FUNCTIONS --------------------- */ /* connectSock */ volatile SOCKET connectsock(char *host, char *service, char *protocol) { struct hostent *pHostEntry; // pointer to host entry struct servent FAR *pServiceEntry; // pointer to service entry struct protoent FAR *pProtoEntry; // pointer to protocol entry volatile SOCKET sSocket; // socket int nSocketType; // socket type short pproto; int iFlag = 1; // initialize socket address structure memset((char *)&saSockAddr, 0, sizeof(saSockAddr)); saSockAddr.sin_family = AF_INET; // get service port number from name if (pServiceEntry = getservbyname(service, protocol)) { if (uiFtpPort != 21) { printf("Overridding Ftp port number with %u\n",uiFtpPort); saSockAddr.sin_port = htons((u_short)uiFtpPort); } else saSockAddr.sin_port=pServiceEntry->s_port; } else if ((saSockAddr.sin_port = htons((u_short)atoi(service))) == 0) { // lgk new code first try user interface setting if different than 21 if (uiFtpPort != 21) { printf("Overridding Ftp port number with %u\n",uiFtpPort); saSockAddr.sin_port = htons((u_short)uiFtpPort); } else { if(strcmpi(service,"FTP") == 0) saSockAddr.sin_port=htons(21); else { printf("can't get \"%s\" service entry\n",service); return INVALID_SOCKET; } } } // map host to ip, allow ip if (pHostEntry = gethostbyname(host)) memcpy((char *)&saSockAddr.sin_addr, pHostEntry->h_addr, pHostEntry->h_length); else if ((saSockAddr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { printf("can't get \"%s\" host entry, %d\n", host, WSAGetLastError()); return INVALID_SOCKET; } // map protocol name to protocol number if ((pProtoEntry = getprotobyname(protocol)) == 0) { if(strcmpi(protocol,"TCP") == 0) pproto=6; else { printf("can't get \"%s\" protocol entry\n",protocol); return INVALID_SOCKET; } } else pproto = pProtoEntry->p_proto; // use protocol to choose socket type if (strcmp(protocol,"udp") == 0) nSocketType = SOCK_DGRAM; else nSocketType = SOCK_STREAM; // allocate a socket sSocket = socket(AF_INET, nSocketType, pproto); if (sSocket == INVALID_SOCKET) { ReportWSError("create socket",WSAGetLastError()); return INVALID_SOCKET; } // lgk set for reuse if (setsockopt(sSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&iFlag, sizeof(iFlag)) == SOCKET_ERROR) { ReportWSError("setsockopt",WSAGetLastError()); closesocket(data_socket); return INVALID_SOCKET; } memcpy((LPSTR)&saSockAddr1, (LPSTR)&saSockAddr, sizeof(saSockAddr)); saSockAddr1.sin_port = htons(20); // connect the socket if(connect(sSocket, (struct sockaddr *)&saSockAddr, sizeof(saSockAddr)) == SOCKET_ERROR) { printf("Can't connect to %s %s service port %u.\n", host, service, ntohs(saSockAddr.sin_port)); ReportWSError("Connect failed -",WSAGetLastError()); return INVALID_SOCKET; } return sSocket; } /* connectTCP */ volatile SOCKET connectTCP(char *host, char *service) { return connectsock(host,service,"tcp"); } /* * GetFTPListenSocket: * based on WINTEL (ftp.c) and BSD (ftp.c) */ volatile SOCKET GetFTPListenSocket(SOCKET ctrl_skt) { SOCKET listen_skt; int iLength, iLength2; int iRetCode; char *a,*p; int iFlag = 1; struct sockaddr_in saTmpAddr; // create a data socket if ((listen_skt = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET) { ReportWSError("socket create",WSAGetLastError()); return (INVALID_SOCKET); } // let system pick an unused port. we tell remote end with PORT cmd saCtrlAddr.sin_port = htons(0); saCtrlAddr.sin_family = AF_INET; saCtrlAddr.sin_addr.s_addr = 0; // Bind name to socket if( bind((SOCKET)listen_skt, (LPSOCKADDR)&saCtrlAddr, (int)sizeof(struct sockaddr)) == SOCKET_ERROR) { ReportWSError("bind",WSAGetLastError()); closesocket(listen_skt); return (INVALID_SOCKET); } // get the port name that we got for later transmission in PORT cmd iLength = sizeof(saCtrlAddr); if (getsockname(listen_skt, (struct sockaddr *)&saCtrlAddr, &iLength) < 0) { ReportWSError("getsockname",WSAGetLastError()); closesocket(listen_skt); return(INVALID_SOCKET); } // invoke listener if (listen(listen_skt,1) != 0) { ReportWSError("listen",WSAGetLastError()); closesocket(listen_skt); return(INVALID_SOCKET); } // inform remote end about our port that we created. iLength2 = sizeof (saTmpAddr); if (getsockname(ctrl_skt,(LPSOCKADDR)&saTmpAddr, &iLength2) == SOCKET_ERROR) { ReportWSError("getsockname",WSAGetLastError()); } a = (char *)&saTmpAddr.sin_addr; p = (char *)&saCtrlAddr.sin_port; #define UC(b) (((int)b)&0xff) printf("PORT %d,%d,%d,%d,%d,%d\n", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); if((iRetCode = command(ctrl_skt, "PORT %d,%d,%d,%d,%d,%d", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]))) != FTP_COMPLETE) { printf("[%u] remote end didn't understand our port command.", listen_skt); return(listen_skt); } return(listen_skt); } /* --------------------- COMMUNICATION FUNCTIONS --------------------- */ /* command */ int command(SOCKET ctrl_skt, char *fmt,...) { va_list args; char szBuf[90]; va_start(args, fmt); vsprintf(szBuf, fmt, args); va_end(args); return(getreply(ctrl_skt, szBuf)); } /* * getreply: * send a message on the control socket, read and display the resulting * message and return the result value */ int getreply(SOCKET ctrl_skt,LPSTR cmdstring) { int iRetCode = 0; if (ctrl_skt == INVALID_SOCKET) return INVALID_SOCKET; else { if (SendPacket(ctrl_skt,cmdstring) != -1) iRetCode = ReadDisplayLine(ctrl_skt); } return(iRetCode); // 0 - 5 } /* sendstr */ int sendstr(SOCKET sSocket, LPSTR pBuf, int nBytesToWrite) { int nBytesLeft, nWritten; nBytesLeft = nBytesToWrite; while (nBytesLeft > 0) // while we haven't written enough { nWritten = send(sSocket, pBuf, ((nBytesLeft > 1024) ? 1024 : nBytesLeft), 0); // write what we can if (nWritten <= 0) return(nWritten); // error occured nBytesLeft -= nWritten; // count what we wrote pBuf += nWritten; // adjust buffer pointer } return(nBytesToWrite - nBytesLeft); // return count of bytes written } /* SendPacket */ int SendPacket(SOCKET sockfd, LPSTR msg) { int i; if(sockfd == INVALID_SOCKET) return(-1); i = strlen(msg); strcpy(szSendPkt,msg); // append a CRLF to the end of outgoing messages szSendPkt[i++]='\r'; szSendPkt[i++]='\n'; szSendPkt[i]=0; i = sendstr(sockfd,szSendPkt,i); return (i); } /* * ReadLine: * read a reply line back in from the sockfd and return the * value at the beginning of the first line. */ int ReadLine(SOCKET sockfd) { LPSTR szBuf; int nIndex; int iNumBytes,iN1,iN2; int iBytesRead; int iRetCode; int i; char c; // can't do anything if we don't have a socket if (sockfd == INVALID_SOCKET) return(0); // zero our receive buffer memset(szMsgBuf,0,4096); // initialize some variables szBuf = szMsgBuf; iBytesRead = 0; iRetCode = 0; // this routine is a little better as it read 80 characters at a time // (if it works:-) Here we PEEK at what is available, find the LF etc... // lgk here we have a bug and it puts the system in an endless loop // we don't check for a socket error but one happens fix this iNumBytes = recv(sockfd, (LPSTR)szBuf, 82, MSG_PEEK); if (iNumBytes == SOCKET_ERROR) return (SOCKET_ERROR); while (iBytesRead < 4000 && (iNumBytes > 0)) { iN1 = iNumBytes; // must terminate the string so strchr doesn't go wild. szBuf[iNumBytes]=0; // find a LF in the input if it exists for (nIndex = 0; nIndex < iNumBytes ; nIndex++) if (szBuf[nIndex] == 0 || szBuf[nIndex] == 0x0a) { iNumBytes = nIndex+1; break; } // have to treat the UNISYS 5000 (EXOS driver) special. It sends a // line with a CR at end and no LF and then follows it up with a // separate packet that has a CR/LF. Usually this second packet is // not there when we peek but is when we read (answers my question // about the second receive containing new data!!... jaj 931024) if (iNumBytes > 80 && nHostType == HOST_TYPE_U5000) for (nIndex = 0 ; nIndex < iNumBytes ; nIndex++) if (szBuf[nIndex] == 0x0d) { iNumBytes = nIndex+2; break; } iN2 = iNumBytes; // otherwise read up to the full length of what the first recv saw. // Wonder what happens here if the second receive actually returns more // characters than the first receive and there was a LF in the extra data? iNumBytes = recv(sockfd, (LPSTR)szBuf, iNumBytes, 0); // again, terminate the string szBuf[iNumBytes] = 0; // bump the receive buffer pointer szBuf += iNumBytes; // count the bytes that we have read so far iBytesRead += iNumBytes; // if the last character read was a LF, then stop. if(*(szBuf-1) == 0x0a) break; } // in any case terminate what we have *szBuf = 0; // find the retcode at the beginning of the line c = szMsgBuf[3]; szMsgBuf[3] = 0; iRetCode = atoi(szMsgBuf); szMsgBuf[3] = c; // strip trailing blanks, CR's and LF's while ((i = strlen(szMsgBuf)) > 2 && (szMsgBuf[i-1] == 0x0a || szMsgBuf[i-1] == 0x0d || szMsgBuf[i-1] == ' ')) szMsgBuf[i-1] = 0; return(iRetCode); } /* * ReadDisplayLine: * read a reply (may be multi line) and display in debug window */ int ReadDisplayLine(SOCKET sockfd) { int iRetCode; int iContinue; if (sockfd == INVALID_SOCKET) return(0); iMultiLine++; iContinue = 0; iRetCode = ReadLine(sockfd); if (iRetCode == SOCKET_ERROR) return iRetCode; if (((iRetCode < 100) && (iRetCode > 0)) || iRetCode > 599 || szMsgBuf[3] == '-') iContinue = 1; if ((iMultiLine == 1 || iCode == 0) && iRetCode > 99 && iRetCode < 600) iCode = iRetCode; if (iContinue == 1 || (iCode > 0 && iMultiLine > 1 && iRetCode != iCode)) ReadDisplayLine(sockfd); iMultiLine--; if (iCode == 550) return iCode; if (iCode > 99 && iCode < 600) return (iCode/100); else return 0; } /* * ReadMass: * read information from the data socket into a file. */ int ReadMass(SOCKET sockfd, LPSTR filename, LPSTR shortname, BOOL binaryflag) { int iNumBytes; int iRetCode; int iFileHandle; long lBytesRead; // if we don't have a socket, return an error if (sockfd == INVALID_SOCKET ) return 0; // initialize some vars lBytesRead = 0l; iRetCode = 0; // at the moment we are ignoring the fact that the local destination file // may not open correctly. if ((iFileHandle = _lcreat(filename,0)) == -1) { printf("failed to open file %s (%u)\n", filename, errno); printf("Trying shorting name %s\n", shortname); if ((iFileHandle = _lcreat(shortname,0)) == -1) printf("Still failed to open file %s (%u)\n", shortname, errno); } // loop to receive input from remote end while (( iNumBytes = recv(sockfd,(LPSTR)szMsgBuf,4000,0)) > 0) { // write what we received if the file is open if (iFileHandle != -1) _lwrite(iFileHandle,szMsgBuf,iNumBytes); // count the characters that we received lBytesRead += iNumBytes; } // if the output file is open, close it if (iFileHandle != -1) _lclose(iFileHandle); // if we had a recv error, let us know about it if(iNumBytes == SOCKET_ERROR) { ReportWSError("recv",WSAGetLastError()); if (lBytesRead == 0l) return(FALSE); } return (TRUE); } /* * SendMass: * send a file through the data socket */ int SendMass(SOCKET sockfd, LPSTR filename, BOOL binaryflag) { int iNumBytes; int iRetCode; int iFileHandle; long lBytesWritten; iRetCode=0; // if we don't have a socket, return an error if (sockfd == INVALID_SOCKET) return 0; // initialize some vars lBytesWritten = 0l; iRetCode = 0; // at the moment we are ignoring the fact that the local destination file // may not open correctly. if((iFileHandle = _lopen(filename,OF_READ)) == -1) { printf("failed to open file %s (%u)\n", filename, errno); return -1; } else { // loop to send output to remote end while((iNumBytes = _lread(iFileHandle, szMsgBuf, 512)) > 0) { // this forces binary mode at the moment iRetCode = sendstr(sockfd, szMsgBuf, iNumBytes); printf("Sent bytes: %d\n", iRetCode); // count the characters that we received lBytesWritten += iNumBytes; } // if the output file is open, close it _lclose(iFileHandle); iRetCode = TRUE; } Sleep(500); // give socket enough time to read queue return (iRetCode); } /* RetrieveFile */ int RetrieveFile(SOCKET ctrl_skt, LPSTR szCMD, LPSTR localfile, LPSTR shortname, char rtype) { int iRetCode; int iLength; int iFlag = 1; iMultiLine = 0; // if we don't have a valid control socket, can't do anything if (ctrl_skt == INVALID_SOCKET) return(0); // if the requested type is not the same as the default type if (cType != rtype) { if(rtype == TYPE_L) command(ctrl_skt,"TYPE L 8"); else command(ctrl_skt,"TYPE %c",rtype); cType=rtype; } // always transfer in binary mode command(ctrl_skt, "TYPE I"); // create a listener socket, if it is successful if ((listen_socket = GetFTPListenSocket(ctrl_skt)) != INVALID_SOCKET) { // send command to see the result of this all iRetCode = command((SOCKET)ctrl_skt, szCMD); // read the control channel (should return 1xx if it worked) if(iRetCode == FTP_PRELIM) { // get our data connection iLength = sizeof(saSockAddr1); data_socket = accept(listen_socket, (struct sockaddr far *)&saSockAddr1, (int far *)&iLength); // lgk check for error case here if (data_socket == INVALID_SOCKET) { ReportWSError("accept for retrieve", WSAGetLastError()); data_socket = DoClose(data_socket); return 0; } if (setsockopt(data_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&iFlag, sizeof(iFlag)) == SOCKET_ERROR) { ReportWSError("setsockopt", WSAGetLastError()); closesocket(data_socket); return(INVALID_SOCKET); } // if it failed, we have to quit this if(data_socket == INVALID_SOCKET) { ReportWSError("accept", WSAGetLastError()); listen_socket = DoClose(listen_socket); iRetCode=0; } else { // we don't need the listener socket anymore listen_socket = DoClose(listen_socket); // copy the file iRetCode = ReadMass(data_socket, localfile, shortname, rtype == TYPE_I); // shut the data socket down if (shutdown(data_socket,2) != 0) ReportWSError("shutdown", WSAGetLastError()); // close the data socket data_socket = DoClose(data_socket); // read the close control message (should return 2xx) iRetCode = ReadDisplayLine(ctrl_skt); } } else { listen_socket = DoClose(listen_socket); iRetCode = 0; } } else { listen_socket = DoClose(listen_socket); iRetCode = 0; } Sleep(500); return(iRetCode); } /* SendFile */ int SendFile(SOCKET ctrl_skt, LPSTR szCMD, LPSTR localfile, char stype) { int iRetCode; int iLength; int iFlag = 1; iCode = 0; // if we don't have a valid control socket, can't do anything if (ctrl_skt == INVALID_SOCKET) return(0); // if the requested type is not the same as the default type if (cType != stype) { if (stype == TYPE_L) command(ctrl_skt,"TYPE L 8"); else command(ctrl_skt,"TYPE %c", stype); cType=stype; } // always transfer in binary mode command(ctrl_skt, "TYPE I"); // create a listener socket, if it is successful if ((listen_socket = GetFTPListenSocket(ctrl_skt)) != INVALID_SOCKET) { // send command to see the result of this all iRetCode = command((SOCKET)ctrl_skt, szCMD); // read the control channel (should return 1xx if it worked) if(iRetCode == FTP_PRELIM) { // get our data connection iLength = sizeof(saSockAddr1); data_socket = accept(listen_socket, (struct sockaddr far *)&saSockAddr1, (int far *)&iLength); // if it failed, we have to quit this if(data_socket == INVALID_SOCKET) { ReportWSError("accept", WSAGetLastError()); listen_socket = DoClose(listen_socket); iRetCode = 0; } else { // lgk set for reuse if (setsockopt(data_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&iFlag, sizeof(iFlag)) == SOCKET_ERROR) { ReportWSError("setsockopt", WSAGetLastError()); closesocket(data_socket); iRetCode = 0; } else { // we don't need the listener socket anymore listen_socket = DoClose(listen_socket); // copy the file iRetCode = SendMass(data_socket, localfile, stype == TYPE_I); // close the socket data_socket = DoClose(data_socket); // read the close control message (should return 2xx) iRetCode = ReadDisplayLine(ctrl_skt); } // ok setsock } // ok open } else { listen_socket = DoClose(listen_socket); iRetCode = 0; } } // get listen socket failed else { listen_socket = DoClose(listen_socket); iRetCode = 0; } return(iRetCode); } /* --------------------- ERROR FUNCTIONS --------------------- */ /* ReturnWSError */ LPSTR ReturnWSError(UINT nErr,LPSTR lpszBuf) { static char szErrMsg[128]; LPSTR lpszRetStr; switch(nErr) { case WSAVERNOTSUPPORTED: lpszRetStr="version of WinSock not supported"; break; case WSASYSNOTREADY: lpszRetStr="WinSock not present or not responding"; break; case WSAEINVAL: lpszRetStr="app version not supported by DLL"; break; case WSAHOST_NOT_FOUND: lpszRetStr="Authoritive: Host not found"; break; case WSATRY_AGAIN: lpszRetStr="Non-authoritive: host not found or server failure"; break; case WSANO_RECOVERY: lpszRetStr="Non-recoverable: refused or not implemented"; break; case WSANO_DATA: lpszRetStr="Valid name, no data record for type"; break; case WSANOTINITIALISED: lpszRetStr="WSA Startup not initialized"; break; case WSAENETDOWN: lpszRetStr="Network subsystem failed"; break; case WSAEINPROGRESS: lpszRetStr="Blocking operation in progress"; break; case WSAEINTR: lpszRetStr="Blocking call cancelled"; break; case WSAEAFNOSUPPORT: lpszRetStr="address family not supported"; break; case WSAEMFILE: lpszRetStr="no file descriptors available"; break; case WSAENOBUFS: lpszRetStr="no buffer space available"; break; case WSAEPROTONOSUPPORT: lpszRetStr="specified protocol not supported"; break; case WSAEPROTOTYPE: lpszRetStr="protocol wrong type for this socket"; break; case WSAESOCKTNOSUPPORT: lpszRetStr="socket type not supported for address family"; break; case WSAENOTSOCK: lpszRetStr="descriptor is not a socket"; break; case WSAEWOULDBLOCK: lpszRetStr="socket marked as non-blocking and SO_LINGER set not 0"; break; case WSAEADDRINUSE: lpszRetStr="address already in use"; break; case WSAECONNABORTED: lpszRetStr="connection aborted"; break; case WSAECONNRESET: lpszRetStr="connection reset"; break; case WSAENOTCONN: lpszRetStr="not connected"; break; case WSAETIMEDOUT: lpszRetStr="connection timed out"; break; case WSAECONNREFUSED: lpszRetStr="connection refused"; break; case WSAEHOSTDOWN: lpszRetStr="host down"; break; case WSAEHOSTUNREACH: lpszRetStr="host unreachable"; break; case WSAEADDRNOTAVAIL: lpszRetStr="address not available"; break; default: if(lpszBuf==NULL) lpszBuf=szErrMsg; wsprintf((LPSTR)lpszBuf, (LPSTR)"error %u", nErr); return(lpszBuf); } if(lpszBuf!=NULL) { lstrcpy(lpszBuf,lpszRetStr); return(lpszBuf); } return(lpszRetStr); } /* ReportWSError */ void ReportWSError(LPSTR lpszMsg,UINT nErr) { if(lpszMsg!=NULL) printf("%s: %s\n", lpszMsg, ReturnWSError(nErr,NULL)); else printf("%s\n", ReturnWSError(nErr,NULL)); }