408 lines
9.3 KiB
C
408 lines
9.3 KiB
C
|
#include "bothdefs.h"
|
||
|
|
||
|
#ifdef WEBSERVER
|
||
|
|
||
|
#include "iweb.h"
|
||
|
|
||
|
#ifdef CLIENTONLY
|
||
|
IWEBFILE *IWebGenerateFile(char *name)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
#else
|
||
|
|
||
|
char lastrecordedmvd[MAX_QPATH];
|
||
|
|
||
|
IWeb_FileGen_t *IWeb_GenerationBuffer;
|
||
|
int IWeb_GenerationBufferTotal;
|
||
|
|
||
|
void IWeb_MoreGeneratedResize(int newsize)
|
||
|
{
|
||
|
IWeb_FileGen_t *ob;
|
||
|
|
||
|
if (IWeb_GenerationBuffer && IWeb_GenerationBufferTotal >= newsize)
|
||
|
return; //already big enough
|
||
|
|
||
|
ob = IWeb_GenerationBuffer;
|
||
|
IWeb_GenerationBuffer = BZ_Malloc(sizeof(IWeb_GenerationBuffer) + newsize);
|
||
|
|
||
|
IWeb_GenerationBuffer->data = (char *)(IWeb_GenerationBuffer+1);
|
||
|
if (ob)
|
||
|
{
|
||
|
memcpy(IWeb_GenerationBuffer->data, ob->data, ob->len);
|
||
|
BZ_Free(ob);
|
||
|
}
|
||
|
|
||
|
IWeb_GenerationBufferTotal = newsize;
|
||
|
}
|
||
|
void IWeb_Generate(const char *buf)
|
||
|
{
|
||
|
long count = strlen(buf);
|
||
|
if (!IWeb_GenerationBuffer || IWeb_GenerationBuffer->len + count >= IWeb_GenerationBufferTotal)
|
||
|
IWeb_MoreGeneratedResize(IWeb_GenerationBufferTotal + count+(16*1024));
|
||
|
|
||
|
memcpy(&IWeb_GenerationBuffer->data[IWeb_GenerationBuffer->len], buf, count);
|
||
|
IWeb_GenerationBuffer->len+=count;
|
||
|
}
|
||
|
|
||
|
int Rank_Enumerate (unsigned int first, unsigned int last, void (*callback) (const rankinfo_t *ri)); //leader first.
|
||
|
|
||
|
void IWeb_ParseForm(char *info, int infolen, char *text)
|
||
|
{
|
||
|
char *eq, *and;
|
||
|
char *token, *out;
|
||
|
*info = '\0';
|
||
|
if (!text)
|
||
|
return;
|
||
|
while(*text)
|
||
|
{
|
||
|
eq = strchr(text, '=');
|
||
|
if (!eq)
|
||
|
break;
|
||
|
*eq = '\0';
|
||
|
and = strchr(eq+1, '&');
|
||
|
if (and)
|
||
|
*and = '\0';
|
||
|
|
||
|
for (out = token = eq+1; *token;)
|
||
|
{
|
||
|
if (*token == '+')
|
||
|
{
|
||
|
*out++ = ' ';
|
||
|
token++;
|
||
|
}
|
||
|
else if (*token == '%' && token[1] && token[2])
|
||
|
{
|
||
|
int c = 0;
|
||
|
|
||
|
if (token[1] >= '0' && token[1] <= '9')
|
||
|
{
|
||
|
c += token[1] - '0';
|
||
|
}
|
||
|
else if (token[1] >= 'a' && token[1] <= 'f')
|
||
|
{
|
||
|
c += token[1] - 'a'+10;
|
||
|
}
|
||
|
else if (token[1] >= 'A' && token[1] <= 'F')
|
||
|
{
|
||
|
c += token[1] - 'A'+10;
|
||
|
}
|
||
|
c*=16;
|
||
|
if (token[2] >= '0' && token[2] <= '9')
|
||
|
{
|
||
|
c += token[2] - '0';
|
||
|
}
|
||
|
else if (token[2] >= 'a' && token[2] <= 'f')
|
||
|
{
|
||
|
c += token[2] - 'a'+10;
|
||
|
}
|
||
|
else if (token[2] >= 'A' && token[2] <= 'F')
|
||
|
{
|
||
|
c += token[2] - 'A'+10;
|
||
|
}
|
||
|
|
||
|
*out++ = c;
|
||
|
token+=3;
|
||
|
}
|
||
|
else
|
||
|
*out++ = *token++;
|
||
|
}
|
||
|
*out = '\0';
|
||
|
|
||
|
Info_SetValueForKey(info, text, eq+1, infolen);
|
||
|
if (!and)
|
||
|
return;
|
||
|
text = and+1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void IWeb_GenerateAdminFile(char *parms, char *content, int contentlength)
|
||
|
{
|
||
|
extern char outputbuf[]; //redirected buffer - always null termed.
|
||
|
char info[16384];
|
||
|
char *pwd;
|
||
|
char *cmd;
|
||
|
char *mark, *start;
|
||
|
|
||
|
extern cvar_t rcon_password;
|
||
|
IWeb_Generate("<HTML><HEAD><TITLE>FTEQWSV - admin</TITLE></HEAD><BODY>");
|
||
|
if (*rcon_password.string)
|
||
|
{
|
||
|
IWeb_ParseForm(info, sizeof(info), content);
|
||
|
pwd = Info_ValueForKey(info, "pwd");
|
||
|
cmd = Info_ValueForKey(info, "cmd");
|
||
|
|
||
|
IWeb_Generate("<FORM action=\"admin.html\" method=\"post\">");
|
||
|
IWeb_Generate("<CENTER>");
|
||
|
IWeb_Generate("<input name=pwd value=\"");
|
||
|
if (!strcmp(rcon_password.string, pwd))
|
||
|
IWeb_Generate(rcon_password.string);
|
||
|
IWeb_Generate("\">");
|
||
|
IWeb_Generate("<BR>");
|
||
|
IWeb_Generate("<input name=cmd maxsize=255 size=40 value=\"\">");
|
||
|
IWeb_Generate("<BR>");
|
||
|
IWeb_Generate("<input type=submit value=\"Submit\" name=btn>");
|
||
|
IWeb_Generate("</CENTER>");
|
||
|
IWeb_Generate("</FORM>");
|
||
|
|
||
|
if (!strcmp(rcon_password.string, pwd))
|
||
|
{
|
||
|
Con_Printf("Web based rcon: %s\n", cmd);
|
||
|
SV_BeginRedirect(-1);
|
||
|
Cmd_ExecuteString(cmd, RESTRICT_RCON);
|
||
|
for (mark = start = outputbuf; *mark; mark++)
|
||
|
{
|
||
|
if (*mark == '\n')
|
||
|
{
|
||
|
*mark = '\0';
|
||
|
IWeb_Generate(start);
|
||
|
IWeb_Generate("<br>");
|
||
|
start = mark+1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
IWeb_Generate(start);
|
||
|
SV_EndRedirect();
|
||
|
}
|
||
|
else if (*pwd)
|
||
|
IWeb_Generate("Password is incorrect.");
|
||
|
}
|
||
|
else
|
||
|
IWeb_Generate("<H1>Remote administration is not enabled.<H2>");
|
||
|
IWeb_Generate("</BODY></HTML>");
|
||
|
}
|
||
|
|
||
|
|
||
|
void IWeb_GenerateRankingsFileCallback(const rankinfo_t *ri)
|
||
|
{
|
||
|
IWeb_Generate("<TR><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(ri->h.name);
|
||
|
IWeb_Generate("</TD><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(va("%i", ri->s.kills));
|
||
|
IWeb_Generate("</TD><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(va("%i", ri->s.deaths));
|
||
|
IWeb_Generate("</TD>");
|
||
|
IWeb_Generate("</TR>");
|
||
|
}
|
||
|
|
||
|
void IWeb_GenerateRankingsFile (char *parms, char *content, int contentlength)
|
||
|
{
|
||
|
IWeb_Generate("<HTML><HEAD></HEAD><BODY>");
|
||
|
|
||
|
if (Rank_OpenRankings())
|
||
|
{
|
||
|
IWeb_Generate("<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
|
||
|
IWeb_Generate("<CAPTION>Players</CAPTION>");
|
||
|
if (Rank_Enumerate(atoi(parms), atoi(parms)+20, IWeb_GenerateRankingsFileCallback) == 20)
|
||
|
{
|
||
|
IWeb_Generate("</TABLE>");
|
||
|
if (atoi(parms) >= 20)
|
||
|
IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", atoi(parms)-20));
|
||
|
else if (atoi(parms) > 0)
|
||
|
IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", 0));
|
||
|
IWeb_Generate(va("<A HREF=allplayers.html?%i>More</A>", atoi(parms)+20));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IWeb_Generate("</TABLE>");
|
||
|
if (atoi(parms) >= 20)
|
||
|
IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", atoi(parms)-20));
|
||
|
else if (atoi(parms) > 0)
|
||
|
IWeb_Generate(va("<A HREF=allplayers.html?%i>Less</A>", 0));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
IWeb_Generate("<H1>Rankings are disabled. Sorry.<H2>");
|
||
|
IWeb_Generate("</BODY></HTML>");
|
||
|
}
|
||
|
|
||
|
void IWeb_GenerateIndexFile (char *parms, char *content, int contentlength)
|
||
|
{
|
||
|
extern cvar_t rcon_password;
|
||
|
char *s, *o;
|
||
|
char key[128], value[128];
|
||
|
int l;
|
||
|
qboolean added;
|
||
|
client_t *cl;
|
||
|
IWeb_Generate("<HTML><HEAD><TITLE>FTEQWSV</TITLE></HEAD><BODY>");
|
||
|
IWeb_Generate("<H1>");
|
||
|
IWeb_Generate(hostname.string);
|
||
|
IWeb_Generate("</H1>");
|
||
|
|
||
|
IWeb_Generate("<A HREF=\"http://spike.corecodec.org\">Server website</A><P>");
|
||
|
|
||
|
if (Rank_OpenRankings())
|
||
|
IWeb_Generate("<A HREF=\"allplayers.html\">Click here to see ranked players.</A><P>");
|
||
|
if (*rcon_password.string)
|
||
|
IWeb_Generate("<A HREF=\"admin.html\">Admin.</A><P>");
|
||
|
|
||
|
s = svs.info;
|
||
|
|
||
|
IWeb_Generate("<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
|
||
|
IWeb_Generate("<CAPTION>Server Info</CAPTION>");
|
||
|
if (*s == '\\')
|
||
|
s++;
|
||
|
while (*s)
|
||
|
{
|
||
|
o = key;
|
||
|
while (*s && *s != '\\')
|
||
|
*o++ = *s++;
|
||
|
|
||
|
l = o - key;
|
||
|
// if (l < 20)
|
||
|
// {
|
||
|
// memset (o, ' ', 20-l);
|
||
|
// key[20] = 0;
|
||
|
// }
|
||
|
// else
|
||
|
*o = 0;
|
||
|
|
||
|
IWeb_Generate("<TR><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(key);
|
||
|
|
||
|
if (!*s)
|
||
|
{
|
||
|
IWeb_Generate("MISSING VALUE\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
o = value;
|
||
|
s++;
|
||
|
while (*s && *s != '\\')
|
||
|
*o++ = *s++;
|
||
|
*o = 0;
|
||
|
|
||
|
if (*s)
|
||
|
s++;
|
||
|
|
||
|
IWeb_Generate("</TD><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(value);
|
||
|
IWeb_Generate("</TD></TR>");
|
||
|
}
|
||
|
|
||
|
IWeb_Generate("</TABLE>");
|
||
|
|
||
|
IWeb_Generate("<P><TABLE CELLSPACING=\"1\" CELLPADDING=\"1\">");
|
||
|
IWeb_Generate("<CAPTION>Players</CAPTION>");
|
||
|
added = false;
|
||
|
for (l = 0, cl = svs.clients; l < sv.allocated_client_slots; l++, cl++)
|
||
|
{
|
||
|
if (cl->state <= cs_zombie)
|
||
|
continue;
|
||
|
|
||
|
IWeb_Generate("<TR><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(cl->name);
|
||
|
IWeb_Generate("</TD><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate(va("%i", cl->old_frags));
|
||
|
IWeb_Generate("</TD></TR>");
|
||
|
added = true;
|
||
|
}
|
||
|
if (!added)
|
||
|
{
|
||
|
IWeb_Generate("<TR><TD ALIGN = \"center\">");
|
||
|
IWeb_Generate("No players on server");
|
||
|
IWeb_Generate("</TD><TD ALIGN = \"center\">");
|
||
|
}
|
||
|
|
||
|
IWeb_Generate("</TABLE>");
|
||
|
|
||
|
IWeb_Generate("</BODY></HTML>");
|
||
|
}
|
||
|
|
||
|
typedef struct {
|
||
|
char *name;
|
||
|
void (*GenerationFunction) (char *parms, char *content, int contentlength);
|
||
|
float lastgenerationtime;
|
||
|
float oldbysecs;
|
||
|
IWeb_FileGen_t *buffer;
|
||
|
int genid;
|
||
|
} IWebFile_t;
|
||
|
|
||
|
IWebFile_t IWebFiles[] = {
|
||
|
{"allplayers.html", IWeb_GenerateRankingsFile},
|
||
|
{"index.html", IWeb_GenerateIndexFile},
|
||
|
{"admin.html", IWeb_GenerateAdminFile}
|
||
|
};
|
||
|
|
||
|
IWEBFILE *IWebGenerateFile(char *name, char *content, int contentlength)
|
||
|
{
|
||
|
int fnum;
|
||
|
char *parms;
|
||
|
int len;
|
||
|
|
||
|
if (!sv.state)
|
||
|
return NULL;
|
||
|
|
||
|
if (*lastrecordedmvd && !strcmp(name, "lastdemo.mvd"))
|
||
|
if (strcmp(name, "lastdemo.mvd")) //no infinate loops please...
|
||
|
return IWebFOpenRead(lastrecordedmvd);
|
||
|
|
||
|
parms = strchr(name, '?');
|
||
|
if (!parms)
|
||
|
parms = name + strlen(name);
|
||
|
len = parms-name;
|
||
|
if (*parms)
|
||
|
parms++;
|
||
|
|
||
|
if (!*name)
|
||
|
return NULL;
|
||
|
|
||
|
|
||
|
for (fnum = 0; fnum < sizeof(IWebFiles) / sizeof(IWebFile_t); fnum++)
|
||
|
{
|
||
|
if (!Q_strncasecmp(name, IWebFiles[fnum].name, len+1))
|
||
|
{
|
||
|
IWEBFILE *ret;
|
||
|
if (IWebFiles[fnum].buffer)
|
||
|
{
|
||
|
if (IWebFiles[fnum].lastgenerationtime+10 < Sys_DoubleTime() || contentlength||*parms) //10 sec lifetime
|
||
|
{
|
||
|
IWebFiles[fnum].buffer->references--; //remove our reference and check free
|
||
|
if (IWebFiles[fnum].buffer->references<=0)
|
||
|
{
|
||
|
BZ_Free(IWebFiles[fnum].buffer);
|
||
|
IWebFiles[fnum].buffer = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!IWebFiles[fnum].buffer)
|
||
|
{
|
||
|
if (IWeb_GenerationBuffer!=NULL)
|
||
|
Sys_Error("Recursive file generation\n");
|
||
|
IWebFiles[fnum].GenerationFunction(parms, content, contentlength);
|
||
|
IWebFiles[fnum].buffer = IWeb_GenerationBuffer;
|
||
|
|
||
|
if (!contentlength)
|
||
|
{
|
||
|
IWeb_GenerationBuffer->references++; //so it can't be sent once and freed instantly.
|
||
|
IWebFiles[fnum].lastgenerationtime = Sys_DoubleTime();
|
||
|
}
|
||
|
else
|
||
|
IWebFiles[fnum].lastgenerationtime = -10;
|
||
|
}
|
||
|
|
||
|
ret = IWebMalloc(sizeof(IWEBFILE));
|
||
|
if (!ret)
|
||
|
{
|
||
|
BZ_Free(IWeb_GenerationBuffer);
|
||
|
return NULL;
|
||
|
}
|
||
|
ret->f = NULL;
|
||
|
ret->bufferdata = IWebFiles[fnum].buffer;
|
||
|
ret->length = ret->bufferdata->len;
|
||
|
ret->bufferdata->references++;
|
||
|
ret->pos = 0;
|
||
|
ret->start = 0;
|
||
|
ret->end = ret->start+ret->length;
|
||
|
|
||
|
IWeb_GenerationBuffer = NULL;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
#endif
|