Index: code/server/server.h =================================================================== --- code/server/server.h (revision 881) +++ code/server/server.h (working copy) @@ -226,6 +226,8 @@ extern cvar_t *sv_rconPassword; extern cvar_t *sv_privatePassword; extern cvar_t *sv_allowDownload; +extern cvar_t *sv_wwwDownload; +extern cvar_t *sv_wwwBaseURL; extern cvar_t *sv_maxclients; extern cvar_t *sv_privateClients; Index: code/server/sv_init.c =================================================================== --- code/server/sv_init.c (revision 881) +++ code/server/sv_init.c (working copy) @@ -606,6 +606,9 @@ Cvar_Get ("nextmap", "", CVAR_TEMP ); sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO); + sv_wwwDownload = Cvar_Get ("sv_wwwDownload", "0", CVAR_SERVERINFO); + sv_wwwBaseURL = Cvar_Get ("sv_wwwBaseURL", "", + CVAR_SERVERINFO | CVAR_ARCHIVE); sv_master[0] = Cvar_Get ("sv_master1", MASTER_SERVER_NAME, 0 ); sv_master[1] = Cvar_Get ("sv_master2", "", CVAR_ARCHIVE ); sv_master[2] = Cvar_Get ("sv_master3", "", CVAR_ARCHIVE ); Index: code/server/sv_main.c =================================================================== --- code/server/sv_main.c (revision 881) +++ code/server/sv_main.c (working copy) @@ -32,6 +32,8 @@ cvar_t *sv_rconPassword; // password for remote server commands cvar_t *sv_privatePassword; // password for the privateClient slots cvar_t *sv_allowDownload; +cvar_t *sv_wwwBaseURL; +cvar_t *sv_wwwDownload; cvar_t *sv_maxclients; cvar_t *sv_privateClients; // number of clients reserved for password Index: code/client/cl_curl.c =================================================================== --- code/client/cl_curl.c (revision 0) +++ code/client/cl_curl.c (revision 0) @@ -0,0 +1,356 @@ +/* +=========================================================================== +Copyright (C) 2006 Tony J. White (tjw@tjw.org) + +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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#if USE_CURL +#include "client.h" +cvar_t *cl_cURLLib; + +#if USE_CURL_DLOPEN + +#if USE_SDL_VIDEO +#include "SDL.h" +#include "SDL_loadso.h" +#define OBJTYPE void * +#define OBJLOAD(x) SDL_LoadObject(x) +#define SYMLOAD(x,y) SDL_LoadFunction(x,y) +#define OBJFREE(x) SDL_UnloadObject(x) + +#elif defined _WIN32 +#include +#define OBJTYPE HMODULE +#define OBJLOAD(x) LoadLibrary(x) +#define SYMLOAD(x,y) GetProcAddress(x,y) +#define OBJFREE(x) FreeLibrary(x) + +#elif defined __linux__ || defined __FreeBSD__ || defined MACOS_X || defined __sun +#include +#define OBJTYPE void * +#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL) +#define SYMLOAD(x,y) dlsym(x,y) +#define OBJFREE(x) dlclose(x) +#else + +#error "Your platform has no lib loading code or it is disabled" +#endif + +#if defined __linux__ || defined __FreeBSD__ || defined MACOS_X +#include +#include +#endif + +char* (*qcurl_version)(void); + +CURL* (*qcurl_easy_init)(void); +CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...); +CURLcode (*qcurl_easy_perform)(CURL *curl); +void (*qcurl_easy_cleanup)(CURL *curl); +CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...); +CURL* (*qcurl_easy_duphandle)(CURL *curl); +void (*qcurl_easy_reset)(CURL *curl); +const char *(*qcurl_easy_strerror)(CURLcode); + +CURLM* (*qcurl_multi_init)(void); +CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle, + CURL *curl_handle); +CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle, + CURL *curl_handle); +CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); +CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle, + int *running_handles); +CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle); +CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle, + int *msgs_in_queue); +const char *(*qcurl_multi_strerror)(CURLMcode); + +static OBJTYPE cURLLib = NULL; + +/* +================= +GPA +================= +*/ +static void *GPA(char *str) +{ + void *rv; + + rv = SYMLOAD(cURLLib, str); + if(!rv) + { + Com_Printf("Can't load symbol %s\n", str); + clc.cURLEnabled = qfalse; + return NULL; + } + else + { + Com_DPrintf("Loaded symbol %s (0x%08X)\n", str, rv); + return rv; + } +} +#endif /* USE_CURL_DLOPEN */ + +/* +================= +CL_cURL_Init +================= +*/ +qboolean CL_cURL_Init() +{ + cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE); + +#if USE_CURL_DLOPEN + if(cURLLib) + return qtrue; + + + Com_Printf("Loading \"%s\"...", cl_cURLLib->string); + if( (cURLLib = OBJLOAD(cl_cURLLib->string)) == 0 ) + { +#ifdef _WIN32 + return qfalse; +#else + char fn[1024]; + getcwd(fn, sizeof(fn)); + strncat(fn, "/", sizeof(fn)); + strncat(fn, cl_cURLLib->string, sizeof(fn)); + + if( (cURLLib = OBJLOAD(fn)) == 0 ) + { + return qfalse; + } +#endif /* _WIN32 */ + } + + clc.cURLEnabled = qtrue; + + qcurl_version = GPA("curl_version"); + + qcurl_easy_init = GPA("curl_easy_init"); + qcurl_easy_setopt = GPA("curl_easy_setopt"); + qcurl_easy_perform = GPA("curl_easy_perform"); + qcurl_easy_cleanup = GPA("curl_easy_cleanup"); + qcurl_easy_getinfo = GPA("curl_easy_getinfo"); + qcurl_easy_duphandle = GPA("curl_easy_duphandle"); + qcurl_easy_reset = GPA("curl_easy_reset"); + qcurl_easy_strerror = GPA("curl_easy_strerror"); + + qcurl_multi_init = GPA("curl_multi_init"); + qcurl_multi_add_handle = GPA("curl_multi_add_handle"); + qcurl_multi_remove_handle = GPA("curl_multi_remove_handle"); + qcurl_multi_fdset = GPA("curl_multi_fdset"); + qcurl_multi_perform = GPA("curl_multi_perform"); + qcurl_multi_cleanup = GPA("curl_multi_cleanup"); + qcurl_multi_info_read = GPA("curl_multi_info_read"); + qcurl_multi_strerror = GPA("curl_multi_strerror"); + + if(!clc.cURLEnabled) + { + CL_cURL_Shutdown(); + Com_Printf("FAIL One or more symbols not found\n"); + return qfalse; + } + Com_Printf("OK\n"); + + return qtrue; +#else + clc.cURLEnabled = qtrue; + return qtrue; +#endif /* USE_CURL_DLOPEN */ +} + +/* +================= +CL_cURL_Shutdown +================= +*/ +void CL_cURL_Shutdown( void ) +{ + CL_cURL_Cleanup(); +#if USE_CURL_DLOPEN + if(cURLLib) + { + OBJFREE(cURLLib); + cURLLib = NULL; + } + qcurl_easy_init = NULL; + qcurl_easy_setopt = NULL; + qcurl_easy_perform = NULL; + qcurl_easy_cleanup = NULL; + qcurl_easy_getinfo = NULL; + qcurl_easy_duphandle = NULL; + qcurl_easy_reset = NULL; + + qcurl_multi_init = NULL; + qcurl_multi_add_handle = NULL; + qcurl_multi_remove_handle = NULL; + qcurl_multi_fdset = NULL; + qcurl_multi_perform = NULL; + qcurl_multi_cleanup = NULL; + qcurl_multi_info_read = NULL; + qcurl_multi_strerror = NULL; +#endif /* USE_CURL_DLOPEN */ +} + +void CL_cURL_Cleanup(void) +{ + if(clc.downloadCURLM) { + if(clc.downloadCURL) { + qcurl_multi_remove_handle(clc.downloadCURLM, + clc.downloadCURL); + } + qcurl_multi_cleanup(clc.downloadCURLM); + clc.downloadCURLM = NULL; + clc.downloadCURL = NULL; + } + else if(clc.downloadCURL) { + qcurl_easy_cleanup(clc.downloadCURL); + clc.downloadCURL = NULL; + } +} + +static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow, + double ultotal, double ulnow ) +{ + clc.downloadSize = (int)dltotal; + Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); + clc.downloadCount = (int)dlnow; + Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); + return 0; +} + +static int CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb, + void *stream) +{ + FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] ); + return size*nmemb; +} + +void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ) +{ + Com_Printf("URL: %s\n", remoteURL); + Com_DPrintf("***** CL_cURL_BeginDownload *****\n" + "Localname: %s\n" + "RemoteURL: %s\n" + "****************************\n", localName, remoteURL); + CL_cURL_Cleanup(); + Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL)); + Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName)); + Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName), + "%s.tmp", localName); + + // Set so UI gets access to it + Cvar_Set("cl_downloadName", localName); + Cvar_Set("cl_downloadSize", "0"); + Cvar_Set("cl_downloadCount", "0"); + Cvar_SetValue("cl_downloadTime", cls.realtime); + + clc.downloadBlock = 0; // Starting new file + clc.downloadCount = 0; + + clc.downloadCURL = qcurl_easy_init(); + if(!clc.downloadCURL) { + Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() " + "failed\n"); + return; + } + clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName); + if(!clc.download) { + Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open " + "%s for writing\n", clc.downloadTempName); + return; + } + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download); + if(com_developer->integer) + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER, va("ioQ3://%s", + NET_AdrToString(clc.serverAddress))); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s", + Q3_VERSION, qcurl_version())); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION, + CL_cURL_CallbackWrite); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION, + CL_cURL_CallbackProgress); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL); + qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1); + clc.downloadCURLM = qcurl_multi_init(); + if(!clc.downloadCURLM) { + qcurl_easy_cleanup(clc.downloadCURL); + clc.downloadCURL = NULL; + Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() " + "failed\n"); + return; + } + qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL); + + if(!clc.cURLDisconnected) { + CL_AddReliableCommand("disconnect"); + CL_WritePacket(); + CL_WritePacket(); + CL_WritePacket(); + clc.cURLDisconnected = qtrue; + } +} + +void CL_cURL_PerformDownload(void) +{ + CURLMcode res; + CURLMsg *msg; + int c; + int i = 0; + + res = qcurl_multi_perform(clc.downloadCURLM, &c); + while(res == CURLM_CALL_MULTI_PERFORM && i < 100) { + res = qcurl_multi_perform(clc.downloadCURLM, &c); + i++; + } + if(res == CURLM_CALL_MULTI_PERFORM) + return; + msg = qcurl_multi_info_read(clc.downloadCURLM, &c); + if(msg == NULL) { + return; + } + FS_FCloseFile(clc.download); + if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) { + FS_SV_Rename(clc.downloadTempName, clc.downloadName); + } + else { + long code; + + //FS_Remove(clc.downloadTempName); + qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, + &code); + Com_Error(ERR_DROP, "Download Error: %s Code: %d URL: %s", + qcurl_easy_strerror(msg->data.result), + code, clc.downloadURL); + } + *clc.downloadTempName = *clc.downloadName = 0; + Cvar_Set( "cl_downloadName", "" ); + CL_NextDownload(); +} +#endif /* USE_CURL */ Index: code/client/client.h =================================================================== --- code/client/client.h (revision 881) +++ code/client/client.h (working copy) @@ -30,6 +30,10 @@ #include "../cgame/cg_public.h" #include "../game/bg_public.h" +#if USE_CURL +#include "cl_curl.h" +#endif /* USE_CURL */ + // tjw: file full of random crap that gets used to create cl_guid #define QKEY_FILE "qkey" @@ -185,6 +189,16 @@ fileHandle_t download; char downloadTempName[MAX_OSPATH]; char downloadName[MAX_OSPATH]; +#ifdef USE_CURL + qboolean cURLEnabled; + qboolean cURLDisconnected; + char downloadURL[MAX_OSPATH]; + CURL *downloadCURL; + CURLM *downloadCURLM; +#endif /* USE_CURL */ + int sv_allowDownload; + int sv_wwwDownload; + char sv_wwwBaseURL[MAX_CVAR_VALUE_STRING]; int downloadNumber; int downloadBlock; // block we are waiting for int downloadCount; // how many bytes we got @@ -351,6 +365,7 @@ extern cvar_t *cl_activeAction; extern cvar_t *cl_allowDownload; +extern cvar_t *cl_wwwDownload; extern cvar_t *cl_conXOffset; extern cvar_t *cl_inGameVideo; Index: code/client/cl_curl.h =================================================================== --- code/client/cl_curl.h (revision 0) +++ code/client/cl_curl.h (revision 0) @@ -0,0 +1,99 @@ +/* +=========================================================================== +Copyright (C) 2006 Tony J. White (tjw@tjw.org) + +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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + + +#ifndef __QCURL_H__ +#define __QCURL_H__ + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" + +#ifdef WIN32 +#define DEFAULT_CURL_LIB "libcurl-3.dll" +#elif defined(MACOS_X) +#define DEFAULT_CURL_LIB "libcurl.dylib" +#else +#define DEFAULT_CURL_LIB "libcurl.so" +#endif + +#if USE_LOCAL_HEADERS + #include "../libcurl/curl/curl.h" +#else + #include +#endif + + +#if USE_CURL_DLOPEN +extern char* (*qcurl_version)(void); + +extern CURL* (*qcurl_easy_init)(void); +extern CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...); +extern CURLcode (*qcurl_easy_perform)(CURL *curl); +extern void (*qcurl_easy_cleanup)(CURL *curl); +extern CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...); +extern void (*qcurl_easy_reset)(CURL *curl); +extern const char *(*qcurl_easy_strerror)(CURLcode); + +extern CURLM* (*qcurl_multi_init)(void); +extern CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle, + CURL *curl_handle); +extern CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle, + CURL *curl_handle); +extern CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); +extern CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle, + int *running_handles); +extern CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle); +extern CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle, + int *msgs_in_queue); +extern const char *(*qcurl_multi_strerror)(CURLMcode); +#else +#define qcurl_version curl_version + +#define qcurl_easy_init curl_easy_init +#define qcurl_easy_setopt curl_easy_setopt +#define qcurl_easy_perform curl_easy_perform +#define qcurl_easy_cleanup curl_easy_cleanup +#define qcurl_easy_getinfo curl_easy_getinfo +#define qcurl_easy_duphandle curl_easy_duphandle +#define qcurl_easy_reset curl_easy_reset +#define qcurl_easy_strerror curl_easy_strerror + +#define qcurl_multi_init curl_multi_init +#define qcurl_multi_add_handle curl_multi_add_handle +#define qcurl_multi_remove_handle curl_multi_remove_handle +#define qcurl_multi_fdset curl_multi_fdset +#define qcurl_multi_perform curl_multi_perform +#define qcurl_multi_cleanup curl_multi_cleanup +#define qcurl_multi_info_read curl_multi_info_read +#define qcurl_multi_strerror curl_multi_strerror +#endif + +qboolean CL_cURL_Init( void ); +void CL_cURL_Shutdown( void ); +void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ); +void CL_cURL_PerformDownload( void ); +void CL_cURL_Cleanup( void ); +#endif // __QCURL_H__ Index: code/client/cl_parse.c =================================================================== --- code/client/cl_parse.c (revision 881) +++ code/client/cl_parse.c (working copy) @@ -414,6 +414,27 @@ /* ================== +CL_ParseServerInfo +================== +*/ +static void CL_ParseServerInfo(void) +{ + const char *serverInfo; + + serverInfo = cl.gameState.stringData + + cl.gameState.stringOffsets[ CS_SERVERINFO ]; + + clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo, + "sv_allowDownload")); + clc.sv_wwwDownload = atoi(Info_ValueForKey(serverInfo, + "sv_wwwDownload")); + Q_strncpyz(clc.sv_wwwBaseURL, + Info_ValueForKey(serverInfo, "sv_wwwBaseURL"), + sizeof(clc.sv_wwwBaseURL)); +} + +/* +================== CL_ParseGamestate ================== */ @@ -479,6 +500,9 @@ // read the checksum feed clc.checksumFeed = MSG_ReadLong( msg ); + // parse useful values out of CS_SERVERINFO + CL_ParseServerInfo(); + // parse serverId and other cvars CL_SystemInfoChanged(); Index: code/client/cl_main.c =================================================================== --- code/client/cl_main.c (revision 881) +++ code/client/cl_main.c (working copy) @@ -66,6 +66,7 @@ cvar_t *cl_motdString; cvar_t *cl_allowDownload; +cvar_t *cl_wwwDownload; cvar_t *cl_conXOffset; cvar_t *cl_inGameVideo; @@ -608,6 +609,9 @@ */ void CL_ShutdownAll(void) { +#if USE_CURL + CL_cURL_Shutdown(); +#endif // clear sounds S_DisableSounds(); // shutdown CGame @@ -1331,6 +1335,18 @@ */ void CL_DownloadsComplete( void ) { +#if USE_CURL + // if we disconnected because of cURL + if( clc.cURLDisconnected ) { + CL_cURL_Shutdown(); + FS_Restart(clc.checksumFeed); + clc.downloadRestart = qfalse; + clc.cURLDisconnected = qfalse; + CL_Reconnect_f(); + return; + } +#endif + // if we downloaded files we need to restart the file system if (clc.downloadRestart) { clc.downloadRestart = qfalse; @@ -1415,9 +1431,10 @@ A download completed or failed ================= */ -void CL_NextDownload(void) { +void CL_NextDownload() { char *s; char *remoteName, *localName; + qboolean useCURL = qfalse; // We are looking to start a download here if (*clc.downloadList) { @@ -1441,8 +1458,33 @@ *s++ = 0; else s = localName + strlen(localName); // point at the nul byte - - CL_BeginDownload( localName, remoteName ); +#if USE_CURL + if( cl_wwwDownload->integer ) { + if(!clc.sv_allowDownload) + Com_Printf("cl_wwwDownload: server does not " + "allow downloads " + "(sv_allowDownload is 0)\n"); + else if(!clc.sv_wwwDownload) + Com_Printf("cl_wwwDownload: server does not " + "allow download redirection " + "(sv_wwwDownload is 0)\n"); + else if(!*clc.sv_wwwBaseURL) + Com_Printf("cl_wwwDownload: server does not " + "have sv_wwwBaseURL set\n"); + else if(!CL_cURL_Init()) { + Com_Printf("cl_wwwDownload: could not load " + "cURL library\n"); + } + else { + CL_cURL_BeginDownload(localName, va("%s/%s", + clc.sv_wwwBaseURL, remoteName)); + useCURL = qtrue; + } + } +#endif /* USE_CURL */ + if(!useCURL) { + CL_BeginDownload( localName, remoteName ); + } clc.downloadRestart = qtrue; @@ -2028,11 +2070,26 @@ return; } +#if USE_CURL + if(clc.downloadCURLM) { + CL_cURL_PerformDownload(); + cls.realFrametime = msec; + cls.frametime = msec; + cls.realtime += cls.frametime; + SCR_UpdateScreen(); + S_Update(); + Con_RunConsole(); + cls.framecount++; + return; + } +#endif + if ( cls.cddialog ) { // bring up the cd error dialog if needed cls.cddialog = qfalse; VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD ); - } else if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI ) + } + else if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI ) && !com_sv_running->integer ) { // if disconnected, bring up the menu S_StopAllSounds(); @@ -2478,6 +2535,7 @@ cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0); cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); + cl_wwwDownload = Cvar_Get ("cl_wwwDownload", "1", CVAR_ARCHIVE); cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); #ifdef MACOS_X Index: Makefile =================================================================== --- Makefile (revision 881) +++ Makefile (working copy) @@ -100,6 +100,18 @@ USE_OPENAL_DLOPEN=0 endif +ifndef USE_CURL +USE_CURL=1 +endif + +ifndef USE_CURL_DLOPEN + ifeq ($(COMPILE_PLATFORM),mingw32) + USE_CURL_DLOPEN=0 + else + USE_CURL_DLOPEN=1 + endif +endif + ifndef USE_CODEC_VORBIS USE_CODEC_VORBIS=0 endif @@ -187,6 +199,13 @@ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1 endif endif + + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL=1 + ifeq ($(USE_CURL_DLOPEN),1) + BASE_CFLAGS += -DUSE_CURL_DLOPEN=1 + endif + endif ifeq ($(USE_CODEC_VORBIS),1) BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 @@ -249,6 +268,12 @@ CLIENT_LDFLAGS += -lopenal endif endif + + ifeq ($(USE_CURL),1) + ifneq ($(USE_CURL_DLOPEN),1) + CLIENT_LDFLAGS += -lcurl + endif + endif ifeq ($(USE_CODEC_VORBIS),1) CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg @@ -347,6 +372,15 @@ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1 endif endif + + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL=1 + ifneq ($(USE_CURL_DLOPEN),1) + CLIENT_LDFLAGS += -lcurl + else + BASE_CFLAGS += -DUSE_CURL_DLOPEN=1 + endif + endif ifeq ($(USE_CODEC_VORBIS),1) BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 @@ -403,6 +437,13 @@ ifeq ($(USE_OPENAL),1) BASE_CFLAGS += -DUSE_OPENAL=1 -DUSE_OPENAL_DLOPEN=1 endif + + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL=1 + ifneq ($(USE_CURL_DLOPEN),1) + BASE_CFLAGS += -DCURL_STATICLIB + endif + endif ifeq ($(USE_CODEC_VORBIS),1) BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 @@ -429,6 +470,12 @@ LDFLAGS= -mwindows -lshfolder -lwsock32 -lgdi32 -lwinmm -lole32 CLIENT_LDFLAGS= + ifeq ($(USE_CURL),1) + ifneq ($(USE_CURL_DLOPEN),1) + CLIENT_LDFLAGS += -L$(LIBSDIR)/win32 -lcurl + endif + endif + ifeq ($(USE_CODEC_VORBIS),1) CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif @@ -846,6 +893,8 @@ $(B)/client/qal.o \ $(B)/client/snd_openal.o \ \ + $(B)/client/cl_curl.o \ + \ $(B)/client/sv_bot.o \ $(B)/client/sv_ccmds.o \ $(B)/client/sv_client.o \ @@ -1066,6 +1115,8 @@ $(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) $(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) +$(B)/client/cl_curl.o : $(CDIR)/cl_curl.c; $(DO_CC) + $(B)/client/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC) $(B)/client/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC) $(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC)