A few user interface changes.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2402 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2006-10-07 22:29:31 +00:00
parent dc4ca9b290
commit 300f84b8c1
8 changed files with 654 additions and 475 deletions

View file

@ -6,6 +6,49 @@ Contains the control routines that handle both incoming and outgoing stuff
// 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;
@ -285,6 +328,9 @@ void DoCommandLine(cluster_t *cluster, int argc, char **argv)
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.
@ -333,8 +379,11 @@ int main(int argc, char **argv)
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")))
{

View file

@ -267,7 +267,7 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox)
prox->flushing = false;
BuildServerData(qtv, &msg, true, 0);
BuildServerData(qtv, &msg, true, 0, true);
Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1);
msg.cursize = 0;
@ -451,6 +451,9 @@ void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
"<BODY>");
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
snprintf(buffer, sizeof(buffer), "<H1>Now Playing on %s</H1>", cluster->hostname);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
for (streams = cluster->servers; streams; streams = streams->next)
{
sprintf(buffer, "<A HREF=\"watch.qtv?sid=%i\">%s (%s: %s)</A><br/>", streams->streamid, streams->server, streams->gamedir, streams->mapname);
@ -466,6 +469,13 @@ void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
}
}
}
if (!cluster->servers)
{
s = "No streams are currently being played";
Net_ProxySend(cluster, dest, s, strlen(s));
}
sprintf(buffer, "</BODY>");
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
}
@ -542,7 +552,8 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, int streamid)
"<TITLE>QuakeTV: Now Playing</TITLE>"
"</HEAD>"
"<BODY>"
"Your client did not send a Host field\n"
"Your client did not send a Host field, which is required in HTTP/1.1\n<BR />"
"Please try a different browser.\n"
"</BODY>"
"</HTML>";
@ -550,7 +561,7 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, int streamid)
return;
}
s = "HTTP/1.1 200 OK\n"
s = "HTTP/1.1 200 OK\n"
"Content-Type: text/x-quaketvident\n"
"Connection: close\n"
"\n";
@ -566,6 +577,166 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, int streamid)
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
}
char *SV_ParsePOST(char *post, char *buffer, int buffersize)
{
while(*post && *post != '&')
{
if (--buffersize>0)
{
if (*post == '+')
*buffer++ = ' ';
else if (*post == '%')
{
*buffer = 0;
post++;
if (*post == '\0' || *post == '&')
break;
else if (*post >= 'a' && *post <= 'f')
*buffer += 10 + *post-'a';
else if (*post >= 'A' && *post <= 'F')
*buffer += 10 + *post-'A';
else if (*post >= '0' && *post <= '9')
*buffer += *post-'0';
*buffer <<= 4;
post++;
if (*post == '\0' || *post == '&')
break;
else if (*post >= 'a' && *post <= 'f')
*buffer += 10 + *post-'a';
else if (*post >= 'A' && *post <= 'F')
*buffer += 10 + *post-'A';
else if (*post >= '0' && *post <= '9')
*buffer += *post-'0';
buffer++;
}
else
*buffer++ = *post;
}
post++;
}
*buffer = 0;
return post;
}
void SV_GenerateAdminHTTP(cluster_t *cluster, oproxy_t *dest, int streamid, char *postbody)
{
char pwd[64];
char cmd[256];
char result[8192];
char *s;
char *o;
if (!*cluster->adminpassword)
{
s = "HTTP/1.1 403 OK\n"
"Content-Type: text/html\n"
"Connection: close\n"
"\n"
"<HEAD><TITLE>QuakeTV</TITLE></HEAD><BODY>The admin password is disabled. You may not log in remotely.</BODY>\n";
Net_ProxySend(cluster, dest, s, strlen(s));
return;
}
pwd[0] = 0;
cmd[0] = 0;
if (postbody)
while (*postbody)
{
if (!strncmp(postbody, "pwd=", 4))
{
postbody = SV_ParsePOST(postbody+4, pwd, sizeof(pwd));
}
else if (!strncmp(postbody, "cmd=", 4))
{
postbody = SV_ParsePOST(postbody+4, cmd, sizeof(cmd));
}
else
{
while(*postbody && *postbody != '&')
{
postbody++;
}
if (*postbody == '&')
postbody++;
}
}
if (!*pwd)
o = "";
else if (!strcmp(pwd, cluster->adminpassword))
{
o = Rcon_Command(cluster, NULL, cmd, result, sizeof(result), false);
}
else
{
o = "Bad Password";
}
if (o != result)
{
strcpy(result, o);
o = result;
}
s = "HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Connection: close\n"
"\n"
"<HTML>"
"<HEAD>"
"<TITLE>QuakeTV: Admin</TITLE>\n"
"<script type=\"text/javascript\">\n"
//"<!--"
"function sf(){document.f.cmd.focus();}\n"
//"// -->"
"</script>\n"
"</HEAD>\n"
"<BODY onload=sf()>";
Net_ProxySend(cluster, dest, s, strlen(s));
s =
"<FORM action=\"admin.html\" method=\"post\" name=f>"
"<CENTER>"
"Password <input name=pwd value=\"";
Net_ProxySend(cluster, dest, s, strlen(s));
if (*o)
Net_ProxySend(cluster, dest, pwd, strlen(pwd));
s = "\">"
"<BR />"
"Command <input name=cmd maxsize=255 size=40 value=\"\">"
"<input type=submit value=\"Submit\" name=btn>"
"</CENTER>"
"</FORM>";
Net_ProxySend(cluster, dest, s, strlen(s));
while(*o)
{
s = strchr(o, '\n');
if (s)
*s = 0;
Net_ProxySend(cluster, dest, o, strlen(o));
Net_ProxySend(cluster, dest, "<BR />", 6);
if (!s)
break;
o = s+1;
}
s = "</BODY>"
"</HTML>";
Net_ProxySend(cluster, dest, s, strlen(s));
}
//returns true if the pending proxy should be unlinked
//truth does not imply that it should be freed/released, just unlinked.
qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
@ -583,6 +754,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
{
closesocket(pend->sock);
free(pend);
cluster->numproxies--;
return true;
}
@ -610,7 +782,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (pend->inbuffersize >= 4)
{
if (strncmp(pend->inbuffer, "QTV\n", 4) && strncmp(pend->inbuffer, "GET ", 4))
if (strncmp(pend->inbuffer, "QTV\n", 4) && strncmp(pend->inbuffer, "GET ", 4) && strncmp(pend->inbuffer, "POST ", 5))
{ //I have no idea what the smeg you are.
pend->drop = true;
return false;
@ -626,8 +798,52 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
}
if (!*s)
return false; //don't have enough yet
s+=3;
if (!strncmp(pend->inbuffer, "GET ", 4))
if (!strncmp(pend->inbuffer, "POST ", 5))
{
if (!SV_GetHTTPHeaderField(pend->inbuffer, "Content-Length", tempbuf, sizeof(tempbuf)))
{
s = "HTTP/1.1 411 OK\n"
"Content-Type: text/html\n"
"Connection: close\n"
"\n"
"<HEAD><TITLE>QuakeTV</TITLE></HEAD><BODY>No Content-Length was provided.</BODY>\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
return false;
}
len = atoi(tempbuf);
if (pend->inbuffersize + len >= sizeof(pend->inbuffer)-20)
{ //too much data
pend->flushing = true;
return false;
}
len = s - pend->inbuffer + len;
if (len > pend->inbuffersize)
return false; //still need the body
// if (len >= pend->inbuffersize)
{
if (!strncmp(pend->inbuffer+5, "/admin", 6))
{
SV_GenerateAdminHTTP(cluster, pend, 0, s);
}
else
{
s = "HTTP/1.1 404 OK\n"
"Content-Type: text/html\n"
"Connection: close\n"
"\n"
"<HEAD><TITLE>QuakeTV</TITLE></HEAD><BODY>That HTTP method is not supported for that URL.</BODY>\n";
Net_ProxySend(cluster, pend, s, strlen(s));
}
pend->flushing = true;
return false;
}
}
else if (!strncmp(pend->inbuffer, "GET ", 4))
{
if (!strncmp(pend->inbuffer+4, "/nowplaying", 11))
{
@ -638,12 +854,16 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
SV_GenerateQTVStub(cluster, pend, atoi(pend->inbuffer+19));
}
else if (!strncmp(pend->inbuffer+4, "/about", 6))
{
{ //redirect them to our funky website
s = "HTTP/1.0 302 Found\n"
"Location: http://www.fteqw.com/\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
}
else if (!strncmp(pend->inbuffer+4, "/admin", 6))
{
SV_GenerateAdminHTTP(cluster, pend, 0, NULL);
}
else if (!strncmp(pend->inbuffer+4, "/ ", 2))
{
s = "HTTP/1.0 302 Found\n"
@ -695,7 +915,11 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (*s)
if (!colon)
{
if (!strcmp(s, "SOURCELIST"))
if (!strcmp(s, "QTV"))
{
//just a qtv request
}
else if (!strcmp(s, "SOURCELIST"))
{ //lists sources that are currently playing
s = "QTVSV 1\n";
Net_ProxySend(cluster, pend, s, strlen(s));

View file

@ -375,6 +375,8 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Info_SetValueForStarKey(tv->serverinfo, "*qtv", VERSION, sizeof(tv->serverinfo));
Info_SetValueForStarKey(tv->serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->serverinfo));
Info_ValueForKey(tv->serverinfo, "hostname", tv->hostname, sizeof(tv->hostname));
//change the hostname (the qtv's hostname with the server's hostname in brackets)
Info_ValueForKey(tv->serverinfo, "hostname", value, sizeof(value));
if (fromproxy && strchr(value, '(') && value[strlen(value)-1] == ')') //already has brackets

View file

@ -25,6 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define LittleShort(x) (x)
#endif
//this is for a future version
//#define COMMENTARY
//each server that we are connected to has it's own state.
//it should be easy enough to use one thread per server.
@ -128,6 +131,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <string.h>
//linux and other systems have strlcat / strlcpy
//we support windows and can't use those
#define Q_strncatz(dest, src, sizeofdest) \
do { \
strncat(dest, src, sizeofdest - strlen(dest) - 1); \
dest[sizeofdest - 1] = 0; \
} while (0)
#define Q_strncpyz(dest, src, sizeofdest) \
do { \
strncpy(dest, src, sizeofdest - 1); \
dest[sizeofdest - 1] = 0; \
} while (0)
#define VERSION "0.01" //this will be added to the serverinfo
#define PROX_DEFAULTLISTENPORT 27501
@ -191,7 +212,7 @@ extern "C" {
typedef unsigned char netadr_t[64];
#define NQ_PACKETS_PER_SECOND 100
#define NQ_PACKETS_PER_SECOND 20
#define MAX_NQMSGLEN 8000
#define MAX_MSGLEN 1400
#define MAX_NQDATAGRAM 1024
@ -217,11 +238,12 @@ typedef unsigned char netadr_t[64];
#define NET_GAMENAME_NQ "QUAKE"
#define NET_PROTOCOL_VERSION 3
#ifdef COMMENTARY
typedef struct soundcapt_s {
int (*update)(struct soundcapt_s *ghnd, int samplechunks, char *buffer);
void (*close)(struct soundcapt_s *ptr);
} soundcapt_t;
#endif
typedef struct {
unsigned int readpos;
@ -339,6 +361,7 @@ typedef struct viewer_s {
qboolean maysend;
qboolean chokeme;
qboolean thinksitsconnected;
qboolean conmenussupported;
int delta_frame;
int servercount;
@ -416,6 +439,13 @@ typedef struct {
unsigned short leafs[MAX_ENTITY_LEAFS];
} entity_t;
#define MAX_ENTITY_FRAMES 64
typedef struct {
int numents;
int maxents;
entity_state_t *ents; //dynamically allocated
} frame_t;
typedef struct {
unsigned char number;
char bits[6];
@ -452,6 +482,7 @@ struct sv_s {
} movevars;
int cdtrack;
entity_t entity[MAX_ENTITIES];
frame_t frame[MAX_ENTITY_FRAMES];
int maxents;
staticsound_t staticsound[MAX_STATICSOUNDS];
int staticsound_count;
@ -528,8 +559,10 @@ struct sv_s {
bsp_t *bsp;
int numinlines;
#ifdef COMMENTARY
//audio stuff
soundcapt_t *comentrycapture;
#endif
//options:
char server[MAX_QPATH];
@ -564,9 +597,13 @@ struct cluster_s {
qboolean lateforward;
qboolean notalking;
qboolean nobsp;
qboolean allownqclients; //nq clients require no challenge
qboolean nouserconnects; //prohibit users from connecting to new streams.
int maxviewers;
int buildnumber;
int numproxies;
int maxproxies;
@ -575,7 +612,10 @@ struct cluster_s {
oproxy_t *pendingproxies;
};
#define MENU_NONE 0
#define MENU_SERVERS 1
#define MENU_ADMIN 2
#define MENU_ADMINSERVER 3
@ -765,7 +805,7 @@ void WriteData(netmsg_t *b, const char *data, int length);
void Multicast(sv_t *tv, char *buffer, int length, int to, unsigned int playermask,int suitablefor);
void Broadcast(cluster_t *cluster, char *buffer, int length, int suitablefor);
void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask);
void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount);
void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qboolean spectatorflag);
void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount);
SOCKET QW_InitUDPSocket(int port);
void QW_UpdateUDPStuff(cluster_t *qtv);

View file

@ -67,7 +67,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /Yu"qtv.h" /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "speex-1.2beta1\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /Yu"qtv.h" /FD /GZ /c
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe

View file

@ -24,10 +24,6 @@ static const filename_t ConnectionlessModelList[] = {{""}, {"maps/start.bsp"}, {
static const filename_t ConnectionlessSoundList[] = {{""}, {""}};
#define MENU_NONE 0
#define MENU_SERVERS 1
#define MENU_ADMIN 2
#define MENU_ADMINSERVER 3
void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum);
void QW_SetMenu(viewer_t *v, int menunum);
@ -197,7 +193,7 @@ SOCKET QW_InitUDPSocket(int port)
return sock;
}
void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount)
void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qboolean spectatorflag)
{
WriteByte(msg, svc_serverdata);
WriteLong(msg, PROTOCOL_VERSION);
@ -211,7 +207,7 @@ void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount)
if (mvd)
WriteFloat(msg, 0);
else
WriteByte(msg, MAX_CLIENTS-1);
WriteByte(msg, MAX_CLIENTS-1 | (spectatorflag?128:0));
WriteString(msg, "FTEQTV Proxy");
@ -242,7 +238,7 @@ void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount)
if (mvd)
WriteFloat(msg, 0);
else
WriteByte(msg, tv->thisplayer);
WriteByte(msg, tv->thisplayer | (spectatorflag?128:0));
WriteString(msg, tv->mapname);
@ -330,7 +326,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum)
WriteByte(msg, tv->cdtrack);
WriteByte(msg, svc_nqsetview);
WriteShort(msg, tv->trackplayer);
WriteShort(msg, 15);
WriteByte(msg, svc_nqsignonnum);
WriteByte(msg, 1);
@ -350,11 +346,11 @@ void SendServerData(sv_t *tv, viewer_t *viewer)
if (tv && (tv->controller == viewer || !tv->controller))
viewer->thisplayer = tv->thisplayer;
else
viewer->thisplayer = 15;
viewer->thisplayer = viewer->netchan.isnqprotocol?15:MAX_CLIENTS-1;
if (viewer->netchan.isnqprotocol)
BuildNQServerData(tv, &msg, false, viewer->thisplayer);
else
BuildServerData(tv, &msg, false, viewer->servercount);
BuildServerData(tv, &msg, false, viewer->servercount, !tv || tv->controller != viewer);
SendBufferToViewer(viewer, msg.data, msg.cursize, true);
@ -650,7 +646,7 @@ void NewClient(cluster_t *cluster, viewer_t *viewer)
}
QW_PrintfToViewer(viewer, "Welcome to FTEQTV\n");
QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber);
QW_StuffcmdToViewer(viewer, "alias admin \"cmd admin\"\n");
QW_StuffcmdToViewer(viewer, "alias \"proxy:up\" \"say proxy:menu up\"\n");
@ -835,6 +831,10 @@ void QW_SetMenu(viewer_t *v, int menunum)
QW_StuffcmdToViewer(v, "alias \"-proxleft\" \"-moveleft\"\n");
QW_StuffcmdToViewer(v, "alias \"-proxright\" \"-moveright\"\n");
}
QW_StuffcmdToViewer(v, "-forward\n");
QW_StuffcmdToViewer(v, "-back\n");
QW_StuffcmdToViewer(v, "-moveleft\n");
QW_StuffcmdToViewer(v, "-moveright\n");
}
v->menunum = menunum;
@ -880,6 +880,10 @@ void QTV_Status(cluster_t *cluster, netadr_t *from)
WriteLong(&msg, -1);
WriteByte(&msg, 'n');
WriteString2(&msg, "\\*QTV\\");
sprintf(elem, "%i", cluster->buildnumber);
WriteString2(&msg, elem);
if (cluster->numservers==1)
{ //show this server's info
sv = cluster->servers;
@ -946,11 +950,11 @@ void QTV_Status(cluster_t *cluster, netadr_t *from)
for (sv = cluster->servers, i = 0; sv; sv = sv->next, i++)
{
sprintf(elem, "\\%i\\", i);
sprintf(elem, "\\%i\\", sv->streamid);
WriteString2(&msg, elem);
WriteString2(&msg, sv->serveraddress);
sprintf(elem, " (%s)", sv->serveraddress);
WriteString2(&msg, sv->serveraddress);
WriteString2(&msg, elem);
}
}
@ -2038,7 +2042,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
{
QW_PrintfToViewer(v, "Website: http://www.fteqw.com/\n"
"Commands:\n"
".qw qwserver:port\n"
".observe qwserver:port\n"
".qtv tcpserver:port\n"
".demo gamedir/demoname.mvd\n"
".disconnect\n"
@ -2046,6 +2050,129 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
".bind\n"
);
}
else if (!strncmp(message, ".guimenu", 8))
{
sv_t *sv;
int y;
qboolean shownheader = false;
QW_StuffcmdToViewer(v,
"alias menucallback\n"
"{\n"
"menuclear\n"
"if (option == \"OBSERVE\")\n"
"{\necho Spectating server $_server\nsay .observe $_server\n}\n"
"if (option == \"QTV\")\n"
"{\necho Streaming from qtv at $_server\nsay .qtv $_server\n}\n"
"if (option == \"JOIN\")\n"
"{\necho Joining game at $_server\nsay .join $_server\n}\n"
"if (option == \"ADMIN\")\n"
"{\nsay .guiadmin\n}\n"
"if (\"stream \" isin option)\n"
"{\necho Changing stream\nsay .$option\n}\n"
"}\n"
/*
"conmenu menucallback\n"
"menupic 16 4 gfx/qplaque.lmp\n"
"menupic - 4 gfx/p_option.lmp\n"
"menuedit 16 32 \" Server\" \"_server\"\n"
"menutext 72 48 \"Observe\" OBSERVE\n"
"menutext 136 48 \"QTV\" QTV\n"
"menutext 168 48 \"Cancel\" cancel\n"
"menutext 224 48 \"Join\" JOIN\n"
"menutext 264 48 \"Admin\" ADMIN\n"
*/
"conmenu menucallback\n"
"menupic 0 4 gfx/qplaque.lmp\n"
"menupic 96 4 gfx/p_option.lmp\n"
"menuedit 48 36 \"Óåòöåòº\" \"_server\"\n"
"menutext 104 52 \"Join\" JOIN\n"
"menutext 152 52 \"Observe\" OBSERVE\n"
"menutext 224 52 \"QTV\" QTV\n"
"menutext 48 84 \"Admin\" ADMIN\n"
"menutext 48 92 \"Close Menu\" cancel\n"
"menutext 48 116 \"Type in a server address and\"\n"
"menutext 48 124 \"click join to play in the game,\"\n"
"menutext 48 132 \"observe(udp) to watch, or qtv(tcp)\"\n"
"menutext 48 140 \"to connect to a stream or proxy.\"\n"
);
y = 140+16;
for (sv = cluster->servers; sv; sv = sv->next)
{
if (!shownheader)
{
shownheader = true;
QW_StuffcmdToViewer(v, "menutext 72 %i \"Áãôéöå Çáíåóº\"\n", y);
y+=8;
}
QW_StuffcmdToViewer(v, "menutext 32 %i \"%30s\" \"stream %i\"\n", y, *sv->hostname?sv->hostname:sv->server, sv->streamid);
y+=8;
}
if (!shownheader)
QW_StuffcmdToViewer(v, "menutext 72 %i \"There are no active games\"\n", y);
}
else if (!strncmp(message, ".guiadmin", 6))
{
if (!*cluster->adminpassword)
{
QW_StuffcmdToViewer(v,
"alias menucallback\n"
"{\n"
"menuclear\n"
"}\n"
"conmenu menucallback\n"
"menupic 16 4 gfx/qplaque.lmp\n"
"menupic - 4 gfx/p_option.lmp\n"
"menutext 72 48 \"No admin password is set\"\n"
"menutext 72 56 \"Admin access is prohibited\"\n"
);
}
else if (v->isadmin)
//already an admin, so don't show admin login screen
QW_SetMenu(v, MENU_ADMIN);
else
{
QW_StuffcmdToViewer(v,
"alias menucallback\n"
"{\n"
"menuclear\n"
"if (option == \"log\")\n"
"{\nsay $_password\n}\n"
"set _password \"\"\n"
"}\n"
"conmenu menucallback\n"
"menupic 16 4 gfx/qplaque.lmp\n"
"menupic - 4 gfx/p_option.lmp\n"
"menuedit 16 32 \" Password\" \"_password\"\n"
"menutext 72 48 \"Log in QW\" log\n"
"menutext 192 48 \"Cancel\" cancel\n"
);
strcpy(v->expectcommand, "admin");
}
}
else if (!strncmp(message, ".reset", 6))
{
QW_SetViewersServer(v, NULL);
@ -2072,7 +2199,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
QW_StuffcmdToViewer(v, "echo Please enter the rcon password\nmessagemode\n");
}
}
else if (!strncmp(message, ".connect ", 9) || !strncmp(message, ".qw ", 4))
else if (!strncmp(message, ".connect ", 9) || !strncmp(message, ".qw ", 4) || !strncmp(message, ".observe ", 9))
{
if (!strncmp(message, ".qw ", 4))
message += 4;
@ -2118,6 +2245,29 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
else
QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message);
}
else if (!strncmp(message, ".stream ", 7))
{
int id;
message += 7;
id = atoi(message);
for (qtv = cluster->servers; qtv; qtv = qtv->next)
{
if (qtv->streamid == id)
{
break;
}
}
if (qtv)
{
QW_SetMenu(v, MENU_NONE);
QW_SetViewersServer(v, qtv);
QW_PrintfToViewer(v, "Connected\n", message);
}
else
{
QW_PrintfToViewer(v, "Stream not recognised. Stream id is invalid or terminated.\n", message);
}
}
else if (!strncmp(message, ".demo ", 6))
{
message += 6;
@ -2201,26 +2351,38 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
QW_StuffcmdToViewer(v, "bind pause \"proxy:menu\"\n");
QW_StuffcmdToViewer(v, "bind backspace \"proxy:menu back\"\n");
}
else if (!strncmp(message, ".", 1))
else if (!strncmp(message, ".", 1) && strncmp(message, "..", 2))
{
QW_PrintfToViewer(v, "Proxy command not recognised\n");
}
else
{
if (!strncmp(message, ".", 1))
message++;
*v->expectcommand = '\0';
if (cluster->notalking)
return;
if (qtv && qtv->usequkeworldprotocols && !noupwards)
{
if (qtv->controller == v || !*v->name)
{
SendClientCommand(qtv, "say %s\n", message);
if (cluster->notalking)
return;
}
else
{
if (cluster->notalking)
return;
SendClientCommand(qtv, "say %s: %s\n", v->name, message);
}
//FIXME: we ought to broadcast this to everyone not watching that qtv.
}
else
{
if (cluster->notalking)
return;
InitNetMsg(&msg, buf, sizeof(buf));
@ -2334,9 +2496,7 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
}
else if (!strncmp(buf, "name ", 5))
{
/*
fixme
*/
Q_strncpyz(v->name, buf+5, sizeof(v->name));
}
else if (!strncmp(buf, "color ", 6))
{
@ -2344,7 +2504,7 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
fixme
*/
}
else if (!strncmp(buf, "spawn ", 6))
else if (!strncmp(buf, "spawn", 5))
{
msg.data = buf;
msg.maxsize = sizeof(buf);
@ -2442,6 +2602,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
QW_StuffcmdToViewer(v, "cmd new\n");
else
{
QW_StuffcmdToViewer(v, "//querycmd conmenu\n");
SendServerData(qtv, v);
}
}
@ -2648,7 +2809,13 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
if (v->server && v->server->controller == v)
SendClientCommand(v->server, "%s", buf);
}
else if (!strncmp(buf, "cmdsupported ", 13))
{
if (!strcmp(buf+13, "conmenu"))
v->conmenussupported = true;
else if (v->server && v->server->controller == v)
SendClientCommand(v->server, "%s", buf);
}
else if (!qtv)
{
//all the other things need an active server.
@ -2809,7 +2976,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
if (i++ == viewer->menuop)
{ //qw port
QW_StuffcmdToViewer(viewer, "echo You will need to reconnect\n");
cluster->qwlistenportnum += buttonnum?-1:1;
cluster->qwlistenportnum += (buttonnum<0)?-1:1;
}
if (i++ == viewer->menuop)
{ //hostname
@ -2875,7 +3042,8 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
WriteByte(&m, svc_centerprint);
WriteString2(&m, "FTEQTV\n");
sprintf(str, "FTEQTV build %i\n", cluster->buildnumber);
WriteString2(&m, str);
if (strcmp(cluster->hostname, DEFAULT_HOSTNAME))
WriteString2(&m, cluster->hostname);
@ -3216,7 +3384,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster)
}
}
}
if (!v)
if (!v && cluster->allownqclients)
{
//NQ connectionless packet?
m.readpos = 0;

View file

@ -433,66 +433,69 @@ char *Cmd_Exec(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer,
return "Execed\n";
}
}
void catbuffer(char *buffer, int bufsize, char *format, ...)
{
va_list argptr;
char string[1024];
va_start (argptr, format);
vsnprintf (string,sizeof(string)-1, format,argptr);
va_end (argptr);
Q_strncatz(buffer, string, bufsize);
}
char *Cmd_Status(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
buffer[0] = '\0';
sprintf(buffer, "%i connections\n", cluster->numservers);
catbuffer(buffer, sizeofbuffer, "%i sources\n", cluster->numservers);
catbuffer(buffer, sizeofbuffer, "%i viewers\n", cluster->numviewers);
catbuffer(buffer, sizeofbuffer, "%i proxies\n", cluster->numproxies);
strcat(buffer, "Options:\n");
strcat(buffer, " Hostname ");
strcat(buffer, cluster->hostname);
strcat(buffer, "\n");
catbuffer(buffer, sizeofbuffer, "Options:\n");
catbuffer(buffer, sizeofbuffer, " Hostname %s\n", cluster->hostname);
if (cluster->chokeonnotupdated)
strcat(buffer, " Choke\n");
catbuffer(buffer, sizeofbuffer, " Choke\n");
if (cluster->lateforward)
strcat(buffer, " Late forwarding\n");
catbuffer(buffer, sizeofbuffer, " Late forwarding\n");
if (!cluster->notalking)
strcat(buffer, " Talking allowed\n");
catbuffer(buffer, sizeofbuffer, " Talking allowed\n");
if (cluster->nobsp)
strcat(buffer, " No BSP loading\n");
strcat(buffer, "\n");
catbuffer(buffer, sizeofbuffer, " No BSP loading\n");
catbuffer(buffer, sizeofbuffer, "\n");
if (qtv)
{
strcat(buffer, "Selected server: ");
strcat(buffer, qtv->server);
strcat(buffer, "\n");
catbuffer(buffer, sizeofbuffer, "Selected server: %s\n", qtv->server);
if (qtv->file)
strcat(buffer, "Playing from file\n");
catbuffer(buffer, sizeofbuffer, "Playing from file\n");
if (qtv->sourcesock != INVALID_SOCKET)
strcat(buffer, "Connected\n");
catbuffer(buffer, sizeofbuffer, "Connected\n");
if (qtv->parsingqtvheader || qtv->parsingconnectiondata)
strcat(buffer, "Waiting for gamestate\n");
catbuffer(buffer, sizeofbuffer, "Waiting for gamestate\n");
if (qtv->controller)
{
strcat(buffer, "Spectating through ");
strcat(buffer, qtv->controller->name);
strcat(buffer, "\n");
catbuffer(buffer, sizeofbuffer, "Spectating through %s\n");
}
if (*qtv->modellist[1].name)
{
strcat(buffer, "Map name ");
strcat(buffer, qtv->modellist[1].name);
strcat(buffer, "\n");
catbuffer(buffer, sizeofbuffer, "Map name %s\n", qtv->modellist[1].name);
}
if (qtv->connectpassword)
strcat(buffer, "Using a password\n");
if (*qtv->connectpassword)
catbuffer(buffer, sizeofbuffer, "Using a password\n");
if (qtv->tcpsocket != INVALID_SOCKET)
{
strcat(buffer, "Listening for proxies (");
sprintf(arg[0], "%i", qtv->tcplistenportnum);
strcat(buffer, arg[0]);
strcat(buffer, ")\n");
catbuffer(buffer, sizeofbuffer, "Listening for proxies (%i)\n", qtv->tcplistenportnum);
}
if (qtv->bsp)
{
strcat(buffer, "BSP (");
strcat(buffer, qtv->mapname);
strcat(buffer, ") is loaded\n");
catbuffer(buffer, sizeofbuffer, "BSP (%s) is loaded\n", qtv->mapname);
}
}
@ -576,6 +579,17 @@ char *Cmd_Quit(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer,
char *Cmd_Streams(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
catbuffer(buffer, sizeofbuffer, "Streams:\n");
for (qtv = cluster->servers; qtv; qtv = qtv->next)
{
catbuffer(buffer, sizeofbuffer, "%i: %s\n", qtv->streamid, qtv->server);
}
return buffer;
}
@ -679,6 +693,7 @@ const rconcommands_t rconcommands[] =
{"addserver", 0, 1, Cmd_QTVConnect},
{"connect", 0, 1, Cmd_QTVConnect},
{"qw", 0, 1, Cmd_QWConnect},
{"observe", 0, 1, Cmd_QWConnect},
{"demo", 0, 1, Cmd_MVDConnect},
{"playdemo", 0, 1, Cmd_MVDConnect},
{"choke", 0, 1, Cmd_Choke},
@ -691,6 +706,7 @@ const rconcommands_t rconcommands[] =
{"reconnect", 0, 1, Cmd_Reconnect},
{"echo", 0, 1, Cmd_Echo},
{"quit", 0, 1, Cmd_Quit},
{"streams", 0, 1, Cmd_Streams},
@ -704,401 +720,6 @@ const rconcommands_t rconcommands[] =
{NULL}
};
/*
static char *Cluster_Rcon_Dispatch(cluster_t *cluster, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
if (!strcmp(arg[0], "hostname"))
{
strncpy(cluster->hostname, arg[1], sizeof(cluster->hostname)-1);
return "hostname will change at start of next map\n"; //I'm too lazy to alter the serverinfo here.
}
else if (!strcmp(arg[0], "master"))
{
netadr_t addr;
strncpy(cluster->master, arg[1], sizeof(cluster->master)-1);
cluster->mastersendtime = cluster->curtime;
if (NET_StringToAddr(arg[1], &addr, 27000)) //send a ping like a qw server does. this is kinda pointless of course.
NET_SendPacket (cluster, cluster->qwdsocket, 1, "k", addr);
return "Master server set.\n";
}
else if (!strcmp(arg[0], "port"))
{
int news;
int newp = atoi(arg[1]);
news = QW_InitUDPSocket(newp);
if (news != INVALID_SOCKET)
{
cluster->mastersendtime = cluster->curtime;
closesocket(cluster->qwdsocket);
cluster->qwdsocket = news;
cluster->qwlistenportnum = newp;
return "Opened udp port (all connected qw clients will time out)\n";
}
else
return "Failed to open udp port\n";
}
else if (!strcmp(arg[0], "password"))
{
if (!localcommand)
return "Rejecting rcon password change.\n";
strncpy(cluster->password, arg[1], sizeof(cluster->password)-1);
return "Password changed.\n";
}
else if (!strcmp(arg[0], "qtv") || !strcmp(arg[0], "connect") || !strcmp(arg[0], "addserver"))
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "tcp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
}
else if (!strcmp(arg[0], "qw"))
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "udp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
}
else if (!strcmp(arg[0], "demo") || !strcmp(arg[0], "adddemo") || !strcmp(arg[0], "addfile"))
{
if (!*arg[1])
return "adddemo requires an filename parameter\n";
if (!localcommand)
if (*arg[1] == '\\' || *arg[1] == '/' || strstr(arg[1], "..") || arg[1][1] == ':')
return "Absolute paths are prohibited.\n";
memmove(arg[1]+5, arg[1], ARG_LEN-6);
strncpy(arg[1], "file:", 5);
if (!QTV_NewServerConnection(cluster, arg[1], false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
}
else if (!strcmp(arg[0], "exec"))
{
FILE *f;
char line[512], *res;
if (!localcommand)
if (*arg[1] == '\\' || *arg[1] == '/' || strstr(arg[1], "..") || arg[1][1] == ':')
return "Absolute paths are prohibited.\n";
f = fopen(arg[1], "rt");
if (!f)
{
snprintf(buffer, sizeofbuffer, "Couldn't exec \"%s\"\n", arg[1]);
return buffer;
}
else
{
while(fgets(line, sizeof(line)-1, f))
{
res = Rcon_Command(cluster, NULL, line, buffer, sizeofbuffer, localcommand);
Sys_Printf(cluster, "%s", res);
}
fclose(f);
return "Execed\n";
}
}
else if (!strcmp(arg[0], "status"))
{
buffer[0] = '\0';
sprintf(buffer, "%i connections\n", cluster->numservers);
strcat(buffer, "Options:\n");
if (cluster->chokeonnotupdated)
strcat(buffer, " Choke\n");
if (cluster->lateforward)
strcat(buffer, " Late forwarding\n");
if (!cluster->notalking)
strcat(buffer, " Talking allowed\n");
if (cluster->nobsp)
strcat(buffer, " No BSP loading\n");
strcat(buffer, "\n");
return buffer;
}
else if (!strcmp(arg[0], "choke"))
{
cluster->chokeonnotupdated = !!atoi(arg[1]);
return "choke-until-update set\n";
}
else if (!strcmp(arg[0], "late"))
{
cluster->lateforward = !!atoi(arg[1]);
return "late forwarding set\n";
}
else if (!strcmp(arg[0], "talking"))
{
cluster->notalking = !atoi(arg[1]);
return "talking permissions set\n";
}
else if (!strcmp(arg[0], "nobsp"))
{
cluster->nobsp = !!atoi(arg[1]);
return "nobsp will change at start of next map\n";
}
else if (!strcmp(arg[1], "maxviewers"))
{
cluster->maxviewers = atoi(arg[2]);
return "maxviewers set\n";
}
else if (!strcmp(arg[1], "maxproxies"))
{
cluster->maxproxies = atoi(arg[2]);
return "maxproxies set\n";
}
else if (!strcmp(arg[0], "ping"))
{
netadr_t addr;
if (NET_StringToAddr(arg[1], &addr, 27500))
{
NET_SendPacket (cluster, cluster->qwdsocket, 1, "k", addr);
return "pinged\n";
}
return "couldn't resolve\n";
}
else if (!strcmp(arg[0], "help"))
{
return HELPSTRING;
}
else if (!strcmp(arg[0], "mvdport"))
{
return "mvdport requires a targeted server. Connect first.\n";
}
else if (!strcmp(arg[0], "record"))
{
return "record requires a targeted server\n";
}
else if (!strcmp(arg[0], "reconnect"))
{
return "reconnect requires a targeted server\n";
}
else if (!strcmp(arg[0], "stop"))
{ //fixme
return "stop requires a targeted server\n";
}
else if (!strcmp(arg[0], "echo"))
{
return "Poly wants a cracker.\n";
}
else if (!strcmp(arg[0], "quit"))
{
cluster->wanttoexit = true;
return "Shutting down.\n";
}
else
return NULL;
}
static char *Server_Rcon_Dispatch(sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
#define TOKENIZE_PUNCTUATION ""
buffer[0] = '\0';
if (!strcmp(arg[0], "status"))
{
sprintf(buffer, "%i connections\n", qtv->cluster->numservers);
strcat(buffer, "\n");
strcat(buffer, "Selected server: ");
strcat(buffer, qtv->server);
strcat(buffer, "\n");
if (qtv->file)
strcat(buffer, "Playing from file\n");
if (qtv->sourcesock != INVALID_SOCKET)
strcat(buffer, "Connected\n");
if (qtv->parsingconnectiondata)
strcat(buffer, "Waiting for gamestate\n");
if (qtv->listenmvd != INVALID_SOCKET)
{
strcat(buffer, "Listening for proxies (");
sprintf(arg[0], "%i", qtv->tcplistenportnum);
strcat(buffer, arg[0]);
strcat(buffer, ")\n");
}
if (qtv->bsp)
{
strcat(buffer, "BSP (");
strcat(buffer, qtv->mapname);
strcat(buffer, ") is loaded\n");
}
strcat(buffer, "Options:\n");
if (qtv->cluster->chokeonnotupdated)
strcat(buffer, " Choke\n");
if (qtv->cluster->lateforward)
strcat(buffer, " Late forwarding\n");
if (!qtv->cluster->notalking)
strcat(buffer, " Talking allowed\n");
if (qtv->cluster->nobsp)
strcat(buffer, " No BSP loading\n");
strcat(buffer, "\n");
return buffer;
}
else if (!strcmp(arg[0], "connect"))
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
if (QTV_Connect(qtv, arg[1]))
return "Connected, waiting for data\n";
else
return "Failed (will keep trying)\n";
}
else if (!strcmp(arg[0], "disconnect"))
{
QTV_Shutdown(qtv);
return "Disconnected\n";
}
else if (!strcmp(arg[0], "file") || !strcmp(arg[0], "play") || !strcmp(arg[0], "playdemo"))
{
if (!*arg[1])
return "file requires a filename on the proxy's machine\n";
if (!localcommand)
if (*arg[1] == '\\' || *arg[1] == '/' || strstr(arg[1], "..") || arg[1][1] == ':')
return "Absolute paths are prohibited.\n";
memmove(arg[1]+5, arg[1], ARG_LEN-6);
strncpy(arg[1], "file:", 5);
if (QTV_Connect(qtv, arg[1]))
return "File opened successfully\n";
else
return "Failed (will keep trying)\n";
}
else if (!strcmp(arg[0], "record"))
{
if (!*arg[1])
return "record requires a filename on the proxy's machine\n";
if (!localcommand)
if (*arg[1] == '\\' || *arg[1] == '/' || strstr(arg[1], "..") || arg[1][1] == ':')
return "Absolute paths are prohibited.\n";
if (Net_FileProxy(qtv, arg[1]))
return "Recording to disk\n";
else
return "Failed to open file\n";
}
else if (!strcmp(arg[0], "stop"))
{
if (Net_StopFileProxy(qtv))
return "stopped\n";
else
return "not recording to disk\n";
}
else if (!strcmp(arg[0], "reconnect"))
{
if (QTV_Connect(qtv, qtv->server))
return "Reconnected\n";
else
return "Failed to reconnect (will keep trying)\n";
}
else if (!strcmp(arg[0], "mvdport"))
{
int news;
int newp = atoi(arg[1]);
if (!newp)
{
if (qtv->listenmvd != INVALID_SOCKET)
{
closesocket(qtv->listenmvd);
qtv->listenmvd = INVALID_SOCKET;
qtv->tcplistenportnum = 0;
return "mvd port is now closed\n";
}
return "Already closed\n";
}
else
{
news = Net_MVDListen(newp);
if (news != INVALID_SOCKET)
{
if (qtv->listenmvd != INVALID_SOCKET)
closesocket(qtv->listenmvd);
qtv->listenmvd = news;
qtv->disconnectwhennooneiswatching = false;
qtv->tcplistenportnum = newp;
return "Opened tcp port\n";
}
else
return "Failed to open tcp port\n";
}
}
else if (!strcmp(arg[0], "exec"))
{
FILE *f;
char line[512], *res;
if (!localcommand)
if (*arg[1] == '\\' || *arg[1] == '/' || strstr(arg[1], "..") || arg[1][1] == ':')
return "Absolute paths are prohibited.\n";
f = fopen(arg[1], "rt");
if (!f)
{
snprintf(buffer, sizeofbuffer, "Couldn't exec \"%s\"\n", arg[1]);
return buffer;
}
else
{
while(fgets(line, sizeof(line)-1, f))
{
res = Rcon_Command(qtv->cluster, qtv, line, buffer, sizeofbuffer, localcommand);
Sys_Printf(qtv->cluster, "%s", res);
}
fclose(f);
return "Execed\n";
}
}
else
{
return NULL;
}
}
*/
char *Rcon_Command(cluster_t *cluster, sv_t *qtv, char *command, char *buffer, int sizeofbuffer, qboolean localcommand)
{
#define TOKENIZE_PUNCTUATION ""
@ -1106,6 +727,26 @@ char *Rcon_Command(cluster_t *cluster, sv_t *qtv, char *command, char *buffer, i
int i;
char arg[MAX_ARGS][ARG_LEN];
char *argptrs[MAX_ARGS];
char *sid;
for (sid = command; *sid; sid = sid++)
{
if (*sid == ':')
break;
if (*sid < '0' || *sid > '9')
break;
}
if (*sid == ':')
{
i = atoi(command);
command = sid+1;
for (qtv = cluster->servers; qtv; qtv = qtv->next)
if (qtv->streamid == i)
break;
}
for (i = 0; i < MAX_ARGS; i++)
{

View file

@ -821,7 +821,8 @@ void QTV_Shutdown(sv_t *qtv)
if (v->server == qtv)
{
QW_SetViewersServer(v, NULL);
v->menunum = 1;
QW_SetMenu(v, MENU_SERVERS);
QW_PrintfToViewer(v, "Stream %s is closing\n", qtv->server);
}
}
@ -834,6 +835,7 @@ void QTV_Shutdown(sv_t *qtv)
old = prox;
prox = prox->next;
free(old);
cluster->numproxies--;
}
@ -1060,8 +1062,13 @@ void QTV_ParseQWStream(sv_t *qtv)
}
}
#ifdef COMMENTARY
#include <speex/speex.h>
#endif
void QTV_CollectCommentry(sv_t *qtv)
{
#ifdef COMMENTARY
int samps;
unsigned char buffer[8192+6];
unsigned char *uchar;
@ -1070,12 +1077,18 @@ void QTV_CollectCommentry(sv_t *qtv)
if (!qtv->comentrycapture)
{
if (0)
qtv->comentrycapture = SND_InitCapture(11025, 8);
{
if (usespeex)
qtv->comentrycapture = SND_InitCapture(11025, 16);
else
qtv->comentrycapture = SND_InitCapture(11025, 8);
}
return;
}
while(1)
{
//the protocol WILL be different. Don't add compatability for this code.
buffer[0] = 0;
buffer[1] = dem_audio;
buffer[2] = 255;
@ -1083,14 +1096,50 @@ void QTV_CollectCommentry(sv_t *qtv)
buffer[4] = 8;
buffer[5] = 11*5;
samps=qtv->comentrycapture->update(qtv->comentrycapture, 2048, buffer+6);
bytesleft = samps;
schar = buffer+6;
uchar = buffer+6;
while(bytesleft-->0)
if (usespeex)
{
*schar++ = *uchar++ - 128;
SpeexBits bits;
void *enc_state;
int frame_size;
spx_int16_t pcmdata[8192/2];
samps=qtv->comentrycapture->update(qtv->comentrycapture, 2048, (char*)pcmdata);
speex_bits_init(&bits);
enc_state = speex_encoder_init(&speex_nb_mode);
speex_encoder_ctl(enc_state,SPEEX_GET_FRAME_SIZE,&frame_size);
speex_bits_reset(&bits);
speex_encode_int(enc_state, (spx_int16_t*)pcmdata, &bits);
samps = speex_bits_write(&bits, buffer+6, sizeof(buffer)-6);
speex_bits_destroy(&bits);
speex_encoder_destroy(enc_state);
}
else
{
samps=qtv->comentrycapture->update(qtv->comentrycapture, 2048, buffer+6);
bytesleft = samps;
schar = buffer+6;
uchar = buffer+6;
while(bytesleft-->0)
{
*schar++ = *uchar++ - 128;
}
}
buffer[2] = samps&255;
@ -1102,6 +1151,7 @@ void QTV_CollectCommentry(sv_t *qtv)
if (samps < 64)
break;
}
#endif
}
void QTV_Run(sv_t *qtv)
@ -1114,11 +1164,13 @@ void QTV_Run(sv_t *qtv)
if (qtv->drop || (qtv->disconnectwhennooneiswatching && qtv->numviewers == 0 && qtv->proxies == NULL))
{
if (!qtv->drop)
Sys_Printf(qtv->cluster, "Stream %s became inactive\n", qtv->server);
QTV_Shutdown(qtv);
return;
}
//we will read out as many packets as we can until we're up to date
//note: this can cause real issues when we're overloaded for any length of time
//each new packet comes with a leading msec byte (msecs from last packet)
@ -1568,6 +1620,9 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
return qtv;
}
}
if (autoclose)
if (cluster->nouserconnects)
return NULL;
qtv = malloc(sizeof(sv_t));
if (!qtv)