From 300f84b8c1a46409a318038da2185f85ac0335f3 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 7 Oct 2006 22:29:31 +0000 Subject: [PATCH] A few user interface changes. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2402 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- fteqtv/control.c | 49 +++++ fteqtv/forward.c | 238 +++++++++++++++++++++- fteqtv/parse.c | 2 + fteqtv/qtv.h | 48 ++++- fteqtv/qtvprox.dsp | 2 +- fteqtv/qw.c | 222 +++++++++++++++++--- fteqtv/rcon.c | 493 ++++++--------------------------------------- fteqtv/source.c | 75 ++++++- 8 files changed, 654 insertions(+), 475 deletions(-) diff --git a/fteqtv/control.c b/fteqtv/control.c index f6bbb0f7..2a287d24 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -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"))) { diff --git a/fteqtv/forward.c b/fteqtv/forward.c index e1ffddc7..3b3d4294 100644 --- a/fteqtv/forward.c +++ b/fteqtv/forward.c @@ -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) ""); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); + snprintf(buffer, sizeof(buffer), "

Now Playing on %s

", cluster->hostname); + Net_ProxySend(cluster, dest, buffer, strlen(buffer)); + for (streams = cluster->servers; streams; streams = streams->next) { sprintf(buffer, "%s (%s: %s)
", 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, ""); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); } @@ -542,7 +552,8 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, int streamid) "QuakeTV: Now Playing" "" "" - "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
" + "Please try a different browser.\n" "" ""; @@ -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" + "QuakeTVThe admin password is disabled. You may not log in remotely.\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" + + "" + "" + "QuakeTV: Admin\n" +"\n" + "\n" + ""; + + Net_ProxySend(cluster, dest, s, strlen(s)); + + s = + "
" + "
" + "Password " + "
" + "Command " + "" + "
" + "
"; + 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, "
", 6); + if (!s) + break; + o = s+1; + } + + s = "" + ""; + 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" + "QuakeTVNo Content-Length was provided.\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" + "QuakeTVThat HTTP method is not supported for that URL.\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)); diff --git a/fteqtv/parse.c b/fteqtv/parse.c index 83531746..2f5ffab6 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -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 diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index e238d072..a272a0ce 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -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 #include + +//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); diff --git a/fteqtv/qtvprox.dsp b/fteqtv/qtvprox.dsp index 766dab00..813bc4f2 100644 --- a/fteqtv/qtvprox.dsp +++ b/fteqtv/qtvprox.dsp @@ -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 diff --git a/fteqtv/qw.c b/fteqtv/qw.c index d6b3d5ab..5a800105 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -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; diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index 14b7220e..ac888984 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -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++) { diff --git a/fteqtv/source.c b/fteqtv/source.c index e98bf5aa..64013198 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -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 +#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)