diff -wrubN quake3_1.32b/code/client/cl_console.c dfengine_1.05_src/code/client/cl_console.c
--- quake3_1.32b/code/client/cl_console.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_console.c	2009-03-05 11:16:07.000000000 +0100
@@ -23,13 +23,14 @@
 
 #include "client.h"
 
+#include <pcre.h>	// Cgg
 
 int g_console_field_width = 78;
 
 
 #define	NUM_CON_TIMES 4
 
-#define		CON_TEXTSIZE	32768
+#define		CON_TEXTSIZE	0x10000	// Cgg - doubled
 typedef struct {
 	qboolean	initialized;
 
@@ -45,7 +46,7 @@
 
 	float	displayFrac;	// aproaches finalFrac at scr_conspeed
 	float	finalFrac;		// 0.0 to 1.0 lines of console to display
-
+	float	userFrac;		// 0.0 to 1.0 - for user Configurations. Don't want to mess with finalFrac - marky
 	int		vislines;		// in scanlines
 
 	int		times[NUM_CON_TIMES];	// cls.realtime time the line was generated
@@ -60,6 +61,12 @@
 cvar_t		*con_conspeed;
 cvar_t		*con_notifytime;
 
+// Cgg - filter
+#define MAX_CON_FILTERS 20
+cvar_t *con_filters[MAX_CON_FILTERS];
+pcre *con_filters_compiled[MAX_CON_FILTERS];
+// !Cgg
+
 #define	DEFAULT_CONSOLE_WIDTH	78
 
 vec4_t	console_color = {1.0, 1.0, 1.0, 1.0};
@@ -67,6 +74,15 @@
 
 /*
 ================
+Con_ShowPCREVersion_f (Cgg - pcre support)
+================
+*/
+static void Con_ShowPCREVersion_f(void) {
+	Com_Printf("%s\n", pcre_version());
+}
+
+/*
+================
 Con_ToggleConsole_f
 ================
 */
@@ -93,7 +109,10 @@
 	chat_playerNum = -1;
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7;	// -7: "say: " + padding
+	//chatField.widthInChars = 30;
+	// !Cgg
 
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
@@ -107,7 +126,10 @@
 	chat_playerNum = -1;
 	chat_team = qtrue;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 25;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -12; // -12: "say_team: " + padding
+//	chatField.widthInChars = 25;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -124,7 +146,10 @@
 	}
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7;	// -7: "say: " + padding
+//	chatField.widthInChars = 30;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -141,7 +166,10 @@
 	}
 	chat_team = qfalse;
 	Field_Clear( &chatField );
-	chatField.widthInChars = 30;
+	// Cgg
+	chatField.widthInChars = cls.glconfig.vidWidth / TINYCHAR_WIDTH -7; // -7: "say: " + padding
+//	chatField.widthInChars = 30;
+	// !Cgg
 	cls.keyCatchers ^= KEYCATCH_MESSAGE;
 }
 
@@ -250,7 +278,7 @@
 	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
 	MAC_STATIC short	tbuf[CON_TEXTSIZE];
 
-	width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
+	width = (cls.glconfig.vidWidth / SMALLCHAR_WIDTH) - 2;	// Cgg - was SCREEN_WIDTH
 
 	if (width == con.linewidth)
 		return;
@@ -315,6 +343,12 @@
 	con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
 	con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
 
+	// Cgg
+	for (i=0; i<MAX_CON_FILTERS; i++) {
+		con_filters[i] = Cvar_Get(va("con_filter%i", i), "", CVAR_ARCHIVE);
+	}
+	// !Cgg
+
 	Field_Clear( &g_consoleField );
 	g_consoleField.widthInChars = g_console_field_width;
 	for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
@@ -329,6 +363,7 @@
 	Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
 	Cmd_AddCommand ("clear", Con_Clear_f);
 	Cmd_AddCommand ("condump", Con_Dump_f);
+	Cmd_AddCommand ("pcre_version", Con_ShowPCREVersion_f );	// Cgg
 }
 
 
