fteqw/fteqtv/control.c
2006-10-20 14:02:28 +00:00

516 lines
11 KiB
C

/*
Contains the control routines that handle both incoming and outgoing stuff
*/
#include "qtv.h"
// char *date = "Oct 24 1996";
static char *date = __DATE__ ;
static char *mon[12] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char mond[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// returns days since Oct 24 1996
int build_number( void )
{
int m = 0;
int d = 0;
int y = 0;
static int b = 0;
if (b != 0)
return b;
for (m = 0; m < 11; m++)
{
if (strncmp( &date[0], mon[m], 3 ) == 0)
break;
d += mond[m];
}
d += atoi( &date[4] ) - 1;
y = atoi( &date[7] ) - 1900;
b = d + (int)((y - 1) * 365.25);
if (((y % 4) == 0) && m > 1)
{
b += 1;
}
b -= 35778; // Dec 16 1998
return b;
}
typedef struct {
char name[56];
int offset;
int length;
} pakfile;
// PACK, offset, lengthofpakfiles
FILE *FindInPaks(char *gamedir, char *filename, int *size)
{
FILE *f;
char fname[1024];
int i, j;
int numfiles;
unsigned int header[3];
pakfile pf;
for (i = 0; ; i++)
{
sprintf(fname, "%s/pak%i.pak", gamedir, i);
f = fopen(fname, "rb");
if (!f)
return NULL; //ran out of possible pak files.
fread(header, 1, sizeof(header), f);
if (header[0] != *(unsigned int*)"PACK")
{ //err... hmm.
fclose(f);
continue;
}
numfiles = LittleLong(header[2])/sizeof(pakfile);
fseek(f, LittleLong(header[1]), SEEK_SET);
for (j = 0; j < numfiles; j++)
{
fread(&pf, 1, sizeof(pf), f);
if (!strcmp(pf.name, filename))
{
fseek(f, LittleLong(pf.offset), 0);
if (size)
*size = LittleLong(pf.length);
return f;
}
}
fclose(f);
//not found
}
return NULL;
}
unsigned char *FS_ReadFile2(char *gamedir, char *filename, unsigned int *sizep)
{
int size;
unsigned char *data;
FILE *f;
char fname[1024];
if (!*filename)
return NULL;
//try and read it straight out of the file system
sprintf(fname, "%s/%s", gamedir, filename);
f = fopen(fname, "rb");
if (!f)
f = fopen(filename, "rb"); //see if we're being run from inside the gamedir
if (!f)
{
f = FindInPaks(gamedir, filename, &size);
if (!f)
f = FindInPaks("id1", filename, &size);
if (!f)
{
return NULL;
}
}
else
{
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
}
data = malloc(size);
if (data)
fread(data, 1, size, f);
fclose(f);
if (sizep)
*sizep = size;
return data;
}
unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size)
{
char *data;
if (!gamedir || !*gamedir || !strcmp(gamedir, "qw"))
data = NULL;
else
data = FS_ReadFile2(gamedir, filename, size);
if (!data)
{
data = FS_ReadFile2("qw", filename, size);
if (!data)
{
data = FS_ReadFile2("id1", filename, size);
if (!data)
{
return NULL;
}
}
}
return data;
}
void Cluster_Run(cluster_t *cluster, qboolean dowait)
{
oproxy_t *pend, *pend2, *pend3;
sv_t *sv, *old;
int m;
struct timeval timeout;
fd_set socketset;
if (dowait)
{
FD_ZERO(&socketset);
m = 0;
if (cluster->qwdsocket != INVALID_SOCKET)
{
FD_SET(cluster->qwdsocket, &socketset);
if (cluster->qwdsocket >= m)
m = cluster->qwdsocket+1;
}
for (sv = cluster->servers; sv; sv = sv->next)
{
if (sv->usequkeworldprotocols && sv->sourcesock != INVALID_SOCKET)
{
FD_SET(sv->sourcesock, &socketset);
if (sv->sourcesock >= m)
m = sv->sourcesock+1;
}
}
#ifndef _WIN32
#ifndef STDIN
#define STDIN 0
#endif
FD_SET(STDIN, &socketset);
if (STDIN >= m)
m = STDIN+1;
#endif
timeout.tv_sec = 100/1000;
timeout.tv_usec = (100%1000)*1000;
m = select(m, &socketset, NULL, NULL, &timeout);
#ifdef _WIN32
for (;;)
{
char buffer[8192];
char *result;
char c;
if (!_kbhit())
break;
c = _getch();
if (c == '\n' || c == '\r')
{
Sys_Printf(cluster, "\n");
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
else if (c == '\b')
{
if (cluster->inputlength > 0)
{
Sys_Printf(cluster, "%c", c);
Sys_Printf(cluster, " ", c);
Sys_Printf(cluster, "%c", c);
cluster->inputlength--;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
else
{
Sys_Printf(cluster, "%c", c);
if (cluster->inputlength < sizeof(cluster->commandinput)-1)
{
cluster->commandinput[cluster->inputlength++] = c;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
}
#else
if (FD_ISSET(STDIN, &socketset))
{
char buffer[8192];
char *result;
cluster->inputlength = read (0, cluster->commandinput, sizeof(cluster->commandinput));
if (cluster->inputlength >= 1)
{
cluster->commandinput[cluster->inputlength-1] = 0; // rip off the /n and terminate
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
printf("%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
}
#endif
}
cluster->curtime = Sys_Milliseconds();
for (sv = cluster->servers; sv; )
{
old = sv;
sv = sv->next;
QTV_Run(old);
}
SV_FindProxies(cluster->tcpsocket, cluster, NULL); //look for any other proxies wanting to muscle in on the action.
QW_UpdateUDPStuff(cluster);
while(cluster->pendingproxies)
{
pend2 = cluster->pendingproxies->next;
if (SV_ReadPendingProxy(cluster, cluster->pendingproxies))
cluster->pendingproxies = pend2;
else
break;
}
if (cluster->pendingproxies)
{
for(pend = cluster->pendingproxies; pend && pend->next; )
{
pend2 = pend->next;
pend3 = pend2->next;
if (SV_ReadPendingProxy(cluster, pend2))
{
pend->next = pend3;
pend = pend3;
}
else
{
pend = pend2;
}
}
}
}
void DoCommandLine(cluster_t *cluster, int argc, char **argv)
{
int i;
char commandline[8192];
char *start, *end, *result;
char buffer[8192];
result = Rcon_Command(cluster, NULL, "exec qtv.cfg", buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
commandline[0] = '\0';
//build a block of strings.
for (i = 1; i < argc; i++)
{
strcat(commandline, argv[i]);
strcat(commandline, " ");
}
strcat(commandline, "+");
start = commandline;
while(start)
{
end = strchr(start+1, '+');
if (end)
*end = '\0';
if (start[1])
{
result = Rcon_Command(cluster, NULL, start+1, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
}
start = end;
}
}
int main(int argc, char **argv)
{
cluster_t cluster;
#ifndef _WIN32
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
#endif
#ifdef _WIN32
{
WSADATA discard;
WSAStartup(MAKEWORD(2,0), &discard);
}
#endif
memset(&cluster, 0, sizeof(cluster));
cluster.qwdsocket = INVALID_SOCKET;
cluster.tcpsocket = INVALID_SOCKET;
cluster.qwlistenportnum = 0;
cluster.allownqclients = true;
strcpy(cluster.hostname, DEFAULT_HOSTNAME);
cluster.buildnumber = build_number();
Sys_Printf(&cluster, "QTV Build %i.\n", cluster.buildnumber);
if (argc >= 2 && (!strcmp(argv[1], "-view") || !strcmp(argv[1], "-play")))
{
#ifdef VIEWER
sv_t *sv;
sv_t *svtest;
char sourcename[256];
char *s;
printf("Please enter a QTV source\n");
printf("eg: file:test.mvd\n");
printf("eg: udp:localhost:27500\n");
printf("eg: tcp:localhost:27599\n");
fgets(sourcename, sizeof(sourcename), stdin);
for (s = sourcename + strlen(sourcename)-1; s>=sourcename; s--)
{
if (*s == '\r' || *s == '\n')
*s = '\0';
else
break;
}
sv = QTV_NewServerConnection(&cluster, sourcename, "", false, false, true);
if (!sv)
{
printf("Unable to connect\n");
return 0;
}
if (!strcmp(argv[1], "-play"))
sv->proxyplayer = true;
DemoViewer_Init();
while (!cluster.wanttoexit)
{
Cluster_Run(&cluster, false);
for (svtest = cluster.servers; svtest; svtest = svtest->next)
{ //not the cleanest way to do this, of course
if (svtest == sv)
break;
}
if (svtest)
DemoViewer_Update(svtest);
else
cluster.wanttoexit = true;
}
DemoViewer_Shutdown();
while(cluster.viewers)
QW_FreeViewer(&cluster, cluster.viewers);
while(cluster.servers)
QTV_Shutdown(cluster.servers);
#else
Sys_Printf(&cluster, "Demo viewer is not enabled in this build. Sorry.\n");
#endif
return 0;
}
DoCommandLine(&cluster, argc, argv);
if (!cluster.numservers)
{ //probably running on a home user's computer
if (cluster.qwdsocket == INVALID_SOCKET && !cluster.qwlistenportnum)
{
cluster.qwdsocket = QW_InitUDPSocket(cluster.qwlistenportnum = 27599);
if (cluster.qwdsocket != INVALID_SOCKET)
Sys_Printf(&cluster, "opened udp port %i\n", cluster.qwlistenportnum);
}
if (cluster.tcpsocket == INVALID_SOCKET && !cluster.tcplistenportnum)
{
cluster.tcpsocket = Net_MVDListen(cluster.tcplistenportnum = 27599);
if (cluster.tcpsocket != INVALID_SOCKET)
Sys_Printf(&cluster, "opened tcp port %i\n", cluster.tcplistenportnum);
}
Sys_Printf(&cluster, "\n"
"Welcome to FTEQTV\n"
"Please type\n"
"qtv server:port\n"
" to connect to a tcp server.\n"
"qw server:port\n"
" to connect to a regular qw server.\n"
"demo qw/example.mvd\n"
" to play a demo from an mvd.\n"
"\n");
}
while (!cluster.wanttoexit)
Cluster_Run(&cluster, true);
return 0;
}
void Sys_Printf(cluster_t *cluster, char *fmt, ...)
{
va_list argptr;
char string[2048];
unsigned char *t;
va_start (argptr, fmt);
vsnprintf (string, sizeof(string)-1, fmt,argptr);
string[sizeof(string)-1] = 0;
va_end (argptr);
for (t = (unsigned char*)string; *t; t++)
{
if (*t >= 146 && *t < 156)
*t = *t - 146 + '0';
if (*t == 143)
*t = '.';
if (*t == 157 || *t == 158 || *t == 159)
*t = '-';
if (*t >= 128)
*t -= 128;
if (*t == 16)
*t = '[';
if (*t == 17)
*t = ']';
if (*t == 29)
*t = '-';
if (*t == 30)
*t = '-';
if (*t == 31)
*t = '-';
if (*t == '\a') //doh. :D
*t = ' ';
}
printf("%s", string);
}