mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-27 14:12:25 +00:00
9ae7e2621d
Lots of changes. CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit. Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit. Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
868 lines
19 KiB
C
868 lines
19 KiB
C
#include "quakedef.h"
|
|
|
|
#ifdef WEBCLIENT
|
|
|
|
#include "iweb.h"
|
|
|
|
#ifdef _WIN32
|
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
#define EMSGSIZE WSAEMSGSIZE
|
|
#define ECONNRESET WSAECONNRESET
|
|
#define ECONNABORTED WSAECONNABORTED
|
|
#define ECONNREFUSED WSAECONNREFUSED
|
|
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
|
|
|
#define qerrno WSAGetLastError()
|
|
#else
|
|
#define qerrno errno
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/uio.h>
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#ifdef sun
|
|
#include <sys/filio.h>
|
|
#endif
|
|
|
|
#ifdef NeXT
|
|
#include <libc.h>
|
|
#endif
|
|
|
|
#define closesocket close
|
|
#define ioctlsocket ioctl
|
|
#endif
|
|
|
|
|
|
typedef struct FTPclientconn_s{
|
|
char server[256];
|
|
char name[64];
|
|
char pwd[64];
|
|
char path[256];
|
|
char pathprefix[256]; //Urhum.. Without this we can browse various entire hard drives too easily.
|
|
char file[64];
|
|
char localfile[MAX_QPATH];
|
|
|
|
int transfersize;
|
|
int transfered;
|
|
|
|
int controlsock;
|
|
int datasock; //FTP only allows one transfer per connection.
|
|
|
|
enum {ftp_control, ftp_listing, ftp_getting, ftp_putting} type;
|
|
int stage;
|
|
|
|
IWEBFILE *f;
|
|
|
|
struct FTPclientconn_s *next;
|
|
} FTPclientconn_t;
|
|
|
|
FTPclientconn_t *FTPclientconn;
|
|
|
|
FTPclientconn_t *FTP_CreateConnection(char *addy)
|
|
{
|
|
unsigned long _true = true;
|
|
struct sockaddr_qstorage from;
|
|
FTPclientconn_t *con;
|
|
|
|
|
|
|
|
con = IWebMalloc(sizeof(FTPclientconn_t));
|
|
|
|
|
|
|
|
if ((con->controlsock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
|
{
|
|
Sys_Error ("FTP_UDP_OpenSocket: socket: %s\n", strerror(qerrno));
|
|
}
|
|
|
|
|
|
{//quake routines using dns and stuff (Really, I wanna keep quake and ftp fairly seperate)
|
|
netadr_t qaddy;
|
|
NET_StringToAdr (addy, &qaddy);
|
|
if (!qaddy.port)
|
|
qaddy.port = htons(21);
|
|
NetadrToSockadr(&qaddy, &from);
|
|
}
|
|
|
|
//not yet blocking.
|
|
if (connect(con->controlsock, (struct sockaddr *)&from, sizeof(from)) == -1)
|
|
{
|
|
IWebWarnPrintf ("FTP_TCP_OpenSocket: connect: %i %s\n", qerrno, strerror(qerrno));
|
|
closesocket(con->controlsock);
|
|
IWebFree(con);
|
|
return NULL;
|
|
}
|
|
|
|
if (ioctlsocket (con->controlsock, FIONBIO, &_true) == -1) //now make it non blocking.
|
|
{
|
|
Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO: %s\n", strerror(qerrno));
|
|
}
|
|
|
|
Q_strncpyz(con->server, addy, sizeof(con->server));
|
|
strcpy(con->name, "anonymous");
|
|
|
|
con->next = FTPclientconn;
|
|
FTPclientconn = con;
|
|
con->stage = 1;
|
|
con->type = ftp_control;
|
|
|
|
strcpy(con->path, "/");
|
|
con->datasock = INVALID_SOCKET;
|
|
con->transfersize = -1;
|
|
con->transfered = 0;
|
|
|
|
return FTPclientconn;
|
|
}
|
|
//duplicate a connection to get multiple data channels with a server.
|
|
FTPclientconn_t *FTP_DuplicateConnection(FTPclientconn_t *old)
|
|
{
|
|
FTPclientconn_t *new;
|
|
new = FTP_CreateConnection(old->server);
|
|
*new->server = '\0'; //mark it as non control
|
|
strcpy(new->name, old->name);
|
|
strcpy(new->pwd, old->pwd);
|
|
strcpy(new->path, old->path);
|
|
strcpy(new->pathprefix, old->pathprefix);
|
|
|
|
return new;
|
|
}
|
|
|
|
int FTP_CL_makelistensocket(void)
|
|
{
|
|
char name[256];
|
|
unsigned long _true = true;
|
|
int sock;
|
|
struct hostent *hent;
|
|
|
|
struct sockaddr_in address;
|
|
// int fromlen;
|
|
|
|
address.sin_family = AF_INET;
|
|
if (gethostname(name, sizeof(name)) == -1)
|
|
return INVALID_SOCKET;
|
|
hent = gethostbyname(name);
|
|
if (!hent)
|
|
return INVALID_SOCKET;
|
|
address.sin_addr.s_addr = *(int *)(hent->h_addr_list[0]);
|
|
address.sin_port = 0;
|
|
|
|
|
|
|
|
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
|
{
|
|
Sys_Error ("FTP_TCP_OpenSocket: socket:", strerror(qerrno));
|
|
}
|
|
|
|
if (ioctlsocket (sock, FIONBIO, &_true) == -1)
|
|
{
|
|
Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO:", strerror(qerrno));
|
|
}
|
|
|
|
if( bind (sock, (void *)&address, sizeof(address)) == -1)
|
|
{
|
|
closesocket(sock);
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
listen(sock, 1);
|
|
|
|
return sock;
|
|
}
|
|
int FTP_CL_makeconnectsocket(char *ftpdest)
|
|
{
|
|
unsigned long _true = true;
|
|
int sock;
|
|
|
|
struct sockaddr_in address;
|
|
|
|
if (!ftpdest)
|
|
return 0;
|
|
if (*ftpdest == '(')
|
|
ftpdest++;
|
|
|
|
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
|
{
|
|
IWebWarnPrintf ("FTP_UDP_OpenSocket: socket:", strerror(qerrno));
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
if (ioctlsocket (sock, FIONBIO, &_true) == -1)
|
|
{
|
|
closesocket(sock);
|
|
IWebWarnPrintf ("FTTP_UDP_OpenSocket: ioctl FIONBIO:", strerror(qerrno));
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
address.sin_family = AF_INET;
|
|
|
|
address.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
address.sin_port = 0;
|
|
|
|
if( bind (sock, (void *)&address, sizeof(address)) == -1)
|
|
{
|
|
closesocket(sock);
|
|
|
|
IWebWarnPrintf ("FTTP_UDP_OpenSocket: bind:", strerror(qerrno));
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
FTP_StringToAdr(ftpdest, (qbyte *)&address.sin_addr, (qbyte *)&address.sin_port);
|
|
|
|
//this is commented out because connect always reports would_block, no matter what happens. So why check?
|
|
//if (
|
|
connect(sock, (struct sockaddr *)&address, sizeof(address));// == -1)
|
|
/* {
|
|
closesocket(sock);
|
|
|
|
Con_Printf ("FTTP_UDP_OpenSocket: ioctl FIONBIO:", strerror(qerrno));
|
|
return INVALID_SOCKET;
|
|
}
|
|
*/
|
|
return sock;
|
|
}
|
|
|
|
iwboolean FTP_SocketToString (int socket, char *s)
|
|
{
|
|
struct sockaddr_in addr;
|
|
int adrlen = sizeof(addr);
|
|
|
|
if (getsockname(socket, (struct sockaddr*)&addr, &adrlen) == -1)
|
|
return false;
|
|
|
|
sprintf(s, "%i,%i,%i,%i,%i,%i", ((qbyte*)&addr.sin_addr)[0], ((qbyte*)&addr.sin_addr)[1], ((qbyte*)&addr.sin_addr)[2], ((qbyte*)&addr.sin_addr)[3], ((qbyte *)&addr.sin_port)[0], ((qbyte *)&addr.sin_port)[1]);
|
|
return true;
|
|
}
|
|
|
|
iwboolean FTP_ClientConnThink (FTPclientconn_t *con) //true to kill con
|
|
{
|
|
char *line, *msg;
|
|
int ret;
|
|
|
|
char readdata[8192];
|
|
char tempbuff[8192];
|
|
|
|
if (con->stage == 6)
|
|
{
|
|
int len;
|
|
if (con->type == ftp_getting)
|
|
{
|
|
if (!cls.downloadmethod || (cls.downloadmethod == DL_FTP && !strcmp(cls.downloadname, con->localfile)))
|
|
{
|
|
strcpy(cls.downloadname, con->localfile);
|
|
cls.downloadmethod = DL_FTP;
|
|
if (con->transfersize == -1)
|
|
cls.downloadpercent=50;
|
|
else
|
|
cls.downloadpercent = con->transfered*100.0f/con->transfersize;
|
|
}
|
|
while((len = recv(con->datasock, readdata, sizeof(readdata), 0)) >0 )
|
|
{
|
|
IWebFWrite(readdata, len, 1, con->f);
|
|
con->transfered += len;
|
|
}
|
|
if (len == 0)
|
|
{
|
|
closesocket(con->datasock);
|
|
con->datasock = INVALID_SOCKET;
|
|
}
|
|
}
|
|
else if (con->type == ftp_putting)
|
|
{
|
|
int pos, sent;
|
|
int ammount, wanted = sizeof(readdata);
|
|
|
|
pos = IWebFTell(con->f);
|
|
ammount = IWebFRead(readdata, 1, wanted, con->f);
|
|
sent = send(con->datasock, readdata, ammount, 0);
|
|
if (sent == -1)
|
|
IWebFSeek(con->f, pos, SEEK_SET); //go back. Too much data
|
|
else
|
|
{
|
|
IWebFSeek(con->f, pos + sent, SEEK_SET); //written this much
|
|
|
|
if (!ammount) //file is over
|
|
{
|
|
closesocket(con->datasock);
|
|
con->datasock = INVALID_SOCKET;
|
|
|
|
// msg = "226 Transfer complete.\r\n";
|
|
// send (con->controlsock, msg, strlen(msg), 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = recv(con->controlsock, (char *)readdata, sizeof(readdata)-1, 0);
|
|
if (ret == -1)
|
|
{
|
|
if (qerrno == EWOULDBLOCK)
|
|
return false;
|
|
|
|
if (qerrno == ECONNABORTED || qerrno == ECONNRESET)
|
|
{
|
|
Con_TPrintf (TL_CONNECTIONLOSTORABORTED);
|
|
return true;
|
|
}
|
|
|
|
// Con_TPrintf (TL_NETGETPACKETERROR, strerror(qerrno));
|
|
return true;
|
|
}
|
|
|
|
readdata[ret] = '\0'; //null terminate. (it's a string)
|
|
|
|
//we now have a message.
|
|
//We've got to work out what has happened already.
|
|
|
|
//a server can send many lines of text for one reply
|
|
//220-hello
|
|
// this
|
|
//220-is
|
|
// 220-all
|
|
//220 one reply
|
|
//so we only read lines that contain number space words, without any leading space
|
|
line = readdata;
|
|
while (1)
|
|
{
|
|
msg = line;
|
|
while (*line)
|
|
{
|
|
if (*line == '\n')
|
|
break;
|
|
line++;
|
|
}
|
|
if (!*line) //broken message
|
|
break;
|
|
*line = '\0';
|
|
line++;
|
|
|
|
if (*con->server)
|
|
IWebDPrintf("^2FTP: %s\n", COM_TrimString(msg));
|
|
|
|
if (*msg < '0' || *msg > '9') //make sure it starts with number
|
|
continue;
|
|
ret = atoi(msg);
|
|
while(*msg >= '0' && *msg <= '9') //find next non number
|
|
msg++;
|
|
if (*msg != ' ') //must be a space (definatly not a '-')
|
|
continue;
|
|
msg++;
|
|
|
|
if (ret == 220)
|
|
{
|
|
sprintf(tempbuff, "USER %s\r\n", con->name);
|
|
send(con->controlsock, tempbuff, strlen(tempbuff), 0);
|
|
con->stage = 1;
|
|
}
|
|
else if (ret == 331)
|
|
{
|
|
if (con->type == ftp_control)
|
|
sprintf(tempbuff, "PASS %s\r\nPWD %s\r\n", con->pwd, con->path);
|
|
else
|
|
sprintf(tempbuff, "PASS %s\r\n", con->pwd);
|
|
send(con->controlsock, tempbuff, strlen(tempbuff), 0);
|
|
con->stage = 2;
|
|
}
|
|
else if (ret == 230) //we must now do something useful
|
|
{
|
|
char adr[64];
|
|
if (con->type == ftp_control) //control is for browsing and duplicating
|
|
continue;
|
|
|
|
con->datasock = FTP_CL_makelistensocket();
|
|
if (!con->datasock || !FTP_SocketToString(con->datasock, adr))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
sprintf(tempbuff, "CWD %s%s\r\nPORT %s\r\n", con->pathprefix, con->path, adr);
|
|
send(con->controlsock, tempbuff, strlen(tempbuff), 0);
|
|
con->stage = 3;
|
|
}
|
|
else if (ret == 200)
|
|
{
|
|
struct sockaddr addr;
|
|
int addrlen = sizeof(addr);
|
|
int temp;
|
|
if (con->type == ftp_control)
|
|
continue;
|
|
if (con->stage == 3)
|
|
{
|
|
temp = accept(con->datasock, &addr, &addrlen);
|
|
closesocket(con->datasock);
|
|
con->datasock = temp;
|
|
|
|
if (temp != INVALID_SOCKET)
|
|
{
|
|
con->stage = 6;
|
|
if (con->type == ftp_getting)
|
|
{
|
|
con->f = IWebFOpenWrite(con->localfile, false);
|
|
if (con->f)
|
|
{
|
|
sprintf(tempbuff, "RETR %s\r\n", con->file);
|
|
con->stage = 6;
|
|
con->transfered = 0;
|
|
con->transfersize = -1;
|
|
}
|
|
else
|
|
{
|
|
sprintf(tempbuff, "QUIT\r\n");
|
|
con->stage = 7;
|
|
}
|
|
}
|
|
else if (con->type == ftp_putting)
|
|
{
|
|
con->f = IWebFOpenRead(con->localfile);
|
|
if (con->f)
|
|
{
|
|
sprintf(tempbuff, "STOR %s\r\n", con->file);
|
|
con->stage = 6;
|
|
con->transfered = 0;
|
|
con->transfersize = con->f->length;
|
|
}
|
|
else
|
|
{
|
|
sprintf(tempbuff, "QUIT\r\n");
|
|
con->stage = 7;
|
|
}
|
|
}
|
|
else
|
|
sprintf(tempbuff, "LIST %s\r\n", con->pwd);
|
|
send(con->controlsock, tempbuff, strlen(tempbuff), 0);
|
|
}
|
|
else
|
|
{
|
|
Con_Printf("FTP: Trying passive server mode\n");
|
|
msg = va("PASV\r\n");
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
con->stage = 4;
|
|
}
|
|
}
|
|
}
|
|
else if (ret == 213)
|
|
{
|
|
con->transfersize = atoi(msg);
|
|
msg = va("RETR %s\r\n", con->file);
|
|
con->stage = 6;
|
|
con->transfered = 0;
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
}
|
|
else if (ret == 125) //begining transfer
|
|
{
|
|
if (con->type == ftp_getting)
|
|
{
|
|
COM_StripExtension(con->localfile, msg);
|
|
strcat(msg, ".tmp");
|
|
con->f = IWebFOpenWrite(msg, false);
|
|
if (!con->f)
|
|
{
|
|
msg = va("ABOR\r\nQUIT\r\n"); //bummer. we couldn't open this file to output to.
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
con->stage = 7;
|
|
return true;
|
|
}
|
|
}
|
|
// msg = va("LIST\r\n");
|
|
// send(con->controlsock, msg, strlen(msg), 0);
|
|
con->stage = 6;
|
|
}
|
|
else if (ret == 226) //transfer complete
|
|
{
|
|
int len;
|
|
char data[1024];
|
|
if (con->f)
|
|
{
|
|
if (con->type == ftp_getting)
|
|
{
|
|
while(1) //this is potentially dodgy.
|
|
{
|
|
len = recv(con->datasock, data, sizeof(data), 0);
|
|
if (len == 0)
|
|
break;
|
|
if (len == -1)
|
|
{
|
|
if (qerrno != EWOULDBLOCK)
|
|
break;
|
|
continue;
|
|
}
|
|
con->transfered+=len;
|
|
data[len] = 0;
|
|
IWebFWrite(data, len, 1, con->f);
|
|
}
|
|
}
|
|
IWebFClose(con->f);
|
|
con->f = NULL;
|
|
closesocket(con->datasock);
|
|
con->datasock = INVALID_SOCKET;
|
|
|
|
if (con->transfersize != -1 && con->transfered != con->transfersize)
|
|
{
|
|
IWebPrintf("Transfer corrupt\nTransfered %i of %i bytes\n", con->transfered, con->transfersize);
|
|
}
|
|
else
|
|
IWebPrintf("Transfer compleate\n");
|
|
}
|
|
else
|
|
{
|
|
while((len = recv(con->datasock, data, sizeof(data), 0)) >0 )
|
|
{
|
|
data[len] = 0;
|
|
if (strchr(data, '\r'))
|
|
{
|
|
line = data;
|
|
for(;;)
|
|
{
|
|
msg = strchr(line, '\r');
|
|
if (!msg)
|
|
break;
|
|
*msg = '\0';
|
|
Con_Printf("%s", line);
|
|
line = msg+1;
|
|
}
|
|
Con_Printf("%s", line);
|
|
}
|
|
else
|
|
Con_Printf("%s", data);
|
|
}
|
|
closesocket(con->datasock);
|
|
con->datasock = INVALID_SOCKET;
|
|
}
|
|
msg = va("QUIT\r\n");
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
|
|
con->stage = 7;
|
|
}
|
|
else if (ret == 227)
|
|
{
|
|
// Con_Printf("FTP: Got passive server mode\n");
|
|
if (con->datasock != INVALID_SOCKET)
|
|
closesocket(con->datasock);
|
|
con->datasock = INVALID_SOCKET;
|
|
|
|
con->datasock = FTP_CL_makeconnectsocket(strchr(msg, '('));
|
|
if (con->datasock != INVALID_SOCKET)
|
|
{
|
|
if (con->type == ftp_getting)
|
|
{
|
|
con->f = IWebFOpenWrite(con->localfile, false);
|
|
if (con->f)
|
|
{
|
|
con->stage = 8;
|
|
msg = va("TYPE I\r\nSIZE %s\r\n", con->file);
|
|
con->transfersize = -1;
|
|
|
|
/*
|
|
msg = va("RETR %s\r\n", con->file);
|
|
con->stage = 6;
|
|
con->transfered = 0;
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
msg = va("QUIT\r\n");
|
|
con->stage = 7;
|
|
Con_Printf("FTP: Failed to open local file %s\n", con->localfile);
|
|
}
|
|
}
|
|
else if (con->type == ftp_putting)
|
|
{
|
|
con->f = IWebFOpenRead(con->localfile);
|
|
if (con->f)
|
|
{
|
|
msg = va("STOR %s\r\n", con->file);
|
|
con->stage = 6;
|
|
con->transfered = 0;
|
|
con->transfersize = con->f->length;
|
|
}
|
|
else
|
|
{
|
|
msg = va("QUIT\r\n");
|
|
con->stage = 7;
|
|
Con_Printf("FTP: Failed to open local file %s\n", con->localfile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg = "LIST\r\n";
|
|
con->stage = 6;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg = "QUIT\r\n";
|
|
con->stage = 7;
|
|
Con_Printf("FTP: Didn't connect\n");
|
|
}
|
|
|
|
send (con->controlsock, msg, strlen(msg), 0);
|
|
}
|
|
else if (ret == 250)
|
|
{
|
|
Con_Printf("FTP: %i %s\n", ret, msg);
|
|
}
|
|
else if (ret == 257)
|
|
{ //stick it on the beginning.
|
|
Con_Printf("FTP: %i %s\n", ret, msg);
|
|
msg = strchr(msg, '"');
|
|
if (msg)
|
|
{
|
|
Q_strncpyz(con->pathprefix, msg+1, sizeof(con->pathprefix));
|
|
msg = strchr(con->pathprefix, '"');
|
|
if (msg)
|
|
*msg = '\0';
|
|
}
|
|
else
|
|
Q_strcpyline(con->pathprefix, msg+4, sizeof(con->pathprefix)-1);
|
|
}
|
|
else
|
|
{
|
|
if (ret < 200)
|
|
continue;
|
|
if (con->stage == 5)
|
|
{
|
|
Con_DPrintf("FTP: Trying passive server mode\n");
|
|
msg = va("PASV\r\n");
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
con->stage = 4;
|
|
continue;
|
|
}
|
|
if (ret != 221)
|
|
Con_Printf("^1FTP: %i %s\n", ret, msg);
|
|
return true;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FTP_ClientThink (void)
|
|
{
|
|
FTPclientconn_t *con, *old=NULL;
|
|
for (con = FTPclientconn; con; con = con->next)
|
|
{
|
|
if (FTP_ClientConnThink(con))
|
|
{
|
|
if (cls.downloadmethod == DL_FTP && !strcmp(cls.downloadname, con->localfile))
|
|
{ //this was us
|
|
cls.downloadmethod = DL_NONE;
|
|
}
|
|
if (con->f)
|
|
IWebFClose(con->f);
|
|
if (con->controlsock != INVALID_SOCKET)
|
|
closesocket(con->controlsock);
|
|
if (con->datasock != INVALID_SOCKET)
|
|
closesocket(con->datasock);
|
|
if (!old)
|
|
{
|
|
FTPclientconn = con->next;
|
|
IWebFree(con);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
old->next = con->next;
|
|
IWebFree(con);
|
|
|
|
break;
|
|
}
|
|
}
|
|
old = con;
|
|
}
|
|
}
|
|
|
|
FTPclientconn_t *FTP_FindControl(void)
|
|
{
|
|
FTPclientconn_t *con;
|
|
|
|
for (con = FTPclientconn; con; con = con->next)
|
|
{
|
|
if (*con->server)
|
|
return con;
|
|
}
|
|
return NULL;
|
|
}
|
|
void FTP_Client_Command (char *cmd)
|
|
{
|
|
char command[64];
|
|
char server[MAX_OSPATH];
|
|
FTPclientconn_t *con;
|
|
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
if (!stricmp(command, "open"))
|
|
{
|
|
if (FTP_FindControl())
|
|
Con_Printf("You are already connected\n");
|
|
else
|
|
{
|
|
cmd = COM_ParseOut(cmd, server, sizeof(server));
|
|
if ((con = FTP_CreateConnection(server)))
|
|
{
|
|
Con_Printf("FTP connect succeded\n");
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
if (cmd)
|
|
{
|
|
Q_strncpyz(con->name, command, sizeof(con->name));
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
if (cmd)
|
|
Q_strncpyz(con->pwd, command, sizeof(con->pwd));
|
|
}
|
|
}
|
|
else
|
|
Con_Printf("FTP connect failed\n");
|
|
}
|
|
}
|
|
else if (!stricmp(command, "download"))
|
|
{
|
|
cmd = COM_ParseOut(cmd, server, sizeof(server));
|
|
con = FTP_CreateConnection(server);
|
|
if (!con)
|
|
{
|
|
Con_Printf("FTP: Couldn't connect\n");
|
|
return;
|
|
}
|
|
*con->server = '\0';
|
|
con->type = ftp_getting;
|
|
cmd = COM_ParseOut(cmd, server, sizeof(server));
|
|
Q_strncpyz(con->file, server, sizeof(con->file));
|
|
Q_strncpyz(con->localfile, server, sizeof(con->localfile));
|
|
|
|
if ((cmd = COM_ParseOut(cmd, server, sizeof(server))))
|
|
Q_strncpyz(con->localfile, server, sizeof(con->localfile));
|
|
}
|
|
else if (!stricmp(command, "quit"))
|
|
{
|
|
con = FTP_FindControl();
|
|
if (con)
|
|
{
|
|
char *msg;
|
|
msg = va("QUIT\r\n");
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
// if (con->datasock)
|
|
// closesocket(con->datasock);
|
|
// closesocket(con->controlsock);
|
|
}
|
|
else
|
|
Con_Printf("No main FTP connection\n");
|
|
}
|
|
else if (!stricmp(command, "list"))
|
|
{
|
|
FTPclientconn_t *new, *con = FTP_FindControl();
|
|
if (!con)
|
|
{
|
|
Con_Printf("Not connected\n");
|
|
return;
|
|
}
|
|
|
|
new = FTP_DuplicateConnection(con);
|
|
if (!new)
|
|
{
|
|
Con_Printf("Failed duplicate connection\n");
|
|
return;
|
|
}
|
|
new->type = ftp_listing;
|
|
}
|
|
else if (!stricmp(command, "get"))
|
|
{
|
|
FTPclientconn_t *new, *con = FTP_FindControl();
|
|
if (!con)
|
|
{
|
|
Con_Printf("Not connected\n");
|
|
return;
|
|
}
|
|
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
if (!cmd)
|
|
{
|
|
Con_Printf("No file specified\n");
|
|
return;
|
|
}
|
|
|
|
new = FTP_DuplicateConnection(con);
|
|
if (!new)
|
|
{
|
|
Con_Printf("Failed duplicate connection\n");
|
|
return;
|
|
}
|
|
new->type = ftp_getting;
|
|
sprintf(new->file, command);
|
|
sprintf(new->localfile, "%s%s", new->path, command);
|
|
}
|
|
else if (!stricmp(command, "put"))
|
|
{
|
|
FTPclientconn_t *new, *con = FTP_FindControl();
|
|
if (!con)
|
|
{
|
|
Con_Printf("Not connected\n");
|
|
return;
|
|
}
|
|
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
if (!cmd)
|
|
{
|
|
Con_Printf("No file specified\n");
|
|
return;
|
|
}
|
|
|
|
new = FTP_DuplicateConnection(con);
|
|
if (!new)
|
|
{
|
|
Con_Printf("Failed duplicate connection\n");
|
|
return;
|
|
}
|
|
new->type = ftp_putting;
|
|
sprintf(new->file, command);
|
|
sprintf(new->localfile, "%s%s", new->path, command);
|
|
}
|
|
else if (!stricmp(command, "cwd"))
|
|
{
|
|
FTPclientconn_t *con = FTP_FindControl();
|
|
if (!con)
|
|
{
|
|
Con_Printf("Not connected\n");
|
|
return;
|
|
}
|
|
Con_Printf("%s\n", con->path);
|
|
}
|
|
else if (!stricmp(command, "cd"))
|
|
{
|
|
char *msg;
|
|
FTPclientconn_t *con = FTP_FindControl();
|
|
if (!con)
|
|
{
|
|
Con_Printf("Not connected\n");
|
|
return;
|
|
}
|
|
|
|
cmd = COM_ParseOut(cmd, command, sizeof(command));
|
|
|
|
if (*command == '/') //absolute
|
|
Q_strncpyz(con->path, command, sizeof(con->path));
|
|
else //bung it on the end
|
|
{
|
|
strncat(con->path, "/", sizeof(con->path)-1);
|
|
strncat(con->path, command, sizeof(con->path)-1);
|
|
}
|
|
|
|
msg = va("CWD %s%s\r\n", con->pathprefix, con->path);
|
|
send(con->controlsock, msg, strlen(msg), 0);
|
|
}
|
|
else
|
|
Con_Printf("Unrecognised FTP command\n");
|
|
/*
|
|
com = COM_ParseOut(com, command, sizeof(command));
|
|
com = COM_ParseOut(com, command, sizeof(command));
|
|
com = COM_ParseOut(com, command, sizeof(command));
|
|
*/
|
|
}
|
|
|
|
#endif
|