@@ -340,6 +375,32 @@
 void Con_Linefeed (qboolean skipnotify)
 {
 	int		i;
+	char txt[MAXPRINTMSG];
+	pcre **re;
+	int ovector[30];
+	char ch;
+	qboolean copy;
+
+	// Cgg
+	if (con.linewidth < sizeof(txt)) {
+		for (i=con.linewidth-1,copy=qfalse; i>=0; i--) {
+			ch = con.text[(con.current%con.totallines)*con.linewidth+i] &0xff;
+			if (ch != ' ') {
+				copy = qtrue;
+			}
+			txt[i] = (copy) ? ch : 0;
+		}
+		for (re=con_filters_compiled; re-con_filters_compiled<MAX_CON_FILTERS; re++) {
+			if (*re && pcre_exec(*re, NULL, txt, strlen(txt), 0, 0, ovector, 30) > 0) {
+				con.x = 0;
+				for(i=0; i<con.linewidth; i++) {
+					con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
+				}
+				return;
+			}
+		}
+	}
+	// !Cgg
 
 	// mark time for transparent overlay
 	if (con.current >= 0)
@@ -367,12 +428,14 @@
 If no console is visible, the text will appear at the top of the game window
 ================
 */
+#define Q_RAW_ESCAPE 1	// Cgg: see below
 void CL_ConsolePrint( char *txt ) {
 	int		y;
 	int		c, l;
 	int		color;
 	qboolean skipnotify = qfalse;		// NERVE - SMF
 	int prev;							// NERVE - SMF
+	char raw;	// Cgg: Q_RAW_ESCAPE char stops color sequences from being interpreted.
 
 	// TTimo - prefix for text that shows up in console but not in notify
 	// backported from RTCW
@@ -398,12 +461,20 @@
 
 	color = ColorIndex(COLOR_WHITE);
 
+	raw = 0;
 	while ( (c = *txt) != 0 ) {
+		if (!raw) {
 		if ( Q_IsColorString( txt ) ) {
 			color = ColorIndex( *(txt+1) );
 			txt += 2;
 			continue;
 		}
+			// Cgg - repeated escape codes (^^) were broken
+			if (*txt == Q_COLOR_ESCAPE && *(txt+1) == Q_COLOR_ESCAPE) {
+				txt++;
+			}
+			// !Cgg
+		}
 
 		// count word length
 		for (l=0 ; l< con.linewidth ; l++) {
@@ -423,7 +494,11 @@
 
 		switch (c)
 		{
+		case Q_RAW_ESCAPE:
+			raw = raw^1;
+			break;
 		case '\n':
+			raw = 0;
 			Con_Linefeed (skipnotify);
 			break;
 		case '\r':
@@ -532,8 +607,8 @@
 			if ( ( text[x] & 0xff ) == ' ' ) {
 				continue;
 			}
-			if ( ( (text[x]>>8)&7 ) != currentColor ) {
-				currentColor = (text[x]>>8)&7;
+			if ( ( ((text[x]>>8)&15)%10 ) != currentColor ) {
+				currentColor = ((text[x]>>8)&15)%10;
 				re.SetColor( g_color_table[currentColor] );
 			}
 			SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
@@ -553,17 +628,28 @@
 	{
 		if (chat_team)
 		{
-			SCR_DrawBigString (8, v, "say_team:", 1.0f );
+			// Cgg
+			SCR_DrawSmallStringExt(8, v, "say_team:", colorWhite, qfalse, qfalse);
+			//SCR_DrawBigString (8, v, "say_team:", 1.0f );
+			// !Cgg
 			skip = 11;
 		}
 		else
 		{
-			SCR_DrawBigString (8, v, "say:", 1.0f );
-			skip = 5;
+			// Cgg
+			SCR_DrawSmallStringExt(8, v, "say:", colorWhite, qfalse, qfalse);
+			skip = 6;
+			//skip = 5;
+			//SCR_DrawBigString (8, v, "say:", 1.0f );
+			// !Cgg
 		}
 
-		Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
-			SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );
+		// Cgg
+		Field_Draw(&chatField,  skip * TINYCHAR_WIDTH, v,
+			SCREEN_WIDTH - ( skip + 1 ) * TINYCHAR_WIDTH, qtrue );
+		//Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
+		//	SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );
+		// !Cgg
 
 		v += BIGCHAR_HEIGHT;
 	}
@@ -599,24 +685,26 @@
 	SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
 
 	// draw the background
-	y = frac * SCREEN_HEIGHT - 2;
+	y = frac * SCREEN_HEIGHT - 1;	// Cgg - was 2
 	if ( y < 1 ) {
 		y = 0;
 	}
 	else {
-		SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
+		// Cgg
+		color[0] = .05f;
+		color[1] = .05f;
+		color[2] = .1f;
+		color[3] = .95f;
+		SCR_FillRect( 0, 0, SCREEN_WIDTH, y, color );
+//		SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
+		// !Cgg
 	}
 
-	color[0] = 1;
-	color[1] = 0;
-	color[2] = 0;
-	color[3] = 1;
-	SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
-
+	SCR_FillRect( 0, y, SCREEN_WIDTH, 1, colorOrange );	// Cgg - orange & 1px instead of 2
 
 	// draw the version number
 
-	re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+	re.SetColor( g_color_table[ColorIndex(COLOR_ORANGE)] );	// Cgg - orange
 
 	i = strlen( Q3_VERSION );
 
@@ -639,7 +727,7 @@
 	if (con.display != con.current)
 	{
 	// draw arrows to show the buffer is backscrolled
-		re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+		re.SetColor( g_color_table[ColorIndex(COLOR_ORANGE)] );	// Cgg - orange
 		for (x=0 ; x<con.linewidth ; x+=4)
 			SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
 		y -= SMALLCHAR_HEIGHT;
@@ -671,8 +759,8 @@
 				continue;
 			}
 
-			if ( ( (text[x]>>8)&7 ) != currentColor ) {
-				currentColor = (text[x]>>8)&7;
+			if ( ( ((text[x]>>8)&15)%10 ) != currentColor ) {
+				currentColor = ((text[x]>>8)&15)%10;
 				re.SetColor( g_color_table[currentColor] );
 			}
 			SCR_DrawSmallChar(  con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
@@ -724,9 +812,34 @@
 ==================
 */
 void Con_RunConsole (void) {
+	// Cgg - check for updated con_filters
+	cvar_t **cvar;
+	pcre **re;
+	const char *errptr;
+	int erroffset;
+	for (cvar=con_filters; cvar-con_filters<MAX_CON_FILTERS; cvar++) {
+		if (!*cvar || !(*cvar)->modified) {
+			continue;
+		}
+		re = con_filters_compiled+(cvar-con_filters);
+		(*cvar)->modified = qfalse;
+		if (!strlen((*cvar)->string)) {
+			*re = NULL;
+			continue;
+		}
+		*re = pcre_compile((*cvar)->string, 0, &errptr, &erroffset, NULL);
+		if (!*re) {
+			Com_Printf("Failed to compile %c%s\n", Q_RAW_ESCAPE, (*cvar)->string);
+			Com_Printf(va("%c%%%ic %%s\n", Q_RAW_ESCAPE, erroffset+19), '^', errptr);
+			Cvar_Set((*cvar)->name, "");
+			(*cvar)->modified = qfalse;
+		}
+	}
+	// !Cgg
+
 	// decide on the destination height of the console
 	if ( cls.keyCatchers & KEYCATCH_CONSOLE )
-		con.finalFrac = 0.5;		// half screen
+		con.finalFrac = con.userFrac;	// marky
 	else
 		con.finalFrac = 0;				// none visible
 	
@@ -747,6 +860,25 @@
 
 }
 
+// marky
+/*
+==================
+Con_SetFrac
+==================
+*/
+void Con_SetFrac(const float conFrac)
+{
+	// clamp the cvar value
+	if (conFrac < .1f) {	// don't let the console be hidden
+		con.userFrac = .1f;
+	} else if (conFrac > 1.0f) {
+		con.userFrac = 1.0f;
+	} else {
+		con.userFrac = conFrac;
+	}
+}
+// !marky
+
 
 void Con_PageUp( void ) {
 	con.display -= 2;
diff -wrubN quake3_1.32b/code/client/cl_download.c dfengine_1.05_src/code/client/cl_download.c
--- quake3_1.32b/code/client/cl_download.c	1970-01-01 01:00:00.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_download.c	2009-03-05 20:41:58.000000000 +0100
@@ -0,0 +1,409 @@
+/*
+===========================================================================
+Copyright (C) 2009 - Cyril Gantin
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+
+Integration of libcurl for requesting maps from an online repository.
+
+Usage: /download <mapname>
+
+Cvar dl_source defines the url from which to query maps, eg: http://someserver/somescript.php?q=%m
+The %m token is replaced with the actual map name in the query.
+
+The server MUST return an appropriate content-type. Accepted content-type values are either application/zip
+or application/octet-stream. Other content-type values will be treated as errors or queries that didn't
+yield results.
+
+The server MAY return a content-disposition header with the actual name of the pk3 file. In the absence
+of a content-disposition header, the client will write the pack to a default <mapname>.pk3 location. The
+filename MUST have a pk3 extension. The filename MUST NOT have directory path information - slashes (/),
+backslashes (\) and colons (:) are not accepted. Finally the filename MUST consist of us-ascii characters
+only (chars 32 to 126, included). A filename that doesn't comply to these specifications will raise an
+error and abort the transfer.
+
+The server MAY redirect the query to another url. Multiple redirections are permitted - limit depends on
+libcurl's default settings. The end query MUST return a "200 OK" http status code.
+
+It is desirable that the server returns a content-length header with the size of the pk3 file.
+
+The server MAY return a custom x-dfengine-motd header. Its value is a string that MUST NOT exceed 127
+chars. The x-dfengine-motd string will be displayed after the download is complete. This is the place
+where you take credits for setting up a server. :)
+
+Downloaded files are written to the current gamedir of the home directory - eg. C:\quake3\mymod\ in
+windows; ~/.q3a/mymod/ in linux. Name collision with an existing pk3 file will result in a failure and
+be left to the user to sort out.
+
+todo:
+	- consider the curl_multi_* interface which is non-blocking, although it's not so helpful for plain
+	console-based downloading.
+	- see if this can be integrated with the client connection code while retaining compatibility with
+	all quake3 servers.
+*/
+
+#include <curl/curl.h>
+#include "client.h"
+
+static cvar_t *dl_verbose;	// 1: show http headers; 2: http headers +curl debug info
+static cvar_t *dl_showprogress;	// show console progress
+static cvar_t *dl_showmotd;	// show server message
+static cvar_t *dl_source;	// url to query maps from; %m token will be replaced by mapname
+
+static qboolean curl_initialized;
+static char useragent[256];
+static CURL *curl;
+static fileHandle_t f;
+static char path[MAX_OSPATH];
+static char dl_error[1024];	// if set, will be used in place of libcurl's error message.
+static char motd[128];
+
+static size_t Curl_WriteCallback_f(void *ptr, size_t size, size_t nmemb, void *stream) {
+	if (!f) {
+		// make sure Content-Type is either "application/octet-stream" or "application/zip".
+		char *c;
+		if (curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &c) != CURLE_OK
+				|| !c
+				|| (stricmp(c, "application/octet-stream")
+					&& stricmp(c, "application/zip"))) {
+			Q_strncpyz(dl_error, "No pk3 returned - requested map is probably unknown.", sizeof(dl_error));
+			return 0;
+		}
+		// make sure the path doesn't have directory information.
+		for (c=path; *c; c++) {
+			if (*c == '\\' || *c == '/' || *c == ':') {
+				Com_sprintf(dl_error, sizeof(dl_error), "Destination filename \"%s\" is not valid.", path);
+				return 0;
+			}
+		}
+		// make sure the file has an appropriate extension.
+		c = path +strlen(path) -4;
+		if (c <= path || strcmp(c, ".pk3")) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Returned file \"%s\" has wrong extension.", path);
+			return 0;
+		}
+		// in case of a name collision, just fail - leave it to the user to sort out.
+		if (FS_FileExists(path)) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Failed to download \"%s\", a pk3 by that name exists locally.", path);
+			return 0;
+		}
+		// change the extension to .tmp - it will be changed back once the download is complete.
+		c = path +strlen(path) -4;
+		strcpy(c, ".tmp"); 
+
+		// FS should write the file in the appropriate gamedir and catch unsanitary paths.
+		f = FS_FOpenFileWrite(path);
+		if (!f) {
+			Com_sprintf(dl_error, sizeof(dl_error), "Failed to open \"%s\" for writing.\n", path);
+			return 0;
+		}
+		Com_Printf("Writing to: %s\n", path);
+	}
+	return FS_Write(ptr, size*nmemb, f);
+}
+
+static size_t Curl_HeaderCallback_f(void *ptr, size_t size, size_t nmemb, void *stream) {
+	char buf[1024];
+	char *c;
+
+	// make a copy and remove the trailing crlf chars.
+	if (size*nmemb >= sizeof(buf)) {
+		Com_Printf("Curl_HeaderCallback_f() overflow.\n");
+		return (size_t)-1;
+	}
+	Q_strncpyz(buf, ptr, size*nmemb+1);
+	c = buf +strlen(buf)-1;
+	while (c>buf && (*c == '\r' || *c == '\n')) {
+		*(c--) = 0;
+	}
+
+	// make sure it's not empty.
+	if (c <= buf) {
+		return size*nmemb;
+	}
+
+	// verbose output
+	if (dl_verbose->integer > 0) {
+		Com_Printf("< %s\n", buf);
+	}
+	/**
+	 * Check whether this is a content-disposition header.
+	 * Apparently RFC2183 has precise rules for the presentation of the filename attribute.
+	 * No one seems to respect those, though.
+	 * Accepted presentations:
+	 *	filename="somefile.pk3"
+	 *	filename='somefile.pk3'
+	 *	filename=somefile.pk3
+	 * Quoted strings won't support escaping (eg. "some\"file.pk3").
+	 * Malformed quoted strings that miss the trailing quotation mark will pass.
+	 * Only us-ascii chars are accepted.
+	 * The actual filename will be validated later, when the transfer is started.
+	 */
+	if (!strncasecmp(buf, "content-disposition:", 20)) {
+		const char *c = strstr(buf, "filename=") +9;
+		if (c != (char*)9) {
+			const char *e;
+			char token=0;
+			if (*c == '"' || *c == '\'') {
+				token = *c++;
+			}
+			for (e=c; *e && *e != token; e++) {
+				if (*e<32 || *e > 126) {
+					Q_strncpyz(dl_error, "Server returned an invalid filename.", sizeof(dl_error));
+					return (size_t)-1;
+				}
+			}
+			if (e > c) {
+				Q_strncpyz(path, c, e-c+1);	// +1 makes room for the trailing \0
+			}
+		}
+	}
+
+	// catch x-dfengine-motd headers
+	if (!strncasecmp(buf, "x-dfengine-motd: ", 17)) {
+		if (strlen(buf) >= 17+sizeof(motd)) {
+			if (dl_showmotd->integer) {
+				Com_Printf("Warning: server motd string too large.\n");
+			}
+		} else {
+			Q_strncpyz(motd, buf+17, sizeof(motd));
+		}
+	}
+	return size*nmemb;
+}
+
+static size_t Curl_VerboseCallback_f(CURL *curl, curl_infotype type, char *data, size_t size, void *userptr) {
+	char buf[1024];
+	char *c, *l;
+
+	if ((type != CURLINFO_HEADER_OUT || dl_verbose->integer < 1)
+			&& (type != CURLINFO_TEXT || dl_verbose->integer < 2)) {
+		return 0;
+	}
+	if (size >= sizeof(buf)) {
+		Com_Printf("Curl_VerboseCallback_f() warning: overflow.\n");
+		return 0;
+	}
+	Q_strncpyz(buf, data, size+1);	// +1 makes room for the trailing \0
+	if (type == CURLINFO_HEADER_OUT) {
+		for (l=c=buf; c-buf<size; c++) {
+			// header lines should have linefeeds.
+			if (*c == '\n' || *c == '\r') {
+				*c = 0;
+				if (c>l) {
+					Com_Printf("> %s\n", l);
+				}
+				l = c+1;
+			}
+		}
+		return 0;
+	}
+	// CURLINFO_TEXT (has its own linefeeds)
+	Com_Printf("%s", buf);	// Com_Printf(buf) would result in random output/segfault if buf has % chars.
+	return 0;
+}
+
+/**
+ * This callback is called on regular intervals, whether data is being transferred or not.
+ */
+static int Curl_ProgressCallback_f(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
+	static double stransferred = -1.0;
+
+	if (dl_showprogress->integer 
+			&& dlnow != stransferred
+			&& f) {	// don't show progress if file hasn't been initialized (might be downloading an error page).
+		double speed;
+		if (dltotal != 0.0	// content-size is known
+				&& dlnow <= dltotal) {	// and appropriate
+			if (dltotal > 1024.0 * 1024.0) {	// MB range
+				Com_Printf("%.1f/%.1fMB", dlnow/1024.0/1024.0, dltotal/1024.0/1024.0);
+			} else if (dltotal > 10240.0) {		// KB range (>10KB)
+				Com_Printf("%.1f/%.1fKB", dlnow/1024.0, dltotal/1024.0);
+			} else {							// byte range
+				Com_Printf("%.0f/%.0fB", dlnow, dltotal);
+			}
+		} else {	// unknown content-size
+			if (dlnow > 1024.0 * 1024.0) {		// MB range
+				Com_Printf("%.1fMB", dlnow/1024.0/1024.0);
+			} else if (dlnow > 10240.0) {		// KB range (>10KB)
+				Com_Printf("%.1fKB", dlnow/1024.0);
+			} else {							// byte range
+				Com_Printf("%.0fB", dlnow, dltotal);
+			}
+		}
+		if (!curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, &speed)) {
+			Com_Printf(" @%.1fKB/s", speed/1024.0);
+		}
+		if (dltotal != 0.0 && dlnow <= dltotal) {
+			Com_Printf(" (%2.1f%%)", 100.0*dlnow/dltotal);
+		}
+		Com_Printf("\n");
+		stransferred = dlnow;
+	}
+
+	// pump events and refresh screen
+	Com_EventLoop();
+	SCR_UpdateScreen();
+	if (Key_IsDown(K_ESCAPE)) {
+		Q_strncpyz(dl_error, "Download aborted.", sizeof(dl_error));
+		return -1;
+	}
+	return 0;
+}
+
+static void Curl_Download_f(void) {
+	char url[1024];
+	CURLcode res;
+	char errorbuf[CURL_ERROR_SIZE];
+	char *c;
+
+	if (Cmd_Argc() < 2) {
+		Com_Printf("usage: download <mapname>\n");
+		return;
+	}
+	if (FS_FileIsInPAK(va("maps/%s.bsp", Cmd_Argv(1)), NULL) != -1) {
+		Com_Printf("Map already exists locally.\n");
+		return;
+	}
+	if (strncasecmp(dl_source->string, "http://", 7)) {
+		if (strstr(dl_source->string, "://")) {
+			Com_Printf("Invalid dl_source.\n");
+			return;
+		}
+		Cvar_Set("dl_source", va("http://%s", dl_source->string));
+	}
+	if ((c = strstr(dl_source->string, "%m")) == 0) {
+		Com_Printf("Cvar dl_source is missing a %%m token.\n");
+		return;
+	}
+	if (strlen(dl_source->string) -2 +strlen(Cmd_Argv(1)) >= sizeof(url)) {
+		Com_Printf("Cvar dl_source too large.\n");
+		return;
+	}
+
+	Q_strncpyz(url, dl_source->string, c-dl_source->string +1);	// +1 makes room for the trailing 0
+	Com_sprintf(url, sizeof(url), "%s%s%s", url, Cmd_Argv(1), c+2);
+
+	// set a default destination filename; Content-Disposition headers will override.
+	Com_sprintf(path, sizeof(path), "%s.pk3", Cmd_Argv(1));
+
+	curl = curl_easy_init();
+	if (!curl) {
+		Com_Printf("Download failed to initialize.\n");
+		return;
+	}
+	*dl_error = 0;
+	*motd = 0;
+	curl_easy_setopt(curl, CURLOPT_URL, url);
+	curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent);
+	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);	// fail if http returns an error code
+	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuf);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Curl_WriteCallback_f);
+	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Curl_HeaderCallback_f);
+	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+	curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, Curl_VerboseCallback_f);
+	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Curl_ProgressCallback_f);
+	Com_Printf("Attempting download: %s\n", url);
+	SCR_UpdateScreen();
+	res = curl_easy_perform(curl);
+	if (res != CURLE_OK) {
+		Com_Printf("%s\n", (*dl_error) ? dl_error : errorbuf);
+	} else {
+		Com_Printf("Download complete, restarting filesystem.\n");
+	}
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	if (f) {
+		FS_FCloseFile(f);
+		f = 0;
+		if (res == CURLE_OK) {	// download succeeded
+			char dest[MAX_OSPATH];
+			Q_strncpyz(dest, path, strlen(path)-3);	// -4 +1 for the trailing \0
+			Q_strcat(dest, sizeof(dest), ".pk3");
+			if (!FS_FileExists(dest)) {
+				FS_Rename(path, dest);
+				FS_Restart(clc.checksumFeed);
+				if (dl_showmotd->integer && *motd) {
+					Com_Printf("Server motd: %s\n", motd);
+				}
+			} else {
+				// normally such errors should be caught upon starting the transfer. Anyway better do
+				// it here again - the filesystem might have changed, plus this may help contain some
+				// bugs / exploitable flaws in the code.
+				Com_Printf("Failed to copy downloaded file to its location - file already exists.\n");
+				FS_RemoveGameDirFile(path);
+			}
+		} else {
+			FS_RemoveGameDirFile(path);
+		}
+	}
+}
+
+static void Curl_ShowVersion_f(void) {
+	Com_Printf("%s\n", curl_version());
+}
+
+
+//
+// Interface
+//
+void DL_Init() {
+	if (!curl_global_init(CURL_GLOBAL_ALL)) {
+		char *c;
+		Cmd_AddCommand("curl_version", Curl_ShowVersion_f);
+		Cmd_AddCommand("download", Curl_Download_f);
+		curl_initialized = qtrue;
+
+		// set user-agent, something along the lines of "dfengine/1.## (libcurl/#.##.# linked libs...)"
+		Q_strncpyz(useragent, Q3_VERSION, sizeof(useragent));
+		for (c=useragent; *c; c++) {
+			if (*c == ' ') *c = '/';
+		}
+		Com_sprintf(useragent, sizeof(useragent), "%s (%s) ", useragent, curl_version());
+	} else {
+		Com_Printf("Failed to initialize libcurl.\n");
+	}
+	dl_verbose = Cvar_Get("dl_verbose", "0", 0);
+	dl_source = Cvar_Get("dl_source", "http://q3a.ath.cx/getpk3bymapname.php/%m", CVAR_ARCHIVE);
+	dl_showprogress = Cvar_Get("dl_showprogress", "1", CVAR_ARCHIVE);
+	dl_showmotd = Cvar_Get("dl_showmotd", "1", CVAR_ARCHIVE);
+}
+
+qboolean DL_Active() {
+	return (f);
+}
+
+// the engine might be going dedicated, remove client commands
+void DL_Shutdown() {
+	if (curl_initialized) {
+		if (curl) {
+			curl_easy_cleanup(curl);
+			curl = NULL;
+		}
+		if (f) {
+			FS_FCloseFile(f);
+			f = 0;
+		}
+		curl_global_cleanup();
+		curl_initialized = qfalse;
+		Cmd_RemoveCommand("curl_version");
+		Cmd_RemoveCommand("download");
+	}
+}
diff -wrubN quake3_1.32b/code/client/client.h dfengine_1.05_src/code/client/client.h
--- quake3_1.32b/code/client/client.h	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/client.h	2009-03-01 16:03:25.000000000 +0100
@@ -297,7 +297,7 @@
 	glconfig_t	glconfig;
 	qhandle_t	charSetShader;
 	qhandle_t	whiteShader;
