diff --git a/fteqtv/forward.c b/fteqtv/forward.c
index b69f8357c..302d75301 100644
--- a/fteqtv/forward.c
+++ b/fteqtv/forward.c
@@ -27,7 +27,6 @@ Password checks and stuff are implemented here. This is server side stuff.
#include "qtv.h"
-
#undef IN
#define IN(x) buffer[(x)&(MAX_PROXY_BUFFER-1)]
@@ -531,6 +530,53 @@ void HTMLprintf(char *outb, int outl, char *fmt, ...)
*outb++ = 0;
}
+static void SV_SendHTTPHeader(cluster_t *cluster, oproxy_t *dest, char *error_code, char *content_type, qboolean nocache)
+{
+ char *s;
+ char buffer[2048];
+
+ if (nocache) {
+ s = "HTTP/1.1 %s OK\n"
+ "Content-Type: %s\n"
+ "Cache-Control: no-cache, must-revalidate\n"
+ "Expires: Mon, 26 Jul 1997 05:00:00 GMT\n"
+ "Connection: close\n"
+ "\n";
+ } else {
+ s = "HTTP/1.1 %s OK\n"
+ "Content-Type: %s\n"
+ "Connection: close\n"
+ "\n";
+ }
+
+ snprintf(buffer, sizeof(buffer), s, error_code, content_type);
+
+ Net_ProxySend(cluster, dest, buffer, strlen(buffer));
+}
+
+static void SV_SendHTMLHeader(cluster_t *cluster, oproxy_t *dest, char *title)
+{
+ char *s;
+ char buffer[2048];
+
+ s = "\n"
+ "\n"
+ "
\n"
+ " \n"
+ " %s\n"
+ " \n"
+ "\n"
+ "";
+
+ snprintf(buffer, sizeof(buffer), s, title);
+
+ Net_ProxySend(cluster, dest, buffer, strlen(buffer));
+}
+
+#define HTMLPRINT(str) { sprintf(buffer, str "\n"); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); }
+
void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
{
int player;
@@ -539,29 +585,21 @@ void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
char plname[64];
sv_t *streams;
- s = "HTTP/1.1 200 OK\n"
- "Content-Type: text/html\n"
- "Connection: close\n"
- "\n";
- Net_ProxySend(cluster, dest, s, strlen(s));
+ SV_SendHTTPHeader(cluster, dest, "200", "text/html", true);
+ SV_SendHTMLHeader(cluster, dest, "QuakeTV: Now Playing");
- sprintf(buffer, ""
- "QuakeTV: Now Playing"
- ""
- "");
- Net_ProxySend(cluster, dest, buffer, strlen(buffer));
-
- snprintf(buffer, sizeof(buffer), "Now Playing on %s
", cluster->hostname);
+ snprintf(buffer, sizeof(buffer), "QuakeTV on %s: Now Playing
", cluster->hostname);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
+ HTMLPRINT("");
for (streams = cluster->servers; streams; streams = streams->next)
{
- sprintf(buffer, "", streams->streamid);
+ HTMLPRINT("- ");
+ HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->gamedir, streams->mapname);
+ Net_ProxySend(cluster, dest, buffer, strlen(buffer));
+ sprintf(buffer, " [ Watch Now ]", streams->streamid);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
- HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->gamedir, streams->mapname);
- Net_ProxySend(cluster, dest, buffer, strlen(buffer));
- s = "
";
- Net_ProxySend(cluster, dest, s, strlen(s));
+ HTMLPRINT("");
for (player = 0; player < MAX_CLIENTS; player++)
{
@@ -569,31 +607,51 @@ void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
{
Info_ValueForKey(streams->players[player].userinfo, "name", plname, sizeof(plname));
- s = " ";
- Net_ProxySend(cluster, dest, s, strlen(s));
+ if (streams->players[player].frags < -90) {
+ HTMLPRINT("- ");
+ } else {
+ HTMLPRINT("
- ");
+ }
+
HTMLprintf(buffer, sizeof(buffer), "%s", plname);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
- s = "
";
- Net_ProxySend(cluster, dest, s, strlen(s));
+ HTMLPRINT(" ");
}
}
+ HTMLPRINT("
");
}
+ HTMLPRINT("
");
if (!cluster->servers)
{
s = "No streams are currently being played
";
Net_ProxySend(cluster, dest, s, strlen(s));
}
- s = "
Available Demos
";
- Net_ProxySend(cluster, dest, s, strlen(s));
- s = "Admin
";
- Net_ProxySend(cluster, dest, s, strlen(s));
-
sprintf(buffer, "
QTV Version: %i www.fteqw.com
", cluster->buildnumber);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
- sprintf(buffer, "");
- Net_ProxySend(cluster, dest, buffer, strlen(buffer));
+ HTMLPRINT("");
+}
+
+void SV_GenerateCSSFile(cluster_t *cluster, oproxy_t *dest)
+{
+ char buffer[1024];
+
+ SV_SendHTTPHeader(cluster, dest, "200", "text/css", false);
+
+ HTMLPRINT("* { font-family: Verdana, Helvetica, sans-serif; }");
+ HTMLPRINT("body { color: #000; background-color: #fff; padding: 0 40px; }");
+ HTMLPRINT("a { color: #00f; }");
+ HTMLPRINT("a.qtvfile { font-weight: bold; }");
+ HTMLPRINT("a:visited { color: #00f; }");
+ HTMLPRINT("a:hover { background-color: black; color: yellow; }");
+ HTMLPRINT("li.spectator { color: #666; font-size: 0.9ex; }");
+ HTMLPRINT("dl.nowplaying dd { margin: 0 0 2em 0; }");
+ HTMLPRINT("dl.nowplaying dt { margin: 1em 0 0 0; font-size: 1.1em; font-weight: bold; }");
+ HTMLPRINT("dl.nowplaying li { list-style: none; margin: 0 0 0 1em; padding: 0; }");
+ HTMLPRINT("dl.nowplaying ul { margin: 0 0 0 1em; padding: 0; }");
+ HTMLPRINT("#navigation { background-color: #eef; }");
+ HTMLPRINT("#navigation li { display: inline; list-style: none; margin: 0 3em; }");
}
qboolean SV_GetHTTPHeaderField(char *s, char *field, char *buffer, int buffersize)
@@ -658,17 +716,10 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, char *streamtype, ch
if (!SV_GetHTTPHeaderField(dest->inbuffer, "Host", hostname, sizeof(hostname)))
{
- s = "HTTP/1.1 400 OK\n"
- "Content-Type: text/html\n"
- "Connection: close\n"
- "\n"
+ SV_SendHTTPHeader(cluster, dest, "400", "text/html", true);
+ SV_SendHTMLHeader(cluster, dest, "QuakeTV: Error");
- ""
- ""
- "QuakeTV: Now Playing"
- ""
- ""
- "Your client did not send a Host field, which is required in HTTP/1.1\n
"
+ s = "Your client did not send a Host field, which is required in HTTP/1.1\n
"
"Please try a different browser.\n"
""
"";
@@ -677,11 +728,7 @@ void SV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, char *streamtype, ch
return;
}
- s = "HTTP/1.1 200 OK\n"
- "Content-Type: text/x-quaketvident\n"
- "Connection: close\n"
- "\n";
- Net_ProxySend(cluster, dest, s, strlen(s));
+ SV_SendHTTPHeader(cluster, dest, "200", "text/x-quaketvident", true);
{
char *ws;
@@ -754,11 +801,10 @@ void SV_GenerateAdminHTTP(cluster_t *cluster, oproxy_t *dest, int streamid, char
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";
+ SV_SendHTTPHeader(cluster, dest, "403", "text/html", true);
+ SV_SendHTMLHeader(cluster, dest, "QuakeTV: Admin Error");
+
+ s = "The admin password is disabled. You may not log in remotely.