-	qhandle_t	consoleShader;
+// Cgg	qhandle_t	consoleShader;
 } clientStatic_t;
 
 extern	clientStatic_t		cls;
@@ -449,6 +449,7 @@
 void Con_Bottom( void );
 void Con_Close( void );
 
+void Con_SetFrac( const float conFrac );	// marky
 
 //
 // cl_scrn.c
@@ -468,7 +469,7 @@
 
 void	SCR_DrawBigString( int x, int y, const char *s, float alpha );			// draws a string with embedded color control characters with fade
 void	SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color );	// ignores embedded color control characters
-void	SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor );
+void	SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean rawmode );
 void	SCR_DrawSmallChar( int x, int y, int ch );
 
 
@@ -517,3 +518,10 @@
 void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg);	//int length, const byte *data );
 void CL_Netchan_TransmitNextFragment( netchan_t *chan );
 qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg );
+
+//
+// cl_download.c
+//
+void DL_Init();
+void DL_Shutdown();
+qboolean DL_Active();
diff -wrubN quake3_1.32b/code/client/cl_keys.c dfengine_1.05_src/code/client/cl_keys.c
--- quake3_1.32b/code/client/cl_keys.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_keys.c	2009-03-05 11:20:03.000000000 +0100
@@ -45,6 +45,8 @@
 qboolean	anykeydown;
 qkey_t		keys[MAX_KEYS];
 
+cvar_t 		*con_height; //marky
+
 
 typedef struct {
 	char	*name;
@@ -245,7 +247,7 @@
 		float	color[4];
 
 		color[0] = color[1] = color[2] = color[3] = 1.0;
-		SCR_DrawSmallStringExt( x, y, str, color, qfalse );
+		SCR_DrawSmallStringExt( x, y, str, color, qfalse, qtrue );
 	} else {
 		// draw big string with drop shadow
 		SCR_DrawBigString( x, y, str, 1.0 );
@@ -266,7 +268,7 @@
 		cursorChar = 10;
 	}
 
-	i = drawLen - ( Q_PrintStrlen( str ) + 1 );
+	i = drawLen - ( strlen( str ) + 1 );	// Cgg - was Q_PrintStrlen()
 
 	if ( size == SMALLCHAR_WIDTH ) {
 		SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
@@ -1070,7 +1072,18 @@
 		if (!down) {
 			return;
 		}
+		//marky
+		con_height = Cvar_Get("con_height", "0.5", CVAR_ARCHIVE);	//called early, used as default (set by user)
+		Con_SetFrac(con_height->value);				
+		if(key == '`' || key == '~') {
+			if(keys[K_ALT].down)
+				Con_SetFrac(1.0f);
+			else if (keys[K_SHIFT].down)			// We use shift because CTRL doesn't want to work...
+				Con_SetFrac(.25f);
+			}
+		// !marky
     Con_ToggleConsole_f ();
+//		Key_ClearStates();	// marky
 		return;
 	}
 
@@ -1087,6 +1100,11 @@
 
 	// escape is always handled special
 	if ( key == K_ESCAPE && down ) {
+		// Cgg
+		if (DL_Active()) {
+			return;
+		}
+		// !Cgg
 		if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
 			// clear message mode
 			Message_Key( key );
@@ -1205,7 +1223,8 @@
 */
 void CL_CharEvent( int key ) {
 	// the console key should never be used as a char
-	if ( key == '`' || key == '~' ) {
+	if ( key == '`' || key == '~' 
+		|| key == 178 ) {	// Cgg - azerty french keyboard layout
 		return;
 	}
 
diff -wrubN quake3_1.32b/code/client/cl_main.c dfengine_1.05_src/code/client/cl_main.c
--- quake3_1.32b/code/client/cl_main.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_main.c	2009-02-16 00:22:06.000000000 +0100
@@ -279,11 +279,11 @@
 		Com_Printf ("You must be in a level to record.\n");
 		return;
 	}
-
+/* Cgg
   // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
 	if ( !Cvar_VariableValue( "g_synchronousClients" ) ) {
 		Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
-	}
+	}*/
 
 	if ( Cmd_Argc() == 2 ) {
 		s = Cmd_Argv(1);
@@ -1973,7 +1973,7 @@
 */
 void CL_CheckUserinfo( void ) {
 	// don't add reliable commands when not yet connected
-	if ( cls.state < CA_CHALLENGING ) {
+	if ( cls.state < CA_CONNECTED && cls.state != CA_CINEMATIC ) {	// Cgg - was < CA_CHALLENGING 
 		return;
 	}
 	// don't overflow the reliable command buffer when paused
@@ -2120,7 +2120,7 @@
 	// load character sets
 	cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
 	cls.whiteShader = re.RegisterShader( "white" );
-	cls.consoleShader = re.RegisterShader( "console" );
+// Cgg	cls.consoleShader = re.RegisterShader( "console" );
 	g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
 	g_consoleField.widthInChars = g_console_field_width;
 }
@@ -2279,7 +2279,10 @@
 	// register our variables
 	//
 	cl_noprint = Cvar_Get( "cl_noprint", "0", 0 );
-	cl_motd = Cvar_Get ("cl_motd", "1", 0);
+	cl_motd = Cvar_Get ("cl_motd", "0", 0);	// Cgg - global q3 motd
+											// Id's server replies with icmp "port unreachable".
+											// Making it disabled by default - saves a dns query, 
+											// an udp packet + the resulting icmp message.
 
 	cl_timeout = Cvar_Get ("cl_timeout", "200", 0);
 
@@ -2396,6 +2399,8 @@
 
 	SCR_Init ();
 
+	DL_Init();	// Cgg - client download
+
 	Cbuf_Execute ();
 
 	Cvar_Set( "cl_running", "1" );
@@ -2448,6 +2453,8 @@
 	Cmd_RemoveCommand ("showip");
 	Cmd_RemoveCommand ("model");
 
+	DL_Shutdown();	// Cgg
+	
 	Cvar_Set( "cl_running", "0" );
 
 	recursive = qfalse;
@@ -3320,5 +3327,3 @@
 
 	return qfalse;
 }
-
-
diff -wrubN quake3_1.32b/code/client/cl_parse.c dfengine_1.05_src/code/client/cl_parse.c
--- quake3_1.32b/code/client/cl_parse.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_parse.c	2008-11-16 15:40:16.000000000 +0100
@@ -255,6 +255,16 @@
 
 	// read areamask
 	len = MSG_ReadByte( msg );
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if(len > sizeof(newSnap.areamask))
+	{
+		Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
+		return;
+	}
+	// !Cgg
 	MSG_ReadData( msg, &newSnap.areamask, len);
 
 	// read playerinfo
@@ -475,6 +485,17 @@
 	unsigned char data[MAX_MSGLEN];
 	int block;
 
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if (!*clc.downloadTempName) {
+		Com_Printf("Server sending download, but no download was requested\n");
+		CL_AddReliableCommand( "stopdl" );
+		return;
+	}
+	// !Cgg
+
 	// read the data
 	block = MSG_ReadShort ( msg );
 
@@ -493,8 +514,17 @@
 	}
 
 	size = MSG_ReadShort ( msg );
-	if (size > 0)
+	// Cgg - ioquake3 rev 796
+	// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+	// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+	// for the advisory.
+	if (size < 0 || size > sizeof(data))
+	{
+		Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
+		return;
+	}
 		MSG_ReadData( msg, data, size );
+	// !Cgg
 
 	if (clc.downloadBlock != block) {
 		Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
@@ -504,11 +534,17 @@
 	// open the file if not opened yet
 	if (!clc.download)
 	{
+		// Cgg - ioquake3 rev 796
+		// Fix remotely exploitable parse download overflow reported by Luigi Auriemma.
+		// See http://lists.grok.org.uk/pipermail/full-disclosure/2006-June/046578.html
+		// for the advisory.
+	/*
 		if (!*clc.downloadTempName) {
 			Com_Printf("Server sending download, but no download was requested\n");
 			CL_AddReliableCommand( "stopdl" );
 			return;
-		}
+		}*/
+		// !Cgg
 
 		clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
 
diff -wrubN quake3_1.32b/code/client/cl_scrn.c dfengine_1.05_src/code/client/cl_scrn.c
--- quake3_1.32b/code/client/cl_scrn.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/client/cl_scrn.c	2009-02-02 17:36:26.000000000 +0100
@@ -30,6 +30,7 @@
 cvar_t		*cl_graphheight;
 cvar_t		*cl_graphscale;
 cvar_t		*cl_graphshift;
+cvar_t		*ch_recordMessage;	// Cgg
 
 /*
 ================
@@ -212,6 +213,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawChar( xx+2, y+2, size, *s );
 		xx += size;
 		s++;
@@ -232,6 +238,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawChar( xx, y, size, *s );
 		xx += size;
 		s++;
@@ -263,7 +274,8 @@
 Coordinates are at 640 by 480 virtual resolution
 ==================
 */
-void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor ) {
+// Cgg - added rawmode: stops color sequences from being interpreted
+void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean rawmode ) {
 	vec4_t		color;
 	const char	*s;
 	int			xx;
@@ -273,7 +285,7 @@
 	xx = x;
 	re.SetColor( setColor );
 	while ( *s ) {
-		if ( Q_IsColorString( s ) ) {
+		if ( !rawmode && Q_IsColorString( s ) ) {
 			if ( !forceColor ) {
 				Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
 				color[3] = setColor[3];
@@ -282,6 +294,11 @@
 			s += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) failed
+		if (!rawmode && *s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
+			s++;
+		}
+		// !Cgg
 		SCR_DrawSmallChar( xx, y, *s );
 		xx += SMALLCHAR_WIDTH;
 		s++;
@@ -301,10 +318,15 @@
 	while ( *s ) {
 		if ( Q_IsColorString( s ) ) {
 			s += 2;
-		} else {
-			count++;
+			continue;
+		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
 			s++;
 		}
+		// !Cgg
+		count++;
+		s++;
 	}
 
 	return count;
@@ -329,6 +351,12 @@
 	char	string[1024];
 	int		pos;
 
+	// Cgg - off by default
+	if (!ch_recordMessage->integer) {
+		return;
+	}
+	// !Cgg
+
 	if ( !clc.demorecording ) {
 		return;
 	}
@@ -421,6 +449,7 @@
 	cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
 	cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
 	cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
+	ch_recordMessage = Cvar_Get ("ch_recordMessage", "0", CVAR_ARCHIVE);	// Cgg
 
 	scr_initialized = qtrue;
 }
diff -wrubN quake3_1.32b/code/game/q_math.c dfengine_1.05_src/code/game/q_math.c
--- quake3_1.32b/code/game/q_math.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/game/q_math.c	2009-01-19 18:11:13.000000000 +0100
@@ -36,11 +36,12 @@
 vec4_t		colorMagenta= {1, 0, 1, 1};
 vec4_t		colorCyan	= {0, 1, 1, 1};
 vec4_t		colorWhite	= {1, 1, 1, 1};
+vec4_t		colorOrange	= {1, 0.5, 0, 1};
 vec4_t		colorLtGrey	= {0.75, 0.75, 0.75, 1};
 vec4_t		colorMdGrey	= {0.5, 0.5, 0.5, 1};
 vec4_t		colorDkGrey	= {0.25, 0.25, 0.25, 1};
 
-vec4_t	g_color_table[8] =
+vec4_t	g_color_table[10] =
 	{
 	{0.0, 0.0, 0.0, 1.0},
 	{1.0, 0.0, 0.0, 1.0},
@@ -50,6 +51,8 @@
 	{0.0, 1.0, 1.0, 1.0},
 	{1.0, 0.0, 1.0, 1.0},
 	{1.0, 1.0, 1.0, 1.0},
+	{1.0, 0.5, 0.0, 1.0},
+	{0.5, 0.5, 0.5, 1.0}
 	};
 
 
diff -wrubN quake3_1.32b/code/game/q_shared.c dfengine_1.05_src/code/game/q_shared.c
--- quake3_1.32b/code/game/q_shared.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/game/q_shared.c	2008-11-18 19:34:31.000000000 +0100
@@ -837,6 +837,11 @@
 			p += 2;
 			continue;
 		}
+		// Cgg - repeated escape codes (^^) were broken
+		if (*p == Q_COLOR_ESCAPE && *(p+1) == Q_COLOR_ESCAPE) {
+			p++;
+		}
+		// !Cgg
 		p++;
 		len++;
 	}
@@ -848,20 +853,25 @@
 char *Q_CleanStr( char *string ) {
 	char*	d;
 	char*	s;
-	int		c;
 
 	s = string;
 	d = string;
-	while ((c = *s) != 0 ) {
+	// Cgg - repeated escape codes (^^) were broken
+	while (*s) {
 		if ( Q_IsColorString( s ) ) {
+			s += 2;
+			continue;
+		}
+		if (*s == Q_COLOR_ESCAPE && *(s+1) == Q_COLOR_ESCAPE) {
 			s++;
 		}		
-		else if ( c >= 0x20 && c <= 0x7E ) {
-			*d++ = c;
+		if (*s >= 0x20 && *s <= 0x7E) {
+			*d++ = *s;
 		}
 		s++;
 	}
 	*d = '\0';
+	// !Cgg
 
 	return string;
 }
diff -wrubN quake3_1.32b/code/game/q_shared.h dfengine_1.05_src/code/game/q_shared.h
--- quake3_1.32b/code/game/q_shared.h	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/game/q_shared.h	2009-03-07 11:35:03.000000000 +0100
@@ -26,7 +26,8 @@
 // q_shared.h -- included first by ALL program modules.
 // A user mod should never modify this file
 
-#define	Q3_VERSION		"Q3 1.32b"
+// Cgg
+#define	Q3_VERSION		"dfengine 1.05"
 // 1.32 released 7-10-2002
 
 #define MAX_TEAMNAME 32
@@ -54,6 +55,13 @@
 #pragma warning(disable : 4702)		// unreachable code
 #pragma warning(disable : 4711)		// selected for automatic inline expansion
 #pragma warning(disable : 4220)		// varargs matches remaining parameters
+// Cgg - disable various recent msvc warnings regarding "deprecated" C library functions.
+// Complying with this would impede the code portability either way.
+// Besides quake for the most part provides its own "secure" implementation of libc functions.
+#define _CRT_SECURE_NO_WARNINGS 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+#pragma warning(disable : 4996)
+// !Cgg
 #endif
 
 /**********************************************************************
@@ -159,6 +167,9 @@
 
 #define	PATH_SEP '\\'
 
+// Cgg - portability
+#define strncasecmp strnicmp
+
 #endif
 
 //======================= MAC OS X DEFINES =====================
@@ -525,6 +536,7 @@
 extern	vec4_t		colorMagenta;
 extern	vec4_t		colorCyan;
 extern	vec4_t		colorWhite;
+extern	vec4_t		colorOrange;
 extern	vec4_t		colorLtGrey;
 extern	vec4_t		colorMdGrey;
 extern	vec4_t		colorDkGrey;
@@ -540,7 +552,9 @@
 #define COLOR_CYAN		'5'
 #define COLOR_MAGENTA	'6'
 #define COLOR_WHITE		'7'
-#define ColorIndex(c)	( ( (c) - '0' ) & 7 )
+#define COLOR_ORANGE	'8'
+#define COLOR_MDGREY	'9'
+#define ColorIndex(c)	( ( ( (c) - '0' ) &15 ) %10 )
 
 #define S_COLOR_BLACK	"^0"
 #define S_COLOR_RED		"^1"
@@ -550,8 +564,10 @@
 #define S_COLOR_CYAN	"^5"
 #define S_COLOR_MAGENTA	"^6"
 #define S_COLOR_WHITE	"^7"
+#define S_COLOR_ORANGE	"^8"
+#define S_COLOR_MDGREY	"^9"
 
-extern vec4_t	g_color_table[8];
+extern vec4_t	g_color_table[10];
 
 #define	MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
 #define	MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
diff -wrubN quake3_1.32b/code/qcommon/cmd.c dfengine_1.05_src/code/qcommon/cmd.c
--- quake3_1.32b/code/qcommon/cmd.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/qcommon/cmd.c	2008-11-16 15:41:31.000000000 +0100
@@ -24,7 +24,10 @@
 #include "../game/q_shared.h"
 #include "qcommon.h"
 
-#define	MAX_CMD_BUFFER	16384
+// Cgg - expanding command buffer from 16k to 64k
+//#define	MAX_CMD_BUFFER	16384
+#define	MAX_CMD_BUFFER	0x10000
+// !Cgg
 #define	MAX_CMD_LINE	1024
 
 typedef struct {
diff -wrubN quake3_1.32b/code/qcommon/common.c dfengine_1.05_src/code/qcommon/common.c
--- quake3_1.32b/code/qcommon/common.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/qcommon/common.c	2009-01-25 22:30:12.000000000 +0100
@@ -45,8 +45,8 @@
 #define DEF_COMHUNKMEGS "64"
 #define DEF_COMZONEMEGS "24"
 #else
-#define DEF_COMHUNKMEGS "56"
-#define DEF_COMZONEMEGS "16"
+#define DEF_COMHUNKMEGS "64"	// Cgg: was 56
+#define DEF_COMZONEMEGS "24"	// Cgg: was 16
 #endif
 
 int		com_argc;
@@ -1387,7 +1387,8 @@
 void Com_InitZoneMemory( void ) {
 	cvar_t	*cv;
 	// allocate the random block zone
-	cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS, CVAR_LATCH | CVAR_ARCHIVE );
+	Com_StartupVariable("com_zoneMegs");	// Cgg: config files and command line options haven't been taken in account yet
+	cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS, CVAR_LATCH );	// Cgg: was CVAR_ARCHIVE. Does not have meaning as this cvar can only be set through the command line
 
 	if ( cv->integer < 20 ) {
 		s_zoneTotal = 1024 * 1024 * 16;
@@ -3184,6 +3185,12 @@
 // field we are working on, passed to Field_CompleteCommand (&g_consoleCommand for instance)
 static field_t *completionField;
 
+// Cgg
+const char *Field_GetCompletionString() {
+	return completionString;
+}
+// !Cgg
+
 /*
 ===============
 FindMatches
@@ -3203,11 +3210,14 @@
 	}
 
 	// cut shortestMatch to the amount common with s
-	for ( i = 0 ; s[i] ; i++ ) {
+	// Cgg - was wrong when s had fewer chars than shortestMatch
+	i = 0;
+	do {
 		if ( tolower(shortestMatch[i]) != tolower(s[i]) ) {
 			shortestMatch[i] = 0;
 		}
-	}
+	} while (s[i++]);
+	// !Cgg
 }
 
 /*
@@ -3222,6 +3232,15 @@
 	}
 }
 
+// Cgg
+static void PrintCvarMatches(const char *s) {
+	if (Q_stricmpn(s, shortestMatch, strlen(shortestMatch))) {
+		return;
+	}
+	Com_Printf("    %-32s ^7\"%s^7\"\n", s, Cvar_VariableString(s));
+}
+// !Cgg
+
 static void keyConcatArgs( void ) {
 	int		i;
 	char	*arg;
@@ -3284,6 +3303,51 @@
 		return;
 	}
 
+	// Cgg - autocompletion on map names
+	if (!Q_stricmp(completionString, "map")
+		|| !Q_stricmp(completionString, "devmap")
+		|| !Q_stricmp(completionString, "vq3")
+		|| !Q_stricmp(completionString, "devvq3")
+		|| !Q_stricmp(completionString, "cpm")
+		|| !Q_stricmp(completionString, "devcpm")) {
+		const char *cmd;
+		cmd = Q_strlwr(Cmd_Argv(0));
+		completionString = Cmd_Argv(1);
+		if ( cmd[0] == '\\' || cmd[0] == '/' ) {
+			cmd++;
+		}
+		Maps_CommandCompletion(FindMatches);
+		Com_sprintf(completionField->buffer, sizeof(completionField->buffer), "\\%s %s", cmd, (shortestMatch[0]) ? shortestMatch : Cmd_Argv(1));
+		completionField->cursor = strlen(completionField->buffer);
+		if (matchCount < 2) {
+			return;
+		}
+		Com_Printf( "]%s\n", completionField->buffer );
+		Maps_CommandCompletion(PrintMatches);
+		return;
+	}
+	// !Cgg
+
+	// Cgg - autocompletion on demo names
+	if (!Q_stricmp(completionString, "demo")) {
+		const char *cmd;
+		cmd = Q_strlwr(Cmd_Argv(0));
+		completionString = Cmd_Argv(1);
+		if ( cmd[0] == '\\' || cmd[0] == '/' ) {
+			cmd++;
+		}
+		Demos_CommandCompletion(FindMatches);
+		Com_sprintf(completionField->buffer, sizeof(completionField->buffer), "\\%s %s", cmd, (shortestMatch[0]) ? shortestMatch : Cmd_Argv(1));
+		completionField->cursor = strlen(completionField->buffer);
+		if (matchCount < 2) {
+			return;
+		}
+		Com_Printf( "]%s\n", completionField->buffer );
+		Demos_CommandCompletion(PrintMatches);
+		return;
+	}
+	// !Cgg
+
 	Cmd_CommandCompletion( FindMatches );
 	Cvar_CommandCompletion( FindMatches );
 
@@ -3313,5 +3377,5 @@
 
 	// run through again, printing matches
 	Cmd_CommandCompletion( PrintMatches );
-	Cvar_CommandCompletion( PrintMatches );
+	Cvar_CommandCompletion( PrintCvarMatches );	// Cgg
 }
diff -wrubN quake3_1.32b/code/qcommon/files.c dfengine_1.05_src/code/qcommon/files.c
--- quake3_1.32b/code/qcommon/files.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/qcommon/files.c	2009-03-01 16:03:25.000000000 +0100
@@ -1705,6 +1705,10 @@
 	{
 		err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
 		if (err != UNZ_OK) {
+			// Cgg - it's better to fail and have the user notified than to have a half-loaded pk3,
+			// or worse a failed pack referenced that results in further failures (yes it does happen)
+			Com_Error(ERR_FATAL, "Corrupted pk3 file \'%s\'", basename);
+			// !Cgg
 			break;
 		}
 		len += strlen(filename_inzip) + 1;
@@ -1746,6 +1750,9 @@
 	{
 		err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
 		if (err != UNZ_OK) {
+			// Cgg - see above
+			Com_Error(ERR_FATAL, "Corrupted pk3 file \'%s\'", basename);
+			// !Cgg
 			break;
 		}
 		if (file_info.uncompressed_size > 0) {
@@ -2436,6 +2443,131 @@
 	}
 }
 
+// Cgg - autocompletion on map & demo names
+void Maps_CommandCompletion(void (*callback) (const char *s)) {
+	char **matches;
+	char m[MAX_QPATH];
+	char *c;
+	int i, n;
+
+	matches = FS_ListFilteredFiles("maps", ".bsp", NULL, &n);
+	FS_SortFileList(matches, n);
+	for (i=0; i<n; i++) {
+		Q_strncpyz(m, matches[i], sizeof(m));
+		for (c=m+strlen(m)-1; c>m; c--) {
+			if (*c != '.') {
+				continue;
+			}
+			*c = 0;
+			break;
+		}
+		callback(m);
+	}
+	FS_FreeFileList(matches);
+}
+const char *Field_GetCompletionString();	// prototype from common.c
+void Demos_CommandCompletion(void (*callback) (const char *s)) {
+	char searchpath[MAX_QPATH];
+	char path[MAX_QPATH];
+	char m[MAX_QPATH];
+	char **matches;
+	char **list;
+	const char *completionString, *c;
+	int i, n, nlist;
+
+	// set up searchpath
+	Q_strncpyz(path, "", sizeof(path));
+	Q_strncpyz(searchpath, "demos", sizeof(searchpath));
+	completionString = Field_GetCompletionString();
+	for (c=completionString+strlen(completionString)-1; c>completionString; c--) {
+		if (*c == '/') {
+			Q_strncpyz(path, completionString, c-completionString+1);	// destsize accounts for the trailing \0
+			Com_sprintf(searchpath, sizeof(searchpath), "demos/%s", path);
+			break;
+		}
+	}
+
+	// set up the list
+	list = Z_Malloc(MAX_FOUND_FILES * sizeof(*list));
+	nlist = 0;
+
+	// directories
+	matches = FS_ListFilteredFiles(searchpath, "/", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter out . .. and hidden files that follow the unix convention
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		// FS_ListFilteredFiles() on directories returns one empty string
+		if (matches[i][0] == 0) {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s/", path, matches[i]);
+		} else {
+			Com_sprintf(m, sizeof(m), "%s/", matches[i]);
+		}
+		nlist = FS_AddFileToList(m, list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// .dm_68
+	matches = FS_ListFilteredFiles(searchpath, ".dm_68", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter hidden files out
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s", path, matches[i]);
+			nlist = FS_AddFileToList(m, list, nlist);
+			continue;
+		}
+		nlist = FS_AddFileToList(matches[i], list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// .dm_67
+	matches = FS_ListFilteredFiles(searchpath, ".dm_67", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter hidden files out
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s", path, matches[i]);
+			nlist = FS_AddFileToList(m, list, nlist);
+			continue;
+		}
+		nlist = FS_AddFileToList(matches[i], list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// .dm_66
+	matches = FS_ListFilteredFiles(searchpath, ".dm_66", NULL, &n);
+	for (i=0; i<n; i++) {
+		// filter hidden files out
+		if (matches[i][0] == '.') {
+			continue;
+		}
+		if (strlen(path)) {
+			Com_sprintf(m, sizeof(m), "%s/%s", path, matches[i]);
+			nlist = FS_AddFileToList(m, list, nlist);
+			continue;
+		}
+		nlist = FS_AddFileToList(matches[i], list, nlist);
+	}
+	FS_FreeFileList(matches);
+
+	// sort list and callback
+	FS_SortFileList(list, nlist);
+	for (i=0; i<nlist; i++) {
+		callback(list[i]);
+	}
+	FS_FreeFileList(list);
+}
+// !Cgg
+
 //===========================================================================
 
 
@@ -2753,7 +2885,7 @@
 		homePath = fs_basepath->string;
 	}
 	fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
-	fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
+	fs_gamedirvar = Cvar_Get ("fs_game", "defrag", CVAR_INIT|CVAR_SYSTEMINFO );
 	fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT );
 
 	// add search path elements in reverse priority order
@@ -3417,3 +3549,29 @@
 	fflush(fsh[f].handleFiles.file.o);
 }
 
+// Cgg - be cautious with this
+void FS_RemoveGameDirFile(const char *filename) {
+	const char *path;
+	char gpath[MAX_QPATH];
+	char *c;
+
+	// ensure it doesn't try to climb up the file hierarchy
+	if (strstr(filename, "..") || strstr(filename, "::")) {
+		Com_Printf("Warning: attempting to remove file with invalid path.\n");
+		return;
+	}
+	// prevent id's pk3 files from being deleted
+	Com_sprintf(gpath, sizeof(gpath), "%s/%s", fs_gamedir, filename);
+	c = gpath + strlen(gpath) -4;
+	if (c > gpath && !strcmp(c, ".pk3")) {
+		*c = 0;
+		if (FS_idPak(gpath, "baseq3") || FS_idPak(gpath, "missionpack")) {
+			Com_Printf("Warning: attempting to remove Id's game packs.\n");
+			return;
+		}
+	}
+	// remove
+	path = FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename);
+	FS_Remove(path);
+}
+// !Cgg
diff -wrubN quake3_1.32b/code/qcommon/qcommon.h dfengine_1.05_src/code/qcommon/qcommon.h
--- quake3_1.32b/code/qcommon/qcommon.h	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/qcommon/qcommon.h	2009-03-01 16:03:25.000000000 +0100
@@ -632,6 +632,14 @@
 
 void FS_Rename( const char *from, const char *to );
 
+// Cgg: remove a file from current gamedir
+void FS_RemoveGameDirFile(const char *filename);
+
+// Cgg - autocompletion on map & demo names
+void Maps_CommandCompletion(void (*callback) (const char *s));
+void Demos_CommandCompletion(void (*callback) (const char *s));
+// !Cgg
+
 /*
 ==============================================================
 
diff -wrubN quake3_1.32b/code/server/sv_init.c dfengine_1.05_src/code/server/sv_init.c
--- quake3_1.32b/code/server/sv_init.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/server/sv_init.c	2008-11-16 15:39:00.000000000 +0100
@@ -520,12 +520,17 @@
 		Cvar_Set( "sv_paks", "" );
 		Cvar_Set( "sv_pakNames", "" );
 	}
+// Cgg - this fails with the large number of defrag pk3s
+// Removing this prevents packs from being auto-downloaded, but so does repacking.
+/*
 	// the server sends these to the clients so they can figure
 	// out which pk3s should be auto-downloaded
 	p = FS_ReferencedPakChecksums();
 	Cvar_Set( "sv_referencedPaks", p );
 	p = FS_ReferencedPakNames();
 	Cvar_Set( "sv_referencedPakNames", p );
+*/
+// !Cgg
 
 	// save systeminfo and serverinfo strings
 	Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) );
diff -wrubN quake3_1.32b/code/win32/win_main.c dfengine_1.05_src/code/win32/win_main.c
--- quake3_1.32b/code/win32/win_main.c	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/win32/win_main.c	2008-11-16 15:39:00.000000000 +0100
@@ -1191,6 +1191,10 @@
         return 0;
 	}
 
+	// Cgg - max number of open files at the crt level
+	_setmaxstdio(2048);
+	// !Cgg
+
 	g_wv.hInstance = hInstance;
 	Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
 
diff -wrubN quake3_1.32b/code/win32/winquake.rc dfengine_1.05_src/code/win32/winquake.rc
--- quake3_1.32b/code/win32/winquake.rc	2008-11-16 15:34:05.000000000 +0100
+++ dfengine_1.05_src/code/win32/winquake.rc	2008-11-16 15:39:00.000000000 +0100
@@ -7,7 +7,10 @@
 //
 // Generated from the TEXTINCLUDE 2 resource.
 //
-#include "winres.h"
+
+// Cgg - this doesn't compile with msvc2008 +windows platform & directx sdk's
+//#include "winres.h"
+// !Cgg
 
 /////////////////////////////////////////////////////////////////////////////
 #undef APSTUDIO_READONLY_SYMBOLS
@@ -16,10 +19,14 @@
 // English (U.S.) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+// Cgg - neither does this
+/*
 #ifdef _WIN32
 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 #pragma code_page(1252)
 #endif //_WIN32
+*/
+// !Cgg
 
 #ifdef APSTUDIO_INVOKED
 /////////////////////////////////////////////////////////////////////////